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: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp> Cc: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
81fc20bd0e
commit
33c8e57c86
|
@ -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,
|
||||||
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,
|
||||||
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,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Phase-1: search any existent instance and get the_nilfs
|
* Search specified snapshot or R/W mode super_block
|
||||||
*/
|
*/
|
||||||
|
if (!sd.cno)
|
||||||
|
/* trying to get the latest checkpoint. */
|
||||||
|
sd.cno = nilfs_last_cno(nilfs);
|
||||||
|
|
||||||
s = sget(fs_type, nilfs_test_bdev_super, nilfs_set_bdev_super, &sd);
|
s = sget(fs_type, nilfs_test_bdev_super, nilfs_set_bdev_super, &sd);
|
||||||
if (IS_ERR(s))
|
if (IS_ERR(s)) {
|
||||||
goto error_s;
|
err = PTR_ERR(s);
|
||||||
|
goto failed_unlock;
|
||||||
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_umount protects super_block from unmount process;
|
|
||||||
* It covers pointers of nilfs_sb_info and the_nilfs.
|
|
||||||
*/
|
|
||||||
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,
|
||||||
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,
|
||||||
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 @@
|
||||||
#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,
|
||||||
* 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)
|
||||||
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)
|
||||||
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)
|
||||||
*/
|
*/
|
||||||
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 {
|
||||||
* 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 {
|
||||||
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)
|
||||||
#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 *);
|
||||||
|
|
Loading…
Reference in a new issue