aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRyusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>2010-09-08 13:07:56 -0400
committerRyusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>2010-10-22 20:24:36 -0400
commit348fe8da13621b3d14ab2d156e74551611997017 (patch)
tree82e60058d2af36e5f6e8bb7851b5b25ba3e72909
parentf11459ad7dab9e9eb5a05b8bd3bec338ea8f485d (diff)
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>
-rw-r--r--fs/nilfs2/ioctl.c4
-rw-r--r--fs/nilfs2/super.c67
-rw-r--r--fs/nilfs2/the_nilfs.c75
-rw-r--r--fs/nilfs2/the_nilfs.h16
4 files changed, 31 insertions, 131 deletions
diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c
index 2ee6843c2e87..338858fc907c 100644
--- a/fs/nilfs2/ioctl.c
+++ b/fs/nilfs2/ioctl.c
@@ -117,7 +117,7 @@ static int nilfs_ioctl_change_cpmode(struct inode *inode, struct file *filp,
117 if (copy_from_user(&cpmode, argp, sizeof(cpmode))) 117 if (copy_from_user(&cpmode, argp, sizeof(cpmode)))
118 goto out; 118 goto out;
119 119
120 mutex_lock(&nilfs->ns_mount_mutex); 120 down_read(&inode->i_sb->s_umount);
121 121
122 nilfs_transaction_begin(inode->i_sb, &ti, 0); 122 nilfs_transaction_begin(inode->i_sb, &ti, 0);
123 ret = nilfs_cpfile_change_cpmode( 123 ret = nilfs_cpfile_change_cpmode(
@@ -127,7 +127,7 @@ static int nilfs_ioctl_change_cpmode(struct inode *inode, struct file *filp,
127 else 127 else
128 nilfs_transaction_commit(inode->i_sb); /* never fails */ 128 nilfs_transaction_commit(inode->i_sb); /* never fails */
129 129
130 mutex_unlock(&nilfs->ns_mount_mutex); 130 up_read(&inode->i_sb->s_umount);
131out: 131out:
132 mnt_drop_write(filp->f_path.mnt); 132 mnt_drop_write(filp->f_path.mnt);
133 return ret; 133 return ret;
diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c
index 2e58e7c629b5..5893cb27c909 100644
--- a/fs/nilfs2/super.c
+++ b/fs/nilfs2/super.c
@@ -356,7 +356,7 @@ static void nilfs_put_super(struct super_block *sb)
356 up_write(&nilfs->ns_sem); 356 up_write(&nilfs->ns_sem);
357 } 357 }
358 358
359 put_nilfs(sbi->s_nilfs); 359 destroy_nilfs(nilfs);
360 sbi->s_super = NULL; 360 sbi->s_super = NULL;
361 sb->s_fs_info = NULL; 361 sb->s_fs_info = NULL;
362 kfree(sbi); 362 kfree(sbi);
@@ -836,15 +836,14 @@ static int nilfs_try_to_shrink_tree(struct dentry *root_dentry)
836 * @sb: super_block 836 * @sb: super_block
837 * @data: mount options 837 * @data: mount options
838 * @silent: silent mode flag 838 * @silent: silent mode flag
839 * @nilfs: the_nilfs struct
840 * 839 *
841 * This function is called exclusively by nilfs->ns_mount_mutex. 840 * This function is called exclusively by nilfs->ns_mount_mutex.
842 * So, the recovery process is protected from other simultaneous mounts. 841 * So, the recovery process is protected from other simultaneous mounts.
843 */ 842 */
844static int 843static int
845nilfs_fill_super(struct super_block *sb, void *data, int silent, 844nilfs_fill_super(struct super_block *sb, void *data, int silent)
846 struct the_nilfs *nilfs)
847{ 845{
846 struct the_nilfs *nilfs;
848 struct nilfs_sb_info *sbi; 847 struct nilfs_sb_info *sbi;
849 struct nilfs_root *fsroot; 848 struct nilfs_root *fsroot;
850 __u64 cno; 849 __u64 cno;
@@ -855,14 +854,18 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent,
855 return -ENOMEM; 854 return -ENOMEM;
856 855
857 sb->s_fs_info = sbi; 856 sb->s_fs_info = sbi;
857 sbi->s_super = sb;
858 858
859 get_nilfs(nilfs); 859 nilfs = alloc_nilfs(sb->s_bdev);
860 if (!nilfs) {
861 err = -ENOMEM;
862 goto failed_sbi;
863 }
860 sbi->s_nilfs = nilfs; 864 sbi->s_nilfs = nilfs;
861 sbi->s_super = sb;
862 865
863 err = init_nilfs(nilfs, sbi, (char *)data); 866 err = init_nilfs(nilfs, sbi, (char *)data);
864 if (err) 867 if (err)
865 goto failed_sbi; 868 goto failed_nilfs;
866 869
867 spin_lock_init(&sbi->s_inode_lock); 870 spin_lock_init(&sbi->s_inode_lock);
868 INIT_LIST_HEAD(&sbi->s_dirty_files); 871 INIT_LIST_HEAD(&sbi->s_dirty_files);
@@ -885,14 +888,14 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent,
885 888
886 err = load_nilfs(nilfs, sbi); 889 err = load_nilfs(nilfs, sbi);
887 if (err) 890 if (err)
888 goto failed_sbi; 891 goto failed_nilfs;
889 892
890 cno = nilfs_last_cno(nilfs); 893 cno = nilfs_last_cno(nilfs);
891 err = nilfs_attach_checkpoint(sbi, cno, true, &fsroot); 894 err = nilfs_attach_checkpoint(sbi, cno, true, &fsroot);
892 if (err) { 895 if (err) {
893 printk(KERN_ERR "NILFS: error loading last checkpoint " 896 printk(KERN_ERR "NILFS: error loading last checkpoint "
894 "(checkpoint number=%llu).\n", (unsigned long long)cno); 897 "(checkpoint number=%llu).\n", (unsigned long long)cno);
895 goto failed_sbi; 898 goto failed_nilfs;
896 } 899 }
897 900
898 if (!(sb->s_flags & MS_RDONLY)) { 901 if (!(sb->s_flags & MS_RDONLY)) {
@@ -921,8 +924,10 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent,
921 failed_checkpoint: 924 failed_checkpoint:
922 nilfs_put_root(fsroot); 925 nilfs_put_root(fsroot);
923 926
927 failed_nilfs:
928 destroy_nilfs(nilfs);
929
924 failed_sbi: 930 failed_sbi:
925 put_nilfs(nilfs);
926 sb->s_fs_info = NULL; 931 sb->s_fs_info = NULL;
927 kfree(sbi); 932 kfree(sbi);
928 return err; 933 return err;
@@ -1077,7 +1082,6 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags,
1077 struct nilfs_super_data sd; 1082 struct nilfs_super_data sd;
1078 struct super_block *s; 1083 struct super_block *s;
1079 fmode_t mode = FMODE_READ; 1084 fmode_t mode = FMODE_READ;
1080 struct the_nilfs *nilfs;
1081 struct dentry *root_dentry; 1085 struct dentry *root_dentry;
1082 int err, s_new = false; 1086 int err, s_new = false;
1083 1087
@@ -1095,18 +1099,10 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags,
1095 goto failed; 1099 goto failed;
1096 } 1100 }
1097 1101
1098 nilfs = find_or_create_nilfs(sd.bdev);
1099 if (!nilfs) {
1100 err = -ENOMEM;
1101 goto failed;
1102 }
1103
1104 mutex_lock(&nilfs->ns_mount_mutex);
1105
1106 s = sget(fs_type, nilfs_test_bdev_super, nilfs_set_bdev_super, sd.bdev); 1102 s = sget(fs_type, nilfs_test_bdev_super, nilfs_set_bdev_super, sd.bdev);
1107 if (IS_ERR(s)) { 1103 if (IS_ERR(s)) {
1108 err = PTR_ERR(s); 1104 err = PTR_ERR(s);
1109 goto failed_unlock; 1105 goto failed;
1110 } 1106 }
1111 1107
1112 if (!s->s_root) { 1108 if (!s->s_root) {
@@ -1120,10 +1116,9 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags,
1120 strlcpy(s->s_id, bdevname(sd.bdev, b), sizeof(s->s_id)); 1116 strlcpy(s->s_id, bdevname(sd.bdev, b), sizeof(s->s_id));
1121 sb_set_blocksize(s, block_size(sd.bdev)); 1117 sb_set_blocksize(s, block_size(sd.bdev));
1122 1118
1123 err = nilfs_fill_super(s, data, flags & MS_SILENT ? 1 : 0, 1119 err = nilfs_fill_super(s, data, flags & MS_SILENT ? 1 : 0);
1124 nilfs);
1125 if (err) 1120 if (err)
1126 goto cancel_new; 1121 goto failed_super;
1127 1122
1128 s->s_flags |= MS_ACTIVE; 1123 s->s_flags |= MS_ACTIVE;
1129 } else if (!sd.cno) { 1124 } else if (!sd.cno) {
@@ -1153,17 +1148,12 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags,
1153 1148
1154 if (sd.cno) { 1149 if (sd.cno) {
1155 err = nilfs_attach_snapshot(s, sd.cno, &root_dentry); 1150 err = nilfs_attach_snapshot(s, sd.cno, &root_dentry);
1156 if (err) { 1151 if (err)
1157 if (s_new)
1158 goto cancel_new;
1159 goto failed_super; 1152 goto failed_super;
1160 }
1161 } else { 1153 } else {
1162 root_dentry = dget(s->s_root); 1154 root_dentry = dget(s->s_root);
1163 } 1155 }
1164 1156
1165 mutex_unlock(&nilfs->ns_mount_mutex);
1166 put_nilfs(nilfs);
1167 if (!s_new) 1157 if (!s_new)
1168 close_bdev_exclusive(sd.bdev, mode); 1158 close_bdev_exclusive(sd.bdev, mode);
1169 1159
@@ -1173,23 +1163,10 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags,
1173 1163
1174 failed_super: 1164 failed_super:
1175 deactivate_locked_super(s); 1165 deactivate_locked_super(s);
1176 failed_unlock:
1177 mutex_unlock(&nilfs->ns_mount_mutex);
1178 put_nilfs(nilfs);
1179 failed:
1180 close_bdev_exclusive(sd.bdev, mode);
1181 return err;
1182 1166
1183 cancel_new: 1167 failed:
1184 /* Abandoning the newly allocated superblock */ 1168 if (!s_new)
1185 mutex_unlock(&nilfs->ns_mount_mutex); 1169 close_bdev_exclusive(sd.bdev, mode);
1186 put_nilfs(nilfs);
1187 deactivate_locked_super(s);
1188 /*
1189 * This deactivate_locked_super() invokes close_bdev_exclusive().
1190 * We must finish all post-cleaning before this call;
1191 * put_nilfs() needs the block device.
1192 */
1193 return err; 1170 return err;
1194} 1171}
1195 1172
diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c
index 960c28797bb2..6eeb4f072f83 100644
--- a/fs/nilfs2/the_nilfs.c
+++ b/fs/nilfs2/the_nilfs.c
@@ -35,9 +35,6 @@
35#include "segbuf.h" 35#include "segbuf.h"
36 36
37 37
38static LIST_HEAD(nilfs_objects);
39static DEFINE_SPINLOCK(nilfs_lock);
40
41static int nilfs_valid_sb(struct nilfs_super_block *sbp); 38static int nilfs_valid_sb(struct nilfs_super_block *sbp);
42 39
43void nilfs_set_last_segment(struct the_nilfs *nilfs, 40void nilfs_set_last_segment(struct the_nilfs *nilfs,
@@ -61,16 +58,13 @@ void nilfs_set_last_segment(struct the_nilfs *nilfs,
61} 58}
62 59
63/** 60/**
64 * alloc_nilfs - allocate the_nilfs structure 61 * alloc_nilfs - allocate a nilfs object
65 * @bdev: block device to which the_nilfs is related 62 * @bdev: block device to which the_nilfs is related
66 * 63 *
67 * alloc_nilfs() allocates memory for the_nilfs and
68 * initializes its reference count and locks.
69 *
70 * Return Value: On success, pointer to the_nilfs is returned. 64 * Return Value: On success, pointer to the_nilfs is returned.
71 * On error, NULL is returned. 65 * On error, NULL is returned.
72 */ 66 */
73static struct the_nilfs *alloc_nilfs(struct block_device *bdev) 67struct the_nilfs *alloc_nilfs(struct block_device *bdev)
74{ 68{
75 struct the_nilfs *nilfs; 69 struct the_nilfs *nilfs;
76 70
@@ -79,12 +73,9 @@ static struct the_nilfs *alloc_nilfs(struct block_device *bdev)
79 return NULL; 73 return NULL;
80 74
81 nilfs->ns_bdev = bdev; 75 nilfs->ns_bdev = bdev;
82 atomic_set(&nilfs->ns_count, 1);
83 atomic_set(&nilfs->ns_ndirtyblks, 0); 76 atomic_set(&nilfs->ns_ndirtyblks, 0);
84 init_rwsem(&nilfs->ns_sem); 77 init_rwsem(&nilfs->ns_sem);
85 mutex_init(&nilfs->ns_mount_mutex);
86 init_rwsem(&nilfs->ns_writer_sem); 78 init_rwsem(&nilfs->ns_writer_sem);
87 INIT_LIST_HEAD(&nilfs->ns_list);
88 INIT_LIST_HEAD(&nilfs->ns_gc_inodes); 79 INIT_LIST_HEAD(&nilfs->ns_gc_inodes);
89 spin_lock_init(&nilfs->ns_last_segment_lock); 80 spin_lock_init(&nilfs->ns_last_segment_lock);
90 nilfs->ns_cptree = RB_ROOT; 81 nilfs->ns_cptree = RB_ROOT;
@@ -95,67 +86,11 @@ static struct the_nilfs *alloc_nilfs(struct block_device *bdev)
95} 86}
96 87
97/** 88/**
98 * find_or_create_nilfs - find or create nilfs object 89 * destroy_nilfs - destroy nilfs object
99 * @bdev: block device to which the_nilfs is related 90 * @nilfs: nilfs object to be released
100 *
101 * find_nilfs() looks up an existent nilfs object created on the
102 * device and gets the reference count of the object. If no nilfs object
103 * is found on the device, a new nilfs object is allocated.
104 *
105 * Return Value: On success, pointer to the nilfs object is returned.
106 * On error, NULL is returned.
107 */
108struct the_nilfs *find_or_create_nilfs(struct block_device *bdev)
109{
110 struct the_nilfs *nilfs, *new = NULL;
111
112 retry:
113 spin_lock(&nilfs_lock);
114 list_for_each_entry(nilfs, &nilfs_objects, ns_list) {
115 if (nilfs->ns_bdev == bdev) {
116 get_nilfs(nilfs);
117 spin_unlock(&nilfs_lock);
118 if (new)
119 put_nilfs(new);
120 return nilfs; /* existing object */
121 }
122 }
123 if (new) {
124 list_add_tail(&new->ns_list, &nilfs_objects);
125 spin_unlock(&nilfs_lock);
126 return new; /* new object */
127 }
128 spin_unlock(&nilfs_lock);
129
130 new = alloc_nilfs(bdev);
131 if (new)
132 goto retry;
133 return NULL; /* insufficient memory */
134}
135
136/**
137 * put_nilfs - release a reference to the_nilfs
138 * @nilfs: the_nilfs structure to be released
139 *
140 * put_nilfs() decrements a reference counter of the_nilfs.
141 * If the reference count reaches zero, the_nilfs is freed.
142 */ 91 */
143void put_nilfs(struct the_nilfs *nilfs) 92void destroy_nilfs(struct the_nilfs *nilfs)
144{ 93{
145 spin_lock(&nilfs_lock);
146 if (!atomic_dec_and_test(&nilfs->ns_count)) {
147 spin_unlock(&nilfs_lock);
148 return;
149 }
150 list_del_init(&nilfs->ns_list);
151 spin_unlock(&nilfs_lock);
152
153 /*
154 * Increment of ns_count never occurs below because the caller
155 * of get_nilfs() holds at least one reference to the_nilfs.
156 * Thus its exclusion control is not required here.
157 */
158
159 might_sleep(); 94 might_sleep();
160 if (nilfs_loaded(nilfs)) { 95 if (nilfs_loaded(nilfs)) {
161 nilfs_mdt_destroy(nilfs->ns_sufile); 96 nilfs_mdt_destroy(nilfs->ns_sufile);
diff --git a/fs/nilfs2/the_nilfs.h b/fs/nilfs2/the_nilfs.h
index 7b43693a69c5..1908dc7bbd8f 100644
--- a/fs/nilfs2/the_nilfs.h
+++ b/fs/nilfs2/the_nilfs.h
@@ -46,13 +46,10 @@ enum {
46/** 46/**
47 * struct the_nilfs - struct to supervise multiple nilfs mount points 47 * struct the_nilfs - struct to supervise multiple nilfs mount points
48 * @ns_flags: flags 48 * @ns_flags: flags
49 * @ns_count: reference count
50 * @ns_list: list head for nilfs_list
51 * @ns_bdev: block device 49 * @ns_bdev: block device
52 * @ns_bdi: backing dev info 50 * @ns_bdi: backing dev info
53 * @ns_writer: back pointer to writable nilfs_sb_info 51 * @ns_writer: back pointer to writable nilfs_sb_info
54 * @ns_sem: semaphore for shared states 52 * @ns_sem: semaphore for shared states
55 * @ns_mount_mutex: mutex protecting mount process of nilfs
56 * @ns_writer_sem: semaphore protecting ns_writer attach/detach 53 * @ns_writer_sem: semaphore protecting ns_writer attach/detach
57 * @ns_sbh: buffer heads of on-disk super blocks 54 * @ns_sbh: buffer heads of on-disk super blocks
58 * @ns_sbp: pointers to super block data 55 * @ns_sbp: pointers to super block data
@@ -94,14 +91,11 @@ enum {
94 */ 91 */
95struct the_nilfs { 92struct the_nilfs {
96 unsigned long ns_flags; 93 unsigned long ns_flags;
97 atomic_t ns_count;
98 struct list_head ns_list;
99 94
100 struct block_device *ns_bdev; 95 struct block_device *ns_bdev;
101 struct backing_dev_info *ns_bdi; 96 struct backing_dev_info *ns_bdi;
102 struct nilfs_sb_info *ns_writer; 97 struct nilfs_sb_info *ns_writer;
103 struct rw_semaphore ns_sem; 98 struct rw_semaphore ns_sem;
104 struct mutex ns_mount_mutex;
105 struct rw_semaphore ns_writer_sem; 99 struct rw_semaphore ns_writer_sem;
106 100
107 /* 101 /*
@@ -239,8 +233,8 @@ static inline int nilfs_sb_will_flip(struct the_nilfs *nilfs)
239} 233}
240 234
241void nilfs_set_last_segment(struct the_nilfs *, sector_t, u64, __u64); 235void nilfs_set_last_segment(struct the_nilfs *, sector_t, u64, __u64);
242struct the_nilfs *find_or_create_nilfs(struct block_device *); 236struct the_nilfs *alloc_nilfs(struct block_device *bdev);
243void put_nilfs(struct the_nilfs *); 237void destroy_nilfs(struct the_nilfs *nilfs);
244int init_nilfs(struct the_nilfs *, struct nilfs_sb_info *, char *); 238int init_nilfs(struct the_nilfs *, struct nilfs_sb_info *, char *);
245int load_nilfs(struct the_nilfs *, struct nilfs_sb_info *); 239int load_nilfs(struct the_nilfs *, struct nilfs_sb_info *);
246int nilfs_discard_segments(struct the_nilfs *, __u64 *, size_t); 240int nilfs_discard_segments(struct the_nilfs *, __u64 *, size_t);
@@ -256,12 +250,6 @@ void nilfs_fall_back_super_block(struct the_nilfs *);
256void nilfs_swap_super_block(struct the_nilfs *); 250void nilfs_swap_super_block(struct the_nilfs *);
257 251
258 252
259static inline void get_nilfs(struct the_nilfs *nilfs)
260{
261 /* Caller must have at least one reference of the_nilfs. */
262 atomic_inc(&nilfs->ns_count);
263}
264
265static inline void nilfs_get_root(struct nilfs_root *root) 253static inline void nilfs_get_root(struct nilfs_root *root)
266{ 254{
267 atomic_inc(&root->count); 255 atomic_inc(&root->count);