diff options
| -rw-r--r-- | fs/nilfs2/super.c | 92 | ||||
| -rw-r--r-- | fs/nilfs2/the_nilfs.h | 3 |
2 files changed, 35 insertions, 60 deletions
diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 3c9833e3e74a..5a8c5e4731b3 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c | |||
| @@ -67,8 +67,6 @@ MODULE_LICENSE("GPL"); | |||
| 67 | 67 | ||
| 68 | static void nilfs_write_super(struct super_block *sb); | 68 | static void nilfs_write_super(struct super_block *sb); |
| 69 | 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); |
| 70 | static int test_exclusive_mount(struct file_system_type *fs_type, | ||
| 71 | struct block_device *bdev, int flags); | ||
| 72 | 70 | ||
| 73 | /** | 71 | /** |
| 74 | * nilfs_error() - report failure condition on a filesystem | 72 | * nilfs_error() - report failure condition on a filesystem |
| @@ -329,6 +327,10 @@ static void nilfs_put_super(struct super_block *sb) | |||
| 329 | nilfs_commit_super(sbi, 1); | 327 | nilfs_commit_super(sbi, 1); |
| 330 | up_write(&nilfs->ns_sem); | 328 | up_write(&nilfs->ns_sem); |
| 331 | } | 329 | } |
| 330 | down_write(&nilfs->ns_sem); | ||
| 331 | if (nilfs->ns_current == sbi) | ||
| 332 | nilfs->ns_current = NULL; | ||
| 333 | up_write(&nilfs->ns_sem); | ||
| 332 | 334 | ||
| 333 | nilfs_detach_checkpoint(sbi); | 335 | nilfs_detach_checkpoint(sbi); |
| 334 | put_nilfs(sbi->s_nilfs); | 336 | put_nilfs(sbi->s_nilfs); |
| @@ -880,6 +882,11 @@ nilfs_fill_super(struct super_block *sb, void *data, int silent, | |||
| 880 | goto failed_root; | 882 | goto failed_root; |
| 881 | } | 883 | } |
| 882 | 884 | ||
| 885 | down_write(&nilfs->ns_sem); | ||
| 886 | if (!nilfs_test_opt(sbi, SNAPSHOT)) | ||
| 887 | nilfs->ns_current = sbi; | ||
| 888 | up_write(&nilfs->ns_sem); | ||
| 889 | |||
| 883 | return 0; | 890 | return 0; |
| 884 | 891 | ||
| 885 | failed_root: | 892 | failed_root: |
| @@ -958,14 +965,16 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data) | |||
| 958 | * by fsck since we originally mounted the partition.) | 965 | * by fsck since we originally mounted the partition.) |
| 959 | */ | 966 | */ |
| 960 | down(&sb->s_bdev->bd_mount_sem); | 967 | down(&sb->s_bdev->bd_mount_sem); |
| 961 | /* Check existing RW-mount */ | 968 | down_read(&nilfs->ns_sem); |
| 962 | if (test_exclusive_mount(sb->s_type, sb->s_bdev, 0)) { | 969 | if (nilfs->ns_current && nilfs->ns_current != sbi) { |
| 963 | printk(KERN_WARNING "NILFS (device %s): couldn't " | 970 | printk(KERN_WARNING "NILFS (device %s): couldn't " |
| 964 | "remount because a RW-mount exists.\n", | 971 | "remount because an RW-mount exists.\n", |
| 965 | sb->s_id); | 972 | sb->s_id); |
| 973 | up_read(&nilfs->ns_sem); | ||
| 966 | err = -EBUSY; | 974 | err = -EBUSY; |
| 967 | goto rw_remount_failed; | 975 | goto rw_remount_failed; |
| 968 | } | 976 | } |
| 977 | up_read(&nilfs->ns_sem); | ||
| 969 | if (sbi->s_snapshot_cno != nilfs_last_cno(nilfs)) { | 978 | if (sbi->s_snapshot_cno != nilfs_last_cno(nilfs)) { |
| 970 | printk(KERN_WARNING "NILFS (device %s): couldn't " | 979 | printk(KERN_WARNING "NILFS (device %s): couldn't " |
| 971 | "remount because the current RO-mount is not " | 980 | "remount because the current RO-mount is not " |
| @@ -984,6 +993,7 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data) | |||
| 984 | 993 | ||
| 985 | down_write(&nilfs->ns_sem); | 994 | down_write(&nilfs->ns_sem); |
| 986 | nilfs_setup_super(sbi); | 995 | nilfs_setup_super(sbi); |
| 996 | nilfs->ns_current = sbi; | ||
| 987 | up_write(&nilfs->ns_sem); | 997 | up_write(&nilfs->ns_sem); |
| 988 | 998 | ||
| 989 | up(&sb->s_bdev->bd_mount_sem); | 999 | up(&sb->s_bdev->bd_mount_sem); |
| @@ -1118,10 +1128,23 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, | |||
| 1118 | } | 1128 | } |
| 1119 | 1129 | ||
| 1120 | down(&sd.bdev->bd_mount_sem); | 1130 | down(&sd.bdev->bd_mount_sem); |
| 1121 | if (!sd.cno && | 1131 | |
| 1122 | (err = test_exclusive_mount(fs_type, sd.bdev, flags ^ MS_RDONLY))) { | 1132 | if (!sd.cno) { |
| 1123 | err = (err < 0) ? : -EBUSY; | 1133 | /* |
| 1124 | goto failed_unlock; | 1134 | * Check if an exclusive mount exists or not. |
| 1135 | * Snapshot mounts coexist with a current mount | ||
| 1136 | * (i.e. rw-mount or ro-mount), whereas rw-mount and | ||
| 1137 | * ro-mount are mutually exclusive. | ||
| 1138 | */ | ||
| 1139 | down_read(&nilfs->ns_sem); | ||
| 1140 | if (nilfs->ns_current && | ||
| 1141 | ((nilfs->ns_current->s_super->s_flags ^ flags) | ||
| 1142 | & MS_RDONLY)) { | ||
| 1143 | up_read(&nilfs->ns_sem); | ||
| 1144 | err = -EBUSY; | ||
| 1145 | goto failed_unlock; | ||
| 1146 | } | ||
| 1147 | up_read(&nilfs->ns_sem); | ||
| 1125 | } | 1148 | } |
| 1126 | 1149 | ||
| 1127 | /* | 1150 | /* |
| @@ -1182,57 +1205,6 @@ nilfs_get_sb(struct file_system_type *fs_type, int flags, | |||
| 1182 | return err; | 1205 | return err; |
| 1183 | } | 1206 | } |
| 1184 | 1207 | ||
| 1185 | static int nilfs_test_bdev_super3(struct super_block *s, void *data) | ||
| 1186 | { | ||
| 1187 | struct nilfs_super_data *sd = data; | ||
| 1188 | int ret; | ||
| 1189 | |||
| 1190 | if (s->s_bdev != sd->bdev) | ||
| 1191 | return 0; | ||
| 1192 | if (down_read_trylock(&s->s_umount)) { | ||
| 1193 | ret = (s->s_flags & MS_RDONLY) && s->s_root && | ||
| 1194 | nilfs_test_opt(NILFS_SB(s), SNAPSHOT); | ||
| 1195 | up_read(&s->s_umount); | ||
| 1196 | if (ret) | ||
| 1197 | return 0; /* ignore snapshot mounts */ | ||
| 1198 | } | ||
| 1199 | return !((sd->flags ^ s->s_flags) & MS_RDONLY); | ||
| 1200 | } | ||
| 1201 | |||
| 1202 | static int __false_bdev_super(struct super_block *s, void *data) | ||
| 1203 | { | ||
| 1204 | #if 0 /* XXX: workaround for lock debug. This is not good idea */ | ||
| 1205 | up_write(&s->s_umount); | ||
| 1206 | #endif | ||
| 1207 | return -EFAULT; | ||
| 1208 | } | ||
| 1209 | |||
| 1210 | /** | ||
| 1211 | * test_exclusive_mount - check whether an exclusive RW/RO mount exists or not. | ||
| 1212 | * fs_type: filesystem type | ||
| 1213 | * bdev: block device | ||
| 1214 | * flag: 0 (check rw-mount) or MS_RDONLY (check ro-mount) | ||
| 1215 | * res: pointer to an integer to store result | ||
| 1216 | * | ||
| 1217 | * This function must be called within a section protected by bd_mount_mutex. | ||
| 1218 | */ | ||
| 1219 | static int test_exclusive_mount(struct file_system_type *fs_type, | ||
| 1220 | struct block_device *bdev, int flags) | ||
| 1221 | { | ||
| 1222 | struct super_block *s; | ||
| 1223 | struct nilfs_super_data sd = { .flags = flags, .bdev = bdev }; | ||
| 1224 | |||
| 1225 | s = sget(fs_type, nilfs_test_bdev_super3, __false_bdev_super, &sd); | ||
| 1226 | if (IS_ERR(s)) { | ||
| 1227 | if (PTR_ERR(s) != -EFAULT) | ||
| 1228 | return PTR_ERR(s); | ||
| 1229 | return 0; /* Not found */ | ||
| 1230 | } | ||
| 1231 | up_write(&s->s_umount); | ||
| 1232 | deactivate_super(s); | ||
| 1233 | return 1; /* Found */ | ||
| 1234 | } | ||
| 1235 | |||
| 1236 | struct file_system_type nilfs_fs_type = { | 1208 | struct file_system_type nilfs_fs_type = { |
| 1237 | .owner = THIS_MODULE, | 1209 | .owner = THIS_MODULE, |
| 1238 | .name = "nilfs2", | 1210 | .name = "nilfs2", |
diff --git a/fs/nilfs2/the_nilfs.h b/fs/nilfs2/the_nilfs.h index 116caf96e7f3..99f7e29a5335 100644 --- a/fs/nilfs2/the_nilfs.h +++ b/fs/nilfs2/the_nilfs.h | |||
| @@ -50,6 +50,7 @@ enum { | |||
| 50 | * @ns_sem: semaphore for shared states | 50 | * @ns_sem: semaphore for shared states |
| 51 | * @ns_writer_mutex: mutex protecting ns_writer attach/detach | 51 | * @ns_writer_mutex: mutex protecting ns_writer attach/detach |
| 52 | * @ns_writer_refcount: number of referrers on ns_writer | 52 | * @ns_writer_refcount: number of referrers on ns_writer |
| 53 | * @ns_current: back pointer to current mount | ||
| 53 | * @ns_sbh: buffer heads of on-disk super blocks | 54 | * @ns_sbh: buffer heads of on-disk super blocks |
| 54 | * @ns_sbp: pointers to super block data | 55 | * @ns_sbp: pointers to super block data |
| 55 | * @ns_sbwtime: previous write time of super blocks | 56 | * @ns_sbwtime: previous write time of super blocks |
| @@ -98,6 +99,8 @@ struct the_nilfs { | |||
| 98 | struct mutex ns_writer_mutex; | 99 | struct mutex ns_writer_mutex; |
| 99 | atomic_t ns_writer_refcount; | 100 | atomic_t ns_writer_refcount; |
| 100 | 101 | ||
| 102 | struct nilfs_sb_info *ns_current; | ||
| 103 | |||
| 101 | /* | 104 | /* |
| 102 | * used for | 105 | * used for |
| 103 | * - loading the latest checkpoint exclusively. | 106 | * - loading the latest checkpoint exclusively. |
