Commit 33c8e57c authored by Ryusuke Konishi's avatar Ryusuke Konishi Committed by Al Viro

nilfs2: get rid of sget use for acquiring nilfs object

This will change the way to obtain nilfs object in nilfs_get_sb()
function.

Previously, a preliminary sget() call was performed, and the nilfs
object was acquired from a super block instance found by the sget()
call.

This patch, instead, instroduces a new dedicated function
find_or_create_nilfs(); as the name implies, the function finds an
existent nilfs object from a global list or creates a new one if no
object is found on the device.
Signed-off-by: default avatarRyusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 81fc20bd
...@@ -1059,13 +1059,6 @@ static int nilfs_set_bdev_super(struct super_block *s, void *data) ...@@ -1059,13 +1059,6 @@ static int nilfs_set_bdev_super(struct super_block *s, void *data)
} }
static int nilfs_test_bdev_super(struct super_block *s, void *data) static int nilfs_test_bdev_super(struct super_block *s, void *data)
{
struct nilfs_super_data *sd = data;
return s->s_bdev == sd->bdev;
}
static int nilfs_test_bdev_super2(struct super_block *s, void *data)
{ {
struct nilfs_super_data *sd = data; struct nilfs_super_data *sd = data;
int ret; int ret;
...@@ -1096,8 +1089,8 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, ...@@ -1096,8 +1089,8 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags,
const char *dev_name, void *data, struct vfsmount *mnt) const char *dev_name, void *data, struct vfsmount *mnt)
{ {
struct nilfs_super_data sd; struct nilfs_super_data sd;
struct super_block *s, *s2; struct super_block *s;
struct the_nilfs *nilfs = NULL; struct the_nilfs *nilfs;
int err, need_to_close = 1; int err, need_to_close = 1;
sd.bdev = open_bdev_exclusive(dev_name, flags, fs_type); sd.bdev = open_bdev_exclusive(dev_name, flags, fs_type);
...@@ -1118,11 +1111,12 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, ...@@ -1118,11 +1111,12 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags,
goto failed; goto failed;
} }
/* nilfs = find_or_create_nilfs(sd.bdev);
* once the super is inserted into the list by sget, s_umount if (!nilfs) {
* will protect the lockfs code from trying to start a snapshot err = -ENOMEM;
* while we are mounting goto failed;
*/ }
down(&sd.bdev->bd_mount_sem); down(&sd.bdev->bd_mount_sem);
if (!sd.cno && if (!sd.cno &&
(err = test_exclusive_mount(fs_type, sd.bdev, flags ^ MS_RDONLY))) { (err = test_exclusive_mount(fs_type, sd.bdev, flags ^ MS_RDONLY))) {
...@@ -1131,51 +1125,22 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, ...@@ -1131,51 +1125,22 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags,
} }
/* /*
* Phase-1: search any existent instance and get the_nilfs * Search specified snapshot or R/W mode super_block
*/ */
s = sget(fs_type, nilfs_test_bdev_super, nilfs_set_bdev_super, &sd); if (!sd.cno)
if (IS_ERR(s)) /* trying to get the latest checkpoint. */
goto error_s; sd.cno = nilfs_last_cno(nilfs);
if (!s->s_root) {
err = -ENOMEM;
nilfs = alloc_nilfs(sd.bdev);
if (!nilfs)
goto cancel_new;
} else {
struct nilfs_sb_info *sbi = NILFS_SB(s);
/* s = sget(fs_type, nilfs_test_bdev_super, nilfs_set_bdev_super, &sd);
* s_umount protects super_block from unmount process; if (IS_ERR(s)) {
* It covers pointers of nilfs_sb_info and the_nilfs. err = PTR_ERR(s);
*/ goto failed_unlock;
nilfs = sbi->s_nilfs;
get_nilfs(nilfs);
up_write(&s->s_umount);
/*
* Phase-2: search specified snapshot or R/W mode super_block
*/
if (!sd.cno)
/* trying to get the latest checkpoint. */
sd.cno = nilfs_last_cno(nilfs);
s2 = sget(fs_type, nilfs_test_bdev_super2,
nilfs_set_bdev_super, &sd);
deactivate_super(s);
/*
* Although deactivate_super() invokes close_bdev_exclusive() at
* kill_block_super(). Here, s is an existent mount; we need
* one more close_bdev_exclusive() call.
*/
s = s2;
if (IS_ERR(s))
goto error_s;
} }
if (!s->s_root) { if (!s->s_root) {
char b[BDEVNAME_SIZE]; char b[BDEVNAME_SIZE];
/* New superblock instance created */
s->s_flags = flags; s->s_flags = 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));
...@@ -1195,15 +1160,9 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, ...@@ -1195,15 +1160,9 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags,
simple_set_mnt(mnt, s); simple_set_mnt(mnt, s);
return 0; return 0;
error_s:
up(&sd.bdev->bd_mount_sem);
if (nilfs)
put_nilfs(nilfs);
close_bdev_exclusive(sd.bdev, flags);
return PTR_ERR(s);
failed_unlock: failed_unlock:
up(&sd.bdev->bd_mount_sem); up(&sd.bdev->bd_mount_sem);
put_nilfs(nilfs);
failed: failed:
close_bdev_exclusive(sd.bdev, flags); close_bdev_exclusive(sd.bdev, flags);
...@@ -1212,8 +1171,7 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, ...@@ -1212,8 +1171,7 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags,
cancel_new: cancel_new:
/* Abandoning the newly allocated superblock */ /* Abandoning the newly allocated superblock */
up(&sd.bdev->bd_mount_sem); up(&sd.bdev->bd_mount_sem);
if (nilfs) put_nilfs(nilfs);
put_nilfs(nilfs);
up_write(&s->s_umount); up_write(&s->s_umount);
deactivate_super(s); deactivate_super(s);
/* /*
......
...@@ -35,6 +35,10 @@ ...@@ -35,6 +35,10 @@
#include "seglist.h" #include "seglist.h"
#include "segbuf.h" #include "segbuf.h"
static LIST_HEAD(nilfs_objects);
static DEFINE_SPINLOCK(nilfs_lock);
void nilfs_set_last_segment(struct the_nilfs *nilfs, void nilfs_set_last_segment(struct the_nilfs *nilfs,
sector_t start_blocknr, u64 seq, __u64 cno) sector_t start_blocknr, u64 seq, __u64 cno)
{ {
...@@ -55,7 +59,7 @@ void nilfs_set_last_segment(struct the_nilfs *nilfs, ...@@ -55,7 +59,7 @@ void nilfs_set_last_segment(struct the_nilfs *nilfs,
* 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.
*/ */
struct the_nilfs *alloc_nilfs(struct block_device *bdev) static struct the_nilfs *alloc_nilfs(struct block_device *bdev)
{ {
struct the_nilfs *nilfs; struct the_nilfs *nilfs;
...@@ -69,6 +73,7 @@ struct the_nilfs *alloc_nilfs(struct block_device *bdev) ...@@ -69,6 +73,7 @@ struct the_nilfs *alloc_nilfs(struct block_device *bdev)
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_writer_mutex); mutex_init(&nilfs->ns_writer_mutex);
INIT_LIST_HEAD(&nilfs->ns_list);
INIT_LIST_HEAD(&nilfs->ns_supers); INIT_LIST_HEAD(&nilfs->ns_supers);
spin_lock_init(&nilfs->ns_last_segment_lock); spin_lock_init(&nilfs->ns_last_segment_lock);
nilfs->ns_gc_inodes_h = NULL; nilfs->ns_gc_inodes_h = NULL;
...@@ -77,6 +82,45 @@ struct the_nilfs *alloc_nilfs(struct block_device *bdev) ...@@ -77,6 +82,45 @@ struct the_nilfs *alloc_nilfs(struct block_device *bdev)
return nilfs; return nilfs;
} }
/**
* find_or_create_nilfs - find or create nilfs object
* @bdev: block device to which the_nilfs is related
*
* 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)
{
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 * put_nilfs - release a reference to the_nilfs
* @nilfs: the_nilfs structure to be released * @nilfs: the_nilfs structure to be released
...@@ -86,13 +130,20 @@ struct the_nilfs *alloc_nilfs(struct block_device *bdev) ...@@ -86,13 +130,20 @@ struct the_nilfs *alloc_nilfs(struct block_device *bdev)
*/ */
void put_nilfs(struct the_nilfs *nilfs) void put_nilfs(struct the_nilfs *nilfs)
{ {
if (!atomic_dec_and_test(&nilfs->ns_count)) spin_lock(&nilfs_lock);
if (!atomic_dec_and_test(&nilfs->ns_count)) {
spin_unlock(&nilfs_lock);
return; return;
}
list_del_init(&nilfs->ns_list);
spin_unlock(&nilfs_lock);
/* /*
* Increment of ns_count never occur below because the caller * Increment of ns_count never occurs below because the caller
* of get_nilfs() holds at least one reference to the_nilfs. * of get_nilfs() holds at least one reference to the_nilfs.
* Thus its exclusion control is not required here. * Thus its exclusion control is not required here.
*/ */
might_sleep(); might_sleep();
if (nilfs_loaded(nilfs)) { if (nilfs_loaded(nilfs)) {
nilfs_mdt_clear(nilfs->ns_sufile); nilfs_mdt_clear(nilfs->ns_sufile);
......
...@@ -43,6 +43,7 @@ enum { ...@@ -43,6 +43,7 @@ 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_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
...@@ -88,6 +89,7 @@ enum { ...@@ -88,6 +89,7 @@ enum {
struct the_nilfs { struct the_nilfs {
unsigned long ns_flags; unsigned long ns_flags;
atomic_t ns_count; 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;
...@@ -191,7 +193,7 @@ THE_NILFS_FNS(DISCONTINUED, discontinued) ...@@ -191,7 +193,7 @@ THE_NILFS_FNS(DISCONTINUED, discontinued)
#define NILFS_ALTSB_FREQ 60 /* spare superblock */ #define NILFS_ALTSB_FREQ 60 /* spare superblock */
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 *alloc_nilfs(struct block_device *); struct the_nilfs *find_or_create_nilfs(struct block_device *);
void put_nilfs(struct the_nilfs *); void put_nilfs(struct the_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 *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment