diff options
Diffstat (limited to 'fs/exofs/super.c')
-rw-r--r-- | fs/exofs/super.c | 190 |
1 files changed, 169 insertions, 21 deletions
diff --git a/fs/exofs/super.c b/fs/exofs/super.c index 8c6c4669b381..06065bd37fc3 100644 --- a/fs/exofs/super.c +++ b/fs/exofs/super.c | |||
@@ -48,6 +48,7 @@ | |||
48 | * struct to hold what we get from mount options | 48 | * struct to hold what we get from mount options |
49 | */ | 49 | */ |
50 | struct exofs_mountopt { | 50 | struct exofs_mountopt { |
51 | bool is_osdname; | ||
51 | const char *dev_name; | 52 | const char *dev_name; |
52 | uint64_t pid; | 53 | uint64_t pid; |
53 | int timeout; | 54 | int timeout; |
@@ -56,7 +57,7 @@ struct exofs_mountopt { | |||
56 | /* | 57 | /* |
57 | * exofs-specific mount-time options. | 58 | * exofs-specific mount-time options. |
58 | */ | 59 | */ |
59 | enum { Opt_pid, Opt_to, Opt_mkfs, Opt_format, Opt_err }; | 60 | enum { Opt_name, Opt_pid, Opt_to, Opt_err }; |
60 | 61 | ||
61 | /* | 62 | /* |
62 | * Our mount-time options. These should ideally be 64-bit unsigned, but the | 63 | * Our mount-time options. These should ideally be 64-bit unsigned, but the |
@@ -64,6 +65,7 @@ enum { Opt_pid, Opt_to, Opt_mkfs, Opt_format, Opt_err }; | |||
64 | * sufficient for most applications now. | 65 | * sufficient for most applications now. |
65 | */ | 66 | */ |
66 | static match_table_t tokens = { | 67 | static match_table_t tokens = { |
68 | {Opt_name, "osdname=%s"}, | ||
67 | {Opt_pid, "pid=%u"}, | 69 | {Opt_pid, "pid=%u"}, |
68 | {Opt_to, "to=%u"}, | 70 | {Opt_to, "to=%u"}, |
69 | {Opt_err, NULL} | 71 | {Opt_err, NULL} |
@@ -94,6 +96,14 @@ static int parse_options(char *options, struct exofs_mountopt *opts) | |||
94 | 96 | ||
95 | token = match_token(p, tokens, args); | 97 | token = match_token(p, tokens, args); |
96 | switch (token) { | 98 | switch (token) { |
99 | case Opt_name: | ||
100 | opts->dev_name = match_strdup(&args[0]); | ||
101 | if (unlikely(!opts->dev_name)) { | ||
102 | EXOFS_ERR("Error allocating dev_name"); | ||
103 | return -ENOMEM; | ||
104 | } | ||
105 | opts->is_osdname = true; | ||
106 | break; | ||
97 | case Opt_pid: | 107 | case Opt_pid: |
98 | if (0 == match_strlcpy(str, &args[0], sizeof(str))) | 108 | if (0 == match_strlcpy(str, &args[0], sizeof(str))) |
99 | return -EINVAL; | 109 | return -EINVAL; |
@@ -203,6 +213,101 @@ static void destroy_inodecache(void) | |||
203 | static const struct super_operations exofs_sops; | 213 | static const struct super_operations exofs_sops; |
204 | static const struct export_operations exofs_export_ops; | 214 | static const struct export_operations exofs_export_ops; |
205 | 215 | ||
216 | static const struct osd_attr g_attr_sb_stats = ATTR_DEF( | ||
217 | EXOFS_APAGE_SB_DATA, | ||
218 | EXOFS_ATTR_SB_STATS, | ||
219 | sizeof(struct exofs_sb_stats)); | ||
220 | |||
221 | static int __sbi_read_stats(struct exofs_sb_info *sbi) | ||
222 | { | ||
223 | struct osd_attr attrs[] = { | ||
224 | [0] = g_attr_sb_stats, | ||
225 | }; | ||
226 | struct exofs_io_state *ios; | ||
227 | int ret; | ||
228 | |||
229 | ret = exofs_get_io_state(&sbi->layout, &ios); | ||
230 | if (unlikely(ret)) { | ||
231 | EXOFS_ERR("%s: exofs_get_io_state failed.\n", __func__); | ||
232 | return ret; | ||
233 | } | ||
234 | |||
235 | ios->cred = sbi->s_cred; | ||
236 | |||
237 | ios->in_attr = attrs; | ||
238 | ios->in_attr_len = ARRAY_SIZE(attrs); | ||
239 | |||
240 | ret = exofs_sbi_read(ios); | ||
241 | if (unlikely(ret)) { | ||
242 | EXOFS_ERR("Error reading super_block stats => %d\n", ret); | ||
243 | goto out; | ||
244 | } | ||
245 | |||
246 | ret = extract_attr_from_ios(ios, &attrs[0]); | ||
247 | if (ret) { | ||
248 | EXOFS_ERR("%s: extract_attr of sb_stats failed\n", __func__); | ||
249 | goto out; | ||
250 | } | ||
251 | if (attrs[0].len) { | ||
252 | struct exofs_sb_stats *ess; | ||
253 | |||
254 | if (unlikely(attrs[0].len != sizeof(*ess))) { | ||
255 | EXOFS_ERR("%s: Wrong version of exofs_sb_stats " | ||
256 | "size(%d) != expected(%zd)\n", | ||
257 | __func__, attrs[0].len, sizeof(*ess)); | ||
258 | goto out; | ||
259 | } | ||
260 | |||
261 | ess = attrs[0].val_ptr; | ||
262 | sbi->s_nextid = le64_to_cpu(ess->s_nextid); | ||
263 | sbi->s_numfiles = le32_to_cpu(ess->s_numfiles); | ||
264 | } | ||
265 | |||
266 | out: | ||
267 | exofs_put_io_state(ios); | ||
268 | return ret; | ||
269 | } | ||
270 | |||
271 | static void stats_done(struct exofs_io_state *ios, void *p) | ||
272 | { | ||
273 | exofs_put_io_state(ios); | ||
274 | /* Good thanks nothing to do anymore */ | ||
275 | } | ||
276 | |||
277 | /* Asynchronously write the stats attribute */ | ||
278 | int exofs_sbi_write_stats(struct exofs_sb_info *sbi) | ||
279 | { | ||
280 | struct osd_attr attrs[] = { | ||
281 | [0] = g_attr_sb_stats, | ||
282 | }; | ||
283 | struct exofs_io_state *ios; | ||
284 | int ret; | ||
285 | |||
286 | ret = exofs_get_io_state(&sbi->layout, &ios); | ||
287 | if (unlikely(ret)) { | ||
288 | EXOFS_ERR("%s: exofs_get_io_state failed.\n", __func__); | ||
289 | return ret; | ||
290 | } | ||
291 | |||
292 | sbi->s_ess.s_nextid = cpu_to_le64(sbi->s_nextid); | ||
293 | sbi->s_ess.s_numfiles = cpu_to_le64(sbi->s_numfiles); | ||
294 | attrs[0].val_ptr = &sbi->s_ess; | ||
295 | |||
296 | ios->cred = sbi->s_cred; | ||
297 | ios->done = stats_done; | ||
298 | ios->private = sbi; | ||
299 | ios->out_attr = attrs; | ||
300 | ios->out_attr_len = ARRAY_SIZE(attrs); | ||
301 | |||
302 | ret = exofs_sbi_write(ios); | ||
303 | if (unlikely(ret)) { | ||
304 | EXOFS_ERR("%s: exofs_sbi_write failed.\n", __func__); | ||
305 | exofs_put_io_state(ios); | ||
306 | } | ||
307 | |||
308 | return ret; | ||
309 | } | ||
310 | |||
206 | /* | 311 | /* |
207 | * Write the superblock to the OSD | 312 | * Write the superblock to the OSD |
208 | */ | 313 | */ |
@@ -213,18 +318,25 @@ int exofs_sync_fs(struct super_block *sb, int wait) | |||
213 | struct exofs_io_state *ios; | 318 | struct exofs_io_state *ios; |
214 | int ret = -ENOMEM; | 319 | int ret = -ENOMEM; |
215 | 320 | ||
216 | lock_super(sb); | 321 | fscb = kmalloc(sizeof(*fscb), GFP_KERNEL); |
322 | if (unlikely(!fscb)) | ||
323 | return -ENOMEM; | ||
324 | |||
217 | sbi = sb->s_fs_info; | 325 | sbi = sb->s_fs_info; |
218 | fscb = &sbi->s_fscb; | ||
219 | 326 | ||
327 | /* NOTE: We no longer dirty the super_block anywhere in exofs. The | ||
328 | * reason we write the fscb here on unmount is so we can stay backwards | ||
329 | * compatible with fscb->s_version == 1. (What we are not compatible | ||
330 | * with is if a new version FS crashed and then we try to mount an old | ||
331 | * version). Otherwise the exofs_fscb is read-only from mkfs time. All | ||
332 | * the writeable info is set in exofs_sbi_write_stats() above. | ||
333 | */ | ||
220 | ret = exofs_get_io_state(&sbi->layout, &ios); | 334 | ret = exofs_get_io_state(&sbi->layout, &ios); |
221 | if (ret) | 335 | if (unlikely(ret)) |
222 | goto out; | 336 | goto out; |
223 | 337 | ||
224 | /* Note: We only write the changing part of the fscb. .i.e upto the | 338 | lock_super(sb); |
225 | * the fscb->s_dev_table_oid member. There is no read-modify-write | 339 | |
226 | * here. | ||
227 | */ | ||
228 | ios->length = offsetof(struct exofs_fscb, s_dev_table_oid); | 340 | ios->length = offsetof(struct exofs_fscb, s_dev_table_oid); |
229 | memset(fscb, 0, ios->length); | 341 | memset(fscb, 0, ios->length); |
230 | fscb->s_nextid = cpu_to_le64(sbi->s_nextid); | 342 | fscb->s_nextid = cpu_to_le64(sbi->s_nextid); |
@@ -239,16 +351,17 @@ int exofs_sync_fs(struct super_block *sb, int wait) | |||
239 | ios->cred = sbi->s_cred; | 351 | ios->cred = sbi->s_cred; |
240 | 352 | ||
241 | ret = exofs_sbi_write(ios); | 353 | ret = exofs_sbi_write(ios); |
242 | if (unlikely(ret)) { | 354 | if (unlikely(ret)) |
243 | EXOFS_ERR("%s: exofs_sbi_write failed.\n", __func__); | 355 | EXOFS_ERR("%s: exofs_sbi_write failed.\n", __func__); |
244 | goto out; | 356 | else |
245 | } | 357 | sb->s_dirt = 0; |
246 | sb->s_dirt = 0; | 358 | |
247 | 359 | ||
360 | unlock_super(sb); | ||
248 | out: | 361 | out: |
249 | EXOFS_DBGMSG("s_nextid=0x%llx ret=%d\n", _LLU(sbi->s_nextid), ret); | 362 | EXOFS_DBGMSG("s_nextid=0x%llx ret=%d\n", _LLU(sbi->s_nextid), ret); |
250 | exofs_put_io_state(ios); | 363 | exofs_put_io_state(ios); |
251 | unlock_super(sb); | 364 | kfree(fscb); |
252 | return ret; | 365 | return ret; |
253 | } | 366 | } |
254 | 367 | ||
@@ -292,13 +405,14 @@ static void exofs_put_super(struct super_block *sb) | |||
292 | int num_pend; | 405 | int num_pend; |
293 | struct exofs_sb_info *sbi = sb->s_fs_info; | 406 | struct exofs_sb_info *sbi = sb->s_fs_info; |
294 | 407 | ||
295 | if (sb->s_dirt) | ||
296 | exofs_write_super(sb); | ||
297 | |||
298 | /* make sure there are no pending commands */ | 408 | /* make sure there are no pending commands */ |
299 | for (num_pend = atomic_read(&sbi->s_curr_pending); num_pend > 0; | 409 | for (num_pend = atomic_read(&sbi->s_curr_pending); num_pend > 0; |
300 | num_pend = atomic_read(&sbi->s_curr_pending)) { | 410 | num_pend = atomic_read(&sbi->s_curr_pending)) { |
301 | wait_queue_head_t wq; | 411 | wait_queue_head_t wq; |
412 | |||
413 | printk(KERN_NOTICE "%s: !!Pending operations in flight. " | ||
414 | "This is a BUG. please report to osd-dev@open-osd.org\n", | ||
415 | __func__); | ||
302 | init_waitqueue_head(&wq); | 416 | init_waitqueue_head(&wq); |
303 | wait_event_timeout(wq, | 417 | wait_event_timeout(wq, |
304 | (atomic_read(&sbi->s_curr_pending) == 0), | 418 | (atomic_read(&sbi->s_curr_pending) == 0), |
@@ -390,6 +504,23 @@ static int _read_and_match_data_map(struct exofs_sb_info *sbi, unsigned numdevs, | |||
390 | return 0; | 504 | return 0; |
391 | } | 505 | } |
392 | 506 | ||
507 | static unsigned __ra_pages(struct exofs_layout *layout) | ||
508 | { | ||
509 | const unsigned _MIN_RA = 32; /* min 128K read-ahead */ | ||
510 | unsigned ra_pages = layout->group_width * layout->stripe_unit / | ||
511 | PAGE_SIZE; | ||
512 | unsigned max_io_pages = exofs_max_io_pages(layout, ~0); | ||
513 | |||
514 | ra_pages *= 2; /* two stripes */ | ||
515 | if (ra_pages < _MIN_RA) | ||
516 | ra_pages = roundup(_MIN_RA, ra_pages / 2); | ||
517 | |||
518 | if (ra_pages > max_io_pages) | ||
519 | ra_pages = max_io_pages; | ||
520 | |||
521 | return ra_pages; | ||
522 | } | ||
523 | |||
393 | /* @odi is valid only as long as @fscb_dev is valid */ | 524 | /* @odi is valid only as long as @fscb_dev is valid */ |
394 | static int exofs_devs_2_odi(struct exofs_dt_device_info *dt_dev, | 525 | static int exofs_devs_2_odi(struct exofs_dt_device_info *dt_dev, |
395 | struct osd_dev_info *odi) | 526 | struct osd_dev_info *odi) |
@@ -495,7 +626,7 @@ static int exofs_read_lookup_dev_table(struct exofs_sb_info **psbi, | |||
495 | } | 626 | } |
496 | 627 | ||
497 | od = osduld_info_lookup(&odi); | 628 | od = osduld_info_lookup(&odi); |
498 | if (unlikely(IS_ERR(od))) { | 629 | if (IS_ERR(od)) { |
499 | ret = PTR_ERR(od); | 630 | ret = PTR_ERR(od); |
500 | EXOFS_ERR("ERROR: device requested is not found " | 631 | EXOFS_ERR("ERROR: device requested is not found " |
501 | "osd_name-%s =>%d\n", odi.osdname, ret); | 632 | "osd_name-%s =>%d\n", odi.osdname, ret); |
@@ -558,9 +689,17 @@ static int exofs_fill_super(struct super_block *sb, void *data, int silent) | |||
558 | goto free_bdi; | 689 | goto free_bdi; |
559 | 690 | ||
560 | /* use mount options to fill superblock */ | 691 | /* use mount options to fill superblock */ |
561 | od = osduld_path_lookup(opts->dev_name); | 692 | if (opts->is_osdname) { |
693 | struct osd_dev_info odi = {.systemid_len = 0}; | ||
694 | |||
695 | odi.osdname_len = strlen(opts->dev_name); | ||
696 | odi.osdname = (u8 *)opts->dev_name; | ||
697 | od = osduld_info_lookup(&odi); | ||
698 | } else { | ||
699 | od = osduld_path_lookup(opts->dev_name); | ||
700 | } | ||
562 | if (IS_ERR(od)) { | 701 | if (IS_ERR(od)) { |
563 | ret = PTR_ERR(od); | 702 | ret = -EINVAL; |
564 | goto free_sbi; | 703 | goto free_sbi; |
565 | } | 704 | } |
566 | 705 | ||
@@ -594,6 +733,7 @@ static int exofs_fill_super(struct super_block *sb, void *data, int silent) | |||
594 | goto free_sbi; | 733 | goto free_sbi; |
595 | 734 | ||
596 | sb->s_magic = le16_to_cpu(fscb.s_magic); | 735 | sb->s_magic = le16_to_cpu(fscb.s_magic); |
736 | /* NOTE: we read below to be backward compatible with old versions */ | ||
597 | sbi->s_nextid = le64_to_cpu(fscb.s_nextid); | 737 | sbi->s_nextid = le64_to_cpu(fscb.s_nextid); |
598 | sbi->s_numfiles = le32_to_cpu(fscb.s_numfiles); | 738 | sbi->s_numfiles = le32_to_cpu(fscb.s_numfiles); |
599 | 739 | ||
@@ -604,7 +744,7 @@ static int exofs_fill_super(struct super_block *sb, void *data, int silent) | |||
604 | ret = -EINVAL; | 744 | ret = -EINVAL; |
605 | goto free_sbi; | 745 | goto free_sbi; |
606 | } | 746 | } |
607 | if (le32_to_cpu(fscb.s_version) != EXOFS_FSCB_VER) { | 747 | if (le32_to_cpu(fscb.s_version) > EXOFS_FSCB_VER) { |
608 | EXOFS_ERR("ERROR: Bad FSCB version expected-%d got-%d\n", | 748 | EXOFS_ERR("ERROR: Bad FSCB version expected-%d got-%d\n", |
609 | EXOFS_FSCB_VER, le32_to_cpu(fscb.s_version)); | 749 | EXOFS_FSCB_VER, le32_to_cpu(fscb.s_version)); |
610 | ret = -EINVAL; | 750 | ret = -EINVAL; |
@@ -622,7 +762,10 @@ static int exofs_fill_super(struct super_block *sb, void *data, int silent) | |||
622 | goto free_sbi; | 762 | goto free_sbi; |
623 | } | 763 | } |
624 | 764 | ||
765 | __sbi_read_stats(sbi); | ||
766 | |||
625 | /* set up operation vectors */ | 767 | /* set up operation vectors */ |
768 | sbi->bdi.ra_pages = __ra_pages(&sbi->layout); | ||
626 | sb->s_bdi = &sbi->bdi; | 769 | sb->s_bdi = &sbi->bdi; |
627 | sb->s_fs_info = sbi; | 770 | sb->s_fs_info = sbi; |
628 | sb->s_op = &exofs_sops; | 771 | sb->s_op = &exofs_sops; |
@@ -652,6 +795,8 @@ static int exofs_fill_super(struct super_block *sb, void *data, int silent) | |||
652 | 795 | ||
653 | _exofs_print_device("Mounting", opts->dev_name, sbi->layout.s_ods[0], | 796 | _exofs_print_device("Mounting", opts->dev_name, sbi->layout.s_ods[0], |
654 | sbi->layout.s_pid); | 797 | sbi->layout.s_pid); |
798 | if (opts->is_osdname) | ||
799 | kfree(opts->dev_name); | ||
655 | return 0; | 800 | return 0; |
656 | 801 | ||
657 | free_sbi: | 802 | free_sbi: |
@@ -660,6 +805,8 @@ free_bdi: | |||
660 | EXOFS_ERR("Unable to mount exofs on %s pid=0x%llx err=%d\n", | 805 | EXOFS_ERR("Unable to mount exofs on %s pid=0x%llx err=%d\n", |
661 | opts->dev_name, sbi->layout.s_pid, ret); | 806 | opts->dev_name, sbi->layout.s_pid, ret); |
662 | exofs_free_sbi(sbi); | 807 | exofs_free_sbi(sbi); |
808 | if (opts->is_osdname) | ||
809 | kfree(opts->dev_name); | ||
663 | return ret; | 810 | return ret; |
664 | } | 811 | } |
665 | 812 | ||
@@ -677,7 +824,8 @@ static struct dentry *exofs_mount(struct file_system_type *type, | |||
677 | if (ret) | 824 | if (ret) |
678 | return ERR_PTR(ret); | 825 | return ERR_PTR(ret); |
679 | 826 | ||
680 | opts.dev_name = dev_name; | 827 | if (!opts.dev_name) |
828 | opts.dev_name = dev_name; | ||
681 | return mount_nodev(type, flags, &opts, exofs_fill_super); | 829 | return mount_nodev(type, flags, &opts, exofs_fill_super); |
682 | } | 830 | } |
683 | 831 | ||