mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 21:38:32 +08:00
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:
parent
f11459ad7d
commit
348fe8da13
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user