diff options
Diffstat (limited to 'fs/nilfs2')
| -rw-r--r-- | fs/nilfs2/cpfile.c | 12 | ||||
| -rw-r--r-- | fs/nilfs2/ioctl.c | 2 | ||||
| -rw-r--r-- | fs/nilfs2/sb.h | 1 | ||||
| -rw-r--r-- | fs/nilfs2/super.c | 256 | ||||
| -rw-r--r-- | fs/nilfs2/the_nilfs.c | 115 | ||||
| -rw-r--r-- | fs/nilfs2/the_nilfs.h | 23 |
6 files changed, 232 insertions, 177 deletions
diff --git a/fs/nilfs2/cpfile.c b/fs/nilfs2/cpfile.c index e90b60dfced9..cadd36b14d07 100644 --- a/fs/nilfs2/cpfile.c +++ b/fs/nilfs2/cpfile.c | |||
| @@ -311,7 +311,7 @@ int nilfs_cpfile_delete_checkpoints(struct inode *cpfile, | |||
| 311 | ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh); | 311 | ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh); |
| 312 | if (ret < 0) { | 312 | if (ret < 0) { |
| 313 | if (ret != -ENOENT) | 313 | if (ret != -ENOENT) |
| 314 | goto out_sem; | 314 | goto out_header; |
| 315 | /* skip hole */ | 315 | /* skip hole */ |
| 316 | ret = 0; | 316 | ret = 0; |
| 317 | continue; | 317 | continue; |
| @@ -344,7 +344,7 @@ int nilfs_cpfile_delete_checkpoints(struct inode *cpfile, | |||
| 344 | continue; | 344 | continue; |
| 345 | printk(KERN_ERR "%s: cannot delete block\n", | 345 | printk(KERN_ERR "%s: cannot delete block\n", |
| 346 | __func__); | 346 | __func__); |
| 347 | goto out_sem; | 347 | goto out_header; |
| 348 | } | 348 | } |
| 349 | } | 349 | } |
| 350 | 350 | ||
| @@ -361,6 +361,8 @@ int nilfs_cpfile_delete_checkpoints(struct inode *cpfile, | |||
| 361 | nilfs_mdt_mark_dirty(cpfile); | 361 | nilfs_mdt_mark_dirty(cpfile); |
| 362 | kunmap_atomic(kaddr, KM_USER0); | 362 | kunmap_atomic(kaddr, KM_USER0); |
| 363 | } | 363 | } |
| 364 | |||
| 365 | out_header: | ||
| 364 | brelse(header_bh); | 366 | brelse(header_bh); |
| 365 | 367 | ||
| 366 | out_sem: | 368 | out_sem: |
| @@ -862,11 +864,11 @@ int nilfs_cpfile_change_cpmode(struct inode *cpfile, __u64 cno, int mode) | |||
| 862 | case NILFS_CHECKPOINT: | 864 | case NILFS_CHECKPOINT: |
| 863 | /* | 865 | /* |
| 864 | * Check for protecting existing snapshot mounts: | 866 | * Check for protecting existing snapshot mounts: |
| 865 | * bd_mount_sem is used to make this operation atomic and | 867 | * ns_mount_mutex is used to make this operation atomic and |
| 866 | * exclusive with a new mount job. Though it doesn't cover | 868 | * exclusive with a new mount job. Though it doesn't cover |
| 867 | * umount, it's enough for the purpose. | 869 | * umount, it's enough for the purpose. |
| 868 | */ | 870 | */ |
| 869 | down(&nilfs->ns_bdev->bd_mount_sem); | 871 | mutex_lock(&nilfs->ns_mount_mutex); |
| 870 | if (nilfs_checkpoint_is_mounted(nilfs, cno, 1)) { | 872 | if (nilfs_checkpoint_is_mounted(nilfs, cno, 1)) { |
| 871 | /* Current implementation does not have to protect | 873 | /* Current implementation does not have to protect |
| 872 | plain read-only mounts since they are exclusive | 874 | plain read-only mounts since they are exclusive |
| @@ -875,7 +877,7 @@ int nilfs_cpfile_change_cpmode(struct inode *cpfile, __u64 cno, int mode) | |||
| 875 | ret = -EBUSY; | 877 | ret = -EBUSY; |
| 876 | } else | 878 | } else |
| 877 | ret = nilfs_cpfile_clear_snapshot(cpfile, cno); | 879 | ret = nilfs_cpfile_clear_snapshot(cpfile, cno); |
| 878 | up(&nilfs->ns_bdev->bd_mount_sem); | 880 | mutex_unlock(&nilfs->ns_mount_mutex); |
| 879 | return ret; | 881 | return ret; |
| 880 | case NILFS_SNAPSHOT: | 882 | case NILFS_SNAPSHOT: |
| 881 | return nilfs_cpfile_set_snapshot(cpfile, cno); | 883 | return nilfs_cpfile_set_snapshot(cpfile, cno); |
diff --git a/fs/nilfs2/ioctl.c b/fs/nilfs2/ioctl.c index 50ff3f2cdf24..d6759b92006f 100644 --- a/fs/nilfs2/ioctl.c +++ b/fs/nilfs2/ioctl.c | |||
| @@ -576,7 +576,7 @@ static int nilfs_ioctl_clean_segments(struct inode *inode, struct file *filp, | |||
| 576 | ret = nilfs_clean_segments(inode->i_sb, argv, kbufs); | 576 | ret = nilfs_clean_segments(inode->i_sb, argv, kbufs); |
| 577 | 577 | ||
| 578 | out_free: | 578 | out_free: |
| 579 | while (--n > 0) | 579 | while (--n >= 0) |
| 580 | vfree(kbufs[n]); | 580 | vfree(kbufs[n]); |
| 581 | kfree(kbufs[4]); | 581 | kfree(kbufs[4]); |
| 582 | return ret; | 582 | return ret; |
diff --git a/fs/nilfs2/sb.h b/fs/nilfs2/sb.h index adccd4fc654e..0776ccc2504a 100644 --- a/fs/nilfs2/sb.h +++ b/fs/nilfs2/sb.h | |||
| @@ -60,6 +60,7 @@ struct nilfs_sb_info { | |||
| 60 | struct super_block *s_super; /* reverse pointer to super_block */ | 60 | struct super_block *s_super; /* reverse pointer to super_block */ |
| 61 | struct the_nilfs *s_nilfs; | 61 | struct the_nilfs *s_nilfs; |
| 62 | struct list_head s_list; /* list head for nilfs->ns_supers */ | 62 | struct list_head s_list; /* list head for nilfs->ns_supers */ |
| 63 | atomic_t s_count; /* reference count */ | ||
| 63 | 64 | ||
| 64 | /* Segment constructor */ | 65 | /* Segment constructor */ |
| 65 | struct list_head s_dirty_files; /* dirty files list */ | 66 | struct list_head s_dirty_files; /* dirty files list */ |
diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 6989b03e97ab..1777a3467bd2 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c | |||
| @@ -65,9 +65,8 @@ MODULE_DESCRIPTION("A New Implementation of the Log-structured Filesystem " | |||
| 65 | "(NILFS)"); | 65 | "(NILFS)"); |
| 66 | MODULE_LICENSE("GPL"); | 66 | MODULE_LICENSE("GPL"); |
| 67 | 67 | ||
| 68 | static void nilfs_write_super(struct super_block *sb); | ||
| 68 | static int nilfs_remount(struct super_block *sb, int *flags, char *data); | 69 | static int nilfs_remount(struct super_block *sb, int *flags, char *data); |
| 69 | static int test_exclusive_mount(struct file_system_type *fs_type, | ||
| 70 | struct block_device *bdev, int flags); | ||
| 71 | 70 | ||
| 72 | /** | 71 | /** |
| 73 | * nilfs_error() - report failure condition on a filesystem | 72 | * nilfs_error() - report failure condition on a filesystem |
| @@ -315,6 +314,11 @@ static void nilfs_put_super(struct super_block *sb) | |||
| 315 | struct nilfs_sb_info *sbi = NILFS_SB(sb); | 314 | struct nilfs_sb_info *sbi = NILFS_SB(sb); |
| 316 | struct the_nilfs *nilfs = sbi->s_nilfs; | 315 | struct the_nilfs *nilfs = sbi->s_nilfs; |
| 317 | 316 | ||
| 317 | lock_kernel(); | ||
| 318 | |||
| 319 | if (sb->s_dirt) | ||
| 320 | nilfs_write_super(sb); | ||
| 321 | |||
| 318 | nilfs_detach_segment_constructor(sbi); | 322 | nilfs_detach_segment_constructor(sbi); |
| 319 | 323 | ||
| 320 | if (!(sb->s_flags & MS_RDONLY)) { | 324 | if (!(sb->s_flags & MS_RDONLY)) { |
| @@ -323,12 +327,18 @@ static void nilfs_put_super(struct super_block *sb) | |||
| 323 | nilfs_commit_super(sbi, 1); | 327 | nilfs_commit_super(sbi, 1); |
| 324 | up_write(&nilfs->ns_sem); | 328 | up_write(&nilfs->ns_sem); |
| 325 | } | 329 | } |
| 330 | down_write(&nilfs->ns_super_sem); | ||
| 331 | if (nilfs->ns_current == sbi) | ||
| 332 | nilfs->ns_current = NULL; | ||
| 333 | up_write(&nilfs->ns_super_sem); | ||
| 326 | 334 | ||
| 327 | nilfs_detach_checkpoint(sbi); | 335 | nilfs_detach_checkpoint(sbi); |
| 328 | put_nilfs(sbi->s_nilfs); | 336 | put_nilfs(sbi->s_nilfs); |
| 329 | sbi->s_super = NULL; | 337 | sbi->s_super = NULL; |
| 330 | sb->s_fs_info = NULL; | 338 | sb->s_fs_info = NULL; |
| 331 | kfree(sbi); | 339 | nilfs_put_sbinfo(sbi); |
| 340 | |||
| 341 | unlock_kernel(); | ||
| 332 | } | 342 | } |
| 333 | 343 | ||
| 334 | /** | 344 | /** |
| @@ -383,6 +393,8 @@ static int nilfs_sync_fs(struct super_block *sb, int wait) | |||
| 383 | { | 393 | { |
| 384 | int err = 0; | 394 | int err = 0; |
| 385 | 395 | ||
| 396 | nilfs_write_super(sb); | ||
| 397 | |||
| 386 | /* This function is called when super block should be written back */ | 398 | /* This function is called when super block should be written back */ |
| 387 | if (wait) | 399 | if (wait) |
| 388 | err = nilfs_construct_segment(sb); | 400 | err = nilfs_construct_segment(sb); |
| @@ -396,9 +408,9 @@ int nilfs_attach_checkpoint(struct nilfs_sb_info *sbi, __u64 cno) | |||
| 396 | struct buffer_head *bh_cp; | 408 | struct buffer_head *bh_cp; |
| 397 | int err; | 409 | int err; |
| 398 | 410 | ||
| 399 | down_write(&nilfs->ns_sem); | 411 | down_write(&nilfs->ns_super_sem); |
| 400 | list_add(&sbi->s_list, &nilfs->ns_supers); | 412 | list_add(&sbi->s_list, &nilfs->ns_supers); |
| 401 | up_write(&nilfs->ns_sem); | 413 | up_write(&nilfs->ns_super_sem); |
| 402 | 414 | ||
| 403 | sbi->s_ifile = nilfs_mdt_new( | 415 | sbi->s_ifile = nilfs_mdt_new( |
| 404 | nilfs, sbi->s_super, NILFS_IFILE_INO, NILFS_IFILE_GFP); | 416 | nilfs, sbi->s_super, NILFS_IFILE_INO, NILFS_IFILE_GFP); |
| @@ -436,9 +448,9 @@ int nilfs_attach_checkpoint(struct nilfs_sb_info *sbi, __u64 cno) | |||
| 436 | nilfs_mdt_destroy(sbi->s_ifile); | 448 | nilfs_mdt_destroy(sbi->s_ifile); |
| 437 | sbi->s_ifile = NULL; | 449 | sbi->s_ifile = NULL; |
| 438 | 450 | ||
| 439 | down_write(&nilfs->ns_sem); | 451 | down_write(&nilfs->ns_super_sem); |
| 440 | list_del_init(&sbi->s_list); | 452 | list_del_init(&sbi->s_list); |
| 441 | up_write(&nilfs->ns_sem); | 453 | up_write(&nilfs->ns_super_sem); |
| 442 | 454 | ||
| 443 | return err; | 455 | return err; |
| 444 | } | 456 | } |
| @@ -450,9 +462,9 @@ void nilfs_detach_checkpoint(struct nilfs_sb_info *sbi) | |||
| 450 | nilfs_mdt_clear(sbi->s_ifile); | 462 | nilfs_mdt_clear(sbi->s_ifile); |
| 451 | nilfs_mdt_destroy(sbi->s_ifile); | 463 | nilfs_mdt_destroy(sbi->s_ifile); |
| 452 | sbi->s_ifile = NULL; | 464 | sbi->s_ifile = NULL; |
| 453 | down_write(&nilfs->ns_sem); | 465 | down_write(&nilfs->ns_super_sem); |
| 454 | list_del_init(&sbi->s_list); | 466 | list_del_init(&sbi->s_list); |
| 455 | up_write(&nilfs->ns_sem); | 467 | up_write(&nilfs->ns_super_sem); |
| 456 | } | 468 | } |
| 457 | 469 | ||
| 458 | static int nilfs_mark_recovery_complete(struct nilfs_sb_info *sbi) | 470 | static int nilfs_mark_recovery_complete(struct nilfs_sb_info *sbi) |
| @@ -752,7 +764,7 @@ int nilfs_store_magic_and_option(struct super_block *sb, | |||
| 752 | * @silent: silent mode flag | 764 | * @silent: silent mode flag |
| 753 | * @nilfs: the_nilfs struct | 765 | * @nilfs: the_nilfs struct |
| 754 | * | 766 | * |
| 755 | * This function is called exclusively by bd_mount_mutex. | 767 | * This function is called exclusively by nilfs->ns_mount_mutex. |
| 756 | * So, the recovery process is protected from other simultaneous mounts. | 768 | * So, the recovery process is protected from other simultaneous mounts. |
| 757 | */ | 769 | */ |
| 758 | static int | 770 | static int |
| @@ -773,6 +785,7 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent, | |||
| 773 | get_nilfs(nilfs); | 785 | get_nilfs(nilfs); |
| 774 | sbi->s_nilfs = nilfs; | 786 | sbi->s_nilfs = nilfs; |
| 775 | sbi->s_super = sb; | 787 | sbi->s_super = sb; |
| 788 | atomic_set(&sbi->s_count, 1); | ||
| 776 | 789 | ||
| 777 | err = init_nilfs(nilfs, sbi, (char *)data); | 790 | err = init_nilfs(nilfs, sbi, (char *)data); |
| 778 | if (err) | 791 | if (err) |
| @@ -870,6 +883,11 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent, | |||
| 870 | goto failed_root; | 883 | goto failed_root; |
| 871 | } | 884 | } |
| 872 | 885 | ||
| 886 | down_write(&nilfs->ns_super_sem); | ||
| 887 | if (!nilfs_test_opt(sbi, SNAPSHOT)) | ||
| 888 | nilfs->ns_current = sbi; | ||
| 889 | up_write(&nilfs->ns_super_sem); | ||
| 890 | |||
| 873 | return 0; | 891 | return 0; |
| 874 | 892 | ||
| 875 | failed_root: | 893 | failed_root: |
| @@ -885,7 +903,7 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent, | |||
| 885 | failed_sbi: | 903 | failed_sbi: |
| 886 | put_nilfs(nilfs); | 904 | put_nilfs(nilfs); |
| 887 | sb->s_fs_info = NULL; | 905 | sb->s_fs_info = NULL; |
| 888 | kfree(sbi); | 906 | nilfs_put_sbinfo(sbi); |
| 889 | return err; | 907 | return err; |
| 890 | } | 908 | } |
| 891 | 909 | ||
| @@ -898,6 +916,9 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data) | |||
| 898 | struct nilfs_mount_options old_opts; | 916 | struct nilfs_mount_options old_opts; |
| 899 | int err; | 917 | int err; |
| 900 | 918 | ||
| 919 | lock_kernel(); | ||
| 920 | |||
| 921 | down_write(&nilfs->ns_super_sem); | ||
| 901 | old_sb_flags = sb->s_flags; | 922 | old_sb_flags = sb->s_flags; |
| 902 | old_opts.mount_opt = sbi->s_mount_opt; | 923 | old_opts.mount_opt = sbi->s_mount_opt; |
| 903 | old_opts.snapshot_cno = sbi->s_snapshot_cno; | 924 | old_opts.snapshot_cno = sbi->s_snapshot_cno; |
| @@ -945,14 +966,12 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data) | |||
| 945 | * store the current valid flag. (It may have been changed | 966 | * store the current valid flag. (It may have been changed |
| 946 | * by fsck since we originally mounted the partition.) | 967 | * by fsck since we originally mounted the partition.) |
| 947 | */ | 968 | */ |
| 948 | down(&sb->s_bdev->bd_mount_sem); | 969 | if (nilfs->ns_current && nilfs->ns_current != sbi) { |
| 949 | /* Check existing RW-mount */ | ||
| 950 | if (test_exclusive_mount(sb->s_type, sb->s_bdev, 0)) { | ||
| 951 | printk(KERN_WARNING "NILFS (device %s): couldn't " | 970 | printk(KERN_WARNING "NILFS (device %s): couldn't " |
| 952 | "remount because a RW-mount exists.\n", | 971 | "remount because an RW-mount exists.\n", |
| 953 | sb->s_id); | 972 | sb->s_id); |
| 954 | err = -EBUSY; | 973 | err = -EBUSY; |
| 955 | goto rw_remount_failed; | 974 | goto restore_opts; |
| 956 | } | 975 | } |
| 957 | if (sbi->s_snapshot_cno != nilfs_last_cno(nilfs)) { | 976 | if (sbi->s_snapshot_cno != nilfs_last_cno(nilfs)) { |
| 958 | printk(KERN_WARNING "NILFS (device %s): couldn't " | 977 | printk(KERN_WARNING "NILFS (device %s): couldn't " |
| @@ -960,7 +979,7 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data) | |||
| 960 | "the latest one.\n", | 979 | "the latest one.\n", |
| 961 | sb->s_id); | 980 | sb->s_id); |
| 962 | err = -EINVAL; | 981 | err = -EINVAL; |
| 963 | goto rw_remount_failed; | 982 | goto restore_opts; |
| 964 | } | 983 | } |
| 965 | sb->s_flags &= ~MS_RDONLY; | 984 | sb->s_flags &= ~MS_RDONLY; |
| 966 | nilfs_clear_opt(sbi, SNAPSHOT); | 985 | nilfs_clear_opt(sbi, SNAPSHOT); |
| @@ -968,28 +987,31 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data) | |||
| 968 | 987 | ||
| 969 | err = nilfs_attach_segment_constructor(sbi); | 988 | err = nilfs_attach_segment_constructor(sbi); |
| 970 | if (err) | 989 | if (err) |
| 971 | goto rw_remount_failed; | 990 | goto restore_opts; |
| 972 | 991 | ||
| 973 | down_write(&nilfs->ns_sem); | 992 | down_write(&nilfs->ns_sem); |
| 974 | nilfs_setup_super(sbi); | 993 | nilfs_setup_super(sbi); |
| 975 | up_write(&nilfs->ns_sem); | 994 | up_write(&nilfs->ns_sem); |
| 976 | 995 | ||
| 977 | up(&sb->s_bdev->bd_mount_sem); | 996 | nilfs->ns_current = sbi; |
| 978 | } | 997 | } |
| 979 | out: | 998 | out: |
| 999 | up_write(&nilfs->ns_super_sem); | ||
| 1000 | unlock_kernel(); | ||
| 980 | return 0; | 1001 | return 0; |
| 981 | 1002 | ||
| 982 | rw_remount_failed: | ||
| 983 | up(&sb->s_bdev->bd_mount_sem); | ||
| 984 | restore_opts: | 1003 | restore_opts: |
| 985 | sb->s_flags = old_sb_flags; | 1004 | sb->s_flags = old_sb_flags; |
| 986 | sbi->s_mount_opt = old_opts.mount_opt; | 1005 | sbi->s_mount_opt = old_opts.mount_opt; |
| 987 | sbi->s_snapshot_cno = old_opts.snapshot_cno; | 1006 | sbi->s_snapshot_cno = old_opts.snapshot_cno; |
| 1007 | up_write(&nilfs->ns_super_sem); | ||
| 1008 | unlock_kernel(); | ||
| 988 | return err; | 1009 | return err; |
| 989 | } | 1010 | } |
| 990 | 1011 | ||
| 991 | struct nilfs_super_data { | 1012 | struct nilfs_super_data { |
| 992 | struct block_device *bdev; | 1013 | struct block_device *bdev; |
| 1014 | struct nilfs_sb_info *sbi; | ||
| 993 | __u64 cno; | 1015 | __u64 cno; |
| 994 | int flags; | 1016 | int flags; |
| 995 | }; | 1017 | }; |
| @@ -1048,33 +1070,7 @@ static int nilfs_test_bdev_super(struct super_block *s, void *data) | |||
| 1048 | { | 1070 | { |
| 1049 | struct nilfs_super_data *sd = data; | 1071 | struct nilfs_super_data *sd = data; |
| 1050 | 1072 | ||
| 1051 | return s->s_bdev == sd->bdev; | 1073 | return sd->sbi && s->s_fs_info == (void *)sd->sbi; |
| 1052 | } | ||
| 1053 | |||
| 1054 | static int nilfs_test_bdev_super2(struct super_block *s, void *data) | ||
| 1055 | { | ||
| 1056 | struct nilfs_super_data *sd = data; | ||
| 1057 | int ret; | ||
| 1058 | |||
| 1059 | if (s->s_bdev != sd->bdev) | ||
| 1060 | return 0; | ||
| 1061 | |||
| 1062 | if (!((s->s_flags | sd->flags) & MS_RDONLY)) | ||
| 1063 | return 1; /* Reuse an old R/W-mode super_block */ | ||
| 1064 | |||
| 1065 | if (s->s_flags & sd->flags & MS_RDONLY) { | ||
| 1066 | if (down_read_trylock(&s->s_umount)) { | ||
| 1067 | ret = s->s_root && | ||
| 1068 | (sd->cno == NILFS_SB(s)->s_snapshot_cno); | ||
| 1069 | up_read(&s->s_umount); | ||
| 1070 | /* | ||
| 1071 | * This path is locked with sb_lock by sget(). | ||
| 1072 | * So, drop_super() causes deadlock. | ||
| 1073 | */ | ||
| 1074 | return ret; | ||
| 1075 | } | ||
| 1076 | } | ||
| 1077 | return 0; | ||
| 1078 | } | 1074 | } |
| 1079 | 1075 | ||
| 1080 | static int | 1076 | static int |
| @@ -1082,8 +1078,8 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, | |||
| 1082 | const char *dev_name, void *data, struct vfsmount *mnt) | 1078 | const char *dev_name, void *data, struct vfsmount *mnt) |
| 1083 | { | 1079 | { |
| 1084 | struct nilfs_super_data sd; | 1080 | struct nilfs_super_data sd; |
| 1085 | struct super_block *s, *s2; | 1081 | struct super_block *s; |
| 1086 | struct the_nilfs *nilfs = NULL; | 1082 | struct the_nilfs *nilfs; |
| 1087 | int err, need_to_close = 1; | 1083 | int err, need_to_close = 1; |
| 1088 | 1084 | ||
| 1089 | sd.bdev = open_bdev_exclusive(dev_name, flags, fs_type); | 1085 | sd.bdev = open_bdev_exclusive(dev_name, flags, fs_type); |
| @@ -1095,7 +1091,6 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, | |||
| 1095 | * much more information than normal filesystems to identify mount | 1091 | * much more information than normal filesystems to identify mount |
| 1096 | * instance. For snapshot mounts, not only a mount type (ro-mount | 1092 | * instance. For snapshot mounts, not only a mount type (ro-mount |
| 1097 | * or rw-mount) but also a checkpoint number is required. | 1093 | * or rw-mount) but also a checkpoint number is required. |
| 1098 | * The results are passed in sget() using nilfs_super_data. | ||
| 1099 | */ | 1094 | */ |
| 1100 | sd.cno = 0; | 1095 | sd.cno = 0; |
| 1101 | sd.flags = flags; | 1096 | sd.flags = flags; |
| @@ -1104,64 +1099,59 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, | |||
| 1104 | goto failed; | 1099 | goto failed; |
| 1105 | } | 1100 | } |
| 1106 | 1101 | ||
| 1107 | /* | 1102 | nilfs = find_or_create_nilfs(sd.bdev); |
| 1108 | * once the super is inserted into the list by sget, s_umount | 1103 | if (!nilfs) { |
| 1109 | * will protect the lockfs code from trying to start a snapshot | 1104 | err = -ENOMEM; |
| 1110 | * while we are mounting | 1105 | goto failed; |
| 1111 | */ | ||
| 1112 | down(&sd.bdev->bd_mount_sem); | ||
| 1113 | if (!sd.cno && | ||
| 1114 | (err = test_exclusive_mount(fs_type, sd.bdev, flags ^ MS_RDONLY))) { | ||
| 1115 | err = (err < 0) ? : -EBUSY; | ||
| 1116 | goto failed_unlock; | ||
| 1117 | } | 1106 | } |
| 1118 | 1107 | ||
| 1119 | /* | 1108 | mutex_lock(&nilfs->ns_mount_mutex); |
| 1120 | * Phase-1: search any existent instance and get the_nilfs | ||
| 1121 | */ | ||
| 1122 | s = sget(fs_type, nilfs_test_bdev_super, nilfs_set_bdev_super, &sd); | ||
| 1123 | if (IS_ERR(s)) | ||
| 1124 | goto error_s; | ||
| 1125 | |||
| 1126 | if (!s->s_root) { | ||
| 1127 | err = -ENOMEM; | ||
| 1128 | nilfs = alloc_nilfs(sd.bdev); | ||
| 1129 | if (!nilfs) | ||
| 1130 | goto cancel_new; | ||
| 1131 | } else { | ||
| 1132 | struct nilfs_sb_info *sbi = NILFS_SB(s); | ||
| 1133 | 1109 | ||
| 1110 | if (!sd.cno) { | ||
| 1134 | /* | 1111 | /* |
| 1135 | * s_umount protects super_block from unmount process; | 1112 | * Check if an exclusive mount exists or not. |
| 1136 | * It covers pointers of nilfs_sb_info and the_nilfs. | 1113 | * Snapshot mounts coexist with a current mount |
| 1114 | * (i.e. rw-mount or ro-mount), whereas rw-mount and | ||
| 1115 | * ro-mount are mutually exclusive. | ||
| 1137 | */ | 1116 | */ |
| 1138 | nilfs = sbi->s_nilfs; | 1117 | down_read(&nilfs->ns_super_sem); |
| 1139 | get_nilfs(nilfs); | 1118 | if (nilfs->ns_current && |
| 1140 | up_write(&s->s_umount); | 1119 | ((nilfs->ns_current->s_super->s_flags ^ flags) |
| 1120 | & MS_RDONLY)) { | ||
| 1121 | up_read(&nilfs->ns_super_sem); | ||
| 1122 | err = -EBUSY; | ||
| 1123 | goto failed_unlock; | ||
| 1124 | } | ||
| 1125 | up_read(&nilfs->ns_super_sem); | ||
| 1126 | } | ||
| 1141 | 1127 | ||
| 1142 | /* | 1128 | /* |
| 1143 | * Phase-2: search specified snapshot or R/W mode super_block | 1129 | * Find existing nilfs_sb_info struct |
| 1144 | */ | 1130 | */ |
| 1145 | if (!sd.cno) | 1131 | sd.sbi = nilfs_find_sbinfo(nilfs, !(flags & MS_RDONLY), sd.cno); |
| 1146 | /* trying to get the latest checkpoint. */ | ||
| 1147 | sd.cno = nilfs_last_cno(nilfs); | ||
| 1148 | 1132 | ||
| 1149 | s2 = sget(fs_type, nilfs_test_bdev_super2, | 1133 | if (!sd.cno) |
| 1150 | nilfs_set_bdev_super, &sd); | 1134 | /* trying to get the latest checkpoint. */ |
| 1151 | deactivate_super(s); | 1135 | sd.cno = nilfs_last_cno(nilfs); |
| 1152 | /* | 1136 | |
| 1153 | * Although deactivate_super() invokes close_bdev_exclusive() at | 1137 | /* |
| 1154 | * kill_block_super(). Here, s is an existent mount; we need | 1138 | * Get super block instance holding the nilfs_sb_info struct. |
| 1155 | * one more close_bdev_exclusive() call. | 1139 | * A new instance is allocated if no existing mount is present or |
| 1156 | */ | 1140 | * existing instance has been unmounted. |
| 1157 | s = s2; | 1141 | */ |
| 1158 | if (IS_ERR(s)) | 1142 | s = sget(fs_type, nilfs_test_bdev_super, nilfs_set_bdev_super, &sd); |
| 1159 | goto error_s; | 1143 | if (sd.sbi) |
| 1144 | nilfs_put_sbinfo(sd.sbi); | ||
| 1145 | |||
| 1146 | if (IS_ERR(s)) { | ||
| 1147 | err = PTR_ERR(s); | ||
| 1148 | goto failed_unlock; | ||
| 1160 | } | 1149 | } |
| 1161 | 1150 | ||
| 1162 | if (!s->s_root) { | 1151 | if (!s->s_root) { |
| 1163 | char b[BDEVNAME_SIZE]; | 1152 | char b[BDEVNAME_SIZE]; |
| 1164 | 1153 | ||
| 1154 | /* New superblock instance created */ | ||
| 1165 | s->s_flags = flags; | 1155 | s->s_flags = flags; |
| 1166 | strlcpy(s->s_id, bdevname(sd.bdev, b), sizeof(s->s_id)); | 1156 | strlcpy(s->s_id, bdevname(sd.bdev, b), sizeof(s->s_id)); |
| 1167 | sb_set_blocksize(s, block_size(sd.bdev)); | 1157 | sb_set_blocksize(s, block_size(sd.bdev)); |
| @@ -1172,26 +1162,18 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, | |||
| 1172 | 1162 | ||
| 1173 | s->s_flags |= MS_ACTIVE; | 1163 | s->s_flags |= MS_ACTIVE; |
| 1174 | need_to_close = 0; | 1164 | need_to_close = 0; |
| 1175 | } else if (!(s->s_flags & MS_RDONLY)) { | ||
| 1176 | err = -EBUSY; | ||
| 1177 | } | 1165 | } |
| 1178 | 1166 | ||
| 1179 | up(&sd.bdev->bd_mount_sem); | 1167 | mutex_unlock(&nilfs->ns_mount_mutex); |
| 1180 | put_nilfs(nilfs); | 1168 | put_nilfs(nilfs); |
| 1181 | if (need_to_close) | 1169 | if (need_to_close) |
| 1182 | close_bdev_exclusive(sd.bdev, flags); | 1170 | close_bdev_exclusive(sd.bdev, flags); |
| 1183 | simple_set_mnt(mnt, s); | 1171 | simple_set_mnt(mnt, s); |
| 1184 | return 0; | 1172 | return 0; |
| 1185 | 1173 | ||
| 1186 | error_s: | ||
| 1187 | up(&sd.bdev->bd_mount_sem); | ||
| 1188 | if (nilfs) | ||
| 1189 | put_nilfs(nilfs); | ||
| 1190 | close_bdev_exclusive(sd.bdev, flags); | ||
| 1191 | return PTR_ERR(s); | ||
| 1192 | |||
| 1193 | failed_unlock: | 1174 | failed_unlock: |
| 1194 | up(&sd.bdev->bd_mount_sem); | 1175 | mutex_unlock(&nilfs->ns_mount_mutex); |
| 1176 | put_nilfs(nilfs); | ||
| 1195 | failed: | 1177 | failed: |
| 1196 | close_bdev_exclusive(sd.bdev, flags); | 1178 | close_bdev_exclusive(sd.bdev, flags); |
| 1197 | 1179 | ||
| @@ -1199,70 +1181,18 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, | |||
| 1199 | 1181 | ||
| 1200 | cancel_new: | 1182 | cancel_new: |
| 1201 | /* Abandoning the newly allocated superblock */ | 1183 | /* Abandoning the newly allocated superblock */ |
| 1202 | up(&sd.bdev->bd_mount_sem); | 1184 | mutex_unlock(&nilfs->ns_mount_mutex); |
| 1203 | if (nilfs) | 1185 | put_nilfs(nilfs); |
| 1204 | put_nilfs(nilfs); | ||
| 1205 | up_write(&s->s_umount); | 1186 | up_write(&s->s_umount); |
| 1206 | deactivate_super(s); | 1187 | deactivate_super(s); |
| 1207 | /* | 1188 | /* |
| 1208 | * deactivate_super() invokes close_bdev_exclusive(). | 1189 | * deactivate_super() invokes close_bdev_exclusive(). |
| 1209 | * We must finish all post-cleaning before this call; | 1190 | * We must finish all post-cleaning before this call; |
| 1210 | * put_nilfs() and unlocking bd_mount_sem need the block device. | 1191 | * put_nilfs() needs the block device. |
| 1211 | */ | 1192 | */ |
| 1212 | return err; | 1193 | return err; |
| 1213 | } | 1194 | } |
| 1214 | 1195 | ||
| 1215 | static int nilfs_test_bdev_super3(struct super_block *s, void *data) | ||
| 1216 | { | ||
| 1217 | struct nilfs_super_data *sd = data; | ||
| 1218 | int ret; | ||
| 1219 | |||
| 1220 | if (s->s_bdev != sd->bdev) | ||
| 1221 | return 0; | ||
| 1222 | if (down_read_trylock(&s->s_umount)) { | ||
| 1223 | ret = (s->s_flags & MS_RDONLY) && s->s_root && | ||
| 1224 | nilfs_test_opt(NILFS_SB(s), SNAPSHOT); | ||
| 1225 | up_read(&s->s_umount); | ||
| 1226 | if (ret) | ||
| 1227 | return 0; /* ignore snapshot mounts */ | ||
| 1228 | } | ||
| 1229 | return !((sd->flags ^ s->s_flags) & MS_RDONLY); | ||
| 1230 | } | ||
| 1231 | |||
| 1232 | static int __false_bdev_super(struct super_block *s, void *data) | ||
| 1233 | { | ||
| 1234 | #if 0 /* XXX: workaround for lock debug. This is not good idea */ | ||
| 1235 | up_write(&s->s_umount); | ||
| 1236 | #endif | ||
| 1237 | return -EFAULT; | ||
| 1238 | } | ||
| 1239 | |||
| 1240 | /** | ||
| 1241 | * test_exclusive_mount - check whether an exclusive RW/RO mount exists or not. | ||
| 1242 | * fs_type: filesystem type | ||
| 1243 | * bdev: block device | ||
| 1244 | * flag: 0 (check rw-mount) or MS_RDONLY (check ro-mount) | ||
| 1245 | * res: pointer to an integer to store result | ||
| 1246 | * | ||
| 1247 | * This function must be called within a section protected by bd_mount_mutex. | ||
| 1248 | */ | ||
| 1249 | static int test_exclusive_mount(struct file_system_type *fs_type, | ||
| 1250 | struct block_device *bdev, int flags) | ||
| 1251 | { | ||
| 1252 | struct super_block *s; | ||
| 1253 | struct nilfs_super_data sd = { .flags = flags, .bdev = bdev }; | ||
| 1254 | |||
| 1255 | s = sget(fs_type, nilfs_test_bdev_super3, __false_bdev_super, &sd); | ||
| 1256 | if (IS_ERR(s)) { | ||
| 1257 | if (PTR_ERR(s) != -EFAULT) | ||
| 1258 | return PTR_ERR(s); | ||
| 1259 | return 0; /* Not found */ | ||
| 1260 | } | ||
| 1261 | up_write(&s->s_umount); | ||
| 1262 | deactivate_super(s); | ||
| 1263 | return 1; /* Found */ | ||
| 1264 | } | ||
| 1265 | |||
| 1266 | struct file_system_type nilfs_fs_type = { | 1196 | struct file_system_type nilfs_fs_type = { |
| 1267 | .owner = THIS_MODULE, | 1197 | .owner = THIS_MODULE, |
| 1268 | .name = "nilfs2", | 1198 | .name = "nilfs2", |
diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c index 7f65b3be4aa9..e4e5c78bcc93 100644 --- a/fs/nilfs2/the_nilfs.c +++ b/fs/nilfs2/the_nilfs.c | |||
| @@ -35,6 +35,10 @@ | |||
| 35 | #include "seglist.h" | 35 | #include "seglist.h" |
| 36 | #include "segbuf.h" | 36 | #include "segbuf.h" |
| 37 | 37 | ||
| 38 | |||
| 39 | static LIST_HEAD(nilfs_objects); | ||
| 40 | static DEFINE_SPINLOCK(nilfs_lock); | ||
| 41 | |||
| 38 | void nilfs_set_last_segment(struct the_nilfs *nilfs, | 42 | void nilfs_set_last_segment(struct the_nilfs *nilfs, |
| 39 | sector_t start_blocknr, u64 seq, __u64 cno) | 43 | sector_t start_blocknr, u64 seq, __u64 cno) |
| 40 | { | 44 | { |
| @@ -55,7 +59,7 @@ void nilfs_set_last_segment(struct the_nilfs *nilfs, | |||
| 55 | * Return Value: On success, pointer to the_nilfs is returned. | 59 | * Return Value: On success, pointer to the_nilfs is returned. |
| 56 | * On error, NULL is returned. | 60 | * On error, NULL is returned. |
| 57 | */ | 61 | */ |
| 58 | struct the_nilfs *alloc_nilfs(struct block_device *bdev) | 62 | static struct the_nilfs *alloc_nilfs(struct block_device *bdev) |
| 59 | { | 63 | { |
| 60 | struct the_nilfs *nilfs; | 64 | struct the_nilfs *nilfs; |
| 61 | 65 | ||
| @@ -68,7 +72,10 @@ struct the_nilfs *alloc_nilfs(struct block_device *bdev) | |||
| 68 | atomic_set(&nilfs->ns_writer_refcount, -1); | 72 | atomic_set(&nilfs->ns_writer_refcount, -1); |
| 69 | atomic_set(&nilfs->ns_ndirtyblks, 0); | 73 | atomic_set(&nilfs->ns_ndirtyblks, 0); |
| 70 | init_rwsem(&nilfs->ns_sem); | 74 | init_rwsem(&nilfs->ns_sem); |
| 75 | init_rwsem(&nilfs->ns_super_sem); | ||
| 76 | mutex_init(&nilfs->ns_mount_mutex); | ||
| 71 | mutex_init(&nilfs->ns_writer_mutex); | 77 | mutex_init(&nilfs->ns_writer_mutex); |
| 78 | INIT_LIST_HEAD(&nilfs->ns_list); | ||
| 72 | INIT_LIST_HEAD(&nilfs->ns_supers); | 79 | INIT_LIST_HEAD(&nilfs->ns_supers); |
| 73 | spin_lock_init(&nilfs->ns_last_segment_lock); | 80 | spin_lock_init(&nilfs->ns_last_segment_lock); |
| 74 | nilfs->ns_gc_inodes_h = NULL; | 81 | nilfs->ns_gc_inodes_h = NULL; |
| @@ -78,6 +85,45 @@ struct the_nilfs *alloc_nilfs(struct block_device *bdev) | |||
| 78 | } | 85 | } |
| 79 | 86 | ||
| 80 | /** | 87 | /** |
| 88 | * find_or_create_nilfs - find or create nilfs object | ||
| 89 | * @bdev: block device to which the_nilfs is related | ||
| 90 | * | ||
| 91 | * find_nilfs() looks up an existent nilfs object created on the | ||
| 92 | * device and gets the reference count of the object. If no nilfs object | ||
| 93 | * is found on the device, a new nilfs object is allocated. | ||
| 94 | * | ||
| 95 | * Return Value: On success, pointer to the nilfs object is returned. | ||
| 96 | * On error, NULL is returned. | ||
| 97 | */ | ||
| 98 | struct the_nilfs *find_or_create_nilfs(struct block_device *bdev) | ||
| 99 | { | ||
| 100 | struct the_nilfs *nilfs, *new = NULL; | ||
| 101 | |||
| 102 | retry: | ||
| 103 | spin_lock(&nilfs_lock); | ||
| 104 | list_for_each_entry(nilfs, &nilfs_objects, ns_list) { | ||
| 105 | if (nilfs->ns_bdev == bdev) { | ||
| 106 | get_nilfs(nilfs); | ||
| 107 | spin_unlock(&nilfs_lock); | ||
| 108 | if (new) | ||
| 109 | put_nilfs(new); | ||
| 110 | return nilfs; /* existing object */ | ||
| 111 | } | ||
| 112 | } | ||
| 113 | if (new) { | ||
| 114 | list_add_tail(&new->ns_list, &nilfs_objects); | ||
| 115 | spin_unlock(&nilfs_lock); | ||
| 116 | return new; /* new object */ | ||
| 117 | } | ||
| 118 | spin_unlock(&nilfs_lock); | ||
| 119 | |||
| 120 | new = alloc_nilfs(bdev); | ||
| 121 | if (new) | ||
| 122 | goto retry; | ||
| 123 | return NULL; /* insufficient memory */ | ||
| 124 | } | ||
| 125 | |||
| 126 | /** | ||
| 81 | * put_nilfs - release a reference to the_nilfs | 127 | * put_nilfs - release a reference to the_nilfs |
| 82 | * @nilfs: the_nilfs structure to be released | 128 | * @nilfs: the_nilfs structure to be released |
| 83 | * | 129 | * |
| @@ -86,13 +132,20 @@ struct the_nilfs *alloc_nilfs(struct block_device *bdev) | |||
| 86 | */ | 132 | */ |
| 87 | void put_nilfs(struct the_nilfs *nilfs) | 133 | void put_nilfs(struct the_nilfs *nilfs) |
| 88 | { | 134 | { |
| 89 | if (!atomic_dec_and_test(&nilfs->ns_count)) | 135 | spin_lock(&nilfs_lock); |
| 136 | if (!atomic_dec_and_test(&nilfs->ns_count)) { | ||
| 137 | spin_unlock(&nilfs_lock); | ||
| 90 | return; | 138 | return; |
| 139 | } | ||
| 140 | list_del_init(&nilfs->ns_list); | ||
| 141 | spin_unlock(&nilfs_lock); | ||
| 142 | |||
| 91 | /* | 143 | /* |
| 92 | * Increment of ns_count never occur below because the caller | 144 | * Increment of ns_count never occurs below because the caller |
| 93 | * of get_nilfs() holds at least one reference to the_nilfs. | 145 | * of get_nilfs() holds at least one reference to the_nilfs. |
| 94 | * Thus its exclusion control is not required here. | 146 | * Thus its exclusion control is not required here. |
| 95 | */ | 147 | */ |
| 148 | |||
| 96 | might_sleep(); | 149 | might_sleep(); |
| 97 | if (nilfs_loaded(nilfs)) { | 150 | if (nilfs_loaded(nilfs)) { |
| 98 | nilfs_mdt_clear(nilfs->ns_sufile); | 151 | nilfs_mdt_clear(nilfs->ns_sufile); |
| @@ -515,7 +568,7 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data) | |||
| 515 | 568 | ||
| 516 | blocksize = BLOCK_SIZE << le32_to_cpu(sbp->s_log_block_size); | 569 | blocksize = BLOCK_SIZE << le32_to_cpu(sbp->s_log_block_size); |
| 517 | if (sb->s_blocksize != blocksize) { | 570 | if (sb->s_blocksize != blocksize) { |
| 518 | int hw_blocksize = bdev_hardsect_size(sb->s_bdev); | 571 | int hw_blocksize = bdev_logical_block_size(sb->s_bdev); |
| 519 | 572 | ||
| 520 | if (blocksize < hw_blocksize) { | 573 | if (blocksize < hw_blocksize) { |
| 521 | printk(KERN_ERR | 574 | printk(KERN_ERR |
| @@ -613,13 +666,63 @@ int nilfs_near_disk_full(struct the_nilfs *nilfs) | |||
| 613 | return ret; | 666 | return ret; |
| 614 | } | 667 | } |
| 615 | 668 | ||
| 669 | /** | ||
| 670 | * nilfs_find_sbinfo - find existing nilfs_sb_info structure | ||
| 671 | * @nilfs: nilfs object | ||
| 672 | * @rw_mount: mount type (non-zero value for read/write mount) | ||
| 673 | * @cno: checkpoint number (zero for read-only mount) | ||
| 674 | * | ||
| 675 | * nilfs_find_sbinfo() returns the nilfs_sb_info structure which | ||
| 676 | * @rw_mount and @cno (in case of snapshots) matched. If no instance | ||
| 677 | * was found, NULL is returned. Although the super block instance can | ||
| 678 | * be unmounted after this function returns, the nilfs_sb_info struct | ||
| 679 | * is kept on memory until nilfs_put_sbinfo() is called. | ||
| 680 | */ | ||
| 681 | struct nilfs_sb_info *nilfs_find_sbinfo(struct the_nilfs *nilfs, | ||
| 682 | int rw_mount, __u64 cno) | ||
| 683 | { | ||
| 684 | struct nilfs_sb_info *sbi; | ||
| 685 | |||
| 686 | down_read(&nilfs->ns_super_sem); | ||
| 687 | /* | ||
| 688 | * The SNAPSHOT flag and sb->s_flags are supposed to be | ||
| 689 | * protected with nilfs->ns_super_sem. | ||
| 690 | */ | ||
| 691 | sbi = nilfs->ns_current; | ||
| 692 | if (rw_mount) { | ||
| 693 | if (sbi && !(sbi->s_super->s_flags & MS_RDONLY)) | ||
| 694 | goto found; /* read/write mount */ | ||
| 695 | else | ||
| 696 | goto out; | ||
| 697 | } else if (cno == 0) { | ||
| 698 | if (sbi && (sbi->s_super->s_flags & MS_RDONLY)) | ||
| 699 | goto found; /* read-only mount */ | ||
| 700 | else | ||
| 701 | goto out; | ||
| 702 | } | ||
| 703 | |||
| 704 | list_for_each_entry(sbi, &nilfs->ns_supers, s_list) { | ||
| 705 | if (nilfs_test_opt(sbi, SNAPSHOT) && | ||
| 706 | sbi->s_snapshot_cno == cno) | ||
| 707 | goto found; /* snapshot mount */ | ||
| 708 | } | ||
| 709 | out: | ||
| 710 | up_read(&nilfs->ns_super_sem); | ||
| 711 | return NULL; | ||
| 712 | |||
| 713 | found: | ||
| 714 | atomic_inc(&sbi->s_count); | ||
| 715 | up_read(&nilfs->ns_super_sem); | ||
| 716 | return sbi; | ||
| 717 | } | ||
| 718 | |||
| 616 | int nilfs_checkpoint_is_mounted(struct the_nilfs *nilfs, __u64 cno, | 719 | int nilfs_checkpoint_is_mounted(struct the_nilfs *nilfs, __u64 cno, |
| 617 | int snapshot_mount) | 720 | int snapshot_mount) |
| 618 | { | 721 | { |
| 619 | struct nilfs_sb_info *sbi; | 722 | struct nilfs_sb_info *sbi; |
| 620 | int ret = 0; | 723 | int ret = 0; |
| 621 | 724 | ||
| 622 | down_read(&nilfs->ns_sem); | 725 | down_read(&nilfs->ns_super_sem); |
| 623 | if (cno == 0 || cno > nilfs->ns_cno) | 726 | if (cno == 0 || cno > nilfs->ns_cno) |
| 624 | goto out_unlock; | 727 | goto out_unlock; |
| 625 | 728 | ||
| @@ -636,6 +739,6 @@ int nilfs_checkpoint_is_mounted(struct the_nilfs *nilfs, __u64 cno, | |||
| 636 | ret++; | 739 | ret++; |
| 637 | 740 | ||
| 638 | out_unlock: | 741 | out_unlock: |
| 639 | up_read(&nilfs->ns_sem); | 742 | up_read(&nilfs->ns_super_sem); |
| 640 | return ret; | 743 | return ret; |
| 641 | } | 744 | } |
diff --git a/fs/nilfs2/the_nilfs.h b/fs/nilfs2/the_nilfs.h index 30fe58778d05..e8adbffc626f 100644 --- a/fs/nilfs2/the_nilfs.h +++ b/fs/nilfs2/the_nilfs.h | |||
| @@ -43,12 +43,16 @@ enum { | |||
| 43 | * struct the_nilfs - struct to supervise multiple nilfs mount points | 43 | * struct the_nilfs - struct to supervise multiple nilfs mount points |
| 44 | * @ns_flags: flags | 44 | * @ns_flags: flags |
| 45 | * @ns_count: reference count | 45 | * @ns_count: reference count |
| 46 | * @ns_list: list head for nilfs_list | ||
| 46 | * @ns_bdev: block device | 47 | * @ns_bdev: block device |
| 47 | * @ns_bdi: backing dev info | 48 | * @ns_bdi: backing dev info |
| 48 | * @ns_writer: back pointer to writable nilfs_sb_info | 49 | * @ns_writer: back pointer to writable nilfs_sb_info |
| 49 | * @ns_sem: semaphore for shared states | 50 | * @ns_sem: semaphore for shared states |
| 51 | * @ns_super_sem: semaphore for global operations across super block instances | ||
| 52 | * @ns_mount_mutex: mutex protecting mount process of nilfs | ||
| 50 | * @ns_writer_mutex: mutex protecting ns_writer attach/detach | 53 | * @ns_writer_mutex: mutex protecting ns_writer attach/detach |
| 51 | * @ns_writer_refcount: number of referrers on ns_writer | 54 | * @ns_writer_refcount: number of referrers on ns_writer |
| 55 | * @ns_current: back pointer to current mount | ||
| 52 | * @ns_sbh: buffer heads of on-disk super blocks | 56 | * @ns_sbh: buffer heads of on-disk super blocks |
| 53 | * @ns_sbp: pointers to super block data | 57 | * @ns_sbp: pointers to super block data |
| 54 | * @ns_sbwtime: previous write time of super blocks | 58 | * @ns_sbwtime: previous write time of super blocks |
| @@ -88,15 +92,24 @@ enum { | |||
| 88 | struct the_nilfs { | 92 | struct the_nilfs { |
| 89 | unsigned long ns_flags; | 93 | unsigned long ns_flags; |
| 90 | atomic_t ns_count; | 94 | atomic_t ns_count; |
| 95 | struct list_head ns_list; | ||
| 91 | 96 | ||
| 92 | struct block_device *ns_bdev; | 97 | struct block_device *ns_bdev; |
| 93 | struct backing_dev_info *ns_bdi; | 98 | struct backing_dev_info *ns_bdi; |
| 94 | struct nilfs_sb_info *ns_writer; | 99 | struct nilfs_sb_info *ns_writer; |
| 95 | struct rw_semaphore ns_sem; | 100 | struct rw_semaphore ns_sem; |
| 101 | struct rw_semaphore ns_super_sem; | ||
| 102 | struct mutex ns_mount_mutex; | ||
| 96 | struct mutex ns_writer_mutex; | 103 | struct mutex ns_writer_mutex; |
| 97 | atomic_t ns_writer_refcount; | 104 | atomic_t ns_writer_refcount; |
| 98 | 105 | ||
| 99 | /* | 106 | /* |
| 107 | * components protected by ns_super_sem | ||
| 108 | */ | ||
| 109 | struct nilfs_sb_info *ns_current; | ||
| 110 | struct list_head ns_supers; | ||
| 111 | |||
| 112 | /* | ||
| 100 | * used for | 113 | * used for |
| 101 | * - loading the latest checkpoint exclusively. | 114 | * - loading the latest checkpoint exclusively. |
| 102 | * - allocating a new full segment. | 115 | * - allocating a new full segment. |
| @@ -108,7 +121,6 @@ struct the_nilfs { | |||
| 108 | time_t ns_sbwtime[2]; | 121 | time_t ns_sbwtime[2]; |
| 109 | unsigned ns_sbsize; | 122 | unsigned ns_sbsize; |
| 110 | unsigned ns_mount_state; | 123 | unsigned ns_mount_state; |
| 111 | struct list_head ns_supers; | ||
| 112 | 124 | ||
| 113 | /* | 125 | /* |
| 114 | * Following fields are dedicated to a writable FS-instance. | 126 | * Following fields are dedicated to a writable FS-instance. |
| @@ -191,11 +203,12 @@ THE_NILFS_FNS(DISCONTINUED, discontinued) | |||
| 191 | #define NILFS_ALTSB_FREQ 60 /* spare superblock */ | 203 | #define NILFS_ALTSB_FREQ 60 /* spare superblock */ |
| 192 | 204 | ||
| 193 | void nilfs_set_last_segment(struct the_nilfs *, sector_t, u64, __u64); | 205 | void nilfs_set_last_segment(struct the_nilfs *, sector_t, u64, __u64); |
| 194 | struct the_nilfs *alloc_nilfs(struct block_device *); | 206 | struct the_nilfs *find_or_create_nilfs(struct block_device *); |
| 195 | void put_nilfs(struct the_nilfs *); | 207 | void put_nilfs(struct the_nilfs *); |
| 196 | int init_nilfs(struct the_nilfs *, struct nilfs_sb_info *, char *); | 208 | int init_nilfs(struct the_nilfs *, struct nilfs_sb_info *, char *); |
| 197 | int load_nilfs(struct the_nilfs *, struct nilfs_sb_info *); | 209 | int load_nilfs(struct the_nilfs *, struct nilfs_sb_info *); |
| 198 | int nilfs_count_free_blocks(struct the_nilfs *, sector_t *); | 210 | int nilfs_count_free_blocks(struct the_nilfs *, sector_t *); |
| 211 | struct nilfs_sb_info *nilfs_find_sbinfo(struct the_nilfs *, int, __u64); | ||
| 199 | int nilfs_checkpoint_is_mounted(struct the_nilfs *, __u64, int); | 212 | int nilfs_checkpoint_is_mounted(struct the_nilfs *, __u64, int); |
| 200 | int nilfs_near_disk_full(struct the_nilfs *); | 213 | int nilfs_near_disk_full(struct the_nilfs *); |
| 201 | void nilfs_fall_back_super_block(struct the_nilfs *); | 214 | void nilfs_fall_back_super_block(struct the_nilfs *); |
| @@ -238,6 +251,12 @@ nilfs_detach_writer(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi) | |||
| 238 | mutex_unlock(&nilfs->ns_writer_mutex); | 251 | mutex_unlock(&nilfs->ns_writer_mutex); |
| 239 | } | 252 | } |
| 240 | 253 | ||
| 254 | static inline void nilfs_put_sbinfo(struct nilfs_sb_info *sbi) | ||
| 255 | { | ||
| 256 | if (!atomic_dec_and_test(&sbi->s_count)) | ||
| 257 | kfree(sbi); | ||
| 258 | } | ||
| 259 | |||
| 241 | static inline void | 260 | static inline void |
| 242 | nilfs_get_segment_range(struct the_nilfs *nilfs, __u64 segnum, | 261 | nilfs_get_segment_range(struct the_nilfs *nilfs, __u64 segnum, |
| 243 | sector_t *seg_start, sector_t *seg_end) | 262 | sector_t *seg_start, sector_t *seg_end) |
