nilfs2: simplify life cycle management of nilfs object

This stops pre-allocating nilfs object in nilfs_get_sb routine, and
stops managing its life cycle by reference counting.

nilfs_find_or_create_nilfs() function, nilfs->ns_mount_mutex,
nilfs_objects list, and the reference counter will be removed through
the simplification.

Signed-off-by: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
This commit is contained in:
Ryusuke Konishi 2010-09-09 02:07:56 +09:00
parent f11459ad7d
commit 348fe8da13
4 changed files with 32 additions and 132 deletions

View File

@ -117,7 +117,7 @@ static int nilfs_ioctl_change_cpmode(struct inode *inode, struct file *filp,
if (copy_from_user(&cpmode, argp, sizeof(cpmode))) if (copy_from_user(&cpmode, argp, sizeof(cpmode)))
goto out; goto out;
mutex_lock(&nilfs->ns_mount_mutex); down_read(&inode->i_sb->s_umount);
nilfs_transaction_begin(inode->i_sb, &ti, 0); nilfs_transaction_begin(inode->i_sb, &ti, 0);
ret = nilfs_cpfile_change_cpmode( ret = nilfs_cpfile_change_cpmode(
@ -127,7 +127,7 @@ static int nilfs_ioctl_change_cpmode(struct inode *inode, struct file *filp,
else else
nilfs_transaction_commit(inode->i_sb); /* never fails */ nilfs_transaction_commit(inode->i_sb); /* never fails */
mutex_unlock(&nilfs->ns_mount_mutex); up_read(&inode->i_sb->s_umount);
out: out:
mnt_drop_write(filp->f_path.mnt); mnt_drop_write(filp->f_path.mnt);
return ret; return ret;

View File

@ -356,7 +356,7 @@ static void nilfs_put_super(struct super_block *sb)
up_write(&nilfs->ns_sem); up_write(&nilfs->ns_sem);
} }
put_nilfs(sbi->s_nilfs); destroy_nilfs(nilfs);
sbi->s_super = NULL; sbi->s_super = NULL;
sb->s_fs_info = NULL; sb->s_fs_info = NULL;
kfree(sbi); kfree(sbi);
@ -836,15 +836,14 @@ static int nilfs_try_to_shrink_tree(struct dentry *root_dentry)
* @sb: super_block * @sb: super_block
* @data: mount options * @data: mount options
* @silent: silent mode flag * @silent: silent mode flag
* @nilfs: the_nilfs struct
* *
* This function is called exclusively by nilfs->ns_mount_mutex. * This function is called exclusively by nilfs->ns_mount_mutex.
* So, the recovery process is protected from other simultaneous mounts. * So, the recovery process is protected from other simultaneous mounts.
*/ */
static int static int
nilfs_fill_super(struct super_block *sb, void *data, int silent, nilfs_fill_super(struct super_block *sb, void *data, int silent)
struct the_nilfs *nilfs)
{ {
struct the_nilfs *nilfs;
struct nilfs_sb_info *sbi; struct nilfs_sb_info *sbi;
struct nilfs_root *fsroot; struct nilfs_root *fsroot;
__u64 cno; __u64 cno;
@ -855,14 +854,18 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent,
return -ENOMEM; return -ENOMEM;
sb->s_fs_info = sbi; sb->s_fs_info = sbi;
get_nilfs(nilfs);
sbi->s_nilfs = nilfs;
sbi->s_super = sb; sbi->s_super = sb;
nilfs = alloc_nilfs(sb->s_bdev);
if (!nilfs) {
err = -ENOMEM;
goto failed_sbi;
}
sbi->s_nilfs = nilfs;
err = init_nilfs(nilfs, sbi, (char *)data); err = init_nilfs(nilfs, sbi, (char *)data);
if (err) if (err)
goto failed_sbi; goto failed_nilfs;
spin_lock_init(&sbi->s_inode_lock); spin_lock_init(&sbi->s_inode_lock);
INIT_LIST_HEAD(&sbi->s_dirty_files); INIT_LIST_HEAD(&sbi->s_dirty_files);
@ -885,14 +888,14 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent,
err = load_nilfs(nilfs, sbi); err = load_nilfs(nilfs, sbi);
if (err) if (err)
goto failed_sbi; goto failed_nilfs;
cno = nilfs_last_cno(nilfs); cno = nilfs_last_cno(nilfs);
err = nilfs_attach_checkpoint(sbi, cno, true, &fsroot); err = nilfs_attach_checkpoint(sbi, cno, true, &fsroot);
if (err) { if (err) {
printk(KERN_ERR "NILFS: error loading last checkpoint " printk(KERN_ERR "NILFS: error loading last checkpoint "
"(checkpoint number=%llu).\n", (unsigned long long)cno); "(checkpoint number=%llu).\n", (unsigned long long)cno);
goto failed_sbi; goto failed_nilfs;
} }
if (!(sb->s_flags & MS_RDONLY)) { if (!(sb->s_flags & MS_RDONLY)) {
@ -921,8 +924,10 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent,
failed_checkpoint: failed_checkpoint:
nilfs_put_root(fsroot); nilfs_put_root(fsroot);
failed_nilfs:
destroy_nilfs(nilfs);
failed_sbi: failed_sbi:
put_nilfs(nilfs);
sb->s_fs_info = NULL; sb->s_fs_info = NULL;
kfree(sbi); kfree(sbi);
return err; return err;
@ -1077,7 +1082,6 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags,
struct nilfs_super_data sd; struct nilfs_super_data sd;
struct super_block *s; struct super_block *s;
fmode_t mode = FMODE_READ; fmode_t mode = FMODE_READ;
struct the_nilfs *nilfs;
struct dentry *root_dentry; struct dentry *root_dentry;
int err, s_new = false; int err, s_new = false;
@ -1095,18 +1099,10 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags,
goto failed; goto failed;
} }
nilfs = find_or_create_nilfs(sd.bdev);
if (!nilfs) {
err = -ENOMEM;
goto failed;
}
mutex_lock(&nilfs->ns_mount_mutex);
s = sget(fs_type, nilfs_test_bdev_super, nilfs_set_bdev_super, sd.bdev); s = sget(fs_type, nilfs_test_bdev_super, nilfs_set_bdev_super, sd.bdev);
if (IS_ERR(s)) { if (IS_ERR(s)) {
err = PTR_ERR(s); err = PTR_ERR(s);
goto failed_unlock; goto failed;
} }
if (!s->s_root) { if (!s->s_root) {
@ -1120,10 +1116,9 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags,
strlcpy(s->s_id, bdevname(sd.bdev, b), sizeof(s->s_id)); strlcpy(s->s_id, bdevname(sd.bdev, b), sizeof(s->s_id));
sb_set_blocksize(s, block_size(sd.bdev)); sb_set_blocksize(s, block_size(sd.bdev));
err = nilfs_fill_super(s, data, flags & MS_SILENT ? 1 : 0, err = nilfs_fill_super(s, data, flags & MS_SILENT ? 1 : 0);
nilfs);
if (err) if (err)
goto cancel_new; goto failed_super;
s->s_flags |= MS_ACTIVE; s->s_flags |= MS_ACTIVE;
} else if (!sd.cno) { } else if (!sd.cno) {
@ -1153,17 +1148,12 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags,
if (sd.cno) { if (sd.cno) {
err = nilfs_attach_snapshot(s, sd.cno, &root_dentry); err = nilfs_attach_snapshot(s, sd.cno, &root_dentry);
if (err) { if (err)
if (s_new)
goto cancel_new;
goto failed_super; goto failed_super;
}
} else { } else {
root_dentry = dget(s->s_root); root_dentry = dget(s->s_root);
} }
mutex_unlock(&nilfs->ns_mount_mutex);
put_nilfs(nilfs);
if (!s_new) if (!s_new)
close_bdev_exclusive(sd.bdev, mode); close_bdev_exclusive(sd.bdev, mode);
@ -1173,23 +1163,10 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags,
failed_super: failed_super:
deactivate_locked_super(s); deactivate_locked_super(s);
failed_unlock:
mutex_unlock(&nilfs->ns_mount_mutex);
put_nilfs(nilfs);
failed:
close_bdev_exclusive(sd.bdev, mode);
return err;
cancel_new: failed:
/* Abandoning the newly allocated superblock */ if (!s_new)
mutex_unlock(&nilfs->ns_mount_mutex); close_bdev_exclusive(sd.bdev, mode);
put_nilfs(nilfs);
deactivate_locked_super(s);
/*
* This deactivate_locked_super() invokes close_bdev_exclusive().
* We must finish all post-cleaning before this call;
* put_nilfs() needs the block device.
*/
return err; return err;
} }

View File

@ -35,9 +35,6 @@
#include "segbuf.h" #include "segbuf.h"
static LIST_HEAD(nilfs_objects);
static DEFINE_SPINLOCK(nilfs_lock);
static int nilfs_valid_sb(struct nilfs_super_block *sbp); static int nilfs_valid_sb(struct nilfs_super_block *sbp);
void nilfs_set_last_segment(struct the_nilfs *nilfs, void nilfs_set_last_segment(struct the_nilfs *nilfs,
@ -61,16 +58,13 @@ void nilfs_set_last_segment(struct the_nilfs *nilfs,
} }
/** /**
* alloc_nilfs - allocate the_nilfs structure * alloc_nilfs - allocate a nilfs object
* @bdev: block device to which the_nilfs is related * @bdev: block device to which the_nilfs is related
* *
* alloc_nilfs() allocates memory for the_nilfs and
* initializes its reference count and locks.
*
* Return Value: On success, pointer to the_nilfs is returned. * Return Value: On success, pointer to the_nilfs is returned.
* On error, NULL is returned. * On error, NULL is returned.
*/ */
static struct the_nilfs *alloc_nilfs(struct block_device *bdev) struct the_nilfs *alloc_nilfs(struct block_device *bdev)
{ {
struct the_nilfs *nilfs; struct the_nilfs *nilfs;
@ -79,12 +73,9 @@ static struct the_nilfs *alloc_nilfs(struct block_device *bdev)
return NULL; return NULL;
nilfs->ns_bdev = bdev; nilfs->ns_bdev = bdev;
atomic_set(&nilfs->ns_count, 1);
atomic_set(&nilfs->ns_ndirtyblks, 0); atomic_set(&nilfs->ns_ndirtyblks, 0);
init_rwsem(&nilfs->ns_sem); init_rwsem(&nilfs->ns_sem);
mutex_init(&nilfs->ns_mount_mutex);
init_rwsem(&nilfs->ns_writer_sem); init_rwsem(&nilfs->ns_writer_sem);
INIT_LIST_HEAD(&nilfs->ns_list);
INIT_LIST_HEAD(&nilfs->ns_gc_inodes); INIT_LIST_HEAD(&nilfs->ns_gc_inodes);
spin_lock_init(&nilfs->ns_last_segment_lock); spin_lock_init(&nilfs->ns_last_segment_lock);
nilfs->ns_cptree = RB_ROOT; nilfs->ns_cptree = RB_ROOT;
@ -95,67 +86,11 @@ static struct the_nilfs *alloc_nilfs(struct block_device *bdev)
} }
/** /**
* find_or_create_nilfs - find or create nilfs object * destroy_nilfs - destroy nilfs object
* @bdev: block device to which the_nilfs is related * @nilfs: nilfs object to be released
*
* find_nilfs() looks up an existent nilfs object created on the
* device and gets the reference count of the object. If no nilfs object
* is found on the device, a new nilfs object is allocated.
*
* Return Value: On success, pointer to the nilfs object is returned.
* On error, NULL is returned.
*/ */
struct the_nilfs *find_or_create_nilfs(struct block_device *bdev) void destroy_nilfs(struct the_nilfs *nilfs)
{ {
struct the_nilfs *nilfs, *new = NULL;
retry:
spin_lock(&nilfs_lock);
list_for_each_entry(nilfs, &nilfs_objects, ns_list) {
if (nilfs->ns_bdev == bdev) {
get_nilfs(nilfs);
spin_unlock(&nilfs_lock);
if (new)
put_nilfs(new);
return nilfs; /* existing object */
}
}
if (new) {
list_add_tail(&new->ns_list, &nilfs_objects);
spin_unlock(&nilfs_lock);
return new; /* new object */
}
spin_unlock(&nilfs_lock);
new = alloc_nilfs(bdev);
if (new)
goto retry;
return NULL; /* insufficient memory */
}
/**
* put_nilfs - release a reference to the_nilfs
* @nilfs: the_nilfs structure to be released
*
* put_nilfs() decrements a reference counter of the_nilfs.
* If the reference count reaches zero, the_nilfs is freed.
*/
void put_nilfs(struct the_nilfs *nilfs)
{
spin_lock(&nilfs_lock);
if (!atomic_dec_and_test(&nilfs->ns_count)) {
spin_unlock(&nilfs_lock);
return;
}
list_del_init(&nilfs->ns_list);
spin_unlock(&nilfs_lock);
/*
* Increment of ns_count never occurs below because the caller
* of get_nilfs() holds at least one reference to the_nilfs.
* Thus its exclusion control is not required here.
*/
might_sleep(); might_sleep();
if (nilfs_loaded(nilfs)) { if (nilfs_loaded(nilfs)) {
nilfs_mdt_destroy(nilfs->ns_sufile); nilfs_mdt_destroy(nilfs->ns_sufile);

View File

@ -46,13 +46,10 @@ enum {
/** /**
* struct the_nilfs - struct to supervise multiple nilfs mount points * struct the_nilfs - struct to supervise multiple nilfs mount points
* @ns_flags: flags * @ns_flags: flags
* @ns_count: reference count
* @ns_list: list head for nilfs_list
* @ns_bdev: block device * @ns_bdev: block device
* @ns_bdi: backing dev info * @ns_bdi: backing dev info
* @ns_writer: back pointer to writable nilfs_sb_info * @ns_writer: back pointer to writable nilfs_sb_info
* @ns_sem: semaphore for shared states * @ns_sem: semaphore for shared states
* @ns_mount_mutex: mutex protecting mount process of nilfs
* @ns_writer_sem: semaphore protecting ns_writer attach/detach * @ns_writer_sem: semaphore protecting ns_writer attach/detach
* @ns_sbh: buffer heads of on-disk super blocks * @ns_sbh: buffer heads of on-disk super blocks
* @ns_sbp: pointers to super block data * @ns_sbp: pointers to super block data
@ -94,14 +91,11 @@ enum {
*/ */
struct the_nilfs { struct the_nilfs {
unsigned long ns_flags; unsigned long ns_flags;
atomic_t ns_count;
struct list_head ns_list;
struct block_device *ns_bdev; struct block_device *ns_bdev;
struct backing_dev_info *ns_bdi; struct backing_dev_info *ns_bdi;
struct nilfs_sb_info *ns_writer; struct nilfs_sb_info *ns_writer;
struct rw_semaphore ns_sem; struct rw_semaphore ns_sem;
struct mutex ns_mount_mutex;
struct rw_semaphore ns_writer_sem; struct rw_semaphore ns_writer_sem;
/* /*
@ -239,8 +233,8 @@ static inline int nilfs_sb_will_flip(struct the_nilfs *nilfs)
} }
void nilfs_set_last_segment(struct the_nilfs *, sector_t, u64, __u64); void nilfs_set_last_segment(struct the_nilfs *, sector_t, u64, __u64);
struct the_nilfs *find_or_create_nilfs(struct block_device *); struct the_nilfs *alloc_nilfs(struct block_device *bdev);
void put_nilfs(struct the_nilfs *); void destroy_nilfs(struct the_nilfs *nilfs);
int init_nilfs(struct the_nilfs *, struct nilfs_sb_info *, char *); int init_nilfs(struct the_nilfs *, struct nilfs_sb_info *, char *);
int load_nilfs(struct the_nilfs *, struct nilfs_sb_info *); int load_nilfs(struct the_nilfs *, struct nilfs_sb_info *);
int nilfs_discard_segments(struct the_nilfs *, __u64 *, size_t); int nilfs_discard_segments(struct the_nilfs *, __u64 *, size_t);
@ -256,12 +250,6 @@ void nilfs_fall_back_super_block(struct the_nilfs *);
void nilfs_swap_super_block(struct the_nilfs *); void nilfs_swap_super_block(struct the_nilfs *);
static inline void get_nilfs(struct the_nilfs *nilfs)
{
/* Caller must have at least one reference of the_nilfs. */
atomic_inc(&nilfs->ns_count);
}
static inline void nilfs_get_root(struct nilfs_root *root) static inline void nilfs_get_root(struct nilfs_root *root)
{ {
atomic_inc(&root->count); atomic_inc(&root->count);