aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2008-06-10 10:40:29 -0400
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:04:03 -0400
commitedf24abe51493ccda384644d487fe2f796ac21c8 (patch)
tree91244ac3bb85fd08c22f109011cc4a625037677f
parent306929f364b993581c91596230807fa1c022268a (diff)
btrfs: sanity mount option parsing and early mount code
Also adds lots of comments to describe what's going on here. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Chris Mason <chris.mason@oracle.com>
-rw-r--r--fs/btrfs/ctree.h3
-rw-r--r--fs/btrfs/disk-io.c5
-rw-r--r--fs/btrfs/super.c241
3 files changed, 141 insertions, 108 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 1dcf4fb5b688..49cbc62b42f9 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -1616,7 +1616,6 @@ int btrfs_delete_xattrs(struct btrfs_trans_handle *trans,
1616 struct btrfs_root *root, struct inode *inode); 1616 struct btrfs_root *root, struct inode *inode);
1617/* super.c */ 1617/* super.c */
1618u64 btrfs_parse_size(char *str); 1618u64 btrfs_parse_size(char *str);
1619int btrfs_parse_options(char *options, struct btrfs_root *root, 1619int btrfs_parse_options(struct btrfs_root *root, char *options);
1620 char **subvol_name);
1621int btrfs_sync_fs(struct super_block *sb, int wait); 1620int btrfs_sync_fs(struct super_block *sb, int wait);
1622#endif 1621#endif
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 3805e7eab82d..b9a53646ceb2 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -1266,8 +1266,11 @@ struct btrfs_root *open_ctree(struct super_block *sb,
1266 if (!btrfs_super_root(disk_super)) 1266 if (!btrfs_super_root(disk_super))
1267 goto fail_sb_buffer; 1267 goto fail_sb_buffer;
1268 1268
1269 btrfs_parse_options(options, tree_root, NULL); 1269 err = btrfs_parse_options(tree_root, options);
1270 if (err)
1271 goto fail_sb_buffer;
1270 1272
1273 err = -EINVAL;
1271 if (btrfs_super_num_devices(disk_super) > fs_devices->open_devices) { 1274 if (btrfs_super_num_devices(disk_super) > fs_devices->open_devices) {
1272 printk("Btrfs: wanted %llu devices, but found %llu\n", 1275 printk("Btrfs: wanted %llu devices, but found %llu\n",
1273 (unsigned long long)btrfs_super_num_devices(disk_super), 1276 (unsigned long long)btrfs_super_num_devices(disk_super),
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 39bb86945ed0..288300fa5848 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -108,15 +108,18 @@ u64 btrfs_parse_size(char *str)
108 return res; 108 return res;
109} 109}
110 110
111int btrfs_parse_options(char *options, struct btrfs_root *root, 111/*
112 char **subvol_name) 112 * Regular mount options parser. Everything that is needed only when
113 * reading in a new superblock is parsed here.
114 */
115int btrfs_parse_options(struct btrfs_root *root, char *options)
113{ 116{
114 char * p; 117 struct btrfs_fs_info *info = root->fs_info;
115 struct btrfs_fs_info *info = NULL;
116 substring_t args[MAX_OPT_ARGS]; 118 substring_t args[MAX_OPT_ARGS];
119 char *p, *num;
117 120
118 if (!options) 121 if (!options)
119 return 1; 122 return 0;
120 123
121 /* 124 /*
122 * strsep changes the string, duplicate it because parse_options 125 * strsep changes the string, duplicate it because parse_options
@@ -126,10 +129,8 @@ int btrfs_parse_options(char *options, struct btrfs_root *root,
126 if (!options) 129 if (!options)
127 return -ENOMEM; 130 return -ENOMEM;
128 131
129 if (root)
130 info = root->fs_info;
131 132
132 while ((p = strsep (&options, ",")) != NULL) { 133 while ((p = strsep(&options, ",")) != NULL) {
133 int token; 134 int token;
134 if (!*p) 135 if (!*p)
135 continue; 136 continue;
@@ -137,83 +138,64 @@ int btrfs_parse_options(char *options, struct btrfs_root *root,
137 token = match_token(p, tokens, args); 138 token = match_token(p, tokens, args);
138 switch (token) { 139 switch (token) {
139 case Opt_degraded: 140 case Opt_degraded:
140 if (info) { 141 printk(KERN_INFO "btrfs: allowing degraded mounts\n");
141 printk("btrfs: allowing degraded mounts\n"); 142 btrfs_set_opt(info->mount_opt, DEGRADED);
142 btrfs_set_opt(info->mount_opt, DEGRADED);
143 }
144 break; 143 break;
145 case Opt_subvol: 144 case Opt_subvol:
146 if (subvol_name) { 145 /*
147 *subvol_name = match_strdup(&args[0]); 146 * This one is parsed by btrfs_parse_early_options
148 } 147 * and can be happily ignored here.
148 */
149 break; 149 break;
150 case Opt_nodatasum: 150 case Opt_nodatasum:
151 if (info) { 151 printk(KERN_INFO "btrfs: setting nodatacsum\n");
152 printk("btrfs: setting nodatacsum\n"); 152 btrfs_set_opt(info->mount_opt, NODATASUM);
153 btrfs_set_opt(info->mount_opt, NODATASUM);
154 }
155 break; 153 break;
156 case Opt_nodatacow: 154 case Opt_nodatacow:
157 if (info) { 155 printk(KERN_INFO "btrfs: setting nodatacow\n");
158 printk("btrfs: setting nodatacow\n"); 156 btrfs_set_opt(info->mount_opt, NODATACOW);
159 btrfs_set_opt(info->mount_opt, NODATACOW); 157 btrfs_set_opt(info->mount_opt, NODATASUM);
160 btrfs_set_opt(info->mount_opt, NODATASUM);
161 }
162 break; 158 break;
163 case Opt_ssd: 159 case Opt_ssd:
164 if (info) { 160 printk(KERN_INFO "btrfs: use ssd allocation scheme\n");
165 printk("btrfs: use ssd allocation scheme\n"); 161 btrfs_set_opt(info->mount_opt, SSD);
166 btrfs_set_opt(info->mount_opt, SSD);
167 }
168 break; 162 break;
169 case Opt_nobarrier: 163 case Opt_nobarrier:
170 if (info) { 164 printk(KERN_INFO "btrfs: turning off barriers\n");
171 printk("btrfs: turning off barriers\n"); 165 btrfs_set_opt(info->mount_opt, NOBARRIER);
172 btrfs_set_opt(info->mount_opt, NOBARRIER);
173 }
174 break; 166 break;
175 case Opt_max_extent: 167 case Opt_max_extent:
176 if (info) { 168 num = match_strdup(&args[0]);
177 char *num = match_strdup(&args[0]); 169 if (num) {
178 if (num) { 170 info->max_extent = btrfs_parse_size(num);
179 info->max_extent = 171 kfree(num);
180 btrfs_parse_size(num); 172
181 kfree(num); 173 info->max_extent = max_t(u64,
182 174 info->max_extent, root->sectorsize);
183 info->max_extent = max_t(u64, 175 printk(KERN_INFO "btrfs: max_extent at %llu\n",
184 info->max_extent, 176 info->max_extent);
185 root->sectorsize);
186 printk("btrfs: max_extent at %Lu\n",
187 info->max_extent);
188 }
189 } 177 }
190 break; 178 break;
191 case Opt_max_inline: 179 case Opt_max_inline:
192 if (info) { 180 num = match_strdup(&args[0]);
193 char *num = match_strdup(&args[0]); 181 if (num) {
194 if (num) { 182 info->max_inline = btrfs_parse_size(num);
195 info->max_inline = 183 kfree(num);
196 btrfs_parse_size(num); 184
197 kfree(num); 185 info->max_inline = max_t(u64,
198 186 info->max_inline, root->sectorsize);
199 info->max_inline = max_t(u64, 187 printk(KERN_INFO "btrfs: max_inline at %llu\n",
200 info->max_inline, 188 info->max_inline);
201 root->sectorsize);
202 printk("btrfs: max_inline at %Lu\n",
203 info->max_inline);
204 }
205 } 189 }
206 break; 190 break;
207 case Opt_alloc_start: 191 case Opt_alloc_start:
208 if (info) { 192 num = match_strdup(&args[0]);
209 char *num = match_strdup(&args[0]); 193 if (num) {
210 if (num) { 194 info->alloc_start = btrfs_parse_size(num);
211 info->alloc_start = 195 kfree(num);
212 btrfs_parse_size(num); 196 printk(KERN_INFO
213 kfree(num); 197 "btrfs: allocations start at %llu\n",
214 printk("btrfs: allocations start at " 198 info->alloc_start);
215 "%Lu\n", info->alloc_start);
216 }
217 } 199 }
218 break; 200 break;
219 default: 201 default:
@@ -221,7 +203,61 @@ int btrfs_parse_options(char *options, struct btrfs_root *root,
221 } 203 }
222 } 204 }
223 kfree(options); 205 kfree(options);
224 return 1; 206 return 0;
207}
208
209/*
210 * Parse mount options that are required early in the mount process.
211 *
212 * All other options will be parsed on much later in the mount process and
213 * only when we need to allocate a new super block.
214 */
215static int btrfs_parse_early_options(const char *options,
216 char **subvol_name)
217{
218 substring_t args[MAX_OPT_ARGS];
219 char *opts, *p;
220 int error = 0;
221
222 if (!options)
223 goto out;
224
225 /*
226 * strsep changes the string, duplicate it because parse_options
227 * gets called twice
228 */
229 opts = kstrdup(options, GFP_KERNEL);
230 if (!opts)
231 return -ENOMEM;
232
233 while ((p = strsep(&opts, ",")) != NULL) {
234 int token;
235 if (!*p)
236 continue;
237
238 token = match_token(p, tokens, args);
239 switch (token) {
240 case Opt_subvol:
241 *subvol_name = match_strdup(&args[0]);
242 break;
243 default:
244 break;
245 }
246 }
247
248 kfree(opts);
249 out:
250 /*
251 * If no subvolume name is specified we use the default one. Allocate
252 * a copy of the string "default" here so that code later in the
253 * mount path doesn't care if it's the default volume or another one.
254 */
255 if (!*subvol_name) {
256 *subvol_name = kstrdup("default", GFP_KERNEL);
257 if (!*subvol_name)
258 return -ENOMEM;
259 }
260 return error;
225} 261}
226 262
227static int btrfs_fill_super(struct super_block * sb, 263static int btrfs_fill_super(struct super_block * sb,
@@ -328,23 +364,33 @@ static int btrfs_test_super(struct super_block *s, void *data)
328 return root->fs_info->fs_devices == test_fs_devices; 364 return root->fs_info->fs_devices == test_fs_devices;
329} 365}
330 366
331int btrfs_get_sb_bdev(struct file_system_type *fs_type, 367/*
332 int flags, const char *dev_name, void *data, 368 * Find a superblock for the given device / mount point.
333 struct vfsmount *mnt, const char *subvol) 369 *
370 * Note: This is based on get_sb_bdev from fs/super.c with a few additions
371 * for multiple device setup. Make sure to keep it in sync.
372 */
373static int btrfs_get_sb(struct file_system_type *fs_type, int flags,
374 const char *dev_name, void *data, struct vfsmount *mnt)
334{ 375{
376 char *subvol_name = NULL;
335 struct block_device *bdev = NULL; 377 struct block_device *bdev = NULL;
336 struct super_block *s; 378 struct super_block *s;
337 struct dentry *root; 379 struct dentry *root;
338 struct btrfs_fs_devices *fs_devices = NULL; 380 struct btrfs_fs_devices *fs_devices = NULL;
339 int error = 0; 381 int error = 0;
340 382
383 error = btrfs_parse_early_options(data, &subvol_name);
384 if (error)
385 goto error;
386
341 error = btrfs_scan_one_device(dev_name, flags, fs_type, &fs_devices); 387 error = btrfs_scan_one_device(dev_name, flags, fs_type, &fs_devices);
342 if (error) 388 if (error)
343 return error; 389 goto error_free_subvol_name;
344 390
345 error = btrfs_open_devices(fs_devices, flags, fs_type); 391 error = btrfs_open_devices(fs_devices, flags, fs_type);
346 if (error) 392 if (error)
347 return error; 393 goto error_free_subvol_name;
348 394
349 bdev = fs_devices->latest_bdev; 395 bdev = fs_devices->latest_bdev;
350 btrfs_lock_volumes(); 396 btrfs_lock_volumes();
@@ -378,51 +424,36 @@ int btrfs_get_sb_bdev(struct file_system_type *fs_type,
378 s->s_flags |= MS_ACTIVE; 424 s->s_flags |= MS_ACTIVE;
379 } 425 }
380 426
381 if (subvol) { 427 root = lookup_one_len(subvol_name, s->s_root, strlen(subvol_name));
382 root = lookup_one_len(subvol, s->s_root, strlen(subvol)); 428 if (IS_ERR(root)) {
383 if (IS_ERR(root)) { 429 up_write(&s->s_umount);
384 up_write(&s->s_umount); 430 deactivate_super(s);
385 deactivate_super(s); 431 error = PTR_ERR(root);
386 error = PTR_ERR(root); 432 goto error;
387 goto error; 433 }
388 } 434 if (!root->d_inode) {
389 if (!root->d_inode) { 435 dput(root);
390 dput(root); 436 up_write(&s->s_umount);
391 up_write(&s->s_umount); 437 deactivate_super(s);
392 deactivate_super(s); 438 error = -ENXIO;
393 error = -ENXIO; 439 goto error;
394 goto error;
395 }
396 } else {
397 root = dget(s->s_root);
398 } 440 }
399 441
400 mnt->mnt_sb = s; 442 mnt->mnt_sb = s;
401 mnt->mnt_root = root; 443 mnt->mnt_root = root;
444
445 kfree(subvol_name);
402 return 0; 446 return 0;
403 447
404error_s: 448error_s:
405 error = PTR_ERR(s); 449 error = PTR_ERR(s);
406error_bdev: 450error_bdev:
407 btrfs_close_devices(fs_devices); 451 btrfs_close_devices(fs_devices);
452error_free_subvol_name:
453 kfree(subvol_name);
408error: 454error:
409 return error; 455 return error;
410} 456}
411/* end copy & paste */
412
413static int btrfs_get_sb(struct file_system_type *fs_type,
414 int flags, const char *dev_name, void *data, struct vfsmount *mnt)
415{
416 int ret;
417 char *subvol_name = NULL;
418
419 btrfs_parse_options((char *)data, NULL, &subvol_name);
420 ret = btrfs_get_sb_bdev(fs_type, flags, dev_name, data, mnt,
421 subvol_name ? subvol_name : "default");
422 if (subvol_name)
423 kfree(subvol_name);
424 return ret;
425}
426 457
427static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf) 458static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf)
428{ 459{