diff options
Diffstat (limited to 'fs')
-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. |