diff options
Diffstat (limited to 'fs')
127 files changed, 1632 insertions, 1700 deletions
diff --git a/fs/adfs/adfs.h b/fs/adfs/adfs.h index e0a85dbeeb88..a6665f37f456 100644 --- a/fs/adfs/adfs.h +++ b/fs/adfs/adfs.h | |||
| @@ -53,6 +53,7 @@ struct adfs_dir_ops { | |||
| 53 | int (*update)(struct adfs_dir *dir, struct object_info *obj); | 53 | int (*update)(struct adfs_dir *dir, struct object_info *obj); |
| 54 | int (*create)(struct adfs_dir *dir, struct object_info *obj); | 54 | int (*create)(struct adfs_dir *dir, struct object_info *obj); |
| 55 | int (*remove)(struct adfs_dir *dir, struct object_info *obj); | 55 | int (*remove)(struct adfs_dir *dir, struct object_info *obj); |
| 56 | int (*sync)(struct adfs_dir *dir); | ||
| 56 | void (*free)(struct adfs_dir *dir); | 57 | void (*free)(struct adfs_dir *dir); |
| 57 | }; | 58 | }; |
| 58 | 59 | ||
| @@ -90,7 +91,8 @@ extern const struct dentry_operations adfs_dentry_operations; | |||
| 90 | extern struct adfs_dir_ops adfs_f_dir_ops; | 91 | extern struct adfs_dir_ops adfs_f_dir_ops; |
| 91 | extern struct adfs_dir_ops adfs_fplus_dir_ops; | 92 | extern struct adfs_dir_ops adfs_fplus_dir_ops; |
| 92 | 93 | ||
| 93 | extern int adfs_dir_update(struct super_block *sb, struct object_info *obj); | 94 | extern int adfs_dir_update(struct super_block *sb, struct object_info *obj, |
| 95 | int wait); | ||
| 94 | 96 | ||
| 95 | /* file.c */ | 97 | /* file.c */ |
| 96 | extern const struct inode_operations adfs_file_inode_operations; | 98 | extern const struct inode_operations adfs_file_inode_operations; |
diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c index e867ccf37246..4d4073447d1a 100644 --- a/fs/adfs/dir.c +++ b/fs/adfs/dir.c | |||
| @@ -83,7 +83,7 @@ out: | |||
| 83 | } | 83 | } |
| 84 | 84 | ||
| 85 | int | 85 | int |
| 86 | adfs_dir_update(struct super_block *sb, struct object_info *obj) | 86 | adfs_dir_update(struct super_block *sb, struct object_info *obj, int wait) |
| 87 | { | 87 | { |
| 88 | int ret = -EINVAL; | 88 | int ret = -EINVAL; |
| 89 | #ifdef CONFIG_ADFS_FS_RW | 89 | #ifdef CONFIG_ADFS_FS_RW |
| @@ -106,6 +106,12 @@ adfs_dir_update(struct super_block *sb, struct object_info *obj) | |||
| 106 | ret = ops->update(&dir, obj); | 106 | ret = ops->update(&dir, obj); |
| 107 | write_unlock(&adfs_dir_lock); | 107 | write_unlock(&adfs_dir_lock); |
| 108 | 108 | ||
| 109 | if (wait) { | ||
| 110 | int err = ops->sync(&dir); | ||
| 111 | if (!ret) | ||
| 112 | ret = err; | ||
| 113 | } | ||
| 114 | |||
| 109 | ops->free(&dir); | 115 | ops->free(&dir); |
| 110 | out: | 116 | out: |
| 111 | #endif | 117 | #endif |
| @@ -199,7 +205,7 @@ const struct file_operations adfs_dir_operations = { | |||
| 199 | .read = generic_read_dir, | 205 | .read = generic_read_dir, |
| 200 | .llseek = generic_file_llseek, | 206 | .llseek = generic_file_llseek, |
| 201 | .readdir = adfs_readdir, | 207 | .readdir = adfs_readdir, |
| 202 | .fsync = file_fsync, | 208 | .fsync = simple_fsync, |
| 203 | }; | 209 | }; |
| 204 | 210 | ||
| 205 | static int | 211 | static int |
diff --git a/fs/adfs/dir_f.c b/fs/adfs/dir_f.c index ea7df2146921..31df6adf0de6 100644 --- a/fs/adfs/dir_f.c +++ b/fs/adfs/dir_f.c | |||
| @@ -437,6 +437,22 @@ bad_dir: | |||
| 437 | #endif | 437 | #endif |
| 438 | } | 438 | } |
| 439 | 439 | ||
| 440 | static int | ||
| 441 | adfs_f_sync(struct adfs_dir *dir) | ||
| 442 | { | ||
| 443 | int err = 0; | ||
| 444 | int i; | ||
| 445 | |||
| 446 | for (i = dir->nr_buffers - 1; i >= 0; i--) { | ||
| 447 | struct buffer_head *bh = dir->bh[i]; | ||
| 448 | sync_dirty_buffer(bh); | ||
| 449 | if (buffer_req(bh) && !buffer_uptodate(bh)) | ||
| 450 | err = -EIO; | ||
| 451 | } | ||
| 452 | |||
| 453 | return err; | ||
| 454 | } | ||
| 455 | |||
| 440 | static void | 456 | static void |
| 441 | adfs_f_free(struct adfs_dir *dir) | 457 | adfs_f_free(struct adfs_dir *dir) |
| 442 | { | 458 | { |
| @@ -456,5 +472,6 @@ struct adfs_dir_ops adfs_f_dir_ops = { | |||
| 456 | .setpos = adfs_f_setpos, | 472 | .setpos = adfs_f_setpos, |
| 457 | .getnext = adfs_f_getnext, | 473 | .getnext = adfs_f_getnext, |
| 458 | .update = adfs_f_update, | 474 | .update = adfs_f_update, |
| 475 | .sync = adfs_f_sync, | ||
| 459 | .free = adfs_f_free | 476 | .free = adfs_f_free |
| 460 | }; | 477 | }; |
diff --git a/fs/adfs/dir_fplus.c b/fs/adfs/dir_fplus.c index 1ec644e32df9..139e0f345f18 100644 --- a/fs/adfs/dir_fplus.c +++ b/fs/adfs/dir_fplus.c | |||
| @@ -161,6 +161,22 @@ out: | |||
| 161 | return ret; | 161 | return ret; |
| 162 | } | 162 | } |
| 163 | 163 | ||
| 164 | static int | ||
| 165 | adfs_fplus_sync(struct adfs_dir *dir) | ||
| 166 | { | ||
| 167 | int err = 0; | ||
| 168 | int i; | ||
| 169 | |||
| 170 | for (i = dir->nr_buffers - 1; i >= 0; i--) { | ||
| 171 | struct buffer_head *bh = dir->bh[i]; | ||
| 172 | sync_dirty_buffer(bh); | ||
| 173 | if (buffer_req(bh) && !buffer_uptodate(bh)) | ||
| 174 | err = -EIO; | ||
| 175 | } | ||
| 176 | |||
| 177 | return err; | ||
| 178 | } | ||
| 179 | |||
| 164 | static void | 180 | static void |
| 165 | adfs_fplus_free(struct adfs_dir *dir) | 181 | adfs_fplus_free(struct adfs_dir *dir) |
| 166 | { | 182 | { |
| @@ -175,5 +191,6 @@ struct adfs_dir_ops adfs_fplus_dir_ops = { | |||
| 175 | .read = adfs_fplus_read, | 191 | .read = adfs_fplus_read, |
| 176 | .setpos = adfs_fplus_setpos, | 192 | .setpos = adfs_fplus_setpos, |
| 177 | .getnext = adfs_fplus_getnext, | 193 | .getnext = adfs_fplus_getnext, |
| 194 | .sync = adfs_fplus_sync, | ||
| 178 | .free = adfs_fplus_free | 195 | .free = adfs_fplus_free |
| 179 | }; | 196 | }; |
diff --git a/fs/adfs/file.c b/fs/adfs/file.c index 36e381c6a99a..8224d54a2afb 100644 --- a/fs/adfs/file.c +++ b/fs/adfs/file.c | |||
| @@ -30,7 +30,7 @@ const struct file_operations adfs_file_operations = { | |||
| 30 | .read = do_sync_read, | 30 | .read = do_sync_read, |
| 31 | .aio_read = generic_file_aio_read, | 31 | .aio_read = generic_file_aio_read, |
| 32 | .mmap = generic_file_mmap, | 32 | .mmap = generic_file_mmap, |
| 33 | .fsync = file_fsync, | 33 | .fsync = simple_fsync, |
| 34 | .write = do_sync_write, | 34 | .write = do_sync_write, |
| 35 | .aio_write = generic_file_aio_write, | 35 | .aio_write = generic_file_aio_write, |
| 36 | .splice_read = generic_file_splice_read, | 36 | .splice_read = generic_file_splice_read, |
diff --git a/fs/adfs/inode.c b/fs/adfs/inode.c index e647200262a2..05b3a677201d 100644 --- a/fs/adfs/inode.c +++ b/fs/adfs/inode.c | |||
| @@ -376,7 +376,7 @@ out: | |||
| 376 | * The adfs-specific inode data has already been updated by | 376 | * The adfs-specific inode data has already been updated by |
| 377 | * adfs_notify_change() | 377 | * adfs_notify_change() |
| 378 | */ | 378 | */ |
| 379 | int adfs_write_inode(struct inode *inode, int unused) | 379 | int adfs_write_inode(struct inode *inode, int wait) |
| 380 | { | 380 | { |
| 381 | struct super_block *sb = inode->i_sb; | 381 | struct super_block *sb = inode->i_sb; |
| 382 | struct object_info obj; | 382 | struct object_info obj; |
| @@ -391,7 +391,7 @@ int adfs_write_inode(struct inode *inode, int unused) | |||
| 391 | obj.attr = ADFS_I(inode)->attr; | 391 | obj.attr = ADFS_I(inode)->attr; |
| 392 | obj.size = inode->i_size; | 392 | obj.size = inode->i_size; |
| 393 | 393 | ||
| 394 | ret = adfs_dir_update(sb, &obj); | 394 | ret = adfs_dir_update(sb, &obj, wait); |
| 395 | unlock_kernel(); | 395 | unlock_kernel(); |
| 396 | return ret; | 396 | return ret; |
| 397 | } | 397 | } |
diff --git a/fs/adfs/map.c b/fs/adfs/map.c index 92ab4fbc2031..568081b93f73 100644 --- a/fs/adfs/map.c +++ b/fs/adfs/map.c | |||
| @@ -62,7 +62,7 @@ static DEFINE_RWLOCK(adfs_map_lock); | |||
| 62 | #define GET_FRAG_ID(_map,_start,_idmask) \ | 62 | #define GET_FRAG_ID(_map,_start,_idmask) \ |
| 63 | ({ \ | 63 | ({ \ |
| 64 | unsigned char *_m = _map + (_start >> 3); \ | 64 | unsigned char *_m = _map + (_start >> 3); \ |
| 65 | u32 _frag = get_unaligned((u32 *)_m); \ | 65 | u32 _frag = get_unaligned_le32(_m); \ |
| 66 | _frag >>= (_start & 7); \ | 66 | _frag >>= (_start & 7); \ |
| 67 | _frag & _idmask; \ | 67 | _frag & _idmask; \ |
| 68 | }) | 68 | }) |
diff --git a/fs/adfs/super.c b/fs/adfs/super.c index dd9becca4241..0ec5aaf47aa7 100644 --- a/fs/adfs/super.c +++ b/fs/adfs/super.c | |||
| @@ -132,11 +132,15 @@ static void adfs_put_super(struct super_block *sb) | |||
| 132 | int i; | 132 | int i; |
| 133 | struct adfs_sb_info *asb = ADFS_SB(sb); | 133 | struct adfs_sb_info *asb = ADFS_SB(sb); |
| 134 | 134 | ||
| 135 | lock_kernel(); | ||
| 136 | |||
| 135 | for (i = 0; i < asb->s_map_size; i++) | 137 | for (i = 0; i < asb->s_map_size; i++) |
| 136 | brelse(asb->s_map[i].dm_bh); | 138 | brelse(asb->s_map[i].dm_bh); |
| 137 | kfree(asb->s_map); | 139 | kfree(asb->s_map); |
| 138 | kfree(asb); | 140 | kfree(asb); |
| 139 | sb->s_fs_info = NULL; | 141 | sb->s_fs_info = NULL; |
| 142 | |||
| 143 | unlock_kernel(); | ||
| 140 | } | 144 | } |
| 141 | 145 | ||
| 142 | static int adfs_show_options(struct seq_file *seq, struct vfsmount *mnt) | 146 | static int adfs_show_options(struct seq_file *seq, struct vfsmount *mnt) |
diff --git a/fs/affs/affs.h b/fs/affs/affs.h index 1a2d5e3c7f4e..e511dc621a2e 100644 --- a/fs/affs/affs.h +++ b/fs/affs/affs.h | |||
| @@ -182,6 +182,7 @@ extern int affs_add_entry(struct inode *dir, struct inode *inode, struct dent | |||
| 182 | 182 | ||
| 183 | void affs_free_prealloc(struct inode *inode); | 183 | void affs_free_prealloc(struct inode *inode); |
| 184 | extern void affs_truncate(struct inode *); | 184 | extern void affs_truncate(struct inode *); |
| 185 | int affs_file_fsync(struct file *, struct dentry *, int); | ||
| 185 | 186 | ||
| 186 | /* dir.c */ | 187 | /* dir.c */ |
| 187 | 188 | ||
diff --git a/fs/affs/dir.c b/fs/affs/dir.c index 7b36904dbeac..8ca8f3a55599 100644 --- a/fs/affs/dir.c +++ b/fs/affs/dir.c | |||
| @@ -21,7 +21,7 @@ const struct file_operations affs_dir_operations = { | |||
| 21 | .read = generic_read_dir, | 21 | .read = generic_read_dir, |
| 22 | .llseek = generic_file_llseek, | 22 | .llseek = generic_file_llseek, |
| 23 | .readdir = affs_readdir, | 23 | .readdir = affs_readdir, |
| 24 | .fsync = file_fsync, | 24 | .fsync = affs_file_fsync, |
| 25 | }; | 25 | }; |
| 26 | 26 | ||
| 27 | /* | 27 | /* |
diff --git a/fs/affs/file.c b/fs/affs/file.c index 9246cb4aa018..184e55c1c9ba 100644 --- a/fs/affs/file.c +++ b/fs/affs/file.c | |||
| @@ -34,7 +34,7 @@ const struct file_operations affs_file_operations = { | |||
| 34 | .mmap = generic_file_mmap, | 34 | .mmap = generic_file_mmap, |
| 35 | .open = affs_file_open, | 35 | .open = affs_file_open, |
| 36 | .release = affs_file_release, | 36 | .release = affs_file_release, |
| 37 | .fsync = file_fsync, | 37 | .fsync = affs_file_fsync, |
| 38 | .splice_read = generic_file_splice_read, | 38 | .splice_read = generic_file_splice_read, |
| 39 | }; | 39 | }; |
| 40 | 40 | ||
| @@ -915,3 +915,15 @@ affs_truncate(struct inode *inode) | |||
| 915 | } | 915 | } |
| 916 | affs_free_prealloc(inode); | 916 | affs_free_prealloc(inode); |
| 917 | } | 917 | } |
| 918 | |||
| 919 | int affs_file_fsync(struct file *filp, struct dentry *dentry, int datasync) | ||
| 920 | { | ||
| 921 | struct inode * inode = dentry->d_inode; | ||
| 922 | int ret, err; | ||
| 923 | |||
| 924 | ret = write_inode_now(inode, 0); | ||
| 925 | err = sync_blockdev(inode->i_sb->s_bdev); | ||
| 926 | if (!ret) | ||
| 927 | ret = err; | ||
| 928 | return ret; | ||
| 929 | } | ||
diff --git a/fs/affs/super.c b/fs/affs/super.c index 63f5183f263b..104fdcb3a7fc 100644 --- a/fs/affs/super.c +++ b/fs/affs/super.c | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include <linux/parser.h> | 16 | #include <linux/parser.h> |
| 17 | #include <linux/magic.h> | 17 | #include <linux/magic.h> |
| 18 | #include <linux/sched.h> | 18 | #include <linux/sched.h> |
| 19 | #include <linux/smp_lock.h> | ||
| 19 | #include "affs.h" | 20 | #include "affs.h" |
| 20 | 21 | ||
| 21 | extern struct timezone sys_tz; | 22 | extern struct timezone sys_tz; |
| @@ -24,49 +25,67 @@ static int affs_statfs(struct dentry *dentry, struct kstatfs *buf); | |||
| 24 | static int affs_remount (struct super_block *sb, int *flags, char *data); | 25 | static int affs_remount (struct super_block *sb, int *flags, char *data); |
| 25 | 26 | ||
| 26 | static void | 27 | static void |
| 28 | affs_commit_super(struct super_block *sb, int clean) | ||
| 29 | { | ||
| 30 | struct affs_sb_info *sbi = AFFS_SB(sb); | ||
| 31 | struct buffer_head *bh = sbi->s_root_bh; | ||
| 32 | struct affs_root_tail *tail = AFFS_ROOT_TAIL(sb, bh); | ||
| 33 | |||
| 34 | tail->bm_flag = cpu_to_be32(clean); | ||
| 35 | secs_to_datestamp(get_seconds(), &tail->disk_change); | ||
| 36 | affs_fix_checksum(sb, bh); | ||
| 37 | mark_buffer_dirty(bh); | ||
| 38 | } | ||
| 39 | |||
| 40 | static void | ||
| 27 | affs_put_super(struct super_block *sb) | 41 | affs_put_super(struct super_block *sb) |
| 28 | { | 42 | { |
| 29 | struct affs_sb_info *sbi = AFFS_SB(sb); | 43 | struct affs_sb_info *sbi = AFFS_SB(sb); |
| 30 | pr_debug("AFFS: put_super()\n"); | 44 | pr_debug("AFFS: put_super()\n"); |
| 31 | 45 | ||
| 32 | if (!(sb->s_flags & MS_RDONLY)) { | 46 | lock_kernel(); |
| 33 | AFFS_ROOT_TAIL(sb, sbi->s_root_bh)->bm_flag = cpu_to_be32(1); | 47 | |
| 34 | secs_to_datestamp(get_seconds(), | 48 | if (!(sb->s_flags & MS_RDONLY)) |
| 35 | &AFFS_ROOT_TAIL(sb, sbi->s_root_bh)->disk_change); | 49 | affs_commit_super(sb, 1); |
| 36 | affs_fix_checksum(sb, sbi->s_root_bh); | ||
| 37 | mark_buffer_dirty(sbi->s_root_bh); | ||
| 38 | } | ||
| 39 | 50 | ||
| 40 | kfree(sbi->s_prefix); | 51 | kfree(sbi->s_prefix); |
| 41 | affs_free_bitmap(sb); | 52 | affs_free_bitmap(sb); |
| 42 | affs_brelse(sbi->s_root_bh); | 53 | affs_brelse(sbi->s_root_bh); |
| 43 | kfree(sbi); | 54 | kfree(sbi); |
| 44 | sb->s_fs_info = NULL; | 55 | sb->s_fs_info = NULL; |
| 45 | return; | 56 | |
| 57 | unlock_kernel(); | ||
| 46 | } | 58 | } |
| 47 | 59 | ||
| 48 | static void | 60 | static void |
| 49 | affs_write_super(struct super_block *sb) | 61 | affs_write_super(struct super_block *sb) |
| 50 | { | 62 | { |
| 51 | int clean = 2; | 63 | int clean = 2; |
| 52 | struct affs_sb_info *sbi = AFFS_SB(sb); | ||
| 53 | 64 | ||
| 65 | lock_super(sb); | ||
| 54 | if (!(sb->s_flags & MS_RDONLY)) { | 66 | if (!(sb->s_flags & MS_RDONLY)) { |
| 55 | // if (sbi->s_bitmap[i].bm_bh) { | 67 | // if (sbi->s_bitmap[i].bm_bh) { |
| 56 | // if (buffer_dirty(sbi->s_bitmap[i].bm_bh)) { | 68 | // if (buffer_dirty(sbi->s_bitmap[i].bm_bh)) { |
| 57 | // clean = 0; | 69 | // clean = 0; |
| 58 | AFFS_ROOT_TAIL(sb, sbi->s_root_bh)->bm_flag = cpu_to_be32(clean); | 70 | affs_commit_super(sb, clean); |
| 59 | secs_to_datestamp(get_seconds(), | ||
| 60 | &AFFS_ROOT_TAIL(sb, sbi->s_root_bh)->disk_change); | ||
| 61 | affs_fix_checksum(sb, sbi->s_root_bh); | ||
| 62 | mark_buffer_dirty(sbi->s_root_bh); | ||
| 63 | sb->s_dirt = !clean; /* redo until bitmap synced */ | 71 | sb->s_dirt = !clean; /* redo until bitmap synced */ |
| 64 | } else | 72 | } else |
| 65 | sb->s_dirt = 0; | 73 | sb->s_dirt = 0; |
| 74 | unlock_super(sb); | ||
| 66 | 75 | ||
| 67 | pr_debug("AFFS: write_super() at %lu, clean=%d\n", get_seconds(), clean); | 76 | pr_debug("AFFS: write_super() at %lu, clean=%d\n", get_seconds(), clean); |
| 68 | } | 77 | } |
| 69 | 78 | ||
| 79 | static int | ||
| 80 | affs_sync_fs(struct super_block *sb, int wait) | ||
| 81 | { | ||
| 82 | lock_super(sb); | ||
| 83 | affs_commit_super(sb, 2); | ||
| 84 | sb->s_dirt = 0; | ||
| 85 | unlock_super(sb); | ||
| 86 | return 0; | ||
| 87 | } | ||
| 88 | |||
| 70 | static struct kmem_cache * affs_inode_cachep; | 89 | static struct kmem_cache * affs_inode_cachep; |
| 71 | 90 | ||
| 72 | static struct inode *affs_alloc_inode(struct super_block *sb) | 91 | static struct inode *affs_alloc_inode(struct super_block *sb) |
| @@ -124,6 +143,7 @@ static const struct super_operations affs_sops = { | |||
| 124 | .clear_inode = affs_clear_inode, | 143 | .clear_inode = affs_clear_inode, |
| 125 | .put_super = affs_put_super, | 144 | .put_super = affs_put_super, |
| 126 | .write_super = affs_write_super, | 145 | .write_super = affs_write_super, |
| 146 | .sync_fs = affs_sync_fs, | ||
| 127 | .statfs = affs_statfs, | 147 | .statfs = affs_statfs, |
| 128 | .remount_fs = affs_remount, | 148 | .remount_fs = affs_remount, |
| 129 | .show_options = generic_show_options, | 149 | .show_options = generic_show_options, |
| @@ -507,6 +527,7 @@ affs_remount(struct super_block *sb, int *flags, char *data) | |||
| 507 | kfree(new_opts); | 527 | kfree(new_opts); |
| 508 | return -EINVAL; | 528 | return -EINVAL; |
| 509 | } | 529 | } |
| 530 | lock_kernel(); | ||
| 510 | replace_mount_options(sb, new_opts); | 531 | replace_mount_options(sb, new_opts); |
| 511 | 532 | ||
| 512 | sbi->s_flags = mount_flags; | 533 | sbi->s_flags = mount_flags; |
| @@ -514,8 +535,10 @@ affs_remount(struct super_block *sb, int *flags, char *data) | |||
| 514 | sbi->s_uid = uid; | 535 | sbi->s_uid = uid; |
| 515 | sbi->s_gid = gid; | 536 | sbi->s_gid = gid; |
| 516 | 537 | ||
| 517 | if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) | 538 | if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) { |
| 539 | unlock_kernel(); | ||
| 518 | return 0; | 540 | return 0; |
| 541 | } | ||
| 519 | if (*flags & MS_RDONLY) { | 542 | if (*flags & MS_RDONLY) { |
| 520 | sb->s_dirt = 1; | 543 | sb->s_dirt = 1; |
| 521 | while (sb->s_dirt) | 544 | while (sb->s_dirt) |
| @@ -524,6 +547,7 @@ affs_remount(struct super_block *sb, int *flags, char *data) | |||
| 524 | } else | 547 | } else |
| 525 | res = affs_init_bitmap(sb, flags); | 548 | res = affs_init_bitmap(sb, flags); |
| 526 | 549 | ||
| 550 | unlock_kernel(); | ||
| 527 | return res; | 551 | return res; |
| 528 | } | 552 | } |
| 529 | 553 | ||
diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c index 2b9e2d03a390..c52be53f6946 100644 --- a/fs/afs/mntpt.c +++ b/fs/afs/mntpt.c | |||
| @@ -244,7 +244,7 @@ static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
| 244 | case -EBUSY: | 244 | case -EBUSY: |
| 245 | /* someone else made a mount here whilst we were busy */ | 245 | /* someone else made a mount here whilst we were busy */ |
| 246 | while (d_mountpoint(nd->path.dentry) && | 246 | while (d_mountpoint(nd->path.dentry) && |
| 247 | follow_down(&nd->path.mnt, &nd->path.dentry)) | 247 | follow_down(&nd->path)) |
| 248 | ; | 248 | ; |
| 249 | err = 0; | 249 | err = 0; |
| 250 | default: | 250 | default: |
diff --git a/fs/afs/super.c b/fs/afs/super.c index 76828e5f8a39..ad0514d0115f 100644 --- a/fs/afs/super.c +++ b/fs/afs/super.c | |||
| @@ -440,8 +440,12 @@ static void afs_put_super(struct super_block *sb) | |||
| 440 | 440 | ||
| 441 | _enter(""); | 441 | _enter(""); |
| 442 | 442 | ||
| 443 | lock_kernel(); | ||
| 444 | |||
| 443 | afs_put_volume(as->volume); | 445 | afs_put_volume(as->volume); |
| 444 | 446 | ||
| 447 | unlock_kernel(); | ||
| 448 | |||
| 445 | _leave(""); | 449 | _leave(""); |
| 446 | } | 450 | } |
| 447 | 451 | ||
diff --git a/fs/autofs/dirhash.c b/fs/autofs/dirhash.c index 4eb4d8dfb2f1..2316e944a109 100644 --- a/fs/autofs/dirhash.c +++ b/fs/autofs/dirhash.c | |||
| @@ -85,13 +85,12 @@ struct autofs_dir_ent *autofs_expire(struct super_block *sb, | |||
| 85 | } | 85 | } |
| 86 | path.mnt = mnt; | 86 | path.mnt = mnt; |
| 87 | path_get(&path); | 87 | path_get(&path); |
| 88 | if (!follow_down(&path.mnt, &path.dentry)) { | 88 | if (!follow_down(&path)) { |
| 89 | path_put(&path); | 89 | path_put(&path); |
| 90 | DPRINTK(("autofs: not expirable (not a mounted directory): %s\n", ent->name)); | 90 | DPRINTK(("autofs: not expirable (not a mounted directory): %s\n", ent->name)); |
| 91 | continue; | 91 | continue; |
| 92 | } | 92 | } |
| 93 | while (d_mountpoint(path.dentry) && | 93 | while (d_mountpoint(path.dentry) && follow_down(&path)); |
| 94 | follow_down(&path.mnt, &path.dentry)) | ||
| 95 | ; | 94 | ; |
| 96 | umount_ok = may_umount(path.mnt); | 95 | umount_ok = may_umount(path.mnt); |
| 97 | path_put(&path); | 96 | path_put(&path); |
diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h index b7ff33c63101..8f7cdde41733 100644 --- a/fs/autofs4/autofs_i.h +++ b/fs/autofs4/autofs_i.h | |||
| @@ -223,12 +223,12 @@ int autofs4_wait(struct autofs_sb_info *,struct dentry *, enum autofs_notify); | |||
| 223 | int autofs4_wait_release(struct autofs_sb_info *,autofs_wqt_t,int); | 223 | int autofs4_wait_release(struct autofs_sb_info *,autofs_wqt_t,int); |
| 224 | void autofs4_catatonic_mode(struct autofs_sb_info *); | 224 | void autofs4_catatonic_mode(struct autofs_sb_info *); |
| 225 | 225 | ||
| 226 | static inline int autofs4_follow_mount(struct vfsmount **mnt, struct dentry **dentry) | 226 | static inline int autofs4_follow_mount(struct path *path) |
| 227 | { | 227 | { |
| 228 | int res = 0; | 228 | int res = 0; |
| 229 | 229 | ||
| 230 | while (d_mountpoint(*dentry)) { | 230 | while (d_mountpoint(path->dentry)) { |
| 231 | int followed = follow_down(mnt, dentry); | 231 | int followed = follow_down(path); |
| 232 | if (!followed) | 232 | if (!followed) |
| 233 | break; | 233 | break; |
| 234 | res = 1; | 234 | res = 1; |
diff --git a/fs/autofs4/dev-ioctl.c b/fs/autofs4/dev-ioctl.c index 84168c0dcc2d..f3da2eb51f56 100644 --- a/fs/autofs4/dev-ioctl.c +++ b/fs/autofs4/dev-ioctl.c | |||
| @@ -192,77 +192,42 @@ static int autofs_dev_ioctl_protosubver(struct file *fp, | |||
| 192 | return 0; | 192 | return 0; |
| 193 | } | 193 | } |
| 194 | 194 | ||
| 195 | /* | 195 | static int find_autofs_mount(const char *pathname, |
| 196 | * Walk down the mount stack looking for an autofs mount that | 196 | struct path *res, |
| 197 | * has the requested device number (aka. new_encode_dev(sb->s_dev). | 197 | int test(struct path *path, void *data), |
| 198 | */ | 198 | void *data) |
| 199 | static int autofs_dev_ioctl_find_super(struct nameidata *nd, dev_t devno) | ||
| 200 | { | 199 | { |
| 201 | struct dentry *dentry; | 200 | struct path path; |
| 202 | struct inode *inode; | 201 | int err = kern_path(pathname, 0, &path); |
| 203 | struct super_block *sb; | 202 | if (err) |
| 204 | dev_t s_dev; | 203 | return err; |
| 205 | unsigned int err; | ||
| 206 | |||
| 207 | err = -ENOENT; | 204 | err = -ENOENT; |
| 208 | 205 | while (path.dentry == path.mnt->mnt_root) { | |
| 209 | /* Lookup the dentry name at the base of our mount point */ | 206 | if (path.mnt->mnt_sb->s_magic == AUTOFS_SUPER_MAGIC) { |
| 210 | dentry = d_lookup(nd->path.dentry, &nd->last); | 207 | if (test(&path, data)) { |
| 211 | if (!dentry) | 208 | path_get(&path); |
| 212 | goto out; | 209 | if (!err) /* already found some */ |
| 213 | 210 | path_put(res); | |
| 214 | dput(nd->path.dentry); | 211 | *res = path; |
| 215 | nd->path.dentry = dentry; | ||
| 216 | |||
| 217 | /* And follow the mount stack looking for our autofs mount */ | ||
| 218 | while (follow_down(&nd->path.mnt, &nd->path.dentry)) { | ||
| 219 | inode = nd->path.dentry->d_inode; | ||
| 220 | if (!inode) | ||
| 221 | break; | ||
| 222 | |||
| 223 | sb = inode->i_sb; | ||
| 224 | s_dev = new_encode_dev(sb->s_dev); | ||
| 225 | if (devno == s_dev) { | ||
| 226 | if (sb->s_magic == AUTOFS_SUPER_MAGIC) { | ||
| 227 | err = 0; | 212 | err = 0; |
| 228 | break; | ||
| 229 | } | 213 | } |
| 230 | } | 214 | } |
| 215 | if (!follow_up(&path)) | ||
| 216 | break; | ||
| 231 | } | 217 | } |
| 232 | out: | 218 | path_put(&path); |
| 233 | return err; | 219 | return err; |
| 234 | } | 220 | } |
| 235 | 221 | ||
| 236 | /* | 222 | static int test_by_dev(struct path *path, void *p) |
| 237 | * Walk down the mount stack looking for an autofs mount that | ||
| 238 | * has the requested mount type (ie. indirect, direct or offset). | ||
| 239 | */ | ||
| 240 | static int autofs_dev_ioctl_find_sbi_type(struct nameidata *nd, unsigned int type) | ||
| 241 | { | 223 | { |
| 242 | struct dentry *dentry; | 224 | return path->mnt->mnt_sb->s_dev == *(dev_t *)p; |
| 243 | struct autofs_info *ino; | 225 | } |
| 244 | unsigned int err; | ||
| 245 | |||
| 246 | err = -ENOENT; | ||
| 247 | |||
| 248 | /* Lookup the dentry name at the base of our mount point */ | ||
| 249 | dentry = d_lookup(nd->path.dentry, &nd->last); | ||
| 250 | if (!dentry) | ||
| 251 | goto out; | ||
| 252 | |||
| 253 | dput(nd->path.dentry); | ||
| 254 | nd->path.dentry = dentry; | ||
| 255 | 226 | ||
| 256 | /* And follow the mount stack looking for our autofs mount */ | 227 | static int test_by_type(struct path *path, void *p) |
| 257 | while (follow_down(&nd->path.mnt, &nd->path.dentry)) { | 228 | { |
| 258 | ino = autofs4_dentry_ino(nd->path.dentry); | 229 | struct autofs_info *ino = autofs4_dentry_ino(path->dentry); |
| 259 | if (ino && ino->sbi->type & type) { | 230 | return ino && ino->sbi->type & *(unsigned *)p; |
| 260 | err = 0; | ||
| 261 | break; | ||
| 262 | } | ||
| 263 | } | ||
| 264 | out: | ||
| 265 | return err; | ||
| 266 | } | 231 | } |
| 267 | 232 | ||
| 268 | static void autofs_dev_ioctl_fd_install(unsigned int fd, struct file *file) | 233 | static void autofs_dev_ioctl_fd_install(unsigned int fd, struct file *file) |
| @@ -283,31 +248,25 @@ static void autofs_dev_ioctl_fd_install(unsigned int fd, struct file *file) | |||
| 283 | * Open a file descriptor on the autofs mount point corresponding | 248 | * Open a file descriptor on the autofs mount point corresponding |
| 284 | * to the given path and device number (aka. new_encode_dev(sb->s_dev)). | 249 | * to the given path and device number (aka. new_encode_dev(sb->s_dev)). |
| 285 | */ | 250 | */ |
| 286 | static int autofs_dev_ioctl_open_mountpoint(const char *path, dev_t devid) | 251 | static int autofs_dev_ioctl_open_mountpoint(const char *name, dev_t devid) |
| 287 | { | 252 | { |
| 288 | struct file *filp; | ||
| 289 | struct nameidata nd; | ||
| 290 | int err, fd; | 253 | int err, fd; |
| 291 | 254 | ||
| 292 | fd = get_unused_fd(); | 255 | fd = get_unused_fd(); |
| 293 | if (likely(fd >= 0)) { | 256 | if (likely(fd >= 0)) { |
| 294 | /* Get nameidata of the parent directory */ | 257 | struct file *filp; |
| 295 | err = path_lookup(path, LOOKUP_PARENT, &nd); | 258 | struct path path; |
| 259 | |||
| 260 | err = find_autofs_mount(name, &path, test_by_dev, &devid); | ||
| 296 | if (err) | 261 | if (err) |
| 297 | goto out; | 262 | goto out; |
| 298 | 263 | ||
| 299 | /* | 264 | /* |
| 300 | * Search down, within the parent, looking for an | 265 | * Find autofs super block that has the device number |
| 301 | * autofs super block that has the device number | ||
| 302 | * corresponding to the autofs fs we want to open. | 266 | * corresponding to the autofs fs we want to open. |
| 303 | */ | 267 | */ |
| 304 | err = autofs_dev_ioctl_find_super(&nd, devid); | ||
| 305 | if (err) { | ||
| 306 | path_put(&nd.path); | ||
| 307 | goto out; | ||
| 308 | } | ||
| 309 | 268 | ||
| 310 | filp = dentry_open(nd.path.dentry, nd.path.mnt, O_RDONLY, | 269 | filp = dentry_open(path.dentry, path.mnt, O_RDONLY, |
| 311 | current_cred()); | 270 | current_cred()); |
| 312 | if (IS_ERR(filp)) { | 271 | if (IS_ERR(filp)) { |
| 313 | err = PTR_ERR(filp); | 272 | err = PTR_ERR(filp); |
| @@ -340,7 +299,7 @@ static int autofs_dev_ioctl_openmount(struct file *fp, | |||
| 340 | param->ioctlfd = -1; | 299 | param->ioctlfd = -1; |
| 341 | 300 | ||
| 342 | path = param->path; | 301 | path = param->path; |
| 343 | devid = param->openmount.devid; | 302 | devid = new_decode_dev(param->openmount.devid); |
| 344 | 303 | ||
| 345 | err = 0; | 304 | err = 0; |
| 346 | fd = autofs_dev_ioctl_open_mountpoint(path, devid); | 305 | fd = autofs_dev_ioctl_open_mountpoint(path, devid); |
| @@ -475,8 +434,7 @@ static int autofs_dev_ioctl_requester(struct file *fp, | |||
| 475 | struct autofs_dev_ioctl *param) | 434 | struct autofs_dev_ioctl *param) |
| 476 | { | 435 | { |
| 477 | struct autofs_info *ino; | 436 | struct autofs_info *ino; |
| 478 | struct nameidata nd; | 437 | struct path path; |
| 479 | const char *path; | ||
| 480 | dev_t devid; | 438 | dev_t devid; |
| 481 | int err = -ENOENT; | 439 | int err = -ENOENT; |
| 482 | 440 | ||
| @@ -485,32 +443,24 @@ static int autofs_dev_ioctl_requester(struct file *fp, | |||
| 485 | goto out; | 443 | goto out; |
| 486 | } | 444 | } |
| 487 | 445 | ||
| 488 | path = param->path; | 446 | devid = sbi->sb->s_dev; |
| 489 | devid = new_encode_dev(sbi->sb->s_dev); | ||
| 490 | 447 | ||
| 491 | param->requester.uid = param->requester.gid = -1; | 448 | param->requester.uid = param->requester.gid = -1; |
| 492 | 449 | ||
| 493 | /* Get nameidata of the parent directory */ | 450 | err = find_autofs_mount(param->path, &path, test_by_dev, &devid); |
| 494 | err = path_lookup(path, LOOKUP_PARENT, &nd); | ||
| 495 | if (err) | 451 | if (err) |
| 496 | goto out; | 452 | goto out; |
| 497 | 453 | ||
| 498 | err = autofs_dev_ioctl_find_super(&nd, devid); | 454 | ino = autofs4_dentry_ino(path.dentry); |
| 499 | if (err) | ||
| 500 | goto out_release; | ||
| 501 | |||
| 502 | ino = autofs4_dentry_ino(nd.path.dentry); | ||
| 503 | if (ino) { | 455 | if (ino) { |
| 504 | err = 0; | 456 | err = 0; |
| 505 | autofs4_expire_wait(nd.path.dentry); | 457 | autofs4_expire_wait(path.dentry); |
| 506 | spin_lock(&sbi->fs_lock); | 458 | spin_lock(&sbi->fs_lock); |
| 507 | param->requester.uid = ino->uid; | 459 | param->requester.uid = ino->uid; |
| 508 | param->requester.gid = ino->gid; | 460 | param->requester.gid = ino->gid; |
| 509 | spin_unlock(&sbi->fs_lock); | 461 | spin_unlock(&sbi->fs_lock); |
| 510 | } | 462 | } |
| 511 | 463 | path_put(&path); | |
| 512 | out_release: | ||
| 513 | path_put(&nd.path); | ||
| 514 | out: | 464 | out: |
| 515 | return err; | 465 | return err; |
| 516 | } | 466 | } |
| @@ -569,8 +519,8 @@ static int autofs_dev_ioctl_ismountpoint(struct file *fp, | |||
| 569 | struct autofs_sb_info *sbi, | 519 | struct autofs_sb_info *sbi, |
| 570 | struct autofs_dev_ioctl *param) | 520 | struct autofs_dev_ioctl *param) |
| 571 | { | 521 | { |
| 572 | struct nameidata nd; | 522 | struct path path; |
| 573 | const char *path; | 523 | const char *name; |
| 574 | unsigned int type; | 524 | unsigned int type; |
| 575 | unsigned int devid, magic; | 525 | unsigned int devid, magic; |
| 576 | int err = -ENOENT; | 526 | int err = -ENOENT; |
| @@ -580,71 +530,46 @@ static int autofs_dev_ioctl_ismountpoint(struct file *fp, | |||
| 580 | goto out; | 530 | goto out; |
| 581 | } | 531 | } |
| 582 | 532 | ||
| 583 | path = param->path; | 533 | name = param->path; |
| 584 | type = param->ismountpoint.in.type; | 534 | type = param->ismountpoint.in.type; |
| 585 | 535 | ||
| 586 | param->ismountpoint.out.devid = devid = 0; | 536 | param->ismountpoint.out.devid = devid = 0; |
| 587 | param->ismountpoint.out.magic = magic = 0; | 537 | param->ismountpoint.out.magic = magic = 0; |
| 588 | 538 | ||
| 589 | if (!fp || param->ioctlfd == -1) { | 539 | if (!fp || param->ioctlfd == -1) { |
| 590 | if (autofs_type_any(type)) { | 540 | if (autofs_type_any(type)) |
| 591 | struct super_block *sb; | 541 | err = kern_path(name, LOOKUP_FOLLOW, &path); |
| 592 | 542 | else | |
| 593 | err = path_lookup(path, LOOKUP_FOLLOW, &nd); | 543 | err = find_autofs_mount(name, &path, test_by_type, &type); |
| 594 | if (err) | 544 | if (err) |
| 595 | goto out; | 545 | goto out; |
| 596 | 546 | devid = new_encode_dev(path.mnt->mnt_sb->s_dev); | |
| 597 | sb = nd.path.dentry->d_sb; | ||
| 598 | devid = new_encode_dev(sb->s_dev); | ||
| 599 | } else { | ||
| 600 | struct autofs_info *ino; | ||
| 601 | |||
| 602 | err = path_lookup(path, LOOKUP_PARENT, &nd); | ||
| 603 | if (err) | ||
| 604 | goto out; | ||
| 605 | |||
| 606 | err = autofs_dev_ioctl_find_sbi_type(&nd, type); | ||
| 607 | if (err) | ||
| 608 | goto out_release; | ||
| 609 | |||
| 610 | ino = autofs4_dentry_ino(nd.path.dentry); | ||
| 611 | devid = autofs4_get_dev(ino->sbi); | ||
| 612 | } | ||
| 613 | |||
| 614 | err = 0; | 547 | err = 0; |
| 615 | if (nd.path.dentry->d_inode && | 548 | if (path.dentry->d_inode && |
| 616 | nd.path.mnt->mnt_root == nd.path.dentry) { | 549 | path.mnt->mnt_root == path.dentry) { |
| 617 | err = 1; | 550 | err = 1; |
| 618 | magic = nd.path.dentry->d_inode->i_sb->s_magic; | 551 | magic = path.dentry->d_inode->i_sb->s_magic; |
| 619 | } | 552 | } |
| 620 | } else { | 553 | } else { |
| 621 | dev_t dev = autofs4_get_dev(sbi); | 554 | dev_t dev = sbi->sb->s_dev; |
| 622 | 555 | ||
| 623 | err = path_lookup(path, LOOKUP_PARENT, &nd); | 556 | err = find_autofs_mount(name, &path, test_by_dev, &dev); |
| 624 | if (err) | 557 | if (err) |
| 625 | goto out; | 558 | goto out; |
| 626 | 559 | ||
| 627 | err = autofs_dev_ioctl_find_super(&nd, dev); | 560 | devid = new_encode_dev(dev); |
| 628 | if (err) | ||
| 629 | goto out_release; | ||
| 630 | |||
| 631 | devid = dev; | ||
| 632 | 561 | ||
| 633 | err = have_submounts(nd.path.dentry); | 562 | err = have_submounts(path.dentry); |
| 634 | 563 | ||
| 635 | if (nd.path.mnt->mnt_mountpoint != nd.path.mnt->mnt_root) { | 564 | if (path.mnt->mnt_mountpoint != path.mnt->mnt_root) { |
| 636 | if (follow_down(&nd.path.mnt, &nd.path.dentry)) { | 565 | if (follow_down(&path)) |
| 637 | struct inode *inode = nd.path.dentry->d_inode; | 566 | magic = path.mnt->mnt_sb->s_magic; |
| 638 | magic = inode->i_sb->s_magic; | ||
| 639 | } | ||
| 640 | } | 567 | } |
| 641 | } | 568 | } |
| 642 | 569 | ||
| 643 | param->ismountpoint.out.devid = devid; | 570 | param->ismountpoint.out.devid = devid; |
| 644 | param->ismountpoint.out.magic = magic; | 571 | param->ismountpoint.out.magic = magic; |
| 645 | 572 | path_put(&path); | |
| 646 | out_release: | ||
| 647 | path_put(&nd.path); | ||
| 648 | out: | 573 | out: |
| 649 | return err; | 574 | return err; |
| 650 | } | 575 | } |
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c index 3077d8f16523..aa39ae83f019 100644 --- a/fs/autofs4/expire.c +++ b/fs/autofs4/expire.c | |||
| @@ -48,19 +48,19 @@ static inline int autofs4_can_expire(struct dentry *dentry, | |||
| 48 | static int autofs4_mount_busy(struct vfsmount *mnt, struct dentry *dentry) | 48 | static int autofs4_mount_busy(struct vfsmount *mnt, struct dentry *dentry) |
| 49 | { | 49 | { |
| 50 | struct dentry *top = dentry; | 50 | struct dentry *top = dentry; |
| 51 | struct path path = {.mnt = mnt, .dentry = dentry}; | ||
| 51 | int status = 1; | 52 | int status = 1; |
| 52 | 53 | ||
| 53 | DPRINTK("dentry %p %.*s", | 54 | DPRINTK("dentry %p %.*s", |
| 54 | dentry, (int)dentry->d_name.len, dentry->d_name.name); | 55 | dentry, (int)dentry->d_name.len, dentry->d_name.name); |
| 55 | 56 | ||
| 56 | mntget(mnt); | 57 | path_get(&path); |
| 57 | dget(dentry); | ||
| 58 | 58 | ||
| 59 | if (!follow_down(&mnt, &dentry)) | 59 | if (!follow_down(&path)) |
| 60 | goto done; | 60 | goto done; |
| 61 | 61 | ||
| 62 | if (is_autofs4_dentry(dentry)) { | 62 | if (is_autofs4_dentry(path.dentry)) { |
| 63 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); | 63 | struct autofs_sb_info *sbi = autofs4_sbi(path.dentry->d_sb); |
| 64 | 64 | ||
| 65 | /* This is an autofs submount, we can't expire it */ | 65 | /* This is an autofs submount, we can't expire it */ |
| 66 | if (autofs_type_indirect(sbi->type)) | 66 | if (autofs_type_indirect(sbi->type)) |
| @@ -70,7 +70,7 @@ static int autofs4_mount_busy(struct vfsmount *mnt, struct dentry *dentry) | |||
| 70 | * Otherwise it's an offset mount and we need to check | 70 | * Otherwise it's an offset mount and we need to check |
| 71 | * if we can umount its mount, if there is one. | 71 | * if we can umount its mount, if there is one. |
| 72 | */ | 72 | */ |
| 73 | if (!d_mountpoint(dentry)) { | 73 | if (!d_mountpoint(path.dentry)) { |
| 74 | status = 0; | 74 | status = 0; |
| 75 | goto done; | 75 | goto done; |
| 76 | } | 76 | } |
| @@ -86,8 +86,7 @@ static int autofs4_mount_busy(struct vfsmount *mnt, struct dentry *dentry) | |||
| 86 | status = 0; | 86 | status = 0; |
| 87 | done: | 87 | done: |
| 88 | DPRINTK("returning = %d", status); | 88 | DPRINTK("returning = %d", status); |
| 89 | dput(dentry); | 89 | path_put(&path); |
| 90 | mntput(mnt); | ||
| 91 | return status; | 90 | return status; |
| 92 | } | 91 | } |
| 93 | 92 | ||
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index e383bf0334f1..b96a3c57359d 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c | |||
| @@ -181,7 +181,7 @@ static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
| 181 | nd->flags); | 181 | nd->flags); |
| 182 | /* | 182 | /* |
| 183 | * For an expire of a covered direct or offset mount we need | 183 | * For an expire of a covered direct or offset mount we need |
| 184 | * to beeak out of follow_down() at the autofs mount trigger | 184 | * to break out of follow_down() at the autofs mount trigger |
| 185 | * (d_mounted--), so we can see the expiring flag, and manage | 185 | * (d_mounted--), so we can see the expiring flag, and manage |
| 186 | * the blocking and following here until the expire is completed. | 186 | * the blocking and following here until the expire is completed. |
| 187 | */ | 187 | */ |
| @@ -190,7 +190,7 @@ static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd) | |||
| 190 | if (ino->flags & AUTOFS_INF_EXPIRING) { | 190 | if (ino->flags & AUTOFS_INF_EXPIRING) { |
| 191 | spin_unlock(&sbi->fs_lock); | 191 | spin_unlock(&sbi->fs_lock); |
| 192 | /* Follow down to our covering mount. */ | 192 | /* Follow down to our covering mount. */ |
| 193 | if (!follow_down(&nd->path.mnt, &nd->path.dentry)) | 193 | if (!follow_down(&nd->path)) |
| 194 | goto done; | 194 | goto done; |
| 195 | goto follow; | 195 | goto follow; |
| 196 | } | 196 | } |
| @@ -230,8 +230,7 @@ follow: | |||
| 230 | * to follow it. | 230 | * to follow it. |
| 231 | */ | 231 | */ |
| 232 | if (d_mountpoint(dentry)) { | 232 | if (d_mountpoint(dentry)) { |
| 233 | if (!autofs4_follow_mount(&nd->path.mnt, | 233 | if (!autofs4_follow_mount(&nd->path)) { |
| 234 | &nd->path.dentry)) { | ||
| 235 | status = -ENOENT; | 234 | status = -ENOENT; |
| 236 | goto out_error; | 235 | goto out_error; |
| 237 | } | 236 | } |
diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index 76afd0d6b86c..9367b6297d84 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c | |||
| @@ -737,6 +737,8 @@ parse_options(char *options, befs_mount_options * opts) | |||
| 737 | static void | 737 | static void |
| 738 | befs_put_super(struct super_block *sb) | 738 | befs_put_super(struct super_block *sb) |
| 739 | { | 739 | { |
| 740 | lock_kernel(); | ||
| 741 | |||
| 740 | kfree(BEFS_SB(sb)->mount_opts.iocharset); | 742 | kfree(BEFS_SB(sb)->mount_opts.iocharset); |
| 741 | BEFS_SB(sb)->mount_opts.iocharset = NULL; | 743 | BEFS_SB(sb)->mount_opts.iocharset = NULL; |
| 742 | 744 | ||
| @@ -747,7 +749,8 @@ befs_put_super(struct super_block *sb) | |||
| 747 | 749 | ||
| 748 | kfree(sb->s_fs_info); | 750 | kfree(sb->s_fs_info); |
| 749 | sb->s_fs_info = NULL; | 751 | sb->s_fs_info = NULL; |
| 750 | return; | 752 | |
| 753 | unlock_kernel(); | ||
| 751 | } | 754 | } |
| 752 | 755 | ||
| 753 | /* Allocate private field of the superblock, fill it. | 756 | /* Allocate private field of the superblock, fill it. |
diff --git a/fs/bfs/dir.c b/fs/bfs/dir.c index 4dd1b623f937..54bd07d44e68 100644 --- a/fs/bfs/dir.c +++ b/fs/bfs/dir.c | |||
| @@ -79,7 +79,7 @@ static int bfs_readdir(struct file *f, void *dirent, filldir_t filldir) | |||
| 79 | const struct file_operations bfs_dir_operations = { | 79 | const struct file_operations bfs_dir_operations = { |
| 80 | .read = generic_read_dir, | 80 | .read = generic_read_dir, |
| 81 | .readdir = bfs_readdir, | 81 | .readdir = bfs_readdir, |
| 82 | .fsync = file_fsync, | 82 | .fsync = simple_fsync, |
| 83 | .llseek = generic_file_llseek, | 83 | .llseek = generic_file_llseek, |
| 84 | }; | 84 | }; |
| 85 | 85 | ||
| @@ -205,7 +205,7 @@ static int bfs_unlink(struct inode *dir, struct dentry *dentry) | |||
| 205 | inode->i_nlink = 1; | 205 | inode->i_nlink = 1; |
| 206 | } | 206 | } |
| 207 | de->ino = 0; | 207 | de->ino = 0; |
| 208 | mark_buffer_dirty(bh); | 208 | mark_buffer_dirty_inode(bh, dir); |
| 209 | dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC; | 209 | dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC; |
| 210 | mark_inode_dirty(dir); | 210 | mark_inode_dirty(dir); |
| 211 | inode->i_ctime = dir->i_ctime; | 211 | inode->i_ctime = dir->i_ctime; |
| @@ -267,7 +267,7 @@ static int bfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
| 267 | new_inode->i_ctime = CURRENT_TIME_SEC; | 267 | new_inode->i_ctime = CURRENT_TIME_SEC; |
| 268 | inode_dec_link_count(new_inode); | 268 | inode_dec_link_count(new_inode); |
| 269 | } | 269 | } |
| 270 | mark_buffer_dirty(old_bh); | 270 | mark_buffer_dirty_inode(old_bh, old_dir); |
| 271 | error = 0; | 271 | error = 0; |
| 272 | 272 | ||
| 273 | end_rename: | 273 | end_rename: |
| @@ -320,7 +320,7 @@ static int bfs_add_entry(struct inode *dir, const unsigned char *name, | |||
| 320 | for (i = 0; i < BFS_NAMELEN; i++) | 320 | for (i = 0; i < BFS_NAMELEN; i++) |
| 321 | de->name[i] = | 321 | de->name[i] = |
| 322 | (i < namelen) ? name[i] : 0; | 322 | (i < namelen) ? name[i] : 0; |
| 323 | mark_buffer_dirty(bh); | 323 | mark_buffer_dirty_inode(bh, dir); |
| 324 | brelse(bh); | 324 | brelse(bh); |
| 325 | return 0; | 325 | return 0; |
| 326 | } | 326 | } |
diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c index cc4062d12ca2..6f60336c6628 100644 --- a/fs/bfs/inode.c +++ b/fs/bfs/inode.c | |||
| @@ -30,6 +30,7 @@ MODULE_LICENSE("GPL"); | |||
| 30 | #define dprintf(x...) | 30 | #define dprintf(x...) |
| 31 | #endif | 31 | #endif |
| 32 | 32 | ||
| 33 | static void bfs_write_super(struct super_block *s); | ||
| 33 | void dump_imap(const char *prefix, struct super_block *s); | 34 | void dump_imap(const char *prefix, struct super_block *s); |
| 34 | 35 | ||
| 35 | struct inode *bfs_iget(struct super_block *sb, unsigned long ino) | 36 | struct inode *bfs_iget(struct super_block *sb, unsigned long ino) |
| @@ -97,14 +98,15 @@ error: | |||
| 97 | return ERR_PTR(-EIO); | 98 | return ERR_PTR(-EIO); |
| 98 | } | 99 | } |
| 99 | 100 | ||
| 100 | static int bfs_write_inode(struct inode *inode, int unused) | 101 | static int bfs_write_inode(struct inode *inode, int wait) |
| 101 | { | 102 | { |
| 103 | struct bfs_sb_info *info = BFS_SB(inode->i_sb); | ||
| 102 | unsigned int ino = (u16)inode->i_ino; | 104 | unsigned int ino = (u16)inode->i_ino; |
| 103 | unsigned long i_sblock; | 105 | unsigned long i_sblock; |
| 104 | struct bfs_inode *di; | 106 | struct bfs_inode *di; |
| 105 | struct buffer_head *bh; | 107 | struct buffer_head *bh; |
| 106 | int block, off; | 108 | int block, off; |
| 107 | struct bfs_sb_info *info = BFS_SB(inode->i_sb); | 109 | int err = 0; |
| 108 | 110 | ||
| 109 | dprintf("ino=%08x\n", ino); | 111 | dprintf("ino=%08x\n", ino); |
| 110 | 112 | ||
| @@ -145,9 +147,14 @@ static int bfs_write_inode(struct inode *inode, int unused) | |||
| 145 | di->i_eoffset = cpu_to_le32(i_sblock * BFS_BSIZE + inode->i_size - 1); | 147 | di->i_eoffset = cpu_to_le32(i_sblock * BFS_BSIZE + inode->i_size - 1); |
| 146 | 148 | ||
| 147 | mark_buffer_dirty(bh); | 149 | mark_buffer_dirty(bh); |
| 150 | if (wait) { | ||
| 151 | sync_dirty_buffer(bh); | ||
| 152 | if (buffer_req(bh) && !buffer_uptodate(bh)) | ||
| 153 | err = -EIO; | ||
| 154 | } | ||
| 148 | brelse(bh); | 155 | brelse(bh); |
| 149 | mutex_unlock(&info->bfs_lock); | 156 | mutex_unlock(&info->bfs_lock); |
| 150 | return 0; | 157 | return err; |
| 151 | } | 158 | } |
| 152 | 159 | ||
| 153 | static void bfs_delete_inode(struct inode *inode) | 160 | static void bfs_delete_inode(struct inode *inode) |
| @@ -209,6 +216,26 @@ static void bfs_delete_inode(struct inode *inode) | |||
| 209 | clear_inode(inode); | 216 | clear_inode(inode); |
| 210 | } | 217 | } |
| 211 | 218 | ||
| 219 | static int bfs_sync_fs(struct super_block *sb, int wait) | ||
| 220 | { | ||
| 221 | struct bfs_sb_info *info = BFS_SB(sb); | ||
| 222 | |||
| 223 | mutex_lock(&info->bfs_lock); | ||
| 224 | mark_buffer_dirty(info->si_sbh); | ||
| 225 | sb->s_dirt = 0; | ||
| 226 | mutex_unlock(&info->bfs_lock); | ||
| 227 | |||
| 228 | return 0; | ||
| 229 | } | ||
| 230 | |||
| 231 | static void bfs_write_super(struct super_block *sb) | ||
| 232 | { | ||
| 233 | if (!(sb->s_flags & MS_RDONLY)) | ||
| 234 | bfs_sync_fs(sb, 1); | ||
| 235 | else | ||
| 236 | sb->s_dirt = 0; | ||
| 237 | } | ||
| 238 | |||
| 212 | static void bfs_put_super(struct super_block *s) | 239 | static void bfs_put_super(struct super_block *s) |
| 213 | { | 240 | { |
| 214 | struct bfs_sb_info *info = BFS_SB(s); | 241 | struct bfs_sb_info *info = BFS_SB(s); |
| @@ -216,11 +243,18 @@ static void bfs_put_super(struct super_block *s) | |||
| 216 | if (!info) | 243 | if (!info) |
| 217 | return; | 244 | return; |
| 218 | 245 | ||
| 246 | lock_kernel(); | ||
| 247 | |||
| 248 | if (s->s_dirt) | ||
| 249 | bfs_write_super(s); | ||
| 250 | |||
| 219 | brelse(info->si_sbh); | 251 | brelse(info->si_sbh); |
| 220 | mutex_destroy(&info->bfs_lock); | 252 | mutex_destroy(&info->bfs_lock); |
| 221 | kfree(info->si_imap); | 253 | kfree(info->si_imap); |
| 222 | kfree(info); | 254 | kfree(info); |
| 223 | s->s_fs_info = NULL; | 255 | s->s_fs_info = NULL; |
| 256 | |||
| 257 | unlock_kernel(); | ||
| 224 | } | 258 | } |
| 225 | 259 | ||
| 226 | static int bfs_statfs(struct dentry *dentry, struct kstatfs *buf) | 260 | static int bfs_statfs(struct dentry *dentry, struct kstatfs *buf) |
| @@ -240,17 +274,6 @@ static int bfs_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
| 240 | return 0; | 274 | return 0; |
| 241 | } | 275 | } |
| 242 | 276 | ||
| 243 | static void bfs_write_super(struct super_block *s) | ||
| 244 | { | ||
| 245 | struct bfs_sb_info *info = BFS_SB(s); | ||
| 246 | |||
| 247 | mutex_lock(&info->bfs_lock); | ||
| 248 | if (!(s->s_flags & MS_RDONLY)) | ||
| 249 | mark_buffer_dirty(info->si_sbh); | ||
| 250 | s->s_dirt = 0; | ||
| 251 | mutex_unlock(&info->bfs_lock); | ||
| 252 | } | ||
| 253 | |||
| 254 | static struct kmem_cache *bfs_inode_cachep; | 277 | static struct kmem_cache *bfs_inode_cachep; |
| 255 | 278 | ||
| 256 | static struct inode *bfs_alloc_inode(struct super_block *sb) | 279 | static struct inode *bfs_alloc_inode(struct super_block *sb) |
| @@ -298,6 +321,7 @@ static const struct super_operations bfs_sops = { | |||
| 298 | .delete_inode = bfs_delete_inode, | 321 | .delete_inode = bfs_delete_inode, |
| 299 | .put_super = bfs_put_super, | 322 | .put_super = bfs_put_super, |
| 300 | .write_super = bfs_write_super, | 323 | .write_super = bfs_write_super, |
| 324 | .sync_fs = bfs_sync_fs, | ||
| 301 | .statfs = bfs_statfs, | 325 | .statfs = bfs_statfs, |
| 302 | }; | 326 | }; |
| 303 | 327 | ||
diff --git a/fs/block_dev.c b/fs/block_dev.c index 931f6b8c4b2f..3a6d4fb2a329 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
| @@ -176,17 +176,22 @@ blkdev_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, | |||
| 176 | iov, offset, nr_segs, blkdev_get_blocks, NULL); | 176 | iov, offset, nr_segs, blkdev_get_blocks, NULL); |
| 177 | } | 177 | } |
| 178 | 178 | ||
| 179 | int __sync_blockdev(struct block_device *bdev, int wait) | ||
| 180 | { | ||
| 181 | if (!bdev) | ||
| 182 | return 0; | ||
| 183 | if (!wait) | ||
| 184 | return filemap_flush(bdev->bd_inode->i_mapping); | ||
| 185 | return filemap_write_and_wait(bdev->bd_inode->i_mapping); | ||
| 186 | } | ||
| 187 | |||
| 179 | /* | 188 | /* |
| 180 | * Write out and wait upon all the dirty data associated with a block | 189 | * Write out and wait upon all the dirty data associated with a block |
| 181 | * device via its mapping. Does not take the superblock lock. | 190 | * device via its mapping. Does not take the superblock lock. |
| 182 | */ | 191 | */ |
| 183 | int sync_blockdev(struct block_device *bdev) | 192 | int sync_blockdev(struct block_device *bdev) |
| 184 | { | 193 | { |
| 185 | int ret = 0; | 194 | return __sync_blockdev(bdev, 1); |
| 186 | |||
| 187 | if (bdev) | ||
| 188 | ret = filemap_write_and_wait(bdev->bd_inode->i_mapping); | ||
| 189 | return ret; | ||
| 190 | } | 195 | } |
| 191 | EXPORT_SYMBOL(sync_blockdev); | 196 | EXPORT_SYMBOL(sync_blockdev); |
| 192 | 197 | ||
| @@ -199,7 +204,7 @@ int fsync_bdev(struct block_device *bdev) | |||
| 199 | { | 204 | { |
| 200 | struct super_block *sb = get_super(bdev); | 205 | struct super_block *sb = get_super(bdev); |
| 201 | if (sb) { | 206 | if (sb) { |
| 202 | int res = fsync_super(sb); | 207 | int res = sync_filesystem(sb); |
| 203 | drop_super(sb); | 208 | drop_super(sb); |
| 204 | return res; | 209 | return res; |
| 205 | } | 210 | } |
| @@ -241,7 +246,7 @@ struct super_block *freeze_bdev(struct block_device *bdev) | |||
| 241 | sb->s_frozen = SB_FREEZE_WRITE; | 246 | sb->s_frozen = SB_FREEZE_WRITE; |
| 242 | smp_wmb(); | 247 | smp_wmb(); |
| 243 | 248 | ||
| 244 | __fsync_super(sb); | 249 | sync_filesystem(sb); |
| 245 | 250 | ||
| 246 | sb->s_frozen = SB_FREEZE_TRANS; | 251 | sb->s_frozen = SB_FREEZE_TRANS; |
| 247 | smp_wmb(); | 252 | smp_wmb(); |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 5b68330f8585..8612b3a09811 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
| @@ -2322,7 +2322,6 @@ err: | |||
| 2322 | btrfs_update_inode(trans, root, dir); | 2322 | btrfs_update_inode(trans, root, dir); |
| 2323 | btrfs_drop_nlink(inode); | 2323 | btrfs_drop_nlink(inode); |
| 2324 | ret = btrfs_update_inode(trans, root, inode); | 2324 | ret = btrfs_update_inode(trans, root, inode); |
| 2325 | dir->i_sb->s_dirt = 1; | ||
| 2326 | out: | 2325 | out: |
| 2327 | return ret; | 2326 | return ret; |
| 2328 | } | 2327 | } |
| @@ -2806,7 +2805,6 @@ error: | |||
| 2806 | pending_del_nr); | 2805 | pending_del_nr); |
| 2807 | } | 2806 | } |
| 2808 | btrfs_free_path(path); | 2807 | btrfs_free_path(path); |
| 2809 | inode->i_sb->s_dirt = 1; | ||
| 2810 | return ret; | 2808 | return ret; |
| 2811 | } | 2809 | } |
| 2812 | 2810 | ||
| @@ -3768,7 +3766,6 @@ static int btrfs_mknod(struct inode *dir, struct dentry *dentry, | |||
| 3768 | init_special_inode(inode, inode->i_mode, rdev); | 3766 | init_special_inode(inode, inode->i_mode, rdev); |
| 3769 | btrfs_update_inode(trans, root, inode); | 3767 | btrfs_update_inode(trans, root, inode); |
| 3770 | } | 3768 | } |
| 3771 | dir->i_sb->s_dirt = 1; | ||
| 3772 | btrfs_update_inode_block_group(trans, inode); | 3769 | btrfs_update_inode_block_group(trans, inode); |
| 3773 | btrfs_update_inode_block_group(trans, dir); | 3770 | btrfs_update_inode_block_group(trans, dir); |
| 3774 | out_unlock: | 3771 | out_unlock: |
| @@ -3833,7 +3830,6 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry, | |||
| 3833 | inode->i_op = &btrfs_file_inode_operations; | 3830 | inode->i_op = &btrfs_file_inode_operations; |
| 3834 | BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops; | 3831 | BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops; |
| 3835 | } | 3832 | } |
| 3836 | dir->i_sb->s_dirt = 1; | ||
| 3837 | btrfs_update_inode_block_group(trans, inode); | 3833 | btrfs_update_inode_block_group(trans, inode); |
| 3838 | btrfs_update_inode_block_group(trans, dir); | 3834 | btrfs_update_inode_block_group(trans, dir); |
| 3839 | out_unlock: | 3835 | out_unlock: |
| @@ -3880,7 +3876,6 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir, | |||
| 3880 | if (err) | 3876 | if (err) |
| 3881 | drop_inode = 1; | 3877 | drop_inode = 1; |
| 3882 | 3878 | ||
| 3883 | dir->i_sb->s_dirt = 1; | ||
| 3884 | btrfs_update_inode_block_group(trans, dir); | 3879 | btrfs_update_inode_block_group(trans, dir); |
| 3885 | err = btrfs_update_inode(trans, root, inode); | 3880 | err = btrfs_update_inode(trans, root, inode); |
| 3886 | 3881 | ||
| @@ -3962,7 +3957,6 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
| 3962 | 3957 | ||
| 3963 | d_instantiate(dentry, inode); | 3958 | d_instantiate(dentry, inode); |
| 3964 | drop_on_err = 0; | 3959 | drop_on_err = 0; |
| 3965 | dir->i_sb->s_dirt = 1; | ||
| 3966 | btrfs_update_inode_block_group(trans, inode); | 3960 | btrfs_update_inode_block_group(trans, inode); |
| 3967 | btrfs_update_inode_block_group(trans, dir); | 3961 | btrfs_update_inode_block_group(trans, dir); |
| 3968 | 3962 | ||
| @@ -4991,7 +4985,6 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry, | |||
| 4991 | inode->i_op = &btrfs_file_inode_operations; | 4985 | inode->i_op = &btrfs_file_inode_operations; |
| 4992 | BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops; | 4986 | BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops; |
| 4993 | } | 4987 | } |
| 4994 | dir->i_sb->s_dirt = 1; | ||
| 4995 | btrfs_update_inode_block_group(trans, inode); | 4988 | btrfs_update_inode_block_group(trans, inode); |
| 4996 | btrfs_update_inode_block_group(trans, dir); | 4989 | btrfs_update_inode_block_group(trans, dir); |
| 4997 | if (drop_inode) | 4990 | if (drop_inode) |
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 708ac06b953b..9f179d4832d5 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c | |||
| @@ -394,10 +394,6 @@ int btrfs_sync_fs(struct super_block *sb, int wait) | |||
| 394 | struct btrfs_root *root = btrfs_sb(sb); | 394 | struct btrfs_root *root = btrfs_sb(sb); |
| 395 | int ret; | 395 | int ret; |
| 396 | 396 | ||
| 397 | if (sb->s_flags & MS_RDONLY) | ||
| 398 | return 0; | ||
| 399 | |||
| 400 | sb->s_dirt = 0; | ||
| 401 | if (!wait) { | 397 | if (!wait) { |
| 402 | filemap_flush(root->fs_info->btree_inode->i_mapping); | 398 | filemap_flush(root->fs_info->btree_inode->i_mapping); |
| 403 | return 0; | 399 | return 0; |
| @@ -408,7 +404,6 @@ int btrfs_sync_fs(struct super_block *sb, int wait) | |||
| 408 | 404 | ||
| 409 | trans = btrfs_start_transaction(root, 1); | 405 | trans = btrfs_start_transaction(root, 1); |
| 410 | ret = btrfs_commit_transaction(trans, root); | 406 | ret = btrfs_commit_transaction(trans, root); |
| 411 | sb->s_dirt = 0; | ||
| 412 | return ret; | 407 | return ret; |
| 413 | } | 408 | } |
| 414 | 409 | ||
| @@ -454,11 +449,6 @@ static int btrfs_show_options(struct seq_file *seq, struct vfsmount *vfs) | |||
| 454 | return 0; | 449 | return 0; |
| 455 | } | 450 | } |
| 456 | 451 | ||
| 457 | static void btrfs_write_super(struct super_block *sb) | ||
| 458 | { | ||
| 459 | sb->s_dirt = 0; | ||
| 460 | } | ||
| 461 | |||
| 462 | static int btrfs_test_super(struct super_block *s, void *data) | 452 | static int btrfs_test_super(struct super_block *s, void *data) |
| 463 | { | 453 | { |
| 464 | struct btrfs_fs_devices *test_fs_devices = data; | 454 | struct btrfs_fs_devices *test_fs_devices = data; |
| @@ -689,7 +679,6 @@ static int btrfs_unfreeze(struct super_block *sb) | |||
| 689 | static struct super_operations btrfs_super_ops = { | 679 | static struct super_operations btrfs_super_ops = { |
| 690 | .delete_inode = btrfs_delete_inode, | 680 | .delete_inode = btrfs_delete_inode, |
| 691 | .put_super = btrfs_put_super, | 681 | .put_super = btrfs_put_super, |
| 692 | .write_super = btrfs_write_super, | ||
| 693 | .sync_fs = btrfs_sync_fs, | 682 | .sync_fs = btrfs_sync_fs, |
| 694 | .show_options = btrfs_show_options, | 683 | .show_options = btrfs_show_options, |
| 695 | .write_inode = btrfs_write_inode, | 684 | .write_inode = btrfs_write_inode, |
diff --git a/fs/cachefiles/interface.c b/fs/cachefiles/interface.c index 1e962348d111..431accd475a7 100644 --- a/fs/cachefiles/interface.c +++ b/fs/cachefiles/interface.c | |||
| @@ -354,7 +354,9 @@ static void cachefiles_sync_cache(struct fscache_cache *_cache) | |||
| 354 | /* make sure all pages pinned by operations on behalf of the netfs are | 354 | /* make sure all pages pinned by operations on behalf of the netfs are |
| 355 | * written to disc */ | 355 | * written to disc */ |
| 356 | cachefiles_begin_secure(cache, &saved_cred); | 356 | cachefiles_begin_secure(cache, &saved_cred); |
| 357 | ret = fsync_super(cache->mnt->mnt_sb); | 357 | down_read(&cache->mnt->mnt_sb->s_umount); |
| 358 | ret = sync_filesystem(cache->mnt->mnt_sb); | ||
| 359 | up_read(&cache->mnt->mnt_sb->s_umount); | ||
| 358 | cachefiles_end_secure(cache, saved_cred); | 360 | cachefiles_end_secure(cache, saved_cred); |
| 359 | 361 | ||
| 360 | if (ret == -EIO) | 362 | if (ret == -EIO) |
diff --git a/fs/char_dev.c b/fs/char_dev.c index 38f71222a552..b7c9d5187a75 100644 --- a/fs/char_dev.c +++ b/fs/char_dev.c | |||
| @@ -375,7 +375,6 @@ static int chrdev_open(struct inode *inode, struct file *filp) | |||
| 375 | p = inode->i_cdev; | 375 | p = inode->i_cdev; |
| 376 | if (!p) { | 376 | if (!p) { |
| 377 | inode->i_cdev = p = new; | 377 | inode->i_cdev = p = new; |
| 378 | inode->i_cindex = idx; | ||
| 379 | list_add(&inode->i_devices, &p->list); | 378 | list_add(&inode->i_devices, &p->list); |
| 380 | new = NULL; | 379 | new = NULL; |
| 381 | } else if (!cdev_get(p)) | 380 | } else if (!cdev_get(p)) |
| @@ -405,6 +404,18 @@ static int chrdev_open(struct inode *inode, struct file *filp) | |||
| 405 | return ret; | 404 | return ret; |
| 406 | } | 405 | } |
| 407 | 406 | ||
| 407 | int cdev_index(struct inode *inode) | ||
| 408 | { | ||
| 409 | int idx; | ||
| 410 | struct kobject *kobj; | ||
| 411 | |||
| 412 | kobj = kobj_lookup(cdev_map, inode->i_rdev, &idx); | ||
| 413 | if (!kobj) | ||
| 414 | return -1; | ||
| 415 | kobject_put(kobj); | ||
| 416 | return idx; | ||
| 417 | } | ||
| 418 | |||
| 408 | void cd_forget(struct inode *inode) | 419 | void cd_forget(struct inode *inode) |
| 409 | { | 420 | { |
| 410 | spin_lock(&cdev_lock); | 421 | spin_lock(&cdev_lock); |
| @@ -557,6 +568,7 @@ EXPORT_SYMBOL(cdev_init); | |||
| 557 | EXPORT_SYMBOL(cdev_alloc); | 568 | EXPORT_SYMBOL(cdev_alloc); |
| 558 | EXPORT_SYMBOL(cdev_del); | 569 | EXPORT_SYMBOL(cdev_del); |
| 559 | EXPORT_SYMBOL(cdev_add); | 570 | EXPORT_SYMBOL(cdev_add); |
| 571 | EXPORT_SYMBOL(cdev_index); | ||
| 560 | EXPORT_SYMBOL(register_chrdev); | 572 | EXPORT_SYMBOL(register_chrdev); |
| 561 | EXPORT_SYMBOL(unregister_chrdev); | 573 | EXPORT_SYMBOL(unregister_chrdev); |
| 562 | EXPORT_SYMBOL(directly_mappable_cdev_bdi); | 574 | EXPORT_SYMBOL(directly_mappable_cdev_bdi); |
diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c index 83d62759c7c7..3bb11be8b6a8 100644 --- a/fs/cifs/cifs_dfs_ref.c +++ b/fs/cifs/cifs_dfs_ref.c | |||
| @@ -275,7 +275,7 @@ static int add_mount_helper(struct vfsmount *newmnt, struct nameidata *nd, | |||
| 275 | case -EBUSY: | 275 | case -EBUSY: |
| 276 | /* someone else made a mount here whilst we were busy */ | 276 | /* someone else made a mount here whilst we were busy */ |
| 277 | while (d_mountpoint(nd->path.dentry) && | 277 | while (d_mountpoint(nd->path.dentry) && |
| 278 | follow_down(&nd->path.mnt, &nd->path.dentry)) | 278 | follow_down(&nd->path)) |
| 279 | ; | 279 | ; |
| 280 | err = 0; | 280 | err = 0; |
| 281 | default: | 281 | default: |
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 0a10a59b6392..0d92114195ab 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
| @@ -204,6 +204,9 @@ cifs_put_super(struct super_block *sb) | |||
| 204 | cFYI(1, ("Empty cifs superblock info passed to unmount")); | 204 | cFYI(1, ("Empty cifs superblock info passed to unmount")); |
| 205 | return; | 205 | return; |
| 206 | } | 206 | } |
| 207 | |||
| 208 | lock_kernel(); | ||
| 209 | |||
| 207 | rc = cifs_umount(sb, cifs_sb); | 210 | rc = cifs_umount(sb, cifs_sb); |
| 208 | if (rc) | 211 | if (rc) |
| 209 | cERROR(1, ("cifs_umount failed with return code %d", rc)); | 212 | cERROR(1, ("cifs_umount failed with return code %d", rc)); |
| @@ -216,7 +219,8 @@ cifs_put_super(struct super_block *sb) | |||
| 216 | 219 | ||
| 217 | unload_nls(cifs_sb->local_nls); | 220 | unload_nls(cifs_sb->local_nls); |
| 218 | kfree(cifs_sb); | 221 | kfree(cifs_sb); |
| 219 | return; | 222 | |
| 223 | unlock_kernel(); | ||
| 220 | } | 224 | } |
| 221 | 225 | ||
| 222 | static int | 226 | static int |
diff --git a/fs/compat.c b/fs/compat.c index bb2a9b2e8173..6aefb776dfeb 100644 --- a/fs/compat.c +++ b/fs/compat.c | |||
| @@ -812,10 +812,8 @@ asmlinkage long compat_sys_mount(char __user * dev_name, char __user * dir_name, | |||
| 812 | } | 812 | } |
| 813 | } | 813 | } |
| 814 | 814 | ||
| 815 | lock_kernel(); | ||
| 816 | retval = do_mount((char*)dev_page, dir_page, (char*)type_page, | 815 | retval = do_mount((char*)dev_page, dir_page, (char*)type_page, |
| 817 | flags, (void*)data_page); | 816 | flags, (void*)data_page); |
| 818 | unlock_kernel(); | ||
| 819 | 817 | ||
| 820 | out4: | 818 | out4: |
| 821 | free_page(data_page); | 819 | free_page(data_page); |
diff --git a/fs/dcache.c b/fs/dcache.c index 75659a6fd1f8..9e5cd3c3a6ba 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
| @@ -1910,7 +1910,7 @@ char *__d_path(const struct path *path, struct path *root, | |||
| 1910 | 1910 | ||
| 1911 | spin_lock(&vfsmount_lock); | 1911 | spin_lock(&vfsmount_lock); |
| 1912 | prepend(&end, &buflen, "\0", 1); | 1912 | prepend(&end, &buflen, "\0", 1); |
| 1913 | if (!IS_ROOT(dentry) && d_unhashed(dentry) && | 1913 | if (d_unlinked(dentry) && |
| 1914 | (prepend(&end, &buflen, " (deleted)", 10) != 0)) | 1914 | (prepend(&end, &buflen, " (deleted)", 10) != 0)) |
| 1915 | goto Elong; | 1915 | goto Elong; |
| 1916 | 1916 | ||
| @@ -2035,7 +2035,7 @@ char *dentry_path(struct dentry *dentry, char *buf, int buflen) | |||
| 2035 | 2035 | ||
| 2036 | spin_lock(&dcache_lock); | 2036 | spin_lock(&dcache_lock); |
| 2037 | prepend(&end, &buflen, "\0", 1); | 2037 | prepend(&end, &buflen, "\0", 1); |
| 2038 | if (!IS_ROOT(dentry) && d_unhashed(dentry) && | 2038 | if (d_unlinked(dentry) && |
| 2039 | (prepend(&end, &buflen, "//deleted", 9) != 0)) | 2039 | (prepend(&end, &buflen, "//deleted", 9) != 0)) |
| 2040 | goto Elong; | 2040 | goto Elong; |
| 2041 | if (buflen < 1) | 2041 | if (buflen < 1) |
| @@ -2097,9 +2097,8 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size) | |||
| 2097 | read_unlock(¤t->fs->lock); | 2097 | read_unlock(¤t->fs->lock); |
| 2098 | 2098 | ||
| 2099 | error = -ENOENT; | 2099 | error = -ENOENT; |
| 2100 | /* Has the current directory has been unlinked? */ | ||
| 2101 | spin_lock(&dcache_lock); | 2100 | spin_lock(&dcache_lock); |
| 2102 | if (IS_ROOT(pwd.dentry) || !d_unhashed(pwd.dentry)) { | 2101 | if (!d_unlinked(pwd.dentry)) { |
| 2103 | unsigned long len; | 2102 | unsigned long len; |
| 2104 | struct path tmp = root; | 2103 | struct path tmp = root; |
| 2105 | char * cwd; | 2104 | char * cwd; |
diff --git a/fs/ecryptfs/super.c b/fs/ecryptfs/super.c index fa4c7e7d15d9..12d649602d3a 100644 --- a/fs/ecryptfs/super.c +++ b/fs/ecryptfs/super.c | |||
| @@ -27,6 +27,7 @@ | |||
| 27 | #include <linux/mount.h> | 27 | #include <linux/mount.h> |
| 28 | #include <linux/key.h> | 28 | #include <linux/key.h> |
| 29 | #include <linux/seq_file.h> | 29 | #include <linux/seq_file.h> |
| 30 | #include <linux/smp_lock.h> | ||
| 30 | #include <linux/file.h> | 31 | #include <linux/file.h> |
| 31 | #include <linux/crypto.h> | 32 | #include <linux/crypto.h> |
| 32 | #include "ecryptfs_kernel.h" | 33 | #include "ecryptfs_kernel.h" |
| @@ -120,9 +121,13 @@ static void ecryptfs_put_super(struct super_block *sb) | |||
| 120 | { | 121 | { |
| 121 | struct ecryptfs_sb_info *sb_info = ecryptfs_superblock_to_private(sb); | 122 | struct ecryptfs_sb_info *sb_info = ecryptfs_superblock_to_private(sb); |
| 122 | 123 | ||
| 124 | lock_kernel(); | ||
| 125 | |||
| 123 | ecryptfs_destroy_mount_crypt_stat(&sb_info->mount_crypt_stat); | 126 | ecryptfs_destroy_mount_crypt_stat(&sb_info->mount_crypt_stat); |
| 124 | kmem_cache_free(ecryptfs_sb_info_cache, sb_info); | 127 | kmem_cache_free(ecryptfs_sb_info_cache, sb_info); |
| 125 | ecryptfs_set_superblock_private(sb, NULL); | 128 | ecryptfs_set_superblock_private(sb, NULL); |
| 129 | |||
| 130 | unlock_kernel(); | ||
| 126 | } | 131 | } |
| 127 | 132 | ||
| 128 | /** | 133 | /** |
diff --git a/fs/exofs/super.c b/fs/exofs/super.c index 9f1985e857e2..8216c5b77b53 100644 --- a/fs/exofs/super.c +++ b/fs/exofs/super.c | |||
| @@ -200,20 +200,21 @@ static const struct export_operations exofs_export_ops; | |||
| 200 | /* | 200 | /* |
| 201 | * Write the superblock to the OSD | 201 | * Write the superblock to the OSD |
| 202 | */ | 202 | */ |
| 203 | static void exofs_write_super(struct super_block *sb) | 203 | static int exofs_sync_fs(struct super_block *sb, int wait) |
| 204 | { | 204 | { |
| 205 | struct exofs_sb_info *sbi; | 205 | struct exofs_sb_info *sbi; |
| 206 | struct exofs_fscb *fscb; | 206 | struct exofs_fscb *fscb; |
| 207 | struct osd_request *or; | 207 | struct osd_request *or; |
| 208 | struct osd_obj_id obj; | 208 | struct osd_obj_id obj; |
| 209 | int ret; | 209 | int ret = -ENOMEM; |
| 210 | 210 | ||
| 211 | fscb = kzalloc(sizeof(struct exofs_fscb), GFP_KERNEL); | 211 | fscb = kzalloc(sizeof(struct exofs_fscb), GFP_KERNEL); |
| 212 | if (!fscb) { | 212 | if (!fscb) { |
| 213 | EXOFS_ERR("exofs_write_super: memory allocation failed.\n"); | 213 | EXOFS_ERR("exofs_write_super: memory allocation failed.\n"); |
| 214 | return; | 214 | return -ENOMEM; |
| 215 | } | 215 | } |
| 216 | 216 | ||
| 217 | lock_super(sb); | ||
| 217 | lock_kernel(); | 218 | lock_kernel(); |
| 218 | sbi = sb->s_fs_info; | 219 | sbi = sb->s_fs_info; |
| 219 | fscb->s_nextid = cpu_to_le64(sbi->s_nextid); | 220 | fscb->s_nextid = cpu_to_le64(sbi->s_nextid); |
| @@ -246,7 +247,17 @@ out: | |||
| 246 | if (or) | 247 | if (or) |
| 247 | osd_end_request(or); | 248 | osd_end_request(or); |
| 248 | unlock_kernel(); | 249 | unlock_kernel(); |
| 250 | unlock_super(sb); | ||
| 249 | kfree(fscb); | 251 | kfree(fscb); |
| 252 | return ret; | ||
| 253 | } | ||
| 254 | |||
| 255 | static void exofs_write_super(struct super_block *sb) | ||
| 256 | { | ||
| 257 | if (!(sb->s_flags & MS_RDONLY)) | ||
| 258 | exofs_sync_fs(sb, 1); | ||
| 259 | else | ||
| 260 | sb->s_dirt = 0; | ||
| 250 | } | 261 | } |
| 251 | 262 | ||
| 252 | /* | 263 | /* |
| @@ -258,6 +269,11 @@ static void exofs_put_super(struct super_block *sb) | |||
| 258 | int num_pend; | 269 | int num_pend; |
| 259 | struct exofs_sb_info *sbi = sb->s_fs_info; | 270 | struct exofs_sb_info *sbi = sb->s_fs_info; |
| 260 | 271 | ||
| 272 | lock_kernel(); | ||
| 273 | |||
| 274 | if (sb->s_dirt) | ||
| 275 | exofs_write_super(sb); | ||
| 276 | |||
| 261 | /* make sure there are no pending commands */ | 277 | /* make sure there are no pending commands */ |
| 262 | for (num_pend = atomic_read(&sbi->s_curr_pending); num_pend > 0; | 278 | for (num_pend = atomic_read(&sbi->s_curr_pending); num_pend > 0; |
| 263 | num_pend = atomic_read(&sbi->s_curr_pending)) { | 279 | num_pend = atomic_read(&sbi->s_curr_pending)) { |
| @@ -271,6 +287,8 @@ static void exofs_put_super(struct super_block *sb) | |||
| 271 | osduld_put_device(sbi->s_dev); | 287 | osduld_put_device(sbi->s_dev); |
| 272 | kfree(sb->s_fs_info); | 288 | kfree(sb->s_fs_info); |
| 273 | sb->s_fs_info = NULL; | 289 | sb->s_fs_info = NULL; |
| 290 | |||
| 291 | unlock_kernel(); | ||
| 274 | } | 292 | } |
| 275 | 293 | ||
| 276 | /* | 294 | /* |
| @@ -484,6 +502,7 @@ static const struct super_operations exofs_sops = { | |||
| 484 | .delete_inode = exofs_delete_inode, | 502 | .delete_inode = exofs_delete_inode, |
| 485 | .put_super = exofs_put_super, | 503 | .put_super = exofs_put_super, |
| 486 | .write_super = exofs_write_super, | 504 | .write_super = exofs_write_super, |
| 505 | .sync_fs = exofs_sync_fs, | ||
| 487 | .statfs = exofs_statfs, | 506 | .statfs = exofs_statfs, |
| 488 | }; | 507 | }; |
| 489 | 508 | ||
diff --git a/fs/ext2/Makefile b/fs/ext2/Makefile index e0b2b43c1fdb..f42af45cfd88 100644 --- a/fs/ext2/Makefile +++ b/fs/ext2/Makefile | |||
| @@ -4,7 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | obj-$(CONFIG_EXT2_FS) += ext2.o | 5 | obj-$(CONFIG_EXT2_FS) += ext2.o |
| 6 | 6 | ||
| 7 | ext2-y := balloc.o dir.o file.o fsync.o ialloc.o inode.o \ | 7 | ext2-y := balloc.o dir.o file.o ialloc.o inode.o \ |
| 8 | ioctl.o namei.o super.o symlink.o | 8 | ioctl.o namei.o super.o symlink.o |
| 9 | 9 | ||
| 10 | ext2-$(CONFIG_EXT2_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o | 10 | ext2-$(CONFIG_EXT2_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o |
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c index 2999d72153b7..003500498c22 100644 --- a/fs/ext2/dir.c +++ b/fs/ext2/dir.c | |||
| @@ -720,5 +720,5 @@ const struct file_operations ext2_dir_operations = { | |||
| 720 | #ifdef CONFIG_COMPAT | 720 | #ifdef CONFIG_COMPAT |
| 721 | .compat_ioctl = ext2_compat_ioctl, | 721 | .compat_ioctl = ext2_compat_ioctl, |
| 722 | #endif | 722 | #endif |
| 723 | .fsync = ext2_sync_file, | 723 | .fsync = simple_fsync, |
| 724 | }; | 724 | }; |
diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h index 3203042b36ef..b2bbf45039e0 100644 --- a/fs/ext2/ext2.h +++ b/fs/ext2/ext2.h | |||
| @@ -113,9 +113,6 @@ extern int ext2_empty_dir (struct inode *); | |||
| 113 | extern struct ext2_dir_entry_2 * ext2_dotdot (struct inode *, struct page **); | 113 | extern struct ext2_dir_entry_2 * ext2_dotdot (struct inode *, struct page **); |
| 114 | extern void ext2_set_link(struct inode *, struct ext2_dir_entry_2 *, struct page *, struct inode *); | 114 | extern void ext2_set_link(struct inode *, struct ext2_dir_entry_2 *, struct page *, struct inode *); |
| 115 | 115 | ||
| 116 | /* fsync.c */ | ||
| 117 | extern int ext2_sync_file (struct file *, struct dentry *, int); | ||
| 118 | |||
| 119 | /* ialloc.c */ | 116 | /* ialloc.c */ |
| 120 | extern struct inode * ext2_new_inode (struct inode *, int); | 117 | extern struct inode * ext2_new_inode (struct inode *, int); |
| 121 | extern void ext2_free_inode (struct inode *); | 118 | extern void ext2_free_inode (struct inode *); |
diff --git a/fs/ext2/file.c b/fs/ext2/file.c index 45ed07122182..2b9e47dc9222 100644 --- a/fs/ext2/file.c +++ b/fs/ext2/file.c | |||
| @@ -55,7 +55,7 @@ const struct file_operations ext2_file_operations = { | |||
| 55 | .mmap = generic_file_mmap, | 55 | .mmap = generic_file_mmap, |
| 56 | .open = generic_file_open, | 56 | .open = generic_file_open, |
| 57 | .release = ext2_release_file, | 57 | .release = ext2_release_file, |
| 58 | .fsync = ext2_sync_file, | 58 | .fsync = simple_fsync, |
| 59 | .splice_read = generic_file_splice_read, | 59 | .splice_read = generic_file_splice_read, |
| 60 | .splice_write = generic_file_splice_write, | 60 | .splice_write = generic_file_splice_write, |
| 61 | }; | 61 | }; |
| @@ -72,7 +72,7 @@ const struct file_operations ext2_xip_file_operations = { | |||
| 72 | .mmap = xip_file_mmap, | 72 | .mmap = xip_file_mmap, |
| 73 | .open = generic_file_open, | 73 | .open = generic_file_open, |
| 74 | .release = ext2_release_file, | 74 | .release = ext2_release_file, |
| 75 | .fsync = ext2_sync_file, | 75 | .fsync = simple_fsync, |
| 76 | }; | 76 | }; |
| 77 | #endif | 77 | #endif |
| 78 | 78 | ||
diff --git a/fs/ext2/fsync.c b/fs/ext2/fsync.c deleted file mode 100644 index fc66c93fcb5c..000000000000 --- a/fs/ext2/fsync.c +++ /dev/null | |||
| @@ -1,50 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * linux/fs/ext2/fsync.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 1993 Stephen Tweedie (sct@dcs.ed.ac.uk) | ||
| 5 | * from | ||
| 6 | * Copyright (C) 1992 Remy Card (card@masi.ibp.fr) | ||
| 7 | * Laboratoire MASI - Institut Blaise Pascal | ||
| 8 | * Universite Pierre et Marie Curie (Paris VI) | ||
| 9 | * from | ||
| 10 | * linux/fs/minix/truncate.c Copyright (C) 1991, 1992 Linus Torvalds | ||
| 11 | * | ||
| 12 | * ext2fs fsync primitive | ||
| 13 | * | ||
| 14 | * Big-endian to little-endian byte-swapping/bitmaps by | ||
| 15 | * David S. Miller (davem@caip.rutgers.edu), 1995 | ||
| 16 | * | ||
| 17 | * Removed unnecessary code duplication for little endian machines | ||
| 18 | * and excessive __inline__s. | ||
| 19 | * Andi Kleen, 1997 | ||
| 20 | * | ||
| 21 | * Major simplications and cleanup - we only need to do the metadata, because | ||
| 22 | * we can depend on generic_block_fdatasync() to sync the data blocks. | ||
| 23 | */ | ||
| 24 | |||
| 25 | #include "ext2.h" | ||
| 26 | #include <linux/buffer_head.h> /* for sync_mapping_buffers() */ | ||
| 27 | |||
| 28 | |||
| 29 | /* | ||
| 30 | * File may be NULL when we are called. Perhaps we shouldn't | ||
| 31 | * even pass file to fsync ? | ||
| 32 | */ | ||
| 33 | |||
| 34 | int ext2_sync_file(struct file *file, struct dentry *dentry, int datasync) | ||
| 35 | { | ||
| 36 | struct inode *inode = dentry->d_inode; | ||
| 37 | int err; | ||
| 38 | int ret; | ||
| 39 | |||
| 40 | ret = sync_mapping_buffers(inode->i_mapping); | ||
| 41 | if (!(inode->i_state & I_DIRTY)) | ||
| 42 | return ret; | ||
| 43 | if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) | ||
| 44 | return ret; | ||
| 45 | |||
| 46 | err = ext2_sync_inode(inode); | ||
| 47 | if (ret == 0) | ||
| 48 | ret = err; | ||
| 49 | return ret; | ||
| 50 | } | ||
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index acf678831103..29ed682061f6 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c | |||
| @@ -41,8 +41,6 @@ MODULE_AUTHOR("Remy Card and others"); | |||
| 41 | MODULE_DESCRIPTION("Second Extended Filesystem"); | 41 | MODULE_DESCRIPTION("Second Extended Filesystem"); |
| 42 | MODULE_LICENSE("GPL"); | 42 | MODULE_LICENSE("GPL"); |
| 43 | 43 | ||
| 44 | static int ext2_update_inode(struct inode * inode, int do_sync); | ||
| 45 | |||
| 46 | /* | 44 | /* |
| 47 | * Test whether an inode is a fast symlink. | 45 | * Test whether an inode is a fast symlink. |
| 48 | */ | 46 | */ |
| @@ -66,7 +64,7 @@ void ext2_delete_inode (struct inode * inode) | |||
| 66 | goto no_delete; | 64 | goto no_delete; |
| 67 | EXT2_I(inode)->i_dtime = get_seconds(); | 65 | EXT2_I(inode)->i_dtime = get_seconds(); |
| 68 | mark_inode_dirty(inode); | 66 | mark_inode_dirty(inode); |
| 69 | ext2_update_inode(inode, inode_needs_sync(inode)); | 67 | ext2_write_inode(inode, inode_needs_sync(inode)); |
| 70 | 68 | ||
| 71 | inode->i_size = 0; | 69 | inode->i_size = 0; |
| 72 | if (inode->i_blocks) | 70 | if (inode->i_blocks) |
| @@ -1337,7 +1335,7 @@ bad_inode: | |||
| 1337 | return ERR_PTR(ret); | 1335 | return ERR_PTR(ret); |
| 1338 | } | 1336 | } |
| 1339 | 1337 | ||
| 1340 | static int ext2_update_inode(struct inode * inode, int do_sync) | 1338 | int ext2_write_inode(struct inode *inode, int do_sync) |
| 1341 | { | 1339 | { |
| 1342 | struct ext2_inode_info *ei = EXT2_I(inode); | 1340 | struct ext2_inode_info *ei = EXT2_I(inode); |
| 1343 | struct super_block *sb = inode->i_sb; | 1341 | struct super_block *sb = inode->i_sb; |
| @@ -1442,11 +1440,6 @@ static int ext2_update_inode(struct inode * inode, int do_sync) | |||
| 1442 | return err; | 1440 | return err; |
| 1443 | } | 1441 | } |
| 1444 | 1442 | ||
| 1445 | int ext2_write_inode(struct inode *inode, int wait) | ||
| 1446 | { | ||
| 1447 | return ext2_update_inode(inode, wait); | ||
| 1448 | } | ||
| 1449 | |||
| 1450 | int ext2_sync_inode(struct inode *inode) | 1443 | int ext2_sync_inode(struct inode *inode) |
| 1451 | { | 1444 | { |
| 1452 | struct writeback_control wbc = { | 1445 | struct writeback_control wbc = { |
diff --git a/fs/ext2/super.c b/fs/ext2/super.c index e3c748faf2db..458999638c3d 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c | |||
| @@ -42,6 +42,7 @@ static void ext2_sync_super(struct super_block *sb, | |||
| 42 | struct ext2_super_block *es); | 42 | struct ext2_super_block *es); |
| 43 | static int ext2_remount (struct super_block * sb, int * flags, char * data); | 43 | static int ext2_remount (struct super_block * sb, int * flags, char * data); |
| 44 | static int ext2_statfs (struct dentry * dentry, struct kstatfs * buf); | 44 | static int ext2_statfs (struct dentry * dentry, struct kstatfs * buf); |
| 45 | static int ext2_sync_fs(struct super_block *sb, int wait); | ||
| 45 | 46 | ||
| 46 | void ext2_error (struct super_block * sb, const char * function, | 47 | void ext2_error (struct super_block * sb, const char * function, |
| 47 | const char * fmt, ...) | 48 | const char * fmt, ...) |
| @@ -114,6 +115,11 @@ static void ext2_put_super (struct super_block * sb) | |||
| 114 | int i; | 115 | int i; |
| 115 | struct ext2_sb_info *sbi = EXT2_SB(sb); | 116 | struct ext2_sb_info *sbi = EXT2_SB(sb); |
| 116 | 117 | ||
| 118 | lock_kernel(); | ||
| 119 | |||
| 120 | if (sb->s_dirt) | ||
| 121 | ext2_write_super(sb); | ||
| 122 | |||
| 117 | ext2_xattr_put_super(sb); | 123 | ext2_xattr_put_super(sb); |
| 118 | if (!(sb->s_flags & MS_RDONLY)) { | 124 | if (!(sb->s_flags & MS_RDONLY)) { |
| 119 | struct ext2_super_block *es = sbi->s_es; | 125 | struct ext2_super_block *es = sbi->s_es; |
| @@ -135,7 +141,7 @@ static void ext2_put_super (struct super_block * sb) | |||
| 135 | kfree(sbi->s_blockgroup_lock); | 141 | kfree(sbi->s_blockgroup_lock); |
| 136 | kfree(sbi); | 142 | kfree(sbi); |
| 137 | 143 | ||
| 138 | return; | 144 | unlock_kernel(); |
| 139 | } | 145 | } |
| 140 | 146 | ||
| 141 | static struct kmem_cache * ext2_inode_cachep; | 147 | static struct kmem_cache * ext2_inode_cachep; |
| @@ -304,6 +310,7 @@ static const struct super_operations ext2_sops = { | |||
| 304 | .delete_inode = ext2_delete_inode, | 310 | .delete_inode = ext2_delete_inode, |
| 305 | .put_super = ext2_put_super, | 311 | .put_super = ext2_put_super, |
| 306 | .write_super = ext2_write_super, | 312 | .write_super = ext2_write_super, |
| 313 | .sync_fs = ext2_sync_fs, | ||
| 307 | .statfs = ext2_statfs, | 314 | .statfs = ext2_statfs, |
| 308 | .remount_fs = ext2_remount, | 315 | .remount_fs = ext2_remount, |
| 309 | .clear_inode = ext2_clear_inode, | 316 | .clear_inode = ext2_clear_inode, |
| @@ -1127,25 +1134,36 @@ static void ext2_sync_super(struct super_block *sb, struct ext2_super_block *es) | |||
| 1127 | * set s_state to EXT2_VALID_FS after some corrections. | 1134 | * set s_state to EXT2_VALID_FS after some corrections. |
| 1128 | */ | 1135 | */ |
| 1129 | 1136 | ||
| 1130 | void ext2_write_super (struct super_block * sb) | 1137 | static int ext2_sync_fs(struct super_block *sb, int wait) |
| 1131 | { | 1138 | { |
| 1132 | struct ext2_super_block * es; | 1139 | struct ext2_super_block *es = EXT2_SB(sb)->s_es; |
| 1140 | |||
| 1133 | lock_kernel(); | 1141 | lock_kernel(); |
| 1134 | if (!(sb->s_flags & MS_RDONLY)) { | 1142 | if (es->s_state & cpu_to_le16(EXT2_VALID_FS)) { |
| 1135 | es = EXT2_SB(sb)->s_es; | 1143 | ext2_debug("setting valid to 0\n"); |
| 1136 | 1144 | es->s_state &= cpu_to_le16(~EXT2_VALID_FS); | |
| 1137 | if (es->s_state & cpu_to_le16(EXT2_VALID_FS)) { | 1145 | es->s_free_blocks_count = |
| 1138 | ext2_debug ("setting valid to 0\n"); | 1146 | cpu_to_le32(ext2_count_free_blocks(sb)); |
| 1139 | es->s_state &= cpu_to_le16(~EXT2_VALID_FS); | 1147 | es->s_free_inodes_count = |
| 1140 | es->s_free_blocks_count = cpu_to_le32(ext2_count_free_blocks(sb)); | 1148 | cpu_to_le32(ext2_count_free_inodes(sb)); |
| 1141 | es->s_free_inodes_count = cpu_to_le32(ext2_count_free_inodes(sb)); | 1149 | es->s_mtime = cpu_to_le32(get_seconds()); |
| 1142 | es->s_mtime = cpu_to_le32(get_seconds()); | 1150 | ext2_sync_super(sb, es); |
| 1143 | ext2_sync_super(sb, es); | 1151 | } else { |
| 1144 | } else | 1152 | ext2_commit_super(sb, es); |
| 1145 | ext2_commit_super (sb, es); | ||
| 1146 | } | 1153 | } |
| 1147 | sb->s_dirt = 0; | 1154 | sb->s_dirt = 0; |
| 1148 | unlock_kernel(); | 1155 | unlock_kernel(); |
| 1156 | |||
| 1157 | return 0; | ||
| 1158 | } | ||
| 1159 | |||
| 1160 | |||
| 1161 | void ext2_write_super(struct super_block *sb) | ||
| 1162 | { | ||
| 1163 | if (!(sb->s_flags & MS_RDONLY)) | ||
| 1164 | ext2_sync_fs(sb, 1); | ||
| 1165 | else | ||
| 1166 | sb->s_dirt = 0; | ||
| 1149 | } | 1167 | } |
| 1150 | 1168 | ||
| 1151 | static int ext2_remount (struct super_block * sb, int * flags, char * data) | 1169 | static int ext2_remount (struct super_block * sb, int * flags, char * data) |
| @@ -1157,6 +1175,8 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data) | |||
| 1157 | unsigned long old_sb_flags; | 1175 | unsigned long old_sb_flags; |
| 1158 | int err; | 1176 | int err; |
| 1159 | 1177 | ||
| 1178 | lock_kernel(); | ||
| 1179 | |||
| 1160 | /* Store the old options */ | 1180 | /* Store the old options */ |
| 1161 | old_sb_flags = sb->s_flags; | 1181 | old_sb_flags = sb->s_flags; |
| 1162 | old_opts.s_mount_opt = sbi->s_mount_opt; | 1182 | old_opts.s_mount_opt = sbi->s_mount_opt; |
| @@ -1192,12 +1212,16 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data) | |||
| 1192 | sbi->s_mount_opt &= ~EXT2_MOUNT_XIP; | 1212 | sbi->s_mount_opt &= ~EXT2_MOUNT_XIP; |
| 1193 | sbi->s_mount_opt |= old_mount_opt & EXT2_MOUNT_XIP; | 1213 | sbi->s_mount_opt |= old_mount_opt & EXT2_MOUNT_XIP; |
| 1194 | } | 1214 | } |
| 1195 | if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) | 1215 | if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) { |
| 1216 | unlock_kernel(); | ||
| 1196 | return 0; | 1217 | return 0; |
| 1218 | } | ||
| 1197 | if (*flags & MS_RDONLY) { | 1219 | if (*flags & MS_RDONLY) { |
| 1198 | if (le16_to_cpu(es->s_state) & EXT2_VALID_FS || | 1220 | if (le16_to_cpu(es->s_state) & EXT2_VALID_FS || |
| 1199 | !(sbi->s_mount_state & EXT2_VALID_FS)) | 1221 | !(sbi->s_mount_state & EXT2_VALID_FS)) { |
| 1222 | unlock_kernel(); | ||
| 1200 | return 0; | 1223 | return 0; |
| 1224 | } | ||
| 1201 | /* | 1225 | /* |
| 1202 | * OK, we are remounting a valid rw partition rdonly, so set | 1226 | * OK, we are remounting a valid rw partition rdonly, so set |
| 1203 | * the rdonly flag and then mark the partition as valid again. | 1227 | * the rdonly flag and then mark the partition as valid again. |
| @@ -1224,12 +1248,14 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data) | |||
| 1224 | sb->s_flags &= ~MS_RDONLY; | 1248 | sb->s_flags &= ~MS_RDONLY; |
| 1225 | } | 1249 | } |
| 1226 | ext2_sync_super(sb, es); | 1250 | ext2_sync_super(sb, es); |
| 1251 | unlock_kernel(); | ||
| 1227 | return 0; | 1252 | return 0; |
| 1228 | restore_opts: | 1253 | restore_opts: |
| 1229 | sbi->s_mount_opt = old_opts.s_mount_opt; | 1254 | sbi->s_mount_opt = old_opts.s_mount_opt; |
| 1230 | sbi->s_resuid = old_opts.s_resuid; | 1255 | sbi->s_resuid = old_opts.s_resuid; |
| 1231 | sbi->s_resgid = old_opts.s_resgid; | 1256 | sbi->s_resgid = old_opts.s_resgid; |
| 1232 | sb->s_flags = old_sb_flags; | 1257 | sb->s_flags = old_sb_flags; |
| 1258 | unlock_kernel(); | ||
| 1233 | return err; | 1259 | return err; |
| 1234 | } | 1260 | } |
| 1235 | 1261 | ||
diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c index 225202db8974..27967f92e820 100644 --- a/fs/ext3/balloc.c +++ b/fs/ext3/balloc.c | |||
| @@ -649,7 +649,7 @@ do_more: | |||
| 649 | count = overflow; | 649 | count = overflow; |
| 650 | goto do_more; | 650 | goto do_more; |
| 651 | } | 651 | } |
| 652 | sb->s_dirt = 1; | 652 | |
| 653 | error_return: | 653 | error_return: |
| 654 | brelse(bitmap_bh); | 654 | brelse(bitmap_bh); |
| 655 | ext3_std_error(sb, err); | 655 | ext3_std_error(sb, err); |
| @@ -1708,7 +1708,6 @@ allocated: | |||
| 1708 | if (!fatal) | 1708 | if (!fatal) |
| 1709 | fatal = err; | 1709 | fatal = err; |
| 1710 | 1710 | ||
| 1711 | sb->s_dirt = 1; | ||
| 1712 | if (fatal) | 1711 | if (fatal) |
| 1713 | goto out; | 1712 | goto out; |
| 1714 | 1713 | ||
diff --git a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c index dd13d60d524b..b39991285136 100644 --- a/fs/ext3/ialloc.c +++ b/fs/ext3/ialloc.c | |||
| @@ -181,7 +181,7 @@ void ext3_free_inode (handle_t *handle, struct inode * inode) | |||
| 181 | err = ext3_journal_dirty_metadata(handle, bitmap_bh); | 181 | err = ext3_journal_dirty_metadata(handle, bitmap_bh); |
| 182 | if (!fatal) | 182 | if (!fatal) |
| 183 | fatal = err; | 183 | fatal = err; |
| 184 | sb->s_dirt = 1; | 184 | |
| 185 | error_return: | 185 | error_return: |
| 186 | brelse(bitmap_bh); | 186 | brelse(bitmap_bh); |
| 187 | ext3_std_error(sb, fatal); | 187 | ext3_std_error(sb, fatal); |
| @@ -537,7 +537,6 @@ got: | |||
| 537 | percpu_counter_dec(&sbi->s_freeinodes_counter); | 537 | percpu_counter_dec(&sbi->s_freeinodes_counter); |
| 538 | if (S_ISDIR(mode)) | 538 | if (S_ISDIR(mode)) |
| 539 | percpu_counter_inc(&sbi->s_dirs_counter); | 539 | percpu_counter_inc(&sbi->s_dirs_counter); |
| 540 | sb->s_dirt = 1; | ||
| 541 | 540 | ||
| 542 | inode->i_uid = current_fsuid(); | 541 | inode->i_uid = current_fsuid(); |
| 543 | if (test_opt (sb, GRPID)) | 542 | if (test_opt (sb, GRPID)) |
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index fcfa24361856..b0248c6d5d4c 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c | |||
| @@ -2960,7 +2960,6 @@ static int ext3_do_update_inode(handle_t *handle, | |||
| 2960 | ext3_update_dynamic_rev(sb); | 2960 | ext3_update_dynamic_rev(sb); |
| 2961 | EXT3_SET_RO_COMPAT_FEATURE(sb, | 2961 | EXT3_SET_RO_COMPAT_FEATURE(sb, |
| 2962 | EXT3_FEATURE_RO_COMPAT_LARGE_FILE); | 2962 | EXT3_FEATURE_RO_COMPAT_LARGE_FILE); |
| 2963 | sb->s_dirt = 1; | ||
| 2964 | handle->h_sync = 1; | 2963 | handle->h_sync = 1; |
| 2965 | err = ext3_journal_dirty_metadata(handle, | 2964 | err = ext3_journal_dirty_metadata(handle, |
| 2966 | EXT3_SB(sb)->s_sbh); | 2965 | EXT3_SB(sb)->s_sbh); |
diff --git a/fs/ext3/resize.c b/fs/ext3/resize.c index 78fdf3836370..8a0b26340b54 100644 --- a/fs/ext3/resize.c +++ b/fs/ext3/resize.c | |||
| @@ -934,7 +934,6 @@ int ext3_group_add(struct super_block *sb, struct ext3_new_group_data *input) | |||
| 934 | EXT3_INODES_PER_GROUP(sb)); | 934 | EXT3_INODES_PER_GROUP(sb)); |
| 935 | 935 | ||
| 936 | ext3_journal_dirty_metadata(handle, sbi->s_sbh); | 936 | ext3_journal_dirty_metadata(handle, sbi->s_sbh); |
| 937 | sb->s_dirt = 1; | ||
| 938 | 937 | ||
| 939 | exit_journal: | 938 | exit_journal: |
| 940 | unlock_super(sb); | 939 | unlock_super(sb); |
| @@ -1066,7 +1065,6 @@ int ext3_group_extend(struct super_block *sb, struct ext3_super_block *es, | |||
| 1066 | } | 1065 | } |
| 1067 | es->s_blocks_count = cpu_to_le32(o_blocks_count + add); | 1066 | es->s_blocks_count = cpu_to_le32(o_blocks_count + add); |
| 1068 | ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh); | 1067 | ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh); |
| 1069 | sb->s_dirt = 1; | ||
| 1070 | unlock_super(sb); | 1068 | unlock_super(sb); |
| 1071 | ext3_debug("freeing blocks %lu through "E3FSBLK"\n", o_blocks_count, | 1069 | ext3_debug("freeing blocks %lu through "E3FSBLK"\n", o_blocks_count, |
| 1072 | o_blocks_count + add); | 1070 | o_blocks_count + add); |
diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 3c70d52afb10..26aa64dee6aa 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c | |||
| @@ -67,7 +67,6 @@ static const char *ext3_decode_error(struct super_block * sb, int errno, | |||
| 67 | static int ext3_remount (struct super_block * sb, int * flags, char * data); | 67 | static int ext3_remount (struct super_block * sb, int * flags, char * data); |
| 68 | static int ext3_statfs (struct dentry * dentry, struct kstatfs * buf); | 68 | static int ext3_statfs (struct dentry * dentry, struct kstatfs * buf); |
| 69 | static int ext3_unfreeze(struct super_block *sb); | 69 | static int ext3_unfreeze(struct super_block *sb); |
| 70 | static void ext3_write_super (struct super_block * sb); | ||
| 71 | static int ext3_freeze(struct super_block *sb); | 70 | static int ext3_freeze(struct super_block *sb); |
| 72 | 71 | ||
| 73 | /* | 72 | /* |
| @@ -399,6 +398,8 @@ static void ext3_put_super (struct super_block * sb) | |||
| 399 | struct ext3_super_block *es = sbi->s_es; | 398 | struct ext3_super_block *es = sbi->s_es; |
| 400 | int i, err; | 399 | int i, err; |
| 401 | 400 | ||
| 401 | lock_kernel(); | ||
| 402 | |||
| 402 | ext3_xattr_put_super(sb); | 403 | ext3_xattr_put_super(sb); |
| 403 | err = journal_destroy(sbi->s_journal); | 404 | err = journal_destroy(sbi->s_journal); |
| 404 | sbi->s_journal = NULL; | 405 | sbi->s_journal = NULL; |
| @@ -447,7 +448,8 @@ static void ext3_put_super (struct super_block * sb) | |||
| 447 | sb->s_fs_info = NULL; | 448 | sb->s_fs_info = NULL; |
| 448 | kfree(sbi->s_blockgroup_lock); | 449 | kfree(sbi->s_blockgroup_lock); |
| 449 | kfree(sbi); | 450 | kfree(sbi); |
| 450 | return; | 451 | |
| 452 | unlock_kernel(); | ||
| 451 | } | 453 | } |
| 452 | 454 | ||
| 453 | static struct kmem_cache *ext3_inode_cachep; | 455 | static struct kmem_cache *ext3_inode_cachep; |
| @@ -761,7 +763,6 @@ static const struct super_operations ext3_sops = { | |||
| 761 | .dirty_inode = ext3_dirty_inode, | 763 | .dirty_inode = ext3_dirty_inode, |
| 762 | .delete_inode = ext3_delete_inode, | 764 | .delete_inode = ext3_delete_inode, |
| 763 | .put_super = ext3_put_super, | 765 | .put_super = ext3_put_super, |
| 764 | .write_super = ext3_write_super, | ||
| 765 | .sync_fs = ext3_sync_fs, | 766 | .sync_fs = ext3_sync_fs, |
| 766 | .freeze_fs = ext3_freeze, | 767 | .freeze_fs = ext3_freeze, |
| 767 | .unfreeze_fs = ext3_unfreeze, | 768 | .unfreeze_fs = ext3_unfreeze, |
| @@ -1785,7 +1786,6 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) | |||
| 1785 | #else | 1786 | #else |
| 1786 | es->s_flags |= cpu_to_le32(EXT2_FLAGS_SIGNED_HASH); | 1787 | es->s_flags |= cpu_to_le32(EXT2_FLAGS_SIGNED_HASH); |
| 1787 | #endif | 1788 | #endif |
| 1788 | sb->s_dirt = 1; | ||
| 1789 | } | 1789 | } |
| 1790 | 1790 | ||
| 1791 | if (sbi->s_blocks_per_group > blocksize * 8) { | 1791 | if (sbi->s_blocks_per_group > blocksize * 8) { |
| @@ -2265,7 +2265,6 @@ static int ext3_load_journal(struct super_block *sb, | |||
| 2265 | if (journal_devnum && | 2265 | if (journal_devnum && |
| 2266 | journal_devnum != le32_to_cpu(es->s_journal_dev)) { | 2266 | journal_devnum != le32_to_cpu(es->s_journal_dev)) { |
| 2267 | es->s_journal_dev = cpu_to_le32(journal_devnum); | 2267 | es->s_journal_dev = cpu_to_le32(journal_devnum); |
| 2268 | sb->s_dirt = 1; | ||
| 2269 | 2268 | ||
| 2270 | /* Make sure we flush the recovery flag to disk. */ | 2269 | /* Make sure we flush the recovery flag to disk. */ |
| 2271 | ext3_commit_super(sb, es, 1); | 2270 | ext3_commit_super(sb, es, 1); |
| @@ -2308,7 +2307,6 @@ static int ext3_create_journal(struct super_block * sb, | |||
| 2308 | EXT3_SET_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL); | 2307 | EXT3_SET_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL); |
| 2309 | 2308 | ||
| 2310 | es->s_journal_inum = cpu_to_le32(journal_inum); | 2309 | es->s_journal_inum = cpu_to_le32(journal_inum); |
| 2311 | sb->s_dirt = 1; | ||
| 2312 | 2310 | ||
| 2313 | /* Make sure we flush the recovery flag to disk. */ | 2311 | /* Make sure we flush the recovery flag to disk. */ |
| 2314 | ext3_commit_super(sb, es, 1); | 2312 | ext3_commit_super(sb, es, 1); |
| @@ -2354,7 +2352,6 @@ static void ext3_mark_recovery_complete(struct super_block * sb, | |||
| 2354 | if (EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER) && | 2352 | if (EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER) && |
| 2355 | sb->s_flags & MS_RDONLY) { | 2353 | sb->s_flags & MS_RDONLY) { |
| 2356 | EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER); | 2354 | EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER); |
| 2357 | sb->s_dirt = 0; | ||
| 2358 | ext3_commit_super(sb, es, 1); | 2355 | ext3_commit_super(sb, es, 1); |
| 2359 | } | 2356 | } |
| 2360 | unlock_super(sb); | 2357 | unlock_super(sb); |
| @@ -2413,29 +2410,14 @@ int ext3_force_commit(struct super_block *sb) | |||
| 2413 | return 0; | 2410 | return 0; |
| 2414 | 2411 | ||
| 2415 | journal = EXT3_SB(sb)->s_journal; | 2412 | journal = EXT3_SB(sb)->s_journal; |
| 2416 | sb->s_dirt = 0; | ||
| 2417 | ret = ext3_journal_force_commit(journal); | 2413 | ret = ext3_journal_force_commit(journal); |
| 2418 | return ret; | 2414 | return ret; |
| 2419 | } | 2415 | } |
| 2420 | 2416 | ||
| 2421 | /* | ||
| 2422 | * Ext3 always journals updates to the superblock itself, so we don't | ||
| 2423 | * have to propagate any other updates to the superblock on disk at this | ||
| 2424 | * point. (We can probably nuke this function altogether, and remove | ||
| 2425 | * any mention to sb->s_dirt in all of fs/ext3; eventual cleanup...) | ||
| 2426 | */ | ||
| 2427 | static void ext3_write_super (struct super_block * sb) | ||
| 2428 | { | ||
| 2429 | if (mutex_trylock(&sb->s_lock) != 0) | ||
| 2430 | BUG(); | ||
| 2431 | sb->s_dirt = 0; | ||
| 2432 | } | ||
| 2433 | |||
| 2434 | static int ext3_sync_fs(struct super_block *sb, int wait) | 2417 | static int ext3_sync_fs(struct super_block *sb, int wait) |
| 2435 | { | 2418 | { |
| 2436 | tid_t target; | 2419 | tid_t target; |
| 2437 | 2420 | ||
| 2438 | sb->s_dirt = 0; | ||
| 2439 | if (journal_start_commit(EXT3_SB(sb)->s_journal, &target)) { | 2421 | if (journal_start_commit(EXT3_SB(sb)->s_journal, &target)) { |
| 2440 | if (wait) | 2422 | if (wait) |
| 2441 | log_wait_commit(EXT3_SB(sb)->s_journal, target); | 2423 | log_wait_commit(EXT3_SB(sb)->s_journal, target); |
| @@ -2451,7 +2433,6 @@ static int ext3_freeze(struct super_block *sb) | |||
| 2451 | { | 2433 | { |
| 2452 | int error = 0; | 2434 | int error = 0; |
| 2453 | journal_t *journal; | 2435 | journal_t *journal; |
| 2454 | sb->s_dirt = 0; | ||
| 2455 | 2436 | ||
| 2456 | if (!(sb->s_flags & MS_RDONLY)) { | 2437 | if (!(sb->s_flags & MS_RDONLY)) { |
| 2457 | journal = EXT3_SB(sb)->s_journal; | 2438 | journal = EXT3_SB(sb)->s_journal; |
| @@ -2509,7 +2490,10 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data) | |||
| 2509 | int i; | 2490 | int i; |
| 2510 | #endif | 2491 | #endif |
| 2511 | 2492 | ||
| 2493 | lock_kernel(); | ||
| 2494 | |||
| 2512 | /* Store the original options */ | 2495 | /* Store the original options */ |
| 2496 | lock_super(sb); | ||
| 2513 | old_sb_flags = sb->s_flags; | 2497 | old_sb_flags = sb->s_flags; |
| 2514 | old_opts.s_mount_opt = sbi->s_mount_opt; | 2498 | old_opts.s_mount_opt = sbi->s_mount_opt; |
| 2515 | old_opts.s_resuid = sbi->s_resuid; | 2499 | old_opts.s_resuid = sbi->s_resuid; |
| @@ -2617,6 +2601,8 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data) | |||
| 2617 | old_opts.s_qf_names[i] != sbi->s_qf_names[i]) | 2601 | old_opts.s_qf_names[i] != sbi->s_qf_names[i]) |
| 2618 | kfree(old_opts.s_qf_names[i]); | 2602 | kfree(old_opts.s_qf_names[i]); |
| 2619 | #endif | 2603 | #endif |
| 2604 | unlock_super(sb); | ||
| 2605 | unlock_kernel(); | ||
| 2620 | return 0; | 2606 | return 0; |
| 2621 | restore_opts: | 2607 | restore_opts: |
| 2622 | sb->s_flags = old_sb_flags; | 2608 | sb->s_flags = old_sb_flags; |
| @@ -2633,6 +2619,8 @@ restore_opts: | |||
| 2633 | sbi->s_qf_names[i] = old_opts.s_qf_names[i]; | 2619 | sbi->s_qf_names[i] = old_opts.s_qf_names[i]; |
| 2634 | } | 2620 | } |
| 2635 | #endif | 2621 | #endif |
| 2622 | unlock_super(sb); | ||
| 2623 | unlock_kernel(); | ||
| 2636 | return err; | 2624 | return err; |
| 2637 | } | 2625 | } |
| 2638 | 2626 | ||
diff --git a/fs/ext3/xattr.c b/fs/ext3/xattr.c index 83b7be849bd5..545e37c4b91e 100644 --- a/fs/ext3/xattr.c +++ b/fs/ext3/xattr.c | |||
| @@ -463,7 +463,6 @@ static void ext3_xattr_update_super_block(handle_t *handle, | |||
| 463 | 463 | ||
| 464 | if (ext3_journal_get_write_access(handle, EXT3_SB(sb)->s_sbh) == 0) { | 464 | if (ext3_journal_get_write_access(handle, EXT3_SB(sb)->s_sbh) == 0) { |
| 465 | EXT3_SET_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_EXT_ATTR); | 465 | EXT3_SET_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_EXT_ATTR); |
| 466 | sb->s_dirt = 1; | ||
| 467 | ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh); | 466 | ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh); |
| 468 | } | 467 | } |
| 469 | } | 468 | } |
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index f016707597a7..012c4251397e 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
| @@ -576,6 +576,11 @@ static void ext4_put_super(struct super_block *sb) | |||
| 576 | struct ext4_super_block *es = sbi->s_es; | 576 | struct ext4_super_block *es = sbi->s_es; |
| 577 | int i, err; | 577 | int i, err; |
| 578 | 578 | ||
| 579 | lock_super(sb); | ||
| 580 | lock_kernel(); | ||
| 581 | if (sb->s_dirt) | ||
| 582 | ext4_commit_super(sb, 1); | ||
| 583 | |||
| 579 | ext4_release_system_zone(sb); | 584 | ext4_release_system_zone(sb); |
| 580 | ext4_mb_release(sb); | 585 | ext4_mb_release(sb); |
| 581 | ext4_ext_release(sb); | 586 | ext4_ext_release(sb); |
| @@ -642,8 +647,6 @@ static void ext4_put_super(struct super_block *sb) | |||
| 642 | unlock_super(sb); | 647 | unlock_super(sb); |
| 643 | kobject_put(&sbi->s_kobj); | 648 | kobject_put(&sbi->s_kobj); |
| 644 | wait_for_completion(&sbi->s_kobj_unregister); | 649 | wait_for_completion(&sbi->s_kobj_unregister); |
| 645 | lock_super(sb); | ||
| 646 | lock_kernel(); | ||
| 647 | kfree(sbi->s_blockgroup_lock); | 650 | kfree(sbi->s_blockgroup_lock); |
| 648 | kfree(sbi); | 651 | kfree(sbi); |
| 649 | } | 652 | } |
| @@ -3333,7 +3336,9 @@ int ext4_force_commit(struct super_block *sb) | |||
| 3333 | 3336 | ||
| 3334 | static void ext4_write_super(struct super_block *sb) | 3337 | static void ext4_write_super(struct super_block *sb) |
| 3335 | { | 3338 | { |
| 3339 | lock_super(sb); | ||
| 3336 | ext4_commit_super(sb, 1); | 3340 | ext4_commit_super(sb, 1); |
| 3341 | unlock_super(sb); | ||
| 3337 | } | 3342 | } |
| 3338 | 3343 | ||
| 3339 | static int ext4_sync_fs(struct super_block *sb, int wait) | 3344 | static int ext4_sync_fs(struct super_block *sb, int wait) |
| @@ -3417,7 +3422,10 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data) | |||
| 3417 | int i; | 3422 | int i; |
| 3418 | #endif | 3423 | #endif |
| 3419 | 3424 | ||
| 3425 | lock_kernel(); | ||
| 3426 | |||
| 3420 | /* Store the original options */ | 3427 | /* Store the original options */ |
| 3428 | lock_super(sb); | ||
| 3421 | old_sb_flags = sb->s_flags; | 3429 | old_sb_flags = sb->s_flags; |
| 3422 | old_opts.s_mount_opt = sbi->s_mount_opt; | 3430 | old_opts.s_mount_opt = sbi->s_mount_opt; |
| 3423 | old_opts.s_resuid = sbi->s_resuid; | 3431 | old_opts.s_resuid = sbi->s_resuid; |
| @@ -3551,6 +3559,8 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data) | |||
| 3551 | old_opts.s_qf_names[i] != sbi->s_qf_names[i]) | 3559 | old_opts.s_qf_names[i] != sbi->s_qf_names[i]) |
| 3552 | kfree(old_opts.s_qf_names[i]); | 3560 | kfree(old_opts.s_qf_names[i]); |
| 3553 | #endif | 3561 | #endif |
| 3562 | unlock_super(sb); | ||
| 3563 | unlock_kernel(); | ||
| 3554 | return 0; | 3564 | return 0; |
| 3555 | 3565 | ||
| 3556 | restore_opts: | 3566 | restore_opts: |
| @@ -3570,6 +3580,8 @@ restore_opts: | |||
| 3570 | sbi->s_qf_names[i] = old_opts.s_qf_names[i]; | 3580 | sbi->s_qf_names[i] = old_opts.s_qf_names[i]; |
| 3571 | } | 3581 | } |
| 3572 | #endif | 3582 | #endif |
| 3583 | unlock_super(sb); | ||
| 3584 | unlock_kernel(); | ||
| 3573 | return err; | 3585 | return err; |
| 3574 | } | 3586 | } |
| 3575 | 3587 | ||
diff --git a/fs/fat/dir.c b/fs/fat/dir.c index 3a7f603b6982..f3500294eec5 100644 --- a/fs/fat/dir.c +++ b/fs/fat/dir.c | |||
| @@ -840,7 +840,7 @@ const struct file_operations fat_dir_operations = { | |||
| 840 | #ifdef CONFIG_COMPAT | 840 | #ifdef CONFIG_COMPAT |
| 841 | .compat_ioctl = fat_compat_dir_ioctl, | 841 | .compat_ioctl = fat_compat_dir_ioctl, |
| 842 | #endif | 842 | #endif |
| 843 | .fsync = file_fsync, | 843 | .fsync = fat_file_fsync, |
| 844 | }; | 844 | }; |
| 845 | 845 | ||
| 846 | static int fat_get_short_entry(struct inode *dir, loff_t *pos, | 846 | static int fat_get_short_entry(struct inode *dir, loff_t *pos, |
| @@ -967,7 +967,7 @@ static int __fat_remove_entries(struct inode *dir, loff_t pos, int nr_slots) | |||
| 967 | de++; | 967 | de++; |
| 968 | nr_slots--; | 968 | nr_slots--; |
| 969 | } | 969 | } |
| 970 | mark_buffer_dirty(bh); | 970 | mark_buffer_dirty_inode(bh, dir); |
| 971 | if (IS_DIRSYNC(dir)) | 971 | if (IS_DIRSYNC(dir)) |
| 972 | err = sync_dirty_buffer(bh); | 972 | err = sync_dirty_buffer(bh); |
| 973 | brelse(bh); | 973 | brelse(bh); |
| @@ -1001,7 +1001,7 @@ int fat_remove_entries(struct inode *dir, struct fat_slot_info *sinfo) | |||
| 1001 | de--; | 1001 | de--; |
| 1002 | nr_slots--; | 1002 | nr_slots--; |
| 1003 | } | 1003 | } |
| 1004 | mark_buffer_dirty(bh); | 1004 | mark_buffer_dirty_inode(bh, dir); |
| 1005 | if (IS_DIRSYNC(dir)) | 1005 | if (IS_DIRSYNC(dir)) |
| 1006 | err = sync_dirty_buffer(bh); | 1006 | err = sync_dirty_buffer(bh); |
| 1007 | brelse(bh); | 1007 | brelse(bh); |
| @@ -1051,7 +1051,7 @@ static int fat_zeroed_cluster(struct inode *dir, sector_t blknr, int nr_used, | |||
| 1051 | } | 1051 | } |
| 1052 | memset(bhs[n]->b_data, 0, sb->s_blocksize); | 1052 | memset(bhs[n]->b_data, 0, sb->s_blocksize); |
| 1053 | set_buffer_uptodate(bhs[n]); | 1053 | set_buffer_uptodate(bhs[n]); |
| 1054 | mark_buffer_dirty(bhs[n]); | 1054 | mark_buffer_dirty_inode(bhs[n], dir); |
| 1055 | 1055 | ||
| 1056 | n++; | 1056 | n++; |
| 1057 | blknr++; | 1057 | blknr++; |
| @@ -1131,7 +1131,7 @@ int fat_alloc_new_dir(struct inode *dir, struct timespec *ts) | |||
| 1131 | de[0].size = de[1].size = 0; | 1131 | de[0].size = de[1].size = 0; |
| 1132 | memset(de + 2, 0, sb->s_blocksize - 2 * sizeof(*de)); | 1132 | memset(de + 2, 0, sb->s_blocksize - 2 * sizeof(*de)); |
| 1133 | set_buffer_uptodate(bhs[0]); | 1133 | set_buffer_uptodate(bhs[0]); |
| 1134 | mark_buffer_dirty(bhs[0]); | 1134 | mark_buffer_dirty_inode(bhs[0], dir); |
| 1135 | 1135 | ||
| 1136 | err = fat_zeroed_cluster(dir, blknr, 1, bhs, MAX_BUF_PER_PAGE); | 1136 | err = fat_zeroed_cluster(dir, blknr, 1, bhs, MAX_BUF_PER_PAGE); |
| 1137 | if (err) | 1137 | if (err) |
| @@ -1193,7 +1193,7 @@ static int fat_add_new_entries(struct inode *dir, void *slots, int nr_slots, | |||
| 1193 | slots += copy; | 1193 | slots += copy; |
| 1194 | size -= copy; | 1194 | size -= copy; |
| 1195 | set_buffer_uptodate(bhs[n]); | 1195 | set_buffer_uptodate(bhs[n]); |
| 1196 | mark_buffer_dirty(bhs[n]); | 1196 | mark_buffer_dirty_inode(bhs[n], dir); |
| 1197 | if (!size) | 1197 | if (!size) |
| 1198 | break; | 1198 | break; |
| 1199 | n++; | 1199 | n++; |
| @@ -1293,7 +1293,7 @@ found: | |||
| 1293 | for (i = 0; i < long_bhs; i++) { | 1293 | for (i = 0; i < long_bhs; i++) { |
| 1294 | int copy = min_t(int, sb->s_blocksize - offset, size); | 1294 | int copy = min_t(int, sb->s_blocksize - offset, size); |
| 1295 | memcpy(bhs[i]->b_data + offset, slots, copy); | 1295 | memcpy(bhs[i]->b_data + offset, slots, copy); |
| 1296 | mark_buffer_dirty(bhs[i]); | 1296 | mark_buffer_dirty_inode(bhs[i], dir); |
| 1297 | offset = 0; | 1297 | offset = 0; |
| 1298 | slots += copy; | 1298 | slots += copy; |
| 1299 | size -= copy; | 1299 | size -= copy; |
| @@ -1304,7 +1304,7 @@ found: | |||
| 1304 | /* Fill the short name slot. */ | 1304 | /* Fill the short name slot. */ |
| 1305 | int copy = min_t(int, sb->s_blocksize - offset, size); | 1305 | int copy = min_t(int, sb->s_blocksize - offset, size); |
| 1306 | memcpy(bhs[i]->b_data + offset, slots, copy); | 1306 | memcpy(bhs[i]->b_data + offset, slots, copy); |
| 1307 | mark_buffer_dirty(bhs[i]); | 1307 | mark_buffer_dirty_inode(bhs[i], dir); |
| 1308 | if (IS_DIRSYNC(dir)) | 1308 | if (IS_DIRSYNC(dir)) |
| 1309 | err = sync_dirty_buffer(bhs[i]); | 1309 | err = sync_dirty_buffer(bhs[i]); |
| 1310 | } | 1310 | } |
diff --git a/fs/fat/fat.h b/fs/fat/fat.h index ea440d65819c..e4d88527b5dd 100644 --- a/fs/fat/fat.h +++ b/fs/fat/fat.h | |||
| @@ -74,6 +74,7 @@ struct msdos_sb_info { | |||
| 74 | 74 | ||
| 75 | int fatent_shift; | 75 | int fatent_shift; |
| 76 | struct fatent_operations *fatent_ops; | 76 | struct fatent_operations *fatent_ops; |
| 77 | struct inode *fat_inode; | ||
| 77 | 78 | ||
| 78 | spinlock_t inode_hash_lock; | 79 | spinlock_t inode_hash_lock; |
| 79 | struct hlist_head inode_hashtable[FAT_HASH_SIZE]; | 80 | struct hlist_head inode_hashtable[FAT_HASH_SIZE]; |
| @@ -251,6 +252,7 @@ struct fat_entry { | |||
| 251 | } u; | 252 | } u; |
| 252 | int nr_bhs; | 253 | int nr_bhs; |
| 253 | struct buffer_head *bhs[2]; | 254 | struct buffer_head *bhs[2]; |
| 255 | struct inode *fat_inode; | ||
| 254 | }; | 256 | }; |
| 255 | 257 | ||
| 256 | static inline void fatent_init(struct fat_entry *fatent) | 258 | static inline void fatent_init(struct fat_entry *fatent) |
| @@ -259,6 +261,7 @@ static inline void fatent_init(struct fat_entry *fatent) | |||
| 259 | fatent->entry = 0; | 261 | fatent->entry = 0; |
| 260 | fatent->u.ent32_p = NULL; | 262 | fatent->u.ent32_p = NULL; |
| 261 | fatent->bhs[0] = fatent->bhs[1] = NULL; | 263 | fatent->bhs[0] = fatent->bhs[1] = NULL; |
| 264 | fatent->fat_inode = NULL; | ||
| 262 | } | 265 | } |
| 263 | 266 | ||
| 264 | static inline void fatent_set_entry(struct fat_entry *fatent, int entry) | 267 | static inline void fatent_set_entry(struct fat_entry *fatent, int entry) |
| @@ -275,6 +278,7 @@ static inline void fatent_brelse(struct fat_entry *fatent) | |||
| 275 | brelse(fatent->bhs[i]); | 278 | brelse(fatent->bhs[i]); |
| 276 | fatent->nr_bhs = 0; | 279 | fatent->nr_bhs = 0; |
| 277 | fatent->bhs[0] = fatent->bhs[1] = NULL; | 280 | fatent->bhs[0] = fatent->bhs[1] = NULL; |
| 281 | fatent->fat_inode = NULL; | ||
| 278 | } | 282 | } |
| 279 | 283 | ||
| 280 | extern void fat_ent_access_init(struct super_block *sb); | 284 | extern void fat_ent_access_init(struct super_block *sb); |
| @@ -296,6 +300,8 @@ extern int fat_setattr(struct dentry * dentry, struct iattr * attr); | |||
| 296 | extern void fat_truncate(struct inode *inode); | 300 | extern void fat_truncate(struct inode *inode); |
| 297 | extern int fat_getattr(struct vfsmount *mnt, struct dentry *dentry, | 301 | extern int fat_getattr(struct vfsmount *mnt, struct dentry *dentry, |
| 298 | struct kstat *stat); | 302 | struct kstat *stat); |
| 303 | extern int fat_file_fsync(struct file *file, struct dentry *dentry, | ||
| 304 | int datasync); | ||
| 299 | 305 | ||
| 300 | /* fat/inode.c */ | 306 | /* fat/inode.c */ |
| 301 | extern void fat_attach(struct inode *inode, loff_t i_pos); | 307 | extern void fat_attach(struct inode *inode, loff_t i_pos); |
diff --git a/fs/fat/fatent.c b/fs/fat/fatent.c index da6eea47872f..618f5305c2e4 100644 --- a/fs/fat/fatent.c +++ b/fs/fat/fatent.c | |||
| @@ -73,6 +73,8 @@ static int fat12_ent_bread(struct super_block *sb, struct fat_entry *fatent, | |||
| 73 | struct buffer_head **bhs = fatent->bhs; | 73 | struct buffer_head **bhs = fatent->bhs; |
| 74 | 74 | ||
| 75 | WARN_ON(blocknr < MSDOS_SB(sb)->fat_start); | 75 | WARN_ON(blocknr < MSDOS_SB(sb)->fat_start); |
| 76 | fatent->fat_inode = MSDOS_SB(sb)->fat_inode; | ||
| 77 | |||
| 76 | bhs[0] = sb_bread(sb, blocknr); | 78 | bhs[0] = sb_bread(sb, blocknr); |
| 77 | if (!bhs[0]) | 79 | if (!bhs[0]) |
| 78 | goto err; | 80 | goto err; |
| @@ -103,6 +105,7 @@ static int fat_ent_bread(struct super_block *sb, struct fat_entry *fatent, | |||
| 103 | struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops; | 105 | struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops; |
| 104 | 106 | ||
| 105 | WARN_ON(blocknr < MSDOS_SB(sb)->fat_start); | 107 | WARN_ON(blocknr < MSDOS_SB(sb)->fat_start); |
| 108 | fatent->fat_inode = MSDOS_SB(sb)->fat_inode; | ||
| 106 | fatent->bhs[0] = sb_bread(sb, blocknr); | 109 | fatent->bhs[0] = sb_bread(sb, blocknr); |
| 107 | if (!fatent->bhs[0]) { | 110 | if (!fatent->bhs[0]) { |
| 108 | printk(KERN_ERR "FAT: FAT read failed (blocknr %llu)\n", | 111 | printk(KERN_ERR "FAT: FAT read failed (blocknr %llu)\n", |
| @@ -167,9 +170,9 @@ static void fat12_ent_put(struct fat_entry *fatent, int new) | |||
| 167 | } | 170 | } |
| 168 | spin_unlock(&fat12_entry_lock); | 171 | spin_unlock(&fat12_entry_lock); |
| 169 | 172 | ||
| 170 | mark_buffer_dirty(fatent->bhs[0]); | 173 | mark_buffer_dirty_inode(fatent->bhs[0], fatent->fat_inode); |
| 171 | if (fatent->nr_bhs == 2) | 174 | if (fatent->nr_bhs == 2) |
| 172 | mark_buffer_dirty(fatent->bhs[1]); | 175 | mark_buffer_dirty_inode(fatent->bhs[1], fatent->fat_inode); |
| 173 | } | 176 | } |
| 174 | 177 | ||
| 175 | static void fat16_ent_put(struct fat_entry *fatent, int new) | 178 | static void fat16_ent_put(struct fat_entry *fatent, int new) |
| @@ -178,7 +181,7 @@ static void fat16_ent_put(struct fat_entry *fatent, int new) | |||
| 178 | new = EOF_FAT16; | 181 | new = EOF_FAT16; |
| 179 | 182 | ||
| 180 | *fatent->u.ent16_p = cpu_to_le16(new); | 183 | *fatent->u.ent16_p = cpu_to_le16(new); |
| 181 | mark_buffer_dirty(fatent->bhs[0]); | 184 | mark_buffer_dirty_inode(fatent->bhs[0], fatent->fat_inode); |
| 182 | } | 185 | } |
| 183 | 186 | ||
| 184 | static void fat32_ent_put(struct fat_entry *fatent, int new) | 187 | static void fat32_ent_put(struct fat_entry *fatent, int new) |
| @@ -189,7 +192,7 @@ static void fat32_ent_put(struct fat_entry *fatent, int new) | |||
| 189 | WARN_ON(new & 0xf0000000); | 192 | WARN_ON(new & 0xf0000000); |
| 190 | new |= le32_to_cpu(*fatent->u.ent32_p) & ~0x0fffffff; | 193 | new |= le32_to_cpu(*fatent->u.ent32_p) & ~0x0fffffff; |
| 191 | *fatent->u.ent32_p = cpu_to_le32(new); | 194 | *fatent->u.ent32_p = cpu_to_le32(new); |
| 192 | mark_buffer_dirty(fatent->bhs[0]); | 195 | mark_buffer_dirty_inode(fatent->bhs[0], fatent->fat_inode); |
| 193 | } | 196 | } |
| 194 | 197 | ||
| 195 | static int fat12_ent_next(struct fat_entry *fatent) | 198 | static int fat12_ent_next(struct fat_entry *fatent) |
| @@ -381,7 +384,7 @@ static int fat_mirror_bhs(struct super_block *sb, struct buffer_head **bhs, | |||
| 381 | } | 384 | } |
| 382 | memcpy(c_bh->b_data, bhs[n]->b_data, sb->s_blocksize); | 385 | memcpy(c_bh->b_data, bhs[n]->b_data, sb->s_blocksize); |
| 383 | set_buffer_uptodate(c_bh); | 386 | set_buffer_uptodate(c_bh); |
| 384 | mark_buffer_dirty(c_bh); | 387 | mark_buffer_dirty_inode(c_bh, sbi->fat_inode); |
| 385 | if (sb->s_flags & MS_SYNCHRONOUS) | 388 | if (sb->s_flags & MS_SYNCHRONOUS) |
| 386 | err = sync_dirty_buffer(c_bh); | 389 | err = sync_dirty_buffer(c_bh); |
| 387 | brelse(c_bh); | 390 | brelse(c_bh); |
diff --git a/fs/fat/file.c b/fs/fat/file.c index 0a7f4a9918b3..e955a56b4e5e 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c | |||
| @@ -133,6 +133,18 @@ static int fat_file_release(struct inode *inode, struct file *filp) | |||
| 133 | return 0; | 133 | return 0; |
| 134 | } | 134 | } |
| 135 | 135 | ||
| 136 | int fat_file_fsync(struct file *filp, struct dentry *dentry, int datasync) | ||
| 137 | { | ||
| 138 | struct inode *inode = dentry->d_inode; | ||
| 139 | int res, err; | ||
| 140 | |||
| 141 | res = simple_fsync(filp, dentry, datasync); | ||
| 142 | err = sync_mapping_buffers(MSDOS_SB(inode->i_sb)->fat_inode->i_mapping); | ||
| 143 | |||
| 144 | return res ? res : err; | ||
| 145 | } | ||
| 146 | |||
| 147 | |||
| 136 | const struct file_operations fat_file_operations = { | 148 | const struct file_operations fat_file_operations = { |
| 137 | .llseek = generic_file_llseek, | 149 | .llseek = generic_file_llseek, |
| 138 | .read = do_sync_read, | 150 | .read = do_sync_read, |
| @@ -142,7 +154,7 @@ const struct file_operations fat_file_operations = { | |||
| 142 | .mmap = generic_file_mmap, | 154 | .mmap = generic_file_mmap, |
| 143 | .release = fat_file_release, | 155 | .release = fat_file_release, |
| 144 | .ioctl = fat_generic_ioctl, | 156 | .ioctl = fat_generic_ioctl, |
| 145 | .fsync = file_fsync, | 157 | .fsync = fat_file_fsync, |
| 146 | .splice_read = generic_file_splice_read, | 158 | .splice_read = generic_file_splice_read, |
| 147 | }; | 159 | }; |
| 148 | 160 | ||
diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 296785a0dec8..51a5ecf9000a 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c | |||
| @@ -441,16 +441,35 @@ static void fat_clear_inode(struct inode *inode) | |||
| 441 | 441 | ||
| 442 | static void fat_write_super(struct super_block *sb) | 442 | static void fat_write_super(struct super_block *sb) |
| 443 | { | 443 | { |
| 444 | lock_super(sb); | ||
| 444 | sb->s_dirt = 0; | 445 | sb->s_dirt = 0; |
| 445 | 446 | ||
| 446 | if (!(sb->s_flags & MS_RDONLY)) | 447 | if (!(sb->s_flags & MS_RDONLY)) |
| 447 | fat_clusters_flush(sb); | 448 | fat_clusters_flush(sb); |
| 449 | unlock_super(sb); | ||
| 450 | } | ||
| 451 | |||
| 452 | static int fat_sync_fs(struct super_block *sb, int wait) | ||
| 453 | { | ||
| 454 | lock_super(sb); | ||
| 455 | fat_clusters_flush(sb); | ||
| 456 | sb->s_dirt = 0; | ||
| 457 | unlock_super(sb); | ||
| 458 | |||
| 459 | return 0; | ||
| 448 | } | 460 | } |
| 449 | 461 | ||
| 450 | static void fat_put_super(struct super_block *sb) | 462 | static void fat_put_super(struct super_block *sb) |
| 451 | { | 463 | { |
| 452 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | 464 | struct msdos_sb_info *sbi = MSDOS_SB(sb); |
| 453 | 465 | ||
| 466 | lock_kernel(); | ||
| 467 | |||
| 468 | if (sb->s_dirt) | ||
| 469 | fat_write_super(sb); | ||
| 470 | |||
| 471 | iput(sbi->fat_inode); | ||
| 472 | |||
| 454 | if (sbi->nls_disk) { | 473 | if (sbi->nls_disk) { |
| 455 | unload_nls(sbi->nls_disk); | 474 | unload_nls(sbi->nls_disk); |
| 456 | sbi->nls_disk = NULL; | 475 | sbi->nls_disk = NULL; |
| @@ -467,6 +486,8 @@ static void fat_put_super(struct super_block *sb) | |||
| 467 | 486 | ||
| 468 | sb->s_fs_info = NULL; | 487 | sb->s_fs_info = NULL; |
| 469 | kfree(sbi); | 488 | kfree(sbi); |
| 489 | |||
| 490 | unlock_kernel(); | ||
| 470 | } | 491 | } |
| 471 | 492 | ||
| 472 | static struct kmem_cache *fat_inode_cachep; | 493 | static struct kmem_cache *fat_inode_cachep; |
| @@ -632,6 +653,7 @@ static const struct super_operations fat_sops = { | |||
| 632 | .delete_inode = fat_delete_inode, | 653 | .delete_inode = fat_delete_inode, |
| 633 | .put_super = fat_put_super, | 654 | .put_super = fat_put_super, |
| 634 | .write_super = fat_write_super, | 655 | .write_super = fat_write_super, |
| 656 | .sync_fs = fat_sync_fs, | ||
| 635 | .statfs = fat_statfs, | 657 | .statfs = fat_statfs, |
| 636 | .clear_inode = fat_clear_inode, | 658 | .clear_inode = fat_clear_inode, |
| 637 | .remount_fs = fat_remount, | 659 | .remount_fs = fat_remount, |
| @@ -1174,7 +1196,7 @@ static int fat_read_root(struct inode *inode) | |||
| 1174 | int fat_fill_super(struct super_block *sb, void *data, int silent, | 1196 | int fat_fill_super(struct super_block *sb, void *data, int silent, |
| 1175 | const struct inode_operations *fs_dir_inode_ops, int isvfat) | 1197 | const struct inode_operations *fs_dir_inode_ops, int isvfat) |
| 1176 | { | 1198 | { |
| 1177 | struct inode *root_inode = NULL; | 1199 | struct inode *root_inode = NULL, *fat_inode = NULL; |
| 1178 | struct buffer_head *bh; | 1200 | struct buffer_head *bh; |
| 1179 | struct fat_boot_sector *b; | 1201 | struct fat_boot_sector *b; |
| 1180 | struct msdos_sb_info *sbi; | 1202 | struct msdos_sb_info *sbi; |
| @@ -1414,6 +1436,11 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, | |||
| 1414 | } | 1436 | } |
| 1415 | 1437 | ||
| 1416 | error = -ENOMEM; | 1438 | error = -ENOMEM; |
| 1439 | fat_inode = new_inode(sb); | ||
| 1440 | if (!fat_inode) | ||
| 1441 | goto out_fail; | ||
| 1442 | MSDOS_I(fat_inode)->i_pos = 0; | ||
| 1443 | sbi->fat_inode = fat_inode; | ||
| 1417 | root_inode = new_inode(sb); | 1444 | root_inode = new_inode(sb); |
| 1418 | if (!root_inode) | 1445 | if (!root_inode) |
| 1419 | goto out_fail; | 1446 | goto out_fail; |
| @@ -1439,6 +1466,8 @@ out_invalid: | |||
| 1439 | " on dev %s.\n", sb->s_id); | 1466 | " on dev %s.\n", sb->s_id); |
| 1440 | 1467 | ||
| 1441 | out_fail: | 1468 | out_fail: |
| 1469 | if (fat_inode) | ||
| 1470 | iput(fat_inode); | ||
| 1442 | if (root_inode) | 1471 | if (root_inode) |
| 1443 | iput(root_inode); | 1472 | iput(root_inode); |
| 1444 | if (sbi->nls_io) | 1473 | if (sbi->nls_io) |
diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c index da3f361a37dd..20f522861355 100644 --- a/fs/fat/namei_msdos.c +++ b/fs/fat/namei_msdos.c | |||
| @@ -544,7 +544,7 @@ static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name, | |||
| 544 | int start = MSDOS_I(new_dir)->i_logstart; | 544 | int start = MSDOS_I(new_dir)->i_logstart; |
| 545 | dotdot_de->start = cpu_to_le16(start); | 545 | dotdot_de->start = cpu_to_le16(start); |
| 546 | dotdot_de->starthi = cpu_to_le16(start >> 16); | 546 | dotdot_de->starthi = cpu_to_le16(start >> 16); |
| 547 | mark_buffer_dirty(dotdot_bh); | 547 | mark_buffer_dirty_inode(dotdot_bh, old_inode); |
| 548 | if (IS_DIRSYNC(new_dir)) { | 548 | if (IS_DIRSYNC(new_dir)) { |
| 549 | err = sync_dirty_buffer(dotdot_bh); | 549 | err = sync_dirty_buffer(dotdot_bh); |
| 550 | if (err) | 550 | if (err) |
| @@ -586,7 +586,7 @@ error_dotdot: | |||
| 586 | int start = MSDOS_I(old_dir)->i_logstart; | 586 | int start = MSDOS_I(old_dir)->i_logstart; |
| 587 | dotdot_de->start = cpu_to_le16(start); | 587 | dotdot_de->start = cpu_to_le16(start); |
| 588 | dotdot_de->starthi = cpu_to_le16(start >> 16); | 588 | dotdot_de->starthi = cpu_to_le16(start >> 16); |
| 589 | mark_buffer_dirty(dotdot_bh); | 589 | mark_buffer_dirty_inode(dotdot_bh, old_inode); |
| 590 | corrupt |= sync_dirty_buffer(dotdot_bh); | 590 | corrupt |= sync_dirty_buffer(dotdot_bh); |
| 591 | } | 591 | } |
| 592 | error_inode: | 592 | error_inode: |
diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c index a0e00e3a46e9..b50ecbe97f83 100644 --- a/fs/fat/namei_vfat.c +++ b/fs/fat/namei_vfat.c | |||
| @@ -965,7 +965,7 @@ static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
| 965 | int start = MSDOS_I(new_dir)->i_logstart; | 965 | int start = MSDOS_I(new_dir)->i_logstart; |
| 966 | dotdot_de->start = cpu_to_le16(start); | 966 | dotdot_de->start = cpu_to_le16(start); |
| 967 | dotdot_de->starthi = cpu_to_le16(start >> 16); | 967 | dotdot_de->starthi = cpu_to_le16(start >> 16); |
| 968 | mark_buffer_dirty(dotdot_bh); | 968 | mark_buffer_dirty_inode(dotdot_bh, old_inode); |
| 969 | if (IS_DIRSYNC(new_dir)) { | 969 | if (IS_DIRSYNC(new_dir)) { |
| 970 | err = sync_dirty_buffer(dotdot_bh); | 970 | err = sync_dirty_buffer(dotdot_bh); |
| 971 | if (err) | 971 | if (err) |
| @@ -1009,7 +1009,7 @@ error_dotdot: | |||
| 1009 | int start = MSDOS_I(old_dir)->i_logstart; | 1009 | int start = MSDOS_I(old_dir)->i_logstart; |
| 1010 | dotdot_de->start = cpu_to_le16(start); | 1010 | dotdot_de->start = cpu_to_le16(start); |
| 1011 | dotdot_de->starthi = cpu_to_le16(start >> 16); | 1011 | dotdot_de->starthi = cpu_to_le16(start >> 16); |
| 1012 | mark_buffer_dirty(dotdot_bh); | 1012 | mark_buffer_dirty_inode(dotdot_bh, old_inode); |
| 1013 | corrupt |= sync_dirty_buffer(dotdot_bh); | 1013 | corrupt |= sync_dirty_buffer(dotdot_bh); |
| 1014 | } | 1014 | } |
| 1015 | error_inode: | 1015 | error_inode: |
diff --git a/fs/file_table.c b/fs/file_table.c index 54018fe48840..334ce39881f8 100644 --- a/fs/file_table.c +++ b/fs/file_table.c | |||
| @@ -214,7 +214,7 @@ int init_file(struct file *file, struct vfsmount *mnt, struct dentry *dentry, | |||
| 214 | */ | 214 | */ |
| 215 | if ((mode & FMODE_WRITE) && !special_file(dentry->d_inode->i_mode)) { | 215 | if ((mode & FMODE_WRITE) && !special_file(dentry->d_inode->i_mode)) { |
| 216 | file_take_write(file); | 216 | file_take_write(file); |
| 217 | error = mnt_want_write(mnt); | 217 | error = mnt_clone_write(mnt); |
| 218 | WARN_ON(error); | 218 | WARN_ON(error); |
| 219 | } | 219 | } |
| 220 | return error; | 220 | return error; |
| @@ -399,6 +399,44 @@ too_bad: | |||
| 399 | return 0; | 399 | return 0; |
| 400 | } | 400 | } |
| 401 | 401 | ||
| 402 | /** | ||
| 403 | * mark_files_ro - mark all files read-only | ||
| 404 | * @sb: superblock in question | ||
| 405 | * | ||
| 406 | * All files are marked read-only. We don't care about pending | ||
| 407 | * delete files so this should be used in 'force' mode only. | ||
| 408 | */ | ||
| 409 | void mark_files_ro(struct super_block *sb) | ||
| 410 | { | ||
| 411 | struct file *f; | ||
| 412 | |||
| 413 | retry: | ||
| 414 | file_list_lock(); | ||
| 415 | list_for_each_entry(f, &sb->s_files, f_u.fu_list) { | ||
| 416 | struct vfsmount *mnt; | ||
| 417 | if (!S_ISREG(f->f_path.dentry->d_inode->i_mode)) | ||
| 418 | continue; | ||
| 419 | if (!file_count(f)) | ||
| 420 | continue; | ||
| 421 | if (!(f->f_mode & FMODE_WRITE)) | ||
| 422 | continue; | ||
| 423 | f->f_mode &= ~FMODE_WRITE; | ||
| 424 | if (file_check_writeable(f) != 0) | ||
| 425 | continue; | ||
| 426 | file_release_write(f); | ||
| 427 | mnt = mntget(f->f_path.mnt); | ||
| 428 | file_list_unlock(); | ||
| 429 | /* | ||
| 430 | * This can sleep, so we can't hold | ||
| 431 | * the file_list_lock() spinlock. | ||
| 432 | */ | ||
| 433 | mnt_drop_write(mnt); | ||
| 434 | mntput(mnt); | ||
| 435 | goto retry; | ||
| 436 | } | ||
| 437 | file_list_unlock(); | ||
| 438 | } | ||
| 439 | |||
| 402 | void __init files_init(unsigned long mempages) | 440 | void __init files_init(unsigned long mempages) |
| 403 | { | 441 | { |
| 404 | int n; | 442 | int n; |
diff --git a/fs/freevxfs/vxfs_super.c b/fs/freevxfs/vxfs_super.c index 1dacda831577..cdbd1654e4cd 100644 --- a/fs/freevxfs/vxfs_super.c +++ b/fs/freevxfs/vxfs_super.c | |||
| @@ -80,12 +80,16 @@ vxfs_put_super(struct super_block *sbp) | |||
| 80 | { | 80 | { |
| 81 | struct vxfs_sb_info *infp = VXFS_SBI(sbp); | 81 | struct vxfs_sb_info *infp = VXFS_SBI(sbp); |
| 82 | 82 | ||
| 83 | lock_kernel(); | ||
| 84 | |||
| 83 | vxfs_put_fake_inode(infp->vsi_fship); | 85 | vxfs_put_fake_inode(infp->vsi_fship); |
| 84 | vxfs_put_fake_inode(infp->vsi_ilist); | 86 | vxfs_put_fake_inode(infp->vsi_ilist); |
| 85 | vxfs_put_fake_inode(infp->vsi_stilist); | 87 | vxfs_put_fake_inode(infp->vsi_stilist); |
| 86 | 88 | ||
| 87 | brelse(infp->vsi_bp); | 89 | brelse(infp->vsi_bp); |
| 88 | kfree(infp); | 90 | kfree(infp); |
| 91 | |||
| 92 | unlock_kernel(); | ||
| 89 | } | 93 | } |
| 90 | 94 | ||
| 91 | /** | 95 | /** |
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 91013ff7dd53..40308e98c6a4 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c | |||
| @@ -64,6 +64,28 @@ static void writeback_release(struct backing_dev_info *bdi) | |||
| 64 | clear_bit(BDI_pdflush, &bdi->state); | 64 | clear_bit(BDI_pdflush, &bdi->state); |
| 65 | } | 65 | } |
| 66 | 66 | ||
| 67 | static noinline void block_dump___mark_inode_dirty(struct inode *inode) | ||
| 68 | { | ||
| 69 | if (inode->i_ino || strcmp(inode->i_sb->s_id, "bdev")) { | ||
| 70 | struct dentry *dentry; | ||
| 71 | const char *name = "?"; | ||
| 72 | |||
| 73 | dentry = d_find_alias(inode); | ||
| 74 | if (dentry) { | ||
| 75 | spin_lock(&dentry->d_lock); | ||
| 76 | name = (const char *) dentry->d_name.name; | ||
| 77 | } | ||
| 78 | printk(KERN_DEBUG | ||
| 79 | "%s(%d): dirtied inode %lu (%s) on %s\n", | ||
| 80 | current->comm, task_pid_nr(current), inode->i_ino, | ||
| 81 | name, inode->i_sb->s_id); | ||
| 82 | if (dentry) { | ||
| 83 | spin_unlock(&dentry->d_lock); | ||
| 84 | dput(dentry); | ||
| 85 | } | ||
| 86 | } | ||
| 87 | } | ||
| 88 | |||
| 67 | /** | 89 | /** |
| 68 | * __mark_inode_dirty - internal function | 90 | * __mark_inode_dirty - internal function |
| 69 | * @inode: inode to mark | 91 | * @inode: inode to mark |
| @@ -114,23 +136,8 @@ void __mark_inode_dirty(struct inode *inode, int flags) | |||
| 114 | if ((inode->i_state & flags) == flags) | 136 | if ((inode->i_state & flags) == flags) |
| 115 | return; | 137 | return; |
| 116 | 138 | ||
| 117 | if (unlikely(block_dump)) { | 139 | if (unlikely(block_dump)) |
| 118 | struct dentry *dentry = NULL; | 140 | block_dump___mark_inode_dirty(inode); |
| 119 | const char *name = "?"; | ||
| 120 | |||
| 121 | if (!list_empty(&inode->i_dentry)) { | ||
| 122 | dentry = list_entry(inode->i_dentry.next, | ||
| 123 | struct dentry, d_alias); | ||
| 124 | if (dentry && dentry->d_name.name) | ||
| 125 | name = (const char *) dentry->d_name.name; | ||
| 126 | } | ||
| 127 | |||
| 128 | if (inode->i_ino || strcmp(inode->i_sb->s_id, "bdev")) | ||
| 129 | printk(KERN_DEBUG | ||
| 130 | "%s(%d): dirtied inode %lu (%s) on %s\n", | ||
| 131 | current->comm, task_pid_nr(current), inode->i_ino, | ||
| 132 | name, inode->i_sb->s_id); | ||
| 133 | } | ||
| 134 | 141 | ||
| 135 | spin_lock(&inode_lock); | 142 | spin_lock(&inode_lock); |
| 136 | if ((inode->i_state & flags) != flags) { | 143 | if ((inode->i_state & flags) != flags) { |
| @@ -289,7 +296,6 @@ __sync_single_inode(struct inode *inode, struct writeback_control *wbc) | |||
| 289 | int ret; | 296 | int ret; |
| 290 | 297 | ||
| 291 | BUG_ON(inode->i_state & I_SYNC); | 298 | BUG_ON(inode->i_state & I_SYNC); |
| 292 | WARN_ON(inode->i_state & I_NEW); | ||
| 293 | 299 | ||
| 294 | /* Set I_SYNC, reset I_DIRTY */ | 300 | /* Set I_SYNC, reset I_DIRTY */ |
| 295 | dirty = inode->i_state & I_DIRTY; | 301 | dirty = inode->i_state & I_DIRTY; |
| @@ -314,7 +320,6 @@ __sync_single_inode(struct inode *inode, struct writeback_control *wbc) | |||
| 314 | } | 320 | } |
| 315 | 321 | ||
| 316 | spin_lock(&inode_lock); | 322 | spin_lock(&inode_lock); |
| 317 | WARN_ON(inode->i_state & I_NEW); | ||
| 318 | inode->i_state &= ~I_SYNC; | 323 | inode->i_state &= ~I_SYNC; |
| 319 | if (!(inode->i_state & I_FREEING)) { | 324 | if (!(inode->i_state & I_FREEING)) { |
| 320 | if (!(inode->i_state & I_DIRTY) && | 325 | if (!(inode->i_state & I_DIRTY) && |
| @@ -679,55 +684,6 @@ void sync_inodes_sb(struct super_block *sb, int wait) | |||
| 679 | } | 684 | } |
| 680 | 685 | ||
| 681 | /** | 686 | /** |
| 682 | * sync_inodes - writes all inodes to disk | ||
| 683 | * @wait: wait for completion | ||
| 684 | * | ||
| 685 | * sync_inodes() goes through each super block's dirty inode list, writes the | ||
| 686 | * inodes out, waits on the writeout and puts the inodes back on the normal | ||
| 687 | * list. | ||
| 688 | * | ||
| 689 | * This is for sys_sync(). fsync_dev() uses the same algorithm. The subtle | ||
| 690 | * part of the sync functions is that the blockdev "superblock" is processed | ||
| 691 | * last. This is because the write_inode() function of a typical fs will | ||
| 692 | * perform no I/O, but will mark buffers in the blockdev mapping as dirty. | ||
| 693 | * What we want to do is to perform all that dirtying first, and then write | ||
| 694 | * back all those inode blocks via the blockdev mapping in one sweep. So the | ||
| 695 | * additional (somewhat redundant) sync_blockdev() calls here are to make | ||
| 696 | * sure that really happens. Because if we call sync_inodes_sb(wait=1) with | ||
| 697 | * outstanding dirty inodes, the writeback goes block-at-a-time within the | ||
| 698 | * filesystem's write_inode(). This is extremely slow. | ||
| 699 | */ | ||
| 700 | static void __sync_inodes(int wait) | ||
| 701 | { | ||
| 702 | struct super_block *sb; | ||
| 703 | |||
| 704 | spin_lock(&sb_lock); | ||
| 705 | restart: | ||
| 706 | list_for_each_entry(sb, &super_blocks, s_list) { | ||
| 707 | sb->s_count++; | ||
| 708 | spin_unlock(&sb_lock); | ||
| 709 | down_read(&sb->s_umount); | ||
| 710 | if (sb->s_root) { | ||
| 711 | sync_inodes_sb(sb, wait); | ||
| 712 | sync_blockdev(sb->s_bdev); | ||
| 713 | } | ||
| 714 | up_read(&sb->s_umount); | ||
| 715 | spin_lock(&sb_lock); | ||
| 716 | if (__put_super_and_need_restart(sb)) | ||
| 717 | goto restart; | ||
| 718 | } | ||
| 719 | spin_unlock(&sb_lock); | ||
| 720 | } | ||
| 721 | |||
| 722 | void sync_inodes(int wait) | ||
| 723 | { | ||
| 724 | __sync_inodes(0); | ||
| 725 | |||
| 726 | if (wait) | ||
| 727 | __sync_inodes(1); | ||
| 728 | } | ||
| 729 | |||
| 730 | /** | ||
| 731 | * write_inode_now - write an inode to disk | 687 | * write_inode_now - write an inode to disk |
| 732 | * @inode: inode to write to disk | 688 | * @inode: inode to write to disk |
| 733 | * @sync: whether the write should be synchronous or not | 689 | * @sync: whether the write should be synchronous or not |
diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index aa62cf5976e8..f2e449c595b4 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c | |||
| @@ -764,7 +764,6 @@ void __gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl) | |||
| 764 | } | 764 | } |
| 765 | gfs2_log_unlock(sdp); | 765 | gfs2_log_unlock(sdp); |
| 766 | 766 | ||
| 767 | sdp->sd_vfs->s_dirt = 0; | ||
| 768 | up_write(&sdp->sd_log_flush_lock); | 767 | up_write(&sdp->sd_log_flush_lock); |
| 769 | 768 | ||
| 770 | kfree(ai); | 769 | kfree(ai); |
| @@ -823,7 +822,6 @@ void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr) | |||
| 823 | log_refund(sdp, tr); | 822 | log_refund(sdp, tr); |
| 824 | buf_lo_incore_commit(sdp, tr); | 823 | buf_lo_incore_commit(sdp, tr); |
| 825 | 824 | ||
| 826 | sdp->sd_vfs->s_dirt = 1; | ||
| 827 | up_read(&sdp->sd_log_flush_lock); | 825 | up_read(&sdp->sd_log_flush_lock); |
| 828 | 826 | ||
| 829 | gfs2_log_lock(sdp); | 827 | gfs2_log_lock(sdp); |
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 40bcc37e5a70..c8930b31cdf0 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c | |||
| @@ -719,6 +719,8 @@ static void gfs2_put_super(struct super_block *sb) | |||
| 719 | int error; | 719 | int error; |
| 720 | struct gfs2_jdesc *jd; | 720 | struct gfs2_jdesc *jd; |
| 721 | 721 | ||
| 722 | lock_kernel(); | ||
| 723 | |||
| 722 | /* Unfreeze the filesystem, if we need to */ | 724 | /* Unfreeze the filesystem, if we need to */ |
| 723 | 725 | ||
| 724 | mutex_lock(&sdp->sd_freeze_lock); | 726 | mutex_lock(&sdp->sd_freeze_lock); |
| @@ -785,17 +787,8 @@ restart: | |||
| 785 | 787 | ||
| 786 | /* At this point, we're through participating in the lockspace */ | 788 | /* At this point, we're through participating in the lockspace */ |
| 787 | gfs2_sys_fs_del(sdp); | 789 | gfs2_sys_fs_del(sdp); |
| 788 | } | ||
| 789 | |||
| 790 | /** | ||
| 791 | * gfs2_write_super | ||
| 792 | * @sb: the superblock | ||
| 793 | * | ||
| 794 | */ | ||
| 795 | 790 | ||
| 796 | static void gfs2_write_super(struct super_block *sb) | 791 | unlock_kernel(); |
| 797 | { | ||
| 798 | sb->s_dirt = 0; | ||
| 799 | } | 792 | } |
| 800 | 793 | ||
| 801 | /** | 794 | /** |
| @@ -807,7 +800,6 @@ static void gfs2_write_super(struct super_block *sb) | |||
| 807 | 800 | ||
| 808 | static int gfs2_sync_fs(struct super_block *sb, int wait) | 801 | static int gfs2_sync_fs(struct super_block *sb, int wait) |
| 809 | { | 802 | { |
| 810 | sb->s_dirt = 0; | ||
| 811 | if (wait && sb->s_fs_info) | 803 | if (wait && sb->s_fs_info) |
| 812 | gfs2_log_flush(sb->s_fs_info, NULL); | 804 | gfs2_log_flush(sb->s_fs_info, NULL); |
| 813 | return 0; | 805 | return 0; |
| @@ -1324,7 +1316,6 @@ const struct super_operations gfs2_super_ops = { | |||
| 1324 | .write_inode = gfs2_write_inode, | 1316 | .write_inode = gfs2_write_inode, |
| 1325 | .delete_inode = gfs2_delete_inode, | 1317 | .delete_inode = gfs2_delete_inode, |
| 1326 | .put_super = gfs2_put_super, | 1318 | .put_super = gfs2_put_super, |
| 1327 | .write_super = gfs2_write_super, | ||
| 1328 | .sync_fs = gfs2_sync_fs, | 1319 | .sync_fs = gfs2_sync_fs, |
| 1329 | .freeze_fs = gfs2_freeze, | 1320 | .freeze_fs = gfs2_freeze, |
| 1330 | .unfreeze_fs = gfs2_unfreeze, | 1321 | .unfreeze_fs = gfs2_unfreeze, |
diff --git a/fs/hfs/super.c b/fs/hfs/super.c index a36bb749926d..6f833dc8e910 100644 --- a/fs/hfs/super.c +++ b/fs/hfs/super.c | |||
| @@ -49,11 +49,23 @@ MODULE_LICENSE("GPL"); | |||
| 49 | */ | 49 | */ |
| 50 | static void hfs_write_super(struct super_block *sb) | 50 | static void hfs_write_super(struct super_block *sb) |
| 51 | { | 51 | { |
| 52 | lock_super(sb); | ||
| 52 | sb->s_dirt = 0; | 53 | sb->s_dirt = 0; |
| 53 | if (sb->s_flags & MS_RDONLY) | 54 | |
| 54 | return; | ||
| 55 | /* sync everything to the buffers */ | 55 | /* sync everything to the buffers */ |
| 56 | if (!(sb->s_flags & MS_RDONLY)) | ||
| 57 | hfs_mdb_commit(sb); | ||
| 58 | unlock_super(sb); | ||
| 59 | } | ||
| 60 | |||
| 61 | static int hfs_sync_fs(struct super_block *sb, int wait) | ||
| 62 | { | ||
| 63 | lock_super(sb); | ||
| 56 | hfs_mdb_commit(sb); | 64 | hfs_mdb_commit(sb); |
| 65 | sb->s_dirt = 0; | ||
| 66 | unlock_super(sb); | ||
| 67 | |||
| 68 | return 0; | ||
| 57 | } | 69 | } |
| 58 | 70 | ||
| 59 | /* | 71 | /* |
| @@ -65,9 +77,15 @@ static void hfs_write_super(struct super_block *sb) | |||
| 65 | */ | 77 | */ |
| 66 | static void hfs_put_super(struct super_block *sb) | 78 | static void hfs_put_super(struct super_block *sb) |
| 67 | { | 79 | { |
| 80 | lock_kernel(); | ||
| 81 | |||
| 82 | if (sb->s_dirt) | ||
| 83 | hfs_write_super(sb); | ||
| 68 | hfs_mdb_close(sb); | 84 | hfs_mdb_close(sb); |
| 69 | /* release the MDB's resources */ | 85 | /* release the MDB's resources */ |
| 70 | hfs_mdb_put(sb); | 86 | hfs_mdb_put(sb); |
| 87 | |||
| 88 | unlock_kernel(); | ||
| 71 | } | 89 | } |
| 72 | 90 | ||
| 73 | /* | 91 | /* |
| @@ -164,6 +182,7 @@ static const struct super_operations hfs_super_operations = { | |||
| 164 | .clear_inode = hfs_clear_inode, | 182 | .clear_inode = hfs_clear_inode, |
| 165 | .put_super = hfs_put_super, | 183 | .put_super = hfs_put_super, |
| 166 | .write_super = hfs_write_super, | 184 | .write_super = hfs_write_super, |
| 185 | .sync_fs = hfs_sync_fs, | ||
| 167 | .statfs = hfs_statfs, | 186 | .statfs = hfs_statfs, |
| 168 | .remount_fs = hfs_remount, | 187 | .remount_fs = hfs_remount, |
| 169 | .show_options = hfs_show_options, | 188 | .show_options = hfs_show_options, |
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c index f2a64020f42e..9fc3af0c0dab 100644 --- a/fs/hfsplus/super.c +++ b/fs/hfsplus/super.c | |||
| @@ -152,15 +152,14 @@ static void hfsplus_clear_inode(struct inode *inode) | |||
| 152 | } | 152 | } |
| 153 | } | 153 | } |
| 154 | 154 | ||
| 155 | static void hfsplus_write_super(struct super_block *sb) | 155 | static int hfsplus_sync_fs(struct super_block *sb, int wait) |
| 156 | { | 156 | { |
| 157 | struct hfsplus_vh *vhdr = HFSPLUS_SB(sb).s_vhdr; | 157 | struct hfsplus_vh *vhdr = HFSPLUS_SB(sb).s_vhdr; |
| 158 | 158 | ||
| 159 | dprint(DBG_SUPER, "hfsplus_write_super\n"); | 159 | dprint(DBG_SUPER, "hfsplus_write_super\n"); |
| 160 | |||
| 161 | lock_super(sb); | ||
| 160 | sb->s_dirt = 0; | 162 | sb->s_dirt = 0; |
| 161 | if (sb->s_flags & MS_RDONLY) | ||
| 162 | /* warn? */ | ||
| 163 | return; | ||
| 164 | 163 | ||
| 165 | vhdr->free_blocks = cpu_to_be32(HFSPLUS_SB(sb).free_blocks); | 164 | vhdr->free_blocks = cpu_to_be32(HFSPLUS_SB(sb).free_blocks); |
| 166 | vhdr->next_alloc = cpu_to_be32(HFSPLUS_SB(sb).next_alloc); | 165 | vhdr->next_alloc = cpu_to_be32(HFSPLUS_SB(sb).next_alloc); |
| @@ -192,6 +191,16 @@ static void hfsplus_write_super(struct super_block *sb) | |||
| 192 | } | 191 | } |
| 193 | HFSPLUS_SB(sb).flags &= ~HFSPLUS_SB_WRITEBACKUP; | 192 | HFSPLUS_SB(sb).flags &= ~HFSPLUS_SB_WRITEBACKUP; |
| 194 | } | 193 | } |
| 194 | unlock_super(sb); | ||
| 195 | return 0; | ||
| 196 | } | ||
| 197 | |||
| 198 | static void hfsplus_write_super(struct super_block *sb) | ||
| 199 | { | ||
| 200 | if (!(sb->s_flags & MS_RDONLY)) | ||
| 201 | hfsplus_sync_fs(sb, 1); | ||
| 202 | else | ||
| 203 | sb->s_dirt = 0; | ||
| 195 | } | 204 | } |
| 196 | 205 | ||
| 197 | static void hfsplus_put_super(struct super_block *sb) | 206 | static void hfsplus_put_super(struct super_block *sb) |
| @@ -199,6 +208,11 @@ static void hfsplus_put_super(struct super_block *sb) | |||
| 199 | dprint(DBG_SUPER, "hfsplus_put_super\n"); | 208 | dprint(DBG_SUPER, "hfsplus_put_super\n"); |
| 200 | if (!sb->s_fs_info) | 209 | if (!sb->s_fs_info) |
| 201 | return; | 210 | return; |
| 211 | |||
| 212 | lock_kernel(); | ||
| 213 | |||
| 214 | if (sb->s_dirt) | ||
| 215 | hfsplus_write_super(sb); | ||
| 202 | if (!(sb->s_flags & MS_RDONLY) && HFSPLUS_SB(sb).s_vhdr) { | 216 | if (!(sb->s_flags & MS_RDONLY) && HFSPLUS_SB(sb).s_vhdr) { |
| 203 | struct hfsplus_vh *vhdr = HFSPLUS_SB(sb).s_vhdr; | 217 | struct hfsplus_vh *vhdr = HFSPLUS_SB(sb).s_vhdr; |
| 204 | 218 | ||
| @@ -218,6 +232,8 @@ static void hfsplus_put_super(struct super_block *sb) | |||
| 218 | unload_nls(HFSPLUS_SB(sb).nls); | 232 | unload_nls(HFSPLUS_SB(sb).nls); |
| 219 | kfree(sb->s_fs_info); | 233 | kfree(sb->s_fs_info); |
| 220 | sb->s_fs_info = NULL; | 234 | sb->s_fs_info = NULL; |
| 235 | |||
| 236 | unlock_kernel(); | ||
| 221 | } | 237 | } |
| 222 | 238 | ||
| 223 | static int hfsplus_statfs(struct dentry *dentry, struct kstatfs *buf) | 239 | static int hfsplus_statfs(struct dentry *dentry, struct kstatfs *buf) |
| @@ -279,6 +295,7 @@ static const struct super_operations hfsplus_sops = { | |||
| 279 | .clear_inode = hfsplus_clear_inode, | 295 | .clear_inode = hfsplus_clear_inode, |
| 280 | .put_super = hfsplus_put_super, | 296 | .put_super = hfsplus_put_super, |
| 281 | .write_super = hfsplus_write_super, | 297 | .write_super = hfsplus_write_super, |
| 298 | .sync_fs = hfsplus_sync_fs, | ||
| 282 | .statfs = hfsplus_statfs, | 299 | .statfs = hfsplus_statfs, |
| 283 | .remount_fs = hfsplus_remount, | 300 | .remount_fs = hfsplus_remount, |
| 284 | .show_options = hfsplus_show_options, | 301 | .show_options = hfsplus_show_options, |
diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c index fc77965be841..f2feaa06bf26 100644 --- a/fs/hpfs/super.c +++ b/fs/hpfs/super.c | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | #include <linux/statfs.h> | 13 | #include <linux/statfs.h> |
| 14 | #include <linux/magic.h> | 14 | #include <linux/magic.h> |
| 15 | #include <linux/sched.h> | 15 | #include <linux/sched.h> |
| 16 | #include <linux/smp_lock.h> | ||
| 16 | 17 | ||
| 17 | /* Mark the filesystem dirty, so that chkdsk checks it when os/2 booted */ | 18 | /* Mark the filesystem dirty, so that chkdsk checks it when os/2 booted */ |
| 18 | 19 | ||
| @@ -99,11 +100,16 @@ int hpfs_stop_cycles(struct super_block *s, int key, int *c1, int *c2, | |||
| 99 | static void hpfs_put_super(struct super_block *s) | 100 | static void hpfs_put_super(struct super_block *s) |
| 100 | { | 101 | { |
| 101 | struct hpfs_sb_info *sbi = hpfs_sb(s); | 102 | struct hpfs_sb_info *sbi = hpfs_sb(s); |
| 103 | |||
| 104 | lock_kernel(); | ||
| 105 | |||
| 102 | kfree(sbi->sb_cp_table); | 106 | kfree(sbi->sb_cp_table); |
| 103 | kfree(sbi->sb_bmp_dir); | 107 | kfree(sbi->sb_bmp_dir); |
| 104 | unmark_dirty(s); | 108 | unmark_dirty(s); |
| 105 | s->s_fs_info = NULL; | 109 | s->s_fs_info = NULL; |
| 106 | kfree(sbi); | 110 | kfree(sbi); |
| 111 | |||
| 112 | unlock_kernel(); | ||
| 107 | } | 113 | } |
| 108 | 114 | ||
| 109 | unsigned hpfs_count_one_bitmap(struct super_block *s, secno secno) | 115 | unsigned hpfs_count_one_bitmap(struct super_block *s, secno secno) |
| @@ -393,6 +399,8 @@ static int hpfs_remount_fs(struct super_block *s, int *flags, char *data) | |||
| 393 | 399 | ||
| 394 | *flags |= MS_NOATIME; | 400 | *flags |= MS_NOATIME; |
| 395 | 401 | ||
| 402 | lock_kernel(); | ||
| 403 | lock_super(s); | ||
| 396 | uid = sbi->sb_uid; gid = sbi->sb_gid; | 404 | uid = sbi->sb_uid; gid = sbi->sb_gid; |
| 397 | umask = 0777 & ~sbi->sb_mode; | 405 | umask = 0777 & ~sbi->sb_mode; |
| 398 | lowercase = sbi->sb_lowercase; conv = sbi->sb_conv; | 406 | lowercase = sbi->sb_lowercase; conv = sbi->sb_conv; |
| @@ -425,9 +433,13 @@ static int hpfs_remount_fs(struct super_block *s, int *flags, char *data) | |||
| 425 | 433 | ||
| 426 | replace_mount_options(s, new_opts); | 434 | replace_mount_options(s, new_opts); |
| 427 | 435 | ||
| 436 | unlock_super(s); | ||
| 437 | unlock_kernel(); | ||
| 428 | return 0; | 438 | return 0; |
| 429 | 439 | ||
| 430 | out_err: | 440 | out_err: |
| 441 | unlock_super(s); | ||
| 442 | unlock_kernel(); | ||
| 431 | kfree(new_opts); | 443 | kfree(new_opts); |
| 432 | return -EINVAL; | 444 | return -EINVAL; |
| 433 | } | 445 | } |
diff --git a/fs/inode.c b/fs/inode.c index ca337014ae29..a88baebf77cf 100644 --- a/fs/inode.c +++ b/fs/inode.c | |||
| @@ -1422,7 +1422,7 @@ void file_update_time(struct file *file) | |||
| 1422 | if (IS_NOCMTIME(inode)) | 1422 | if (IS_NOCMTIME(inode)) |
| 1423 | return; | 1423 | return; |
| 1424 | 1424 | ||
| 1425 | err = mnt_want_write(file->f_path.mnt); | 1425 | err = mnt_want_write_file(file); |
| 1426 | if (err) | 1426 | if (err) |
| 1427 | return; | 1427 | return; |
| 1428 | 1428 | ||
diff --git a/fs/internal.h b/fs/internal.h index b4dac4fb6b61..d55ef562f0bb 100644 --- a/fs/internal.h +++ b/fs/internal.h | |||
| @@ -25,6 +25,8 @@ static inline int sb_is_blkdev_sb(struct super_block *sb) | |||
| 25 | return sb == blockdev_superblock; | 25 | return sb == blockdev_superblock; |
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | extern int __sync_blockdev(struct block_device *bdev, int wait); | ||
| 29 | |||
| 28 | #else | 30 | #else |
| 29 | static inline void bdev_cache_init(void) | 31 | static inline void bdev_cache_init(void) |
| 30 | { | 32 | { |
| @@ -34,6 +36,11 @@ static inline int sb_is_blkdev_sb(struct super_block *sb) | |||
| 34 | { | 36 | { |
| 35 | return 0; | 37 | return 0; |
| 36 | } | 38 | } |
| 39 | |||
| 40 | static inline int __sync_blockdev(struct block_device *bdev, int wait) | ||
| 41 | { | ||
| 42 | return 0; | ||
| 43 | } | ||
| 37 | #endif | 44 | #endif |
| 38 | 45 | ||
| 39 | /* | 46 | /* |
| @@ -66,3 +73,13 @@ extern void __init mnt_init(void); | |||
| 66 | * fs_struct.c | 73 | * fs_struct.c |
| 67 | */ | 74 | */ |
| 68 | extern void chroot_fs_refs(struct path *, struct path *); | 75 | extern void chroot_fs_refs(struct path *, struct path *); |
| 76 | |||
| 77 | /* | ||
| 78 | * file_table.c | ||
| 79 | */ | ||
| 80 | extern void mark_files_ro(struct super_block *); | ||
| 81 | |||
| 82 | /* | ||
| 83 | * super.c | ||
| 84 | */ | ||
| 85 | extern int do_remount_sb(struct super_block *, int, void *, int); | ||
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index b4cbe9603c7d..068b34b5a107 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c | |||
| @@ -42,11 +42,16 @@ static int isofs_dentry_cmp_ms(struct dentry *dentry, struct qstr *a, struct qst | |||
| 42 | static void isofs_put_super(struct super_block *sb) | 42 | static void isofs_put_super(struct super_block *sb) |
| 43 | { | 43 | { |
| 44 | struct isofs_sb_info *sbi = ISOFS_SB(sb); | 44 | struct isofs_sb_info *sbi = ISOFS_SB(sb); |
| 45 | |||
| 45 | #ifdef CONFIG_JOLIET | 46 | #ifdef CONFIG_JOLIET |
| 47 | lock_kernel(); | ||
| 48 | |||
| 46 | if (sbi->s_nls_iocharset) { | 49 | if (sbi->s_nls_iocharset) { |
| 47 | unload_nls(sbi->s_nls_iocharset); | 50 | unload_nls(sbi->s_nls_iocharset); |
| 48 | sbi->s_nls_iocharset = NULL; | 51 | sbi->s_nls_iocharset = NULL; |
| 49 | } | 52 | } |
| 53 | |||
| 54 | unlock_kernel(); | ||
| 50 | #endif | 55 | #endif |
| 51 | 56 | ||
| 52 | kfree(sbi); | 57 | kfree(sbi); |
diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index 249305d65d5b..3451a81b2142 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c | |||
| @@ -20,6 +20,7 @@ | |||
| 20 | #include <linux/vmalloc.h> | 20 | #include <linux/vmalloc.h> |
| 21 | #include <linux/vfs.h> | 21 | #include <linux/vfs.h> |
| 22 | #include <linux/crc32.h> | 22 | #include <linux/crc32.h> |
| 23 | #include <linux/smp_lock.h> | ||
| 23 | #include "nodelist.h" | 24 | #include "nodelist.h" |
| 24 | 25 | ||
| 25 | static int jffs2_flash_setup(struct jffs2_sb_info *c); | 26 | static int jffs2_flash_setup(struct jffs2_sb_info *c); |
| @@ -387,6 +388,7 @@ int jffs2_remount_fs (struct super_block *sb, int *flags, char *data) | |||
| 387 | This also catches the case where it was stopped and this | 388 | This also catches the case where it was stopped and this |
| 388 | is just a remount to restart it. | 389 | is just a remount to restart it. |
| 389 | Flush the writebuffer, if neccecary, else we loose it */ | 390 | Flush the writebuffer, if neccecary, else we loose it */ |
| 391 | lock_kernel(); | ||
| 390 | if (!(sb->s_flags & MS_RDONLY)) { | 392 | if (!(sb->s_flags & MS_RDONLY)) { |
| 391 | jffs2_stop_garbage_collect_thread(c); | 393 | jffs2_stop_garbage_collect_thread(c); |
| 392 | mutex_lock(&c->alloc_sem); | 394 | mutex_lock(&c->alloc_sem); |
| @@ -399,24 +401,10 @@ int jffs2_remount_fs (struct super_block *sb, int *flags, char *data) | |||
| 399 | 401 | ||
| 400 | *flags |= MS_NOATIME; | 402 | *flags |= MS_NOATIME; |
| 401 | 403 | ||
| 404 | unlock_kernel(); | ||
| 402 | return 0; | 405 | return 0; |
| 403 | } | 406 | } |
| 404 | 407 | ||
| 405 | void jffs2_write_super (struct super_block *sb) | ||
| 406 | { | ||
| 407 | struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); | ||
| 408 | sb->s_dirt = 0; | ||
| 409 | |||
| 410 | if (sb->s_flags & MS_RDONLY) | ||
| 411 | return; | ||
| 412 | |||
| 413 | D1(printk(KERN_DEBUG "jffs2_write_super()\n")); | ||
| 414 | jffs2_garbage_collect_trigger(c); | ||
| 415 | jffs2_erase_pending_blocks(c, 0); | ||
| 416 | jffs2_flush_wbuf_gc(c, 0); | ||
| 417 | } | ||
| 418 | |||
| 419 | |||
| 420 | /* jffs2_new_inode: allocate a new inode and inocache, add it to the hash, | 408 | /* jffs2_new_inode: allocate a new inode and inocache, add it to the hash, |
| 421 | fill in the raw_inode while you're at it. */ | 409 | fill in the raw_inode while you're at it. */ |
| 422 | struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_inode *ri) | 410 | struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_inode *ri) |
diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h index 5e194a5c8e29..2228380c47b9 100644 --- a/fs/jffs2/os-linux.h +++ b/fs/jffs2/os-linux.h | |||
| @@ -181,7 +181,6 @@ void jffs2_dirty_inode(struct inode *inode); | |||
| 181 | struct inode *jffs2_new_inode (struct inode *dir_i, int mode, | 181 | struct inode *jffs2_new_inode (struct inode *dir_i, int mode, |
| 182 | struct jffs2_raw_inode *ri); | 182 | struct jffs2_raw_inode *ri); |
| 183 | int jffs2_statfs (struct dentry *, struct kstatfs *); | 183 | int jffs2_statfs (struct dentry *, struct kstatfs *); |
| 184 | void jffs2_write_super (struct super_block *); | ||
| 185 | int jffs2_remount_fs (struct super_block *, int *, char *); | 184 | int jffs2_remount_fs (struct super_block *, int *, char *); |
| 186 | int jffs2_do_fill_super(struct super_block *sb, void *data, int silent); | 185 | int jffs2_do_fill_super(struct super_block *sb, void *data, int silent); |
| 187 | void jffs2_gc_release_inode(struct jffs2_sb_info *c, | 186 | void jffs2_gc_release_inode(struct jffs2_sb_info *c, |
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index 4c4e18c54a51..07a22caf2687 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c | |||
| @@ -53,10 +53,29 @@ static void jffs2_i_init_once(void *foo) | |||
| 53 | inode_init_once(&f->vfs_inode); | 53 | inode_init_once(&f->vfs_inode); |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | static void jffs2_write_super(struct super_block *sb) | ||
| 57 | { | ||
| 58 | struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); | ||
| 59 | |||
| 60 | lock_super(sb); | ||
| 61 | sb->s_dirt = 0; | ||
| 62 | |||
| 63 | if (!(sb->s_flags & MS_RDONLY)) { | ||
| 64 | D1(printk(KERN_DEBUG "jffs2_write_super()\n")); | ||
| 65 | jffs2_garbage_collect_trigger(c); | ||
| 66 | jffs2_erase_pending_blocks(c, 0); | ||
| 67 | jffs2_flush_wbuf_gc(c, 0); | ||
| 68 | } | ||
| 69 | |||
| 70 | unlock_super(sb); | ||
| 71 | } | ||
| 72 | |||
| 56 | static int jffs2_sync_fs(struct super_block *sb, int wait) | 73 | static int jffs2_sync_fs(struct super_block *sb, int wait) |
| 57 | { | 74 | { |
| 58 | struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); | 75 | struct jffs2_sb_info *c = JFFS2_SB_INFO(sb); |
| 59 | 76 | ||
| 77 | jffs2_write_super(sb); | ||
| 78 | |||
| 60 | mutex_lock(&c->alloc_sem); | 79 | mutex_lock(&c->alloc_sem); |
| 61 | jffs2_flush_wbuf_pad(c); | 80 | jffs2_flush_wbuf_pad(c); |
| 62 | mutex_unlock(&c->alloc_sem); | 81 | mutex_unlock(&c->alloc_sem); |
| @@ -174,6 +193,11 @@ static void jffs2_put_super (struct super_block *sb) | |||
| 174 | 193 | ||
| 175 | D2(printk(KERN_DEBUG "jffs2: jffs2_put_super()\n")); | 194 | D2(printk(KERN_DEBUG "jffs2: jffs2_put_super()\n")); |
| 176 | 195 | ||
| 196 | lock_kernel(); | ||
| 197 | |||
| 198 | if (sb->s_dirt) | ||
| 199 | jffs2_write_super(sb); | ||
| 200 | |||
| 177 | mutex_lock(&c->alloc_sem); | 201 | mutex_lock(&c->alloc_sem); |
| 178 | jffs2_flush_wbuf_pad(c); | 202 | jffs2_flush_wbuf_pad(c); |
| 179 | mutex_unlock(&c->alloc_sem); | 203 | mutex_unlock(&c->alloc_sem); |
| @@ -192,6 +216,8 @@ static void jffs2_put_super (struct super_block *sb) | |||
| 192 | if (c->mtd->sync) | 216 | if (c->mtd->sync) |
| 193 | c->mtd->sync(c->mtd); | 217 | c->mtd->sync(c->mtd); |
| 194 | 218 | ||
| 219 | unlock_kernel(); | ||
| 220 | |||
| 195 | D1(printk(KERN_DEBUG "jffs2_put_super returning\n")); | 221 | D1(printk(KERN_DEBUG "jffs2_put_super returning\n")); |
| 196 | } | 222 | } |
| 197 | 223 | ||
diff --git a/fs/jfs/super.c b/fs/jfs/super.c index d9b0e92b3602..09b1b6ee2186 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c | |||
| @@ -32,6 +32,7 @@ | |||
| 32 | #include <linux/crc32.h> | 32 | #include <linux/crc32.h> |
| 33 | #include <asm/uaccess.h> | 33 | #include <asm/uaccess.h> |
| 34 | #include <linux/seq_file.h> | 34 | #include <linux/seq_file.h> |
| 35 | #include <linux/smp_lock.h> | ||
| 35 | 36 | ||
| 36 | #include "jfs_incore.h" | 37 | #include "jfs_incore.h" |
| 37 | #include "jfs_filsys.h" | 38 | #include "jfs_filsys.h" |
| @@ -183,6 +184,9 @@ static void jfs_put_super(struct super_block *sb) | |||
| 183 | int rc; | 184 | int rc; |
| 184 | 185 | ||
| 185 | jfs_info("In jfs_put_super"); | 186 | jfs_info("In jfs_put_super"); |
| 187 | |||
| 188 | lock_kernel(); | ||
| 189 | |||
| 186 | rc = jfs_umount(sb); | 190 | rc = jfs_umount(sb); |
| 187 | if (rc) | 191 | if (rc) |
| 188 | jfs_err("jfs_umount failed with return code %d", rc); | 192 | jfs_err("jfs_umount failed with return code %d", rc); |
| @@ -195,6 +199,8 @@ static void jfs_put_super(struct super_block *sb) | |||
| 195 | sbi->direct_inode = NULL; | 199 | sbi->direct_inode = NULL; |
| 196 | 200 | ||
| 197 | kfree(sbi); | 201 | kfree(sbi); |
| 202 | |||
| 203 | unlock_kernel(); | ||
| 198 | } | 204 | } |
| 199 | 205 | ||
| 200 | enum { | 206 | enum { |
| @@ -370,19 +376,24 @@ static int jfs_remount(struct super_block *sb, int *flags, char *data) | |||
| 370 | s64 newLVSize = 0; | 376 | s64 newLVSize = 0; |
| 371 | int rc = 0; | 377 | int rc = 0; |
| 372 | int flag = JFS_SBI(sb)->flag; | 378 | int flag = JFS_SBI(sb)->flag; |
| 379 | int ret; | ||
| 373 | 380 | ||
| 374 | if (!parse_options(data, sb, &newLVSize, &flag)) { | 381 | if (!parse_options(data, sb, &newLVSize, &flag)) { |
| 375 | return -EINVAL; | 382 | return -EINVAL; |
| 376 | } | 383 | } |
| 384 | lock_kernel(); | ||
| 377 | if (newLVSize) { | 385 | if (newLVSize) { |
| 378 | if (sb->s_flags & MS_RDONLY) { | 386 | if (sb->s_flags & MS_RDONLY) { |
| 379 | printk(KERN_ERR | 387 | printk(KERN_ERR |
| 380 | "JFS: resize requires volume to be mounted read-write\n"); | 388 | "JFS: resize requires volume to be mounted read-write\n"); |
| 389 | unlock_kernel(); | ||
| 381 | return -EROFS; | 390 | return -EROFS; |
| 382 | } | 391 | } |
| 383 | rc = jfs_extendfs(sb, newLVSize, 0); | 392 | rc = jfs_extendfs(sb, newLVSize, 0); |
| 384 | if (rc) | 393 | if (rc) { |
| 394 | unlock_kernel(); | ||
| 385 | return rc; | 395 | return rc; |
| 396 | } | ||
| 386 | } | 397 | } |
| 387 | 398 | ||
| 388 | if ((sb->s_flags & MS_RDONLY) && !(*flags & MS_RDONLY)) { | 399 | if ((sb->s_flags & MS_RDONLY) && !(*flags & MS_RDONLY)) { |
| @@ -393,23 +404,31 @@ static int jfs_remount(struct super_block *sb, int *flags, char *data) | |||
| 393 | truncate_inode_pages(JFS_SBI(sb)->direct_inode->i_mapping, 0); | 404 | truncate_inode_pages(JFS_SBI(sb)->direct_inode->i_mapping, 0); |
| 394 | 405 | ||
| 395 | JFS_SBI(sb)->flag = flag; | 406 | JFS_SBI(sb)->flag = flag; |
| 396 | return jfs_mount_rw(sb, 1); | 407 | ret = jfs_mount_rw(sb, 1); |
| 408 | unlock_kernel(); | ||
| 409 | return ret; | ||
| 397 | } | 410 | } |
| 398 | if ((!(sb->s_flags & MS_RDONLY)) && (*flags & MS_RDONLY)) { | 411 | if ((!(sb->s_flags & MS_RDONLY)) && (*flags & MS_RDONLY)) { |
| 399 | rc = jfs_umount_rw(sb); | 412 | rc = jfs_umount_rw(sb); |
| 400 | JFS_SBI(sb)->flag = flag; | 413 | JFS_SBI(sb)->flag = flag; |
| 414 | unlock_kernel(); | ||
| 401 | return rc; | 415 | return rc; |
| 402 | } | 416 | } |
| 403 | if ((JFS_SBI(sb)->flag & JFS_NOINTEGRITY) != (flag & JFS_NOINTEGRITY)) | 417 | if ((JFS_SBI(sb)->flag & JFS_NOINTEGRITY) != (flag & JFS_NOINTEGRITY)) |
| 404 | if (!(sb->s_flags & MS_RDONLY)) { | 418 | if (!(sb->s_flags & MS_RDONLY)) { |
| 405 | rc = jfs_umount_rw(sb); | 419 | rc = jfs_umount_rw(sb); |
| 406 | if (rc) | 420 | if (rc) { |
| 421 | unlock_kernel(); | ||
| 407 | return rc; | 422 | return rc; |
| 423 | } | ||
| 408 | JFS_SBI(sb)->flag = flag; | 424 | JFS_SBI(sb)->flag = flag; |
| 409 | return jfs_mount_rw(sb, 1); | 425 | ret = jfs_mount_rw(sb, 1); |
| 426 | unlock_kernel(); | ||
| 427 | return ret; | ||
| 410 | } | 428 | } |
| 411 | JFS_SBI(sb)->flag = flag; | 429 | JFS_SBI(sb)->flag = flag; |
| 412 | 430 | ||
| 431 | unlock_kernel(); | ||
| 413 | return 0; | 432 | return 0; |
| 414 | } | 433 | } |
| 415 | 434 | ||
diff --git a/fs/libfs.c b/fs/libfs.c index 80046ddf5063..ddfa89948c3f 100644 --- a/fs/libfs.c +++ b/fs/libfs.c | |||
| @@ -9,6 +9,8 @@ | |||
| 9 | #include <linux/vfs.h> | 9 | #include <linux/vfs.h> |
| 10 | #include <linux/mutex.h> | 10 | #include <linux/mutex.h> |
| 11 | #include <linux/exportfs.h> | 11 | #include <linux/exportfs.h> |
| 12 | #include <linux/writeback.h> | ||
| 13 | #include <linux/buffer_head.h> | ||
| 12 | 14 | ||
| 13 | #include <asm/uaccess.h> | 15 | #include <asm/uaccess.h> |
| 14 | 16 | ||
| @@ -807,6 +809,29 @@ struct dentry *generic_fh_to_parent(struct super_block *sb, struct fid *fid, | |||
| 807 | } | 809 | } |
| 808 | EXPORT_SYMBOL_GPL(generic_fh_to_parent); | 810 | EXPORT_SYMBOL_GPL(generic_fh_to_parent); |
| 809 | 811 | ||
| 812 | int simple_fsync(struct file *file, struct dentry *dentry, int datasync) | ||
| 813 | { | ||
| 814 | struct writeback_control wbc = { | ||
| 815 | .sync_mode = WB_SYNC_ALL, | ||
| 816 | .nr_to_write = 0, /* metadata-only; caller takes care of data */ | ||
| 817 | }; | ||
| 818 | struct inode *inode = dentry->d_inode; | ||
| 819 | int err; | ||
| 820 | int ret; | ||
| 821 | |||
| 822 | ret = sync_mapping_buffers(inode->i_mapping); | ||
| 823 | if (!(inode->i_state & I_DIRTY)) | ||
| 824 | return ret; | ||
| 825 | if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) | ||
| 826 | return ret; | ||
| 827 | |||
| 828 | err = sync_inode(inode, &wbc); | ||
| 829 | if (ret == 0) | ||
| 830 | ret = err; | ||
| 831 | return ret; | ||
| 832 | } | ||
| 833 | EXPORT_SYMBOL(simple_fsync); | ||
| 834 | |||
| 810 | EXPORT_SYMBOL(dcache_dir_close); | 835 | EXPORT_SYMBOL(dcache_dir_close); |
| 811 | EXPORT_SYMBOL(dcache_dir_lseek); | 836 | EXPORT_SYMBOL(dcache_dir_lseek); |
| 812 | EXPORT_SYMBOL(dcache_dir_open); | 837 | EXPORT_SYMBOL(dcache_dir_open); |
diff --git a/fs/minix/dir.c b/fs/minix/dir.c index d4946c4c90e2..e5f206467e40 100644 --- a/fs/minix/dir.c +++ b/fs/minix/dir.c | |||
| @@ -22,7 +22,7 @@ static int minix_readdir(struct file *, void *, filldir_t); | |||
| 22 | const struct file_operations minix_dir_operations = { | 22 | const struct file_operations minix_dir_operations = { |
| 23 | .read = generic_read_dir, | 23 | .read = generic_read_dir, |
| 24 | .readdir = minix_readdir, | 24 | .readdir = minix_readdir, |
| 25 | .fsync = minix_sync_file, | 25 | .fsync = simple_fsync, |
| 26 | }; | 26 | }; |
| 27 | 27 | ||
| 28 | static inline void dir_put_page(struct page *page) | 28 | static inline void dir_put_page(struct page *page) |
diff --git a/fs/minix/file.c b/fs/minix/file.c index 17765f697e50..3eec3e607a87 100644 --- a/fs/minix/file.c +++ b/fs/minix/file.c | |||
| @@ -6,15 +6,12 @@ | |||
| 6 | * minix regular file handling primitives | 6 | * minix regular file handling primitives |
| 7 | */ | 7 | */ |
| 8 | 8 | ||
| 9 | #include <linux/buffer_head.h> /* for fsync_inode_buffers() */ | ||
| 10 | #include "minix.h" | 9 | #include "minix.h" |
| 11 | 10 | ||
| 12 | /* | 11 | /* |
| 13 | * We have mostly NULLs here: the current defaults are OK for | 12 | * We have mostly NULLs here: the current defaults are OK for |
| 14 | * the minix filesystem. | 13 | * the minix filesystem. |
| 15 | */ | 14 | */ |
| 16 | int minix_sync_file(struct file *, struct dentry *, int); | ||
| 17 | |||
| 18 | const struct file_operations minix_file_operations = { | 15 | const struct file_operations minix_file_operations = { |
| 19 | .llseek = generic_file_llseek, | 16 | .llseek = generic_file_llseek, |
| 20 | .read = do_sync_read, | 17 | .read = do_sync_read, |
| @@ -22,7 +19,7 @@ const struct file_operations minix_file_operations = { | |||
| 22 | .write = do_sync_write, | 19 | .write = do_sync_write, |
| 23 | .aio_write = generic_file_aio_write, | 20 | .aio_write = generic_file_aio_write, |
| 24 | .mmap = generic_file_mmap, | 21 | .mmap = generic_file_mmap, |
| 25 | .fsync = minix_sync_file, | 22 | .fsync = simple_fsync, |
| 26 | .splice_read = generic_file_splice_read, | 23 | .splice_read = generic_file_splice_read, |
| 27 | }; | 24 | }; |
| 28 | 25 | ||
| @@ -30,18 +27,3 @@ const struct inode_operations minix_file_inode_operations = { | |||
| 30 | .truncate = minix_truncate, | 27 | .truncate = minix_truncate, |
| 31 | .getattr = minix_getattr, | 28 | .getattr = minix_getattr, |
| 32 | }; | 29 | }; |
| 33 | |||
| 34 | int minix_sync_file(struct file * file, struct dentry *dentry, int datasync) | ||
| 35 | { | ||
| 36 | struct inode *inode = dentry->d_inode; | ||
| 37 | int err; | ||
| 38 | |||
| 39 | err = sync_mapping_buffers(inode->i_mapping); | ||
| 40 | if (!(inode->i_state & I_DIRTY)) | ||
| 41 | return err; | ||
| 42 | if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) | ||
| 43 | return err; | ||
| 44 | |||
| 45 | err |= minix_sync_inode(inode); | ||
| 46 | return err ? -EIO : 0; | ||
| 47 | } | ||
diff --git a/fs/minix/inode.c b/fs/minix/inode.c index daad3c2740db..f91a23693597 100644 --- a/fs/minix/inode.c +++ b/fs/minix/inode.c | |||
| @@ -35,6 +35,8 @@ static void minix_put_super(struct super_block *sb) | |||
| 35 | int i; | 35 | int i; |
| 36 | struct minix_sb_info *sbi = minix_sb(sb); | 36 | struct minix_sb_info *sbi = minix_sb(sb); |
| 37 | 37 | ||
| 38 | lock_kernel(); | ||
| 39 | |||
| 38 | if (!(sb->s_flags & MS_RDONLY)) { | 40 | if (!(sb->s_flags & MS_RDONLY)) { |
| 39 | if (sbi->s_version != MINIX_V3) /* s_state is now out from V3 sb */ | 41 | if (sbi->s_version != MINIX_V3) /* s_state is now out from V3 sb */ |
| 40 | sbi->s_ms->s_state = sbi->s_mount_state; | 42 | sbi->s_ms->s_state = sbi->s_mount_state; |
| @@ -49,7 +51,7 @@ static void minix_put_super(struct super_block *sb) | |||
| 49 | sb->s_fs_info = NULL; | 51 | sb->s_fs_info = NULL; |
| 50 | kfree(sbi); | 52 | kfree(sbi); |
| 51 | 53 | ||
| 52 | return; | 54 | unlock_kernel(); |
| 53 | } | 55 | } |
| 54 | 56 | ||
| 55 | static struct kmem_cache * minix_inode_cachep; | 57 | static struct kmem_cache * minix_inode_cachep; |
| @@ -554,38 +556,25 @@ static struct buffer_head * V2_minix_update_inode(struct inode * inode) | |||
| 554 | return bh; | 556 | return bh; |
| 555 | } | 557 | } |
| 556 | 558 | ||
| 557 | static struct buffer_head *minix_update_inode(struct inode *inode) | 559 | static int minix_write_inode(struct inode *inode, int wait) |
| 558 | { | ||
| 559 | if (INODE_VERSION(inode) == MINIX_V1) | ||
| 560 | return V1_minix_update_inode(inode); | ||
| 561 | else | ||
| 562 | return V2_minix_update_inode(inode); | ||
| 563 | } | ||
| 564 | |||
| 565 | static int minix_write_inode(struct inode * inode, int wait) | ||
| 566 | { | ||
| 567 | brelse(minix_update_inode(inode)); | ||
| 568 | return 0; | ||
| 569 | } | ||
| 570 | |||
| 571 | int minix_sync_inode(struct inode * inode) | ||
| 572 | { | 560 | { |
| 573 | int err = 0; | 561 | int err = 0; |
| 574 | struct buffer_head *bh; | 562 | struct buffer_head *bh; |
| 575 | 563 | ||
| 576 | bh = minix_update_inode(inode); | 564 | if (INODE_VERSION(inode) == MINIX_V1) |
| 577 | if (bh && buffer_dirty(bh)) | 565 | bh = V1_minix_update_inode(inode); |
| 578 | { | 566 | else |
| 567 | bh = V2_minix_update_inode(inode); | ||
| 568 | if (!bh) | ||
| 569 | return -EIO; | ||
| 570 | if (wait && buffer_dirty(bh)) { | ||
| 579 | sync_dirty_buffer(bh); | 571 | sync_dirty_buffer(bh); |
| 580 | if (buffer_req(bh) && !buffer_uptodate(bh)) | 572 | if (buffer_req(bh) && !buffer_uptodate(bh)) { |
| 581 | { | ||
| 582 | printk("IO error syncing minix inode [%s:%08lx]\n", | 573 | printk("IO error syncing minix inode [%s:%08lx]\n", |
| 583 | inode->i_sb->s_id, inode->i_ino); | 574 | inode->i_sb->s_id, inode->i_ino); |
| 584 | err = -1; | 575 | err = -EIO; |
| 585 | } | 576 | } |
| 586 | } | 577 | } |
| 587 | else if (!bh) | ||
| 588 | err = -1; | ||
| 589 | brelse (bh); | 578 | brelse (bh); |
| 590 | return err; | 579 | return err; |
| 591 | } | 580 | } |
diff --git a/fs/minix/minix.h b/fs/minix/minix.h index e6a0b193bea4..cb7fdd11f9a5 100644 --- a/fs/minix/minix.h +++ b/fs/minix/minix.h | |||
| @@ -57,7 +57,6 @@ extern int __minix_write_begin(struct file *file, struct address_space *mapping, | |||
| 57 | extern void V1_minix_truncate(struct inode *); | 57 | extern void V1_minix_truncate(struct inode *); |
| 58 | extern void V2_minix_truncate(struct inode *); | 58 | extern void V2_minix_truncate(struct inode *); |
| 59 | extern void minix_truncate(struct inode *); | 59 | extern void minix_truncate(struct inode *); |
| 60 | extern int minix_sync_inode(struct inode *); | ||
| 61 | extern void minix_set_inode(struct inode *, dev_t); | 60 | extern void minix_set_inode(struct inode *, dev_t); |
| 62 | extern int V1_minix_get_block(struct inode *, long, struct buffer_head *, int); | 61 | extern int V1_minix_get_block(struct inode *, long, struct buffer_head *, int); |
| 63 | extern int V2_minix_get_block(struct inode *, long, struct buffer_head *, int); | 62 | extern int V2_minix_get_block(struct inode *, long, struct buffer_head *, int); |
| @@ -72,7 +71,6 @@ extern int minix_empty_dir(struct inode*); | |||
| 72 | extern void minix_set_link(struct minix_dir_entry*, struct page*, struct inode*); | 71 | extern void minix_set_link(struct minix_dir_entry*, struct page*, struct inode*); |
| 73 | extern struct minix_dir_entry *minix_dotdot(struct inode*, struct page**); | 72 | extern struct minix_dir_entry *minix_dotdot(struct inode*, struct page**); |
| 74 | extern ino_t minix_inode_by_name(struct dentry*); | 73 | extern ino_t minix_inode_by_name(struct dentry*); |
| 75 | extern int minix_sync_file(struct file *, struct dentry *, int); | ||
| 76 | 74 | ||
| 77 | extern const struct inode_operations minix_file_inode_operations; | 75 | extern const struct inode_operations minix_file_inode_operations; |
| 78 | extern const struct inode_operations minix_dir_inode_operations; | 76 | extern const struct inode_operations minix_dir_inode_operations; |
diff --git a/fs/namei.c b/fs/namei.c index c82805d088e1..527119afb6a5 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
| @@ -552,6 +552,17 @@ static __always_inline int link_path_walk(const char *name, struct nameidata *nd | |||
| 552 | return result; | 552 | return result; |
| 553 | } | 553 | } |
| 554 | 554 | ||
| 555 | static __always_inline void set_root(struct nameidata *nd) | ||
| 556 | { | ||
| 557 | if (!nd->root.mnt) { | ||
| 558 | struct fs_struct *fs = current->fs; | ||
| 559 | read_lock(&fs->lock); | ||
| 560 | nd->root = fs->root; | ||
| 561 | path_get(&nd->root); | ||
| 562 | read_unlock(&fs->lock); | ||
| 563 | } | ||
| 564 | } | ||
| 565 | |||
| 555 | static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *link) | 566 | static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *link) |
| 556 | { | 567 | { |
| 557 | int res = 0; | 568 | int res = 0; |
| @@ -560,14 +571,10 @@ static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *l | |||
| 560 | goto fail; | 571 | goto fail; |
| 561 | 572 | ||
| 562 | if (*link == '/') { | 573 | if (*link == '/') { |
| 563 | struct fs_struct *fs = current->fs; | 574 | set_root(nd); |
| 564 | |||
| 565 | path_put(&nd->path); | 575 | path_put(&nd->path); |
| 566 | 576 | nd->path = nd->root; | |
| 567 | read_lock(&fs->lock); | 577 | path_get(&nd->root); |
| 568 | nd->path = fs->root; | ||
| 569 | path_get(&fs->root); | ||
| 570 | read_unlock(&fs->lock); | ||
| 571 | } | 578 | } |
| 572 | 579 | ||
| 573 | res = link_path_walk(link, nd); | 580 | res = link_path_walk(link, nd); |
| @@ -668,23 +675,23 @@ loop: | |||
| 668 | return err; | 675 | return err; |
| 669 | } | 676 | } |
| 670 | 677 | ||
| 671 | int follow_up(struct vfsmount **mnt, struct dentry **dentry) | 678 | int follow_up(struct path *path) |
| 672 | { | 679 | { |
| 673 | struct vfsmount *parent; | 680 | struct vfsmount *parent; |
| 674 | struct dentry *mountpoint; | 681 | struct dentry *mountpoint; |
| 675 | spin_lock(&vfsmount_lock); | 682 | spin_lock(&vfsmount_lock); |
| 676 | parent=(*mnt)->mnt_parent; | 683 | parent = path->mnt->mnt_parent; |
| 677 | if (parent == *mnt) { | 684 | if (parent == path->mnt) { |
| 678 | spin_unlock(&vfsmount_lock); | 685 | spin_unlock(&vfsmount_lock); |
| 679 | return 0; | 686 | return 0; |
| 680 | } | 687 | } |
| 681 | mntget(parent); | 688 | mntget(parent); |
| 682 | mountpoint=dget((*mnt)->mnt_mountpoint); | 689 | mountpoint = dget(path->mnt->mnt_mountpoint); |
| 683 | spin_unlock(&vfsmount_lock); | 690 | spin_unlock(&vfsmount_lock); |
| 684 | dput(*dentry); | 691 | dput(path->dentry); |
| 685 | *dentry = mountpoint; | 692 | path->dentry = mountpoint; |
| 686 | mntput(*mnt); | 693 | mntput(path->mnt); |
| 687 | *mnt = parent; | 694 | path->mnt = parent; |
| 688 | return 1; | 695 | return 1; |
| 689 | } | 696 | } |
| 690 | 697 | ||
| @@ -695,7 +702,7 @@ static int __follow_mount(struct path *path) | |||
| 695 | { | 702 | { |
| 696 | int res = 0; | 703 | int res = 0; |
| 697 | while (d_mountpoint(path->dentry)) { | 704 | while (d_mountpoint(path->dentry)) { |
| 698 | struct vfsmount *mounted = lookup_mnt(path->mnt, path->dentry); | 705 | struct vfsmount *mounted = lookup_mnt(path); |
| 699 | if (!mounted) | 706 | if (!mounted) |
| 700 | break; | 707 | break; |
| 701 | dput(path->dentry); | 708 | dput(path->dentry); |
| @@ -708,32 +715,32 @@ static int __follow_mount(struct path *path) | |||
| 708 | return res; | 715 | return res; |
| 709 | } | 716 | } |
| 710 | 717 | ||
| 711 | static void follow_mount(struct vfsmount **mnt, struct dentry **dentry) | 718 | static void follow_mount(struct path *path) |
| 712 | { | 719 | { |
| 713 | while (d_mountpoint(*dentry)) { | 720 | while (d_mountpoint(path->dentry)) { |
| 714 | struct vfsmount *mounted = lookup_mnt(*mnt, *dentry); | 721 | struct vfsmount *mounted = lookup_mnt(path); |
| 715 | if (!mounted) | 722 | if (!mounted) |
| 716 | break; | 723 | break; |
| 717 | dput(*dentry); | 724 | dput(path->dentry); |
| 718 | mntput(*mnt); | 725 | mntput(path->mnt); |
| 719 | *mnt = mounted; | 726 | path->mnt = mounted; |
| 720 | *dentry = dget(mounted->mnt_root); | 727 | path->dentry = dget(mounted->mnt_root); |
| 721 | } | 728 | } |
| 722 | } | 729 | } |
| 723 | 730 | ||
| 724 | /* no need for dcache_lock, as serialization is taken care in | 731 | /* no need for dcache_lock, as serialization is taken care in |
| 725 | * namespace.c | 732 | * namespace.c |
| 726 | */ | 733 | */ |
| 727 | int follow_down(struct vfsmount **mnt, struct dentry **dentry) | 734 | int follow_down(struct path *path) |
| 728 | { | 735 | { |
| 729 | struct vfsmount *mounted; | 736 | struct vfsmount *mounted; |
| 730 | 737 | ||
| 731 | mounted = lookup_mnt(*mnt, *dentry); | 738 | mounted = lookup_mnt(path); |
| 732 | if (mounted) { | 739 | if (mounted) { |
| 733 | dput(*dentry); | 740 | dput(path->dentry); |
| 734 | mntput(*mnt); | 741 | mntput(path->mnt); |
| 735 | *mnt = mounted; | 742 | path->mnt = mounted; |
| 736 | *dentry = dget(mounted->mnt_root); | 743 | path->dentry = dget(mounted->mnt_root); |
| 737 | return 1; | 744 | return 1; |
| 738 | } | 745 | } |
| 739 | return 0; | 746 | return 0; |
| @@ -741,19 +748,16 @@ int follow_down(struct vfsmount **mnt, struct dentry **dentry) | |||
| 741 | 748 | ||
| 742 | static __always_inline void follow_dotdot(struct nameidata *nd) | 749 | static __always_inline void follow_dotdot(struct nameidata *nd) |
| 743 | { | 750 | { |
| 744 | struct fs_struct *fs = current->fs; | 751 | set_root(nd); |
| 745 | 752 | ||
| 746 | while(1) { | 753 | while(1) { |
| 747 | struct vfsmount *parent; | 754 | struct vfsmount *parent; |
| 748 | struct dentry *old = nd->path.dentry; | 755 | struct dentry *old = nd->path.dentry; |
| 749 | 756 | ||
| 750 | read_lock(&fs->lock); | 757 | if (nd->path.dentry == nd->root.dentry && |
| 751 | if (nd->path.dentry == fs->root.dentry && | 758 | nd->path.mnt == nd->root.mnt) { |
| 752 | nd->path.mnt == fs->root.mnt) { | ||
| 753 | read_unlock(&fs->lock); | ||
| 754 | break; | 759 | break; |
| 755 | } | 760 | } |
| 756 | read_unlock(&fs->lock); | ||
| 757 | spin_lock(&dcache_lock); | 761 | spin_lock(&dcache_lock); |
| 758 | if (nd->path.dentry != nd->path.mnt->mnt_root) { | 762 | if (nd->path.dentry != nd->path.mnt->mnt_root) { |
| 759 | nd->path.dentry = dget(nd->path.dentry->d_parent); | 763 | nd->path.dentry = dget(nd->path.dentry->d_parent); |
| @@ -775,7 +779,7 @@ static __always_inline void follow_dotdot(struct nameidata *nd) | |||
| 775 | mntput(nd->path.mnt); | 779 | mntput(nd->path.mnt); |
| 776 | nd->path.mnt = parent; | 780 | nd->path.mnt = parent; |
| 777 | } | 781 | } |
| 778 | follow_mount(&nd->path.mnt, &nd->path.dentry); | 782 | follow_mount(&nd->path); |
| 779 | } | 783 | } |
| 780 | 784 | ||
| 781 | /* | 785 | /* |
| @@ -1017,25 +1021,23 @@ static int path_walk(const char *name, struct nameidata *nd) | |||
| 1017 | return link_path_walk(name, nd); | 1021 | return link_path_walk(name, nd); |
| 1018 | } | 1022 | } |
| 1019 | 1023 | ||
| 1020 | /* Returns 0 and nd will be valid on success; Retuns error, otherwise. */ | 1024 | static int path_init(int dfd, const char *name, unsigned int flags, struct nameidata *nd) |
| 1021 | static int do_path_lookup(int dfd, const char *name, | ||
| 1022 | unsigned int flags, struct nameidata *nd) | ||
| 1023 | { | 1025 | { |
| 1024 | int retval = 0; | 1026 | int retval = 0; |
| 1025 | int fput_needed; | 1027 | int fput_needed; |
| 1026 | struct file *file; | 1028 | struct file *file; |
| 1027 | struct fs_struct *fs = current->fs; | ||
| 1028 | 1029 | ||
| 1029 | nd->last_type = LAST_ROOT; /* if there are only slashes... */ | 1030 | nd->last_type = LAST_ROOT; /* if there are only slashes... */ |
| 1030 | nd->flags = flags; | 1031 | nd->flags = flags; |
| 1031 | nd->depth = 0; | 1032 | nd->depth = 0; |
| 1033 | nd->root.mnt = NULL; | ||
| 1032 | 1034 | ||
| 1033 | if (*name=='/') { | 1035 | if (*name=='/') { |
| 1034 | read_lock(&fs->lock); | 1036 | set_root(nd); |
| 1035 | nd->path = fs->root; | 1037 | nd->path = nd->root; |
| 1036 | path_get(&fs->root); | 1038 | path_get(&nd->root); |
| 1037 | read_unlock(&fs->lock); | ||
| 1038 | } else if (dfd == AT_FDCWD) { | 1039 | } else if (dfd == AT_FDCWD) { |
| 1040 | struct fs_struct *fs = current->fs; | ||
| 1039 | read_lock(&fs->lock); | 1041 | read_lock(&fs->lock); |
| 1040 | nd->path = fs->pwd; | 1042 | nd->path = fs->pwd; |
| 1041 | path_get(&fs->pwd); | 1043 | path_get(&fs->pwd); |
| @@ -1063,17 +1065,29 @@ static int do_path_lookup(int dfd, const char *name, | |||
| 1063 | 1065 | ||
| 1064 | fput_light(file, fput_needed); | 1066 | fput_light(file, fput_needed); |
| 1065 | } | 1067 | } |
| 1068 | return 0; | ||
| 1066 | 1069 | ||
| 1067 | retval = path_walk(name, nd); | 1070 | fput_fail: |
| 1071 | fput_light(file, fput_needed); | ||
| 1072 | out_fail: | ||
| 1073 | return retval; | ||
| 1074 | } | ||
| 1075 | |||
| 1076 | /* Returns 0 and nd will be valid on success; Retuns error, otherwise. */ | ||
| 1077 | static int do_path_lookup(int dfd, const char *name, | ||
| 1078 | unsigned int flags, struct nameidata *nd) | ||
| 1079 | { | ||
| 1080 | int retval = path_init(dfd, name, flags, nd); | ||
| 1081 | if (!retval) | ||
| 1082 | retval = path_walk(name, nd); | ||
| 1068 | if (unlikely(!retval && !audit_dummy_context() && nd->path.dentry && | 1083 | if (unlikely(!retval && !audit_dummy_context() && nd->path.dentry && |
| 1069 | nd->path.dentry->d_inode)) | 1084 | nd->path.dentry->d_inode)) |
| 1070 | audit_inode(name, nd->path.dentry); | 1085 | audit_inode(name, nd->path.dentry); |
| 1071 | out_fail: | 1086 | if (nd->root.mnt) { |
| 1087 | path_put(&nd->root); | ||
| 1088 | nd->root.mnt = NULL; | ||
| 1089 | } | ||
| 1072 | return retval; | 1090 | return retval; |
| 1073 | |||
| 1074 | fput_fail: | ||
| 1075 | fput_light(file, fput_needed); | ||
| 1076 | goto out_fail; | ||
| 1077 | } | 1091 | } |
| 1078 | 1092 | ||
| 1079 | int path_lookup(const char *name, unsigned int flags, | 1093 | int path_lookup(const char *name, unsigned int flags, |
| @@ -1113,14 +1127,18 @@ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt, | |||
| 1113 | nd->path.dentry = dentry; | 1127 | nd->path.dentry = dentry; |
| 1114 | nd->path.mnt = mnt; | 1128 | nd->path.mnt = mnt; |
| 1115 | path_get(&nd->path); | 1129 | path_get(&nd->path); |
| 1130 | nd->root = nd->path; | ||
| 1131 | path_get(&nd->root); | ||
| 1116 | 1132 | ||
| 1117 | retval = path_walk(name, nd); | 1133 | retval = path_walk(name, nd); |
| 1118 | if (unlikely(!retval && !audit_dummy_context() && nd->path.dentry && | 1134 | if (unlikely(!retval && !audit_dummy_context() && nd->path.dentry && |
| 1119 | nd->path.dentry->d_inode)) | 1135 | nd->path.dentry->d_inode)) |
| 1120 | audit_inode(name, nd->path.dentry); | 1136 | audit_inode(name, nd->path.dentry); |
| 1121 | 1137 | ||
| 1122 | return retval; | 1138 | path_put(&nd->root); |
| 1139 | nd->root.mnt = NULL; | ||
| 1123 | 1140 | ||
| 1141 | return retval; | ||
| 1124 | } | 1142 | } |
| 1125 | 1143 | ||
| 1126 | /** | 1144 | /** |
| @@ -1676,9 +1694,14 @@ struct file *do_filp_open(int dfd, const char *pathname, | |||
| 1676 | /* | 1694 | /* |
| 1677 | * Create - we need to know the parent. | 1695 | * Create - we need to know the parent. |
| 1678 | */ | 1696 | */ |
| 1679 | error = do_path_lookup(dfd, pathname, LOOKUP_PARENT, &nd); | 1697 | error = path_init(dfd, pathname, LOOKUP_PARENT, &nd); |
| 1680 | if (error) | 1698 | if (error) |
| 1681 | return ERR_PTR(error); | 1699 | return ERR_PTR(error); |
| 1700 | error = path_walk(pathname, &nd); | ||
| 1701 | if (error) | ||
| 1702 | return ERR_PTR(error); | ||
| 1703 | if (unlikely(!audit_dummy_context())) | ||
| 1704 | audit_inode(pathname, nd.path.dentry); | ||
| 1682 | 1705 | ||
| 1683 | /* | 1706 | /* |
| 1684 | * We have the parent and last component. First of all, check | 1707 | * We have the parent and last component. First of all, check |
| @@ -1806,6 +1829,8 @@ exit: | |||
| 1806 | if (!IS_ERR(nd.intent.open.file)) | 1829 | if (!IS_ERR(nd.intent.open.file)) |
| 1807 | release_open_intent(&nd); | 1830 | release_open_intent(&nd); |
| 1808 | exit_parent: | 1831 | exit_parent: |
| 1832 | if (nd.root.mnt) | ||
| 1833 | path_put(&nd.root); | ||
| 1809 | path_put(&nd.path); | 1834 | path_put(&nd.path); |
| 1810 | return ERR_PTR(error); | 1835 | return ERR_PTR(error); |
| 1811 | 1836 | ||
diff --git a/fs/namespace.c b/fs/namespace.c index 134d494158d9..2dd333b0fe7f 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
| @@ -131,10 +131,20 @@ struct vfsmount *alloc_vfsmnt(const char *name) | |||
| 131 | INIT_LIST_HEAD(&mnt->mnt_share); | 131 | INIT_LIST_HEAD(&mnt->mnt_share); |
| 132 | INIT_LIST_HEAD(&mnt->mnt_slave_list); | 132 | INIT_LIST_HEAD(&mnt->mnt_slave_list); |
| 133 | INIT_LIST_HEAD(&mnt->mnt_slave); | 133 | INIT_LIST_HEAD(&mnt->mnt_slave); |
| 134 | atomic_set(&mnt->__mnt_writers, 0); | 134 | #ifdef CONFIG_SMP |
| 135 | mnt->mnt_writers = alloc_percpu(int); | ||
| 136 | if (!mnt->mnt_writers) | ||
| 137 | goto out_free_devname; | ||
| 138 | #else | ||
| 139 | mnt->mnt_writers = 0; | ||
| 140 | #endif | ||
| 135 | } | 141 | } |
| 136 | return mnt; | 142 | return mnt; |
| 137 | 143 | ||
| 144 | #ifdef CONFIG_SMP | ||
| 145 | out_free_devname: | ||
| 146 | kfree(mnt->mnt_devname); | ||
| 147 | #endif | ||
| 138 | out_free_id: | 148 | out_free_id: |
| 139 | mnt_free_id(mnt); | 149 | mnt_free_id(mnt); |
| 140 | out_free_cache: | 150 | out_free_cache: |
| @@ -171,65 +181,38 @@ int __mnt_is_readonly(struct vfsmount *mnt) | |||
| 171 | } | 181 | } |
| 172 | EXPORT_SYMBOL_GPL(__mnt_is_readonly); | 182 | EXPORT_SYMBOL_GPL(__mnt_is_readonly); |
| 173 | 183 | ||
| 174 | struct mnt_writer { | 184 | static inline void inc_mnt_writers(struct vfsmount *mnt) |
| 175 | /* | 185 | { |
| 176 | * If holding multiple instances of this lock, they | 186 | #ifdef CONFIG_SMP |
| 177 | * must be ordered by cpu number. | 187 | (*per_cpu_ptr(mnt->mnt_writers, smp_processor_id()))++; |
| 178 | */ | 188 | #else |
| 179 | spinlock_t lock; | 189 | mnt->mnt_writers++; |
| 180 | struct lock_class_key lock_class; /* compiles out with !lockdep */ | 190 | #endif |
| 181 | unsigned long count; | 191 | } |
| 182 | struct vfsmount *mnt; | ||
| 183 | } ____cacheline_aligned_in_smp; | ||
| 184 | static DEFINE_PER_CPU(struct mnt_writer, mnt_writers); | ||
| 185 | 192 | ||
| 186 | static int __init init_mnt_writers(void) | 193 | static inline void dec_mnt_writers(struct vfsmount *mnt) |
| 187 | { | 194 | { |
| 188 | int cpu; | 195 | #ifdef CONFIG_SMP |
| 189 | for_each_possible_cpu(cpu) { | 196 | (*per_cpu_ptr(mnt->mnt_writers, smp_processor_id()))--; |
| 190 | struct mnt_writer *writer = &per_cpu(mnt_writers, cpu); | 197 | #else |
| 191 | spin_lock_init(&writer->lock); | 198 | mnt->mnt_writers--; |
| 192 | lockdep_set_class(&writer->lock, &writer->lock_class); | 199 | #endif |
| 193 | writer->count = 0; | ||
| 194 | } | ||
| 195 | return 0; | ||
| 196 | } | 200 | } |
| 197 | fs_initcall(init_mnt_writers); | ||
| 198 | 201 | ||
| 199 | static void unlock_mnt_writers(void) | 202 | static unsigned int count_mnt_writers(struct vfsmount *mnt) |
| 200 | { | 203 | { |
| 204 | #ifdef CONFIG_SMP | ||
| 205 | unsigned int count = 0; | ||
| 201 | int cpu; | 206 | int cpu; |
| 202 | struct mnt_writer *cpu_writer; | ||
| 203 | 207 | ||
| 204 | for_each_possible_cpu(cpu) { | 208 | for_each_possible_cpu(cpu) { |
| 205 | cpu_writer = &per_cpu(mnt_writers, cpu); | 209 | count += *per_cpu_ptr(mnt->mnt_writers, cpu); |
| 206 | spin_unlock(&cpu_writer->lock); | ||
| 207 | } | 210 | } |
| 208 | } | ||
| 209 | 211 | ||
| 210 | static inline void __clear_mnt_count(struct mnt_writer *cpu_writer) | 212 | return count; |
| 211 | { | 213 | #else |
| 212 | if (!cpu_writer->mnt) | 214 | return mnt->mnt_writers; |
| 213 | return; | 215 | #endif |
| 214 | /* | ||
| 215 | * This is in case anyone ever leaves an invalid, | ||
| 216 | * old ->mnt and a count of 0. | ||
| 217 | */ | ||
| 218 | if (!cpu_writer->count) | ||
| 219 | return; | ||
| 220 | atomic_add(cpu_writer->count, &cpu_writer->mnt->__mnt_writers); | ||
| 221 | cpu_writer->count = 0; | ||
| 222 | } | ||
| 223 | /* | ||
| 224 | * must hold cpu_writer->lock | ||
| 225 | */ | ||
| 226 | static inline void use_cpu_writer_for_mount(struct mnt_writer *cpu_writer, | ||
| 227 | struct vfsmount *mnt) | ||
| 228 | { | ||
| 229 | if (cpu_writer->mnt == mnt) | ||
| 230 | return; | ||
| 231 | __clear_mnt_count(cpu_writer); | ||
| 232 | cpu_writer->mnt = mnt; | ||
| 233 | } | 216 | } |
| 234 | 217 | ||
| 235 | /* | 218 | /* |
| @@ -253,74 +236,73 @@ static inline void use_cpu_writer_for_mount(struct mnt_writer *cpu_writer, | |||
| 253 | int mnt_want_write(struct vfsmount *mnt) | 236 | int mnt_want_write(struct vfsmount *mnt) |
| 254 | { | 237 | { |
| 255 | int ret = 0; | 238 | int ret = 0; |
| 256 | struct mnt_writer *cpu_writer; | ||
| 257 | 239 | ||
| 258 | cpu_writer = &get_cpu_var(mnt_writers); | 240 | preempt_disable(); |
| 259 | spin_lock(&cpu_writer->lock); | 241 | inc_mnt_writers(mnt); |
| 242 | /* | ||
| 243 | * The store to inc_mnt_writers must be visible before we pass | ||
| 244 | * MNT_WRITE_HOLD loop below, so that the slowpath can see our | ||
| 245 | * incremented count after it has set MNT_WRITE_HOLD. | ||
| 246 | */ | ||
| 247 | smp_mb(); | ||
| 248 | while (mnt->mnt_flags & MNT_WRITE_HOLD) | ||
| 249 | cpu_relax(); | ||
| 250 | /* | ||
| 251 | * After the slowpath clears MNT_WRITE_HOLD, mnt_is_readonly will | ||
| 252 | * be set to match its requirements. So we must not load that until | ||
| 253 | * MNT_WRITE_HOLD is cleared. | ||
| 254 | */ | ||
| 255 | smp_rmb(); | ||
| 260 | if (__mnt_is_readonly(mnt)) { | 256 | if (__mnt_is_readonly(mnt)) { |
| 257 | dec_mnt_writers(mnt); | ||
| 261 | ret = -EROFS; | 258 | ret = -EROFS; |
| 262 | goto out; | 259 | goto out; |
| 263 | } | 260 | } |
| 264 | use_cpu_writer_for_mount(cpu_writer, mnt); | ||
| 265 | cpu_writer->count++; | ||
| 266 | out: | 261 | out: |
| 267 | spin_unlock(&cpu_writer->lock); | 262 | preempt_enable(); |
| 268 | put_cpu_var(mnt_writers); | ||
| 269 | return ret; | 263 | return ret; |
| 270 | } | 264 | } |
| 271 | EXPORT_SYMBOL_GPL(mnt_want_write); | 265 | EXPORT_SYMBOL_GPL(mnt_want_write); |
| 272 | 266 | ||
| 273 | static void lock_mnt_writers(void) | 267 | /** |
| 274 | { | 268 | * mnt_clone_write - get write access to a mount |
| 275 | int cpu; | 269 | * @mnt: the mount on which to take a write |
| 276 | struct mnt_writer *cpu_writer; | 270 | * |
| 277 | 271 | * This is effectively like mnt_want_write, except | |
| 278 | for_each_possible_cpu(cpu) { | 272 | * it must only be used to take an extra write reference |
| 279 | cpu_writer = &per_cpu(mnt_writers, cpu); | 273 | * on a mountpoint that we already know has a write reference |
| 280 | spin_lock(&cpu_writer->lock); | 274 | * on it. This allows some optimisation. |
| 281 | __clear_mnt_count(cpu_writer); | 275 | * |
| 282 | cpu_writer->mnt = NULL; | 276 | * After finished, mnt_drop_write must be called as usual to |
| 283 | } | 277 | * drop the reference. |
| 278 | */ | ||
| 279 | int mnt_clone_write(struct vfsmount *mnt) | ||
| 280 | { | ||
| 281 | /* superblock may be r/o */ | ||
| 282 | if (__mnt_is_readonly(mnt)) | ||
| 283 | return -EROFS; | ||
| 284 | preempt_disable(); | ||
| 285 | inc_mnt_writers(mnt); | ||
| 286 | preempt_enable(); | ||
| 287 | return 0; | ||
| 284 | } | 288 | } |
| 289 | EXPORT_SYMBOL_GPL(mnt_clone_write); | ||
| 285 | 290 | ||
| 286 | /* | 291 | /** |
| 287 | * These per-cpu write counts are not guaranteed to have | 292 | * mnt_want_write_file - get write access to a file's mount |
| 288 | * matched increments and decrements on any given cpu. | 293 | * @file: the file who's mount on which to take a write |
| 289 | * A file open()ed for write on one cpu and close()d on | 294 | * |
| 290 | * another cpu will imbalance this count. Make sure it | 295 | * This is like mnt_want_write, but it takes a file and can |
| 291 | * does not get too far out of whack. | 296 | * do some optimisations if the file is open for write already |
| 292 | */ | 297 | */ |
| 293 | static void handle_write_count_underflow(struct vfsmount *mnt) | 298 | int mnt_want_write_file(struct file *file) |
| 294 | { | 299 | { |
| 295 | if (atomic_read(&mnt->__mnt_writers) >= | 300 | if (!(file->f_mode & FMODE_WRITE)) |
| 296 | MNT_WRITER_UNDERFLOW_LIMIT) | 301 | return mnt_want_write(file->f_path.mnt); |
| 297 | return; | 302 | else |
| 298 | /* | 303 | return mnt_clone_write(file->f_path.mnt); |
| 299 | * It isn't necessary to hold all of the locks | ||
| 300 | * at the same time, but doing it this way makes | ||
| 301 | * us share a lot more code. | ||
| 302 | */ | ||
| 303 | lock_mnt_writers(); | ||
| 304 | /* | ||
| 305 | * vfsmount_lock is for mnt_flags. | ||
| 306 | */ | ||
| 307 | spin_lock(&vfsmount_lock); | ||
| 308 | /* | ||
| 309 | * If coalescing the per-cpu writer counts did not | ||
| 310 | * get us back to a positive writer count, we have | ||
| 311 | * a bug. | ||
| 312 | */ | ||
| 313 | if ((atomic_read(&mnt->__mnt_writers) < 0) && | ||
| 314 | !(mnt->mnt_flags & MNT_IMBALANCED_WRITE_COUNT)) { | ||
| 315 | WARN(1, KERN_DEBUG "leak detected on mount(%p) writers " | ||
| 316 | "count: %d\n", | ||
| 317 | mnt, atomic_read(&mnt->__mnt_writers)); | ||
| 318 | /* use the flag to keep the dmesg spam down */ | ||
| 319 | mnt->mnt_flags |= MNT_IMBALANCED_WRITE_COUNT; | ||
| 320 | } | ||
| 321 | spin_unlock(&vfsmount_lock); | ||
| 322 | unlock_mnt_writers(); | ||
| 323 | } | 304 | } |
| 305 | EXPORT_SYMBOL_GPL(mnt_want_write_file); | ||
| 324 | 306 | ||
| 325 | /** | 307 | /** |
| 326 | * mnt_drop_write - give up write access to a mount | 308 | * mnt_drop_write - give up write access to a mount |
| @@ -332,37 +314,9 @@ static void handle_write_count_underflow(struct vfsmount *mnt) | |||
| 332 | */ | 314 | */ |
| 333 | void mnt_drop_write(struct vfsmount *mnt) | 315 | void mnt_drop_write(struct vfsmount *mnt) |
| 334 | { | 316 | { |
| 335 | int must_check_underflow = 0; | 317 | preempt_disable(); |
| 336 | struct mnt_writer *cpu_writer; | 318 | dec_mnt_writers(mnt); |
| 337 | 319 | preempt_enable(); | |
| 338 | cpu_writer = &get_cpu_var(mnt_writers); | ||
| 339 | spin_lock(&cpu_writer->lock); | ||
| 340 | |||
| 341 | use_cpu_writer_for_mount(cpu_writer, mnt); | ||
| 342 | if (cpu_writer->count > 0) { | ||
| 343 | cpu_writer->count--; | ||
| 344 | } else { | ||
| 345 | must_check_underflow = 1; | ||
| 346 | atomic_dec(&mnt->__mnt_writers); | ||
| 347 | } | ||
| 348 | |||
| 349 | spin_unlock(&cpu_writer->lock); | ||
| 350 | /* | ||
| 351 | * Logically, we could call this each time, | ||
| 352 | * but the __mnt_writers cacheline tends to | ||
| 353 | * be cold, and makes this expensive. | ||
| 354 | */ | ||
| 355 | if (must_check_underflow) | ||
| 356 | handle_write_count_underflow(mnt); | ||
| 357 | /* | ||
| 358 | * This could be done right after the spinlock | ||
| 359 | * is taken because the spinlock keeps us on | ||
| 360 | * the cpu, and disables preemption. However, | ||
| 361 | * putting it here bounds the amount that | ||
| 362 | * __mnt_writers can underflow. Without it, | ||
| 363 | * we could theoretically wrap __mnt_writers. | ||
| 364 | */ | ||
| 365 | put_cpu_var(mnt_writers); | ||
| 366 | } | 320 | } |
| 367 | EXPORT_SYMBOL_GPL(mnt_drop_write); | 321 | EXPORT_SYMBOL_GPL(mnt_drop_write); |
| 368 | 322 | ||
| @@ -370,24 +324,41 @@ static int mnt_make_readonly(struct vfsmount *mnt) | |||
| 370 | { | 324 | { |
| 371 | int ret = 0; | 325 | int ret = 0; |
| 372 | 326 | ||
| 373 | lock_mnt_writers(); | 327 | spin_lock(&vfsmount_lock); |
| 328 | mnt->mnt_flags |= MNT_WRITE_HOLD; | ||
| 374 | /* | 329 | /* |
| 375 | * With all the locks held, this value is stable | 330 | * After storing MNT_WRITE_HOLD, we'll read the counters. This store |
| 331 | * should be visible before we do. | ||
| 376 | */ | 332 | */ |
| 377 | if (atomic_read(&mnt->__mnt_writers) > 0) { | 333 | smp_mb(); |
| 378 | ret = -EBUSY; | 334 | |
| 379 | goto out; | ||
| 380 | } | ||
| 381 | /* | 335 | /* |
| 382 | * nobody can do a successful mnt_want_write() with all | 336 | * With writers on hold, if this value is zero, then there are |
| 383 | * of the counts in MNT_DENIED_WRITE and the locks held. | 337 | * definitely no active writers (although held writers may subsequently |
| 338 | * increment the count, they'll have to wait, and decrement it after | ||
| 339 | * seeing MNT_READONLY). | ||
| 340 | * | ||
| 341 | * It is OK to have counter incremented on one CPU and decremented on | ||
| 342 | * another: the sum will add up correctly. The danger would be when we | ||
| 343 | * sum up each counter, if we read a counter before it is incremented, | ||
| 344 | * but then read another CPU's count which it has been subsequently | ||
| 345 | * decremented from -- we would see more decrements than we should. | ||
| 346 | * MNT_WRITE_HOLD protects against this scenario, because | ||
| 347 | * mnt_want_write first increments count, then smp_mb, then spins on | ||
| 348 | * MNT_WRITE_HOLD, so it can't be decremented by another CPU while | ||
| 349 | * we're counting up here. | ||
| 384 | */ | 350 | */ |
| 385 | spin_lock(&vfsmount_lock); | 351 | if (count_mnt_writers(mnt) > 0) |
| 386 | if (!ret) | 352 | ret = -EBUSY; |
| 353 | else | ||
| 387 | mnt->mnt_flags |= MNT_READONLY; | 354 | mnt->mnt_flags |= MNT_READONLY; |
| 355 | /* | ||
| 356 | * MNT_READONLY must become visible before ~MNT_WRITE_HOLD, so writers | ||
| 357 | * that become unheld will see MNT_READONLY. | ||
| 358 | */ | ||
| 359 | smp_wmb(); | ||
| 360 | mnt->mnt_flags &= ~MNT_WRITE_HOLD; | ||
| 388 | spin_unlock(&vfsmount_lock); | 361 | spin_unlock(&vfsmount_lock); |
| 389 | out: | ||
| 390 | unlock_mnt_writers(); | ||
| 391 | return ret; | 362 | return ret; |
| 392 | } | 363 | } |
| 393 | 364 | ||
| @@ -410,6 +381,9 @@ void free_vfsmnt(struct vfsmount *mnt) | |||
| 410 | { | 381 | { |
| 411 | kfree(mnt->mnt_devname); | 382 | kfree(mnt->mnt_devname); |
| 412 | mnt_free_id(mnt); | 383 | mnt_free_id(mnt); |
| 384 | #ifdef CONFIG_SMP | ||
| 385 | free_percpu(mnt->mnt_writers); | ||
| 386 | #endif | ||
| 413 | kmem_cache_free(mnt_cache, mnt); | 387 | kmem_cache_free(mnt_cache, mnt); |
| 414 | } | 388 | } |
| 415 | 389 | ||
| @@ -442,11 +416,11 @@ struct vfsmount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry, | |||
| 442 | * lookup_mnt increments the ref count before returning | 416 | * lookup_mnt increments the ref count before returning |
| 443 | * the vfsmount struct. | 417 | * the vfsmount struct. |
| 444 | */ | 418 | */ |
| 445 | struct vfsmount *lookup_mnt(struct vfsmount *mnt, struct dentry *dentry) | 419 | struct vfsmount *lookup_mnt(struct path *path) |
| 446 | { | 420 | { |
| 447 | struct vfsmount *child_mnt; | 421 | struct vfsmount *child_mnt; |
| 448 | spin_lock(&vfsmount_lock); | 422 | spin_lock(&vfsmount_lock); |
| 449 | if ((child_mnt = __lookup_mnt(mnt, dentry, 1))) | 423 | if ((child_mnt = __lookup_mnt(path->mnt, path->dentry, 1))) |
| 450 | mntget(child_mnt); | 424 | mntget(child_mnt); |
| 451 | spin_unlock(&vfsmount_lock); | 425 | spin_unlock(&vfsmount_lock); |
| 452 | return child_mnt; | 426 | return child_mnt; |
| @@ -604,38 +578,18 @@ static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root, | |||
| 604 | 578 | ||
| 605 | static inline void __mntput(struct vfsmount *mnt) | 579 | static inline void __mntput(struct vfsmount *mnt) |
| 606 | { | 580 | { |
| 607 | int cpu; | ||
| 608 | struct super_block *sb = mnt->mnt_sb; | 581 | struct super_block *sb = mnt->mnt_sb; |
| 609 | /* | 582 | /* |
| 610 | * We don't have to hold all of the locks at the | ||
| 611 | * same time here because we know that we're the | ||
| 612 | * last reference to mnt and that no new writers | ||
| 613 | * can come in. | ||
| 614 | */ | ||
| 615 | for_each_possible_cpu(cpu) { | ||
| 616 | struct mnt_writer *cpu_writer = &per_cpu(mnt_writers, cpu); | ||
| 617 | spin_lock(&cpu_writer->lock); | ||
| 618 | if (cpu_writer->mnt != mnt) { | ||
| 619 | spin_unlock(&cpu_writer->lock); | ||
| 620 | continue; | ||
| 621 | } | ||
| 622 | atomic_add(cpu_writer->count, &mnt->__mnt_writers); | ||
| 623 | cpu_writer->count = 0; | ||
| 624 | /* | ||
| 625 | * Might as well do this so that no one | ||
| 626 | * ever sees the pointer and expects | ||
| 627 | * it to be valid. | ||
| 628 | */ | ||
| 629 | cpu_writer->mnt = NULL; | ||
| 630 | spin_unlock(&cpu_writer->lock); | ||
| 631 | } | ||
| 632 | /* | ||
| 633 | * This probably indicates that somebody messed | 583 | * This probably indicates that somebody messed |
| 634 | * up a mnt_want/drop_write() pair. If this | 584 | * up a mnt_want/drop_write() pair. If this |
| 635 | * happens, the filesystem was probably unable | 585 | * happens, the filesystem was probably unable |
| 636 | * to make r/w->r/o transitions. | 586 | * to make r/w->r/o transitions. |
| 637 | */ | 587 | */ |
| 638 | WARN_ON(atomic_read(&mnt->__mnt_writers)); | 588 | /* |
| 589 | * atomic_dec_and_lock() used to deal with ->mnt_count decrements | ||
| 590 | * provides barriers, so count_mnt_writers() below is safe. AV | ||
| 591 | */ | ||
| 592 | WARN_ON(count_mnt_writers(mnt)); | ||
| 639 | dput(mnt->mnt_root); | 593 | dput(mnt->mnt_root); |
| 640 | free_vfsmnt(mnt); | 594 | free_vfsmnt(mnt); |
| 641 | deactivate_super(sb); | 595 | deactivate_super(sb); |
| @@ -1106,11 +1060,8 @@ static int do_umount(struct vfsmount *mnt, int flags) | |||
| 1106 | * we just try to remount it readonly. | 1060 | * we just try to remount it readonly. |
| 1107 | */ | 1061 | */ |
| 1108 | down_write(&sb->s_umount); | 1062 | down_write(&sb->s_umount); |
| 1109 | if (!(sb->s_flags & MS_RDONLY)) { | 1063 | if (!(sb->s_flags & MS_RDONLY)) |
| 1110 | lock_kernel(); | ||
| 1111 | retval = do_remount_sb(sb, MS_RDONLY, NULL, 0); | 1064 | retval = do_remount_sb(sb, MS_RDONLY, NULL, 0); |
| 1112 | unlock_kernel(); | ||
| 1113 | } | ||
| 1114 | up_write(&sb->s_umount); | 1065 | up_write(&sb->s_umount); |
| 1115 | return retval; | 1066 | return retval; |
| 1116 | } | 1067 | } |
| @@ -1253,11 +1204,11 @@ Enomem: | |||
| 1253 | return NULL; | 1204 | return NULL; |
| 1254 | } | 1205 | } |
| 1255 | 1206 | ||
| 1256 | struct vfsmount *collect_mounts(struct vfsmount *mnt, struct dentry *dentry) | 1207 | struct vfsmount *collect_mounts(struct path *path) |
| 1257 | { | 1208 | { |
| 1258 | struct vfsmount *tree; | 1209 | struct vfsmount *tree; |
| 1259 | down_write(&namespace_sem); | 1210 | down_write(&namespace_sem); |
| 1260 | tree = copy_tree(mnt, dentry, CL_COPY_ALL | CL_PRIVATE); | 1211 | tree = copy_tree(path->mnt, path->dentry, CL_COPY_ALL | CL_PRIVATE); |
| 1261 | up_write(&namespace_sem); | 1212 | up_write(&namespace_sem); |
| 1262 | return tree; | 1213 | return tree; |
| 1263 | } | 1214 | } |
| @@ -1430,7 +1381,7 @@ static int graft_tree(struct vfsmount *mnt, struct path *path) | |||
| 1430 | goto out_unlock; | 1381 | goto out_unlock; |
| 1431 | 1382 | ||
| 1432 | err = -ENOENT; | 1383 | err = -ENOENT; |
| 1433 | if (IS_ROOT(path->dentry) || !d_unhashed(path->dentry)) | 1384 | if (!d_unlinked(path->dentry)) |
| 1434 | err = attach_recursive_mnt(mnt, path, NULL); | 1385 | err = attach_recursive_mnt(mnt, path, NULL); |
| 1435 | out_unlock: | 1386 | out_unlock: |
| 1436 | mutex_unlock(&path->dentry->d_inode->i_mutex); | 1387 | mutex_unlock(&path->dentry->d_inode->i_mutex); |
| @@ -1601,7 +1552,7 @@ static int do_move_mount(struct path *path, char *old_name) | |||
| 1601 | 1552 | ||
| 1602 | down_write(&namespace_sem); | 1553 | down_write(&namespace_sem); |
| 1603 | while (d_mountpoint(path->dentry) && | 1554 | while (d_mountpoint(path->dentry) && |
| 1604 | follow_down(&path->mnt, &path->dentry)) | 1555 | follow_down(path)) |
| 1605 | ; | 1556 | ; |
| 1606 | err = -EINVAL; | 1557 | err = -EINVAL; |
| 1607 | if (!check_mnt(path->mnt) || !check_mnt(old_path.mnt)) | 1558 | if (!check_mnt(path->mnt) || !check_mnt(old_path.mnt)) |
| @@ -1612,7 +1563,7 @@ static int do_move_mount(struct path *path, char *old_name) | |||
| 1612 | if (IS_DEADDIR(path->dentry->d_inode)) | 1563 | if (IS_DEADDIR(path->dentry->d_inode)) |
| 1613 | goto out1; | 1564 | goto out1; |
| 1614 | 1565 | ||
| 1615 | if (!IS_ROOT(path->dentry) && d_unhashed(path->dentry)) | 1566 | if (d_unlinked(path->dentry)) |
| 1616 | goto out1; | 1567 | goto out1; |
| 1617 | 1568 | ||
| 1618 | err = -EINVAL; | 1569 | err = -EINVAL; |
| @@ -1676,7 +1627,9 @@ static int do_new_mount(struct path *path, char *type, int flags, | |||
| 1676 | if (!capable(CAP_SYS_ADMIN)) | 1627 | if (!capable(CAP_SYS_ADMIN)) |
| 1677 | return -EPERM; | 1628 | return -EPERM; |
| 1678 | 1629 | ||
| 1630 | lock_kernel(); | ||
| 1679 | mnt = do_kern_mount(type, flags, name, data); | 1631 | mnt = do_kern_mount(type, flags, name, data); |
| 1632 | unlock_kernel(); | ||
| 1680 | if (IS_ERR(mnt)) | 1633 | if (IS_ERR(mnt)) |
| 1681 | return PTR_ERR(mnt); | 1634 | return PTR_ERR(mnt); |
| 1682 | 1635 | ||
| @@ -1695,10 +1648,10 @@ int do_add_mount(struct vfsmount *newmnt, struct path *path, | |||
| 1695 | down_write(&namespace_sem); | 1648 | down_write(&namespace_sem); |
| 1696 | /* Something was mounted here while we slept */ | 1649 | /* Something was mounted here while we slept */ |
| 1697 | while (d_mountpoint(path->dentry) && | 1650 | while (d_mountpoint(path->dentry) && |
| 1698 | follow_down(&path->mnt, &path->dentry)) | 1651 | follow_down(path)) |
| 1699 | ; | 1652 | ; |
| 1700 | err = -EINVAL; | 1653 | err = -EINVAL; |
| 1701 | if (!check_mnt(path->mnt)) | 1654 | if (!(mnt_flags & MNT_SHRINKABLE) && !check_mnt(path->mnt)) |
| 1702 | goto unlock; | 1655 | goto unlock; |
| 1703 | 1656 | ||
| 1704 | /* Refuse the same filesystem on the same mount point */ | 1657 | /* Refuse the same filesystem on the same mount point */ |
| @@ -2092,10 +2045,8 @@ SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name, | |||
| 2092 | if (retval < 0) | 2045 | if (retval < 0) |
| 2093 | goto out3; | 2046 | goto out3; |
| 2094 | 2047 | ||
| 2095 | lock_kernel(); | ||
| 2096 | retval = do_mount((char *)dev_page, dir_page, (char *)type_page, | 2048 | retval = do_mount((char *)dev_page, dir_page, (char *)type_page, |
| 2097 | flags, (void *)data_page); | 2049 | flags, (void *)data_page); |
| 2098 | unlock_kernel(); | ||
| 2099 | free_page(data_page); | 2050 | free_page(data_page); |
| 2100 | 2051 | ||
| 2101 | out3: | 2052 | out3: |
| @@ -2175,9 +2126,9 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root, | |||
| 2175 | error = -ENOENT; | 2126 | error = -ENOENT; |
| 2176 | if (IS_DEADDIR(new.dentry->d_inode)) | 2127 | if (IS_DEADDIR(new.dentry->d_inode)) |
| 2177 | goto out2; | 2128 | goto out2; |
| 2178 | if (d_unhashed(new.dentry) && !IS_ROOT(new.dentry)) | 2129 | if (d_unlinked(new.dentry)) |
| 2179 | goto out2; | 2130 | goto out2; |
| 2180 | if (d_unhashed(old.dentry) && !IS_ROOT(old.dentry)) | 2131 | if (d_unlinked(old.dentry)) |
| 2181 | goto out2; | 2132 | goto out2; |
| 2182 | error = -EBUSY; | 2133 | error = -EBUSY; |
| 2183 | if (new.mnt == root.mnt || | 2134 | if (new.mnt == root.mnt || |
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index d642f0e5b365..b99ce205b1bd 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c | |||
| @@ -736,6 +736,8 @@ static void ncp_put_super(struct super_block *sb) | |||
| 736 | { | 736 | { |
| 737 | struct ncp_server *server = NCP_SBP(sb); | 737 | struct ncp_server *server = NCP_SBP(sb); |
| 738 | 738 | ||
| 739 | lock_kernel(); | ||
| 740 | |||
| 739 | ncp_lock_server(server); | 741 | ncp_lock_server(server); |
| 740 | ncp_disconnect(server); | 742 | ncp_disconnect(server); |
| 741 | ncp_unlock_server(server); | 743 | ncp_unlock_server(server); |
| @@ -769,6 +771,8 @@ static void ncp_put_super(struct super_block *sb) | |||
| 769 | vfree(server->packet); | 771 | vfree(server->packet); |
| 770 | sb->s_fs_info = NULL; | 772 | sb->s_fs_info = NULL; |
| 771 | kfree(server); | 773 | kfree(server); |
| 774 | |||
| 775 | unlock_kernel(); | ||
| 772 | } | 776 | } |
| 773 | 777 | ||
| 774 | static int ncp_statfs(struct dentry *dentry, struct kstatfs *buf) | 778 | static int ncp_statfs(struct dentry *dentry, struct kstatfs *buf) |
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index 64a288ee046d..f01caec84463 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c | |||
| @@ -154,7 +154,7 @@ out_err: | |||
| 154 | goto out; | 154 | goto out; |
| 155 | out_follow: | 155 | out_follow: |
| 156 | while (d_mountpoint(nd->path.dentry) && | 156 | while (d_mountpoint(nd->path.dentry) && |
| 157 | follow_down(&nd->path.mnt, &nd->path.dentry)) | 157 | follow_down(&nd->path)) |
| 158 | ; | 158 | ; |
| 159 | err = 0; | 159 | err = 0; |
| 160 | goto out; | 160 | goto out; |
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index d2d67781c579..26127b69a275 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
| @@ -1813,6 +1813,7 @@ nfs_remount(struct super_block *sb, int *flags, char *raw_data) | |||
| 1813 | if (data == NULL) | 1813 | if (data == NULL) |
| 1814 | return -ENOMEM; | 1814 | return -ENOMEM; |
| 1815 | 1815 | ||
| 1816 | lock_kernel(); | ||
| 1816 | /* fill out struct with values from existing mount */ | 1817 | /* fill out struct with values from existing mount */ |
| 1817 | data->flags = nfss->flags; | 1818 | data->flags = nfss->flags; |
| 1818 | data->rsize = nfss->rsize; | 1819 | data->rsize = nfss->rsize; |
| @@ -1837,6 +1838,7 @@ nfs_remount(struct super_block *sb, int *flags, char *raw_data) | |||
| 1837 | error = nfs_compare_remount_data(nfss, data); | 1838 | error = nfs_compare_remount_data(nfss, data); |
| 1838 | out: | 1839 | out: |
| 1839 | kfree(data); | 1840 | kfree(data); |
| 1841 | unlock_kernel(); | ||
| 1840 | return error; | 1842 | return error; |
| 1841 | } | 1843 | } |
| 1842 | 1844 | ||
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 5839b229cd0e..8b1f8efb4690 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c | |||
| @@ -847,9 +847,8 @@ exp_get_fsid_key(svc_client *clp, int fsid) | |||
| 847 | return exp_find_key(clp, FSID_NUM, fsidv, NULL); | 847 | return exp_find_key(clp, FSID_NUM, fsidv, NULL); |
| 848 | } | 848 | } |
| 849 | 849 | ||
| 850 | static svc_export *exp_get_by_name(svc_client *clp, struct vfsmount *mnt, | 850 | static svc_export *exp_get_by_name(svc_client *clp, const struct path *path, |
| 851 | struct dentry *dentry, | 851 | struct cache_req *reqp) |
| 852 | struct cache_req *reqp) | ||
| 853 | { | 852 | { |
| 854 | struct svc_export *exp, key; | 853 | struct svc_export *exp, key; |
| 855 | int err; | 854 | int err; |
| @@ -858,8 +857,7 @@ static svc_export *exp_get_by_name(svc_client *clp, struct vfsmount *mnt, | |||
| 858 | return ERR_PTR(-ENOENT); | 857 | return ERR_PTR(-ENOENT); |
| 859 | 858 | ||
| 860 | key.ex_client = clp; | 859 | key.ex_client = clp; |
| 861 | key.ex_path.mnt = mnt; | 860 | key.ex_path = *path; |
| 862 | key.ex_path.dentry = dentry; | ||
| 863 | 861 | ||
| 864 | exp = svc_export_lookup(&key); | 862 | exp = svc_export_lookup(&key); |
| 865 | if (exp == NULL) | 863 | if (exp == NULL) |
| @@ -873,24 +871,19 @@ static svc_export *exp_get_by_name(svc_client *clp, struct vfsmount *mnt, | |||
| 873 | /* | 871 | /* |
| 874 | * Find the export entry for a given dentry. | 872 | * Find the export entry for a given dentry. |
| 875 | */ | 873 | */ |
| 876 | static struct svc_export *exp_parent(svc_client *clp, struct vfsmount *mnt, | 874 | static struct svc_export *exp_parent(svc_client *clp, struct path *path) |
| 877 | struct dentry *dentry, | ||
| 878 | struct cache_req *reqp) | ||
| 879 | { | 875 | { |
| 880 | svc_export *exp; | 876 | struct dentry *saved = dget(path->dentry); |
| 881 | 877 | svc_export *exp = exp_get_by_name(clp, path, NULL); | |
| 882 | dget(dentry); | 878 | |
| 883 | exp = exp_get_by_name(clp, mnt, dentry, reqp); | 879 | while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(path->dentry)) { |
| 884 | 880 | struct dentry *parent = dget_parent(path->dentry); | |
| 885 | while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(dentry)) { | 881 | dput(path->dentry); |
| 886 | struct dentry *parent; | 882 | path->dentry = parent; |
| 887 | 883 | exp = exp_get_by_name(clp, path, NULL); | |
| 888 | parent = dget_parent(dentry); | ||
| 889 | dput(dentry); | ||
| 890 | dentry = parent; | ||
| 891 | exp = exp_get_by_name(clp, mnt, dentry, reqp); | ||
| 892 | } | 884 | } |
| 893 | dput(dentry); | 885 | dput(path->dentry); |
| 886 | path->dentry = saved; | ||
| 894 | return exp; | 887 | return exp; |
| 895 | } | 888 | } |
| 896 | 889 | ||
| @@ -1018,7 +1011,7 @@ exp_export(struct nfsctl_export *nxp) | |||
| 1018 | goto out_put_clp; | 1011 | goto out_put_clp; |
| 1019 | err = -EINVAL; | 1012 | err = -EINVAL; |
| 1020 | 1013 | ||
| 1021 | exp = exp_get_by_name(clp, path.mnt, path.dentry, NULL); | 1014 | exp = exp_get_by_name(clp, &path, NULL); |
| 1022 | 1015 | ||
| 1023 | memset(&new, 0, sizeof(new)); | 1016 | memset(&new, 0, sizeof(new)); |
| 1024 | 1017 | ||
| @@ -1135,7 +1128,7 @@ exp_unexport(struct nfsctl_export *nxp) | |||
| 1135 | goto out_domain; | 1128 | goto out_domain; |
| 1136 | 1129 | ||
| 1137 | err = -EINVAL; | 1130 | err = -EINVAL; |
| 1138 | exp = exp_get_by_name(dom, path.mnt, path.dentry, NULL); | 1131 | exp = exp_get_by_name(dom, &path, NULL); |
| 1139 | path_put(&path); | 1132 | path_put(&path); |
| 1140 | if (IS_ERR(exp)) | 1133 | if (IS_ERR(exp)) |
| 1141 | goto out_domain; | 1134 | goto out_domain; |
| @@ -1177,7 +1170,7 @@ exp_rootfh(svc_client *clp, char *name, struct knfsd_fh *f, int maxsize) | |||
| 1177 | dprintk("nfsd: exp_rootfh(%s [%p] %s:%s/%ld)\n", | 1170 | dprintk("nfsd: exp_rootfh(%s [%p] %s:%s/%ld)\n", |
| 1178 | name, path.dentry, clp->name, | 1171 | name, path.dentry, clp->name, |
| 1179 | inode->i_sb->s_id, inode->i_ino); | 1172 | inode->i_sb->s_id, inode->i_ino); |
| 1180 | exp = exp_parent(clp, path.mnt, path.dentry, NULL); | 1173 | exp = exp_parent(clp, &path); |
| 1181 | if (IS_ERR(exp)) { | 1174 | if (IS_ERR(exp)) { |
| 1182 | err = PTR_ERR(exp); | 1175 | err = PTR_ERR(exp); |
| 1183 | goto out; | 1176 | goto out; |
| @@ -1207,7 +1200,7 @@ static struct svc_export *exp_find(struct auth_domain *clp, int fsid_type, | |||
| 1207 | if (IS_ERR(ek)) | 1200 | if (IS_ERR(ek)) |
| 1208 | return ERR_CAST(ek); | 1201 | return ERR_CAST(ek); |
| 1209 | 1202 | ||
| 1210 | exp = exp_get_by_name(clp, ek->ek_path.mnt, ek->ek_path.dentry, reqp); | 1203 | exp = exp_get_by_name(clp, &ek->ek_path, reqp); |
| 1211 | cache_put(&ek->h, &svc_expkey_cache); | 1204 | cache_put(&ek->h, &svc_expkey_cache); |
| 1212 | 1205 | ||
| 1213 | if (IS_ERR(exp)) | 1206 | if (IS_ERR(exp)) |
| @@ -1247,8 +1240,7 @@ __be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp) | |||
| 1247 | * use exp_get_by_name() or exp_find(). | 1240 | * use exp_get_by_name() or exp_find(). |
| 1248 | */ | 1241 | */ |
| 1249 | struct svc_export * | 1242 | struct svc_export * |
| 1250 | rqst_exp_get_by_name(struct svc_rqst *rqstp, struct vfsmount *mnt, | 1243 | rqst_exp_get_by_name(struct svc_rqst *rqstp, struct path *path) |
| 1251 | struct dentry *dentry) | ||
| 1252 | { | 1244 | { |
| 1253 | struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT); | 1245 | struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT); |
| 1254 | 1246 | ||
| @@ -1256,8 +1248,7 @@ rqst_exp_get_by_name(struct svc_rqst *rqstp, struct vfsmount *mnt, | |||
| 1256 | goto gss; | 1248 | goto gss; |
| 1257 | 1249 | ||
| 1258 | /* First try the auth_unix client: */ | 1250 | /* First try the auth_unix client: */ |
| 1259 | exp = exp_get_by_name(rqstp->rq_client, mnt, dentry, | 1251 | exp = exp_get_by_name(rqstp->rq_client, path, &rqstp->rq_chandle); |
| 1260 | &rqstp->rq_chandle); | ||
| 1261 | if (PTR_ERR(exp) == -ENOENT) | 1252 | if (PTR_ERR(exp) == -ENOENT) |
| 1262 | goto gss; | 1253 | goto gss; |
| 1263 | if (IS_ERR(exp)) | 1254 | if (IS_ERR(exp)) |
| @@ -1269,8 +1260,7 @@ gss: | |||
| 1269 | /* Otherwise, try falling back on gss client */ | 1260 | /* Otherwise, try falling back on gss client */ |
| 1270 | if (rqstp->rq_gssclient == NULL) | 1261 | if (rqstp->rq_gssclient == NULL) |
| 1271 | return exp; | 1262 | return exp; |
| 1272 | gssexp = exp_get_by_name(rqstp->rq_gssclient, mnt, dentry, | 1263 | gssexp = exp_get_by_name(rqstp->rq_gssclient, path, &rqstp->rq_chandle); |
| 1273 | &rqstp->rq_chandle); | ||
| 1274 | if (PTR_ERR(gssexp) == -ENOENT) | 1264 | if (PTR_ERR(gssexp) == -ENOENT) |
| 1275 | return exp; | 1265 | return exp; |
| 1276 | if (!IS_ERR(exp)) | 1266 | if (!IS_ERR(exp)) |
| @@ -1309,23 +1299,19 @@ gss: | |||
| 1309 | } | 1299 | } |
| 1310 | 1300 | ||
| 1311 | struct svc_export * | 1301 | struct svc_export * |
| 1312 | rqst_exp_parent(struct svc_rqst *rqstp, struct vfsmount *mnt, | 1302 | rqst_exp_parent(struct svc_rqst *rqstp, struct path *path) |
| 1313 | struct dentry *dentry) | ||
| 1314 | { | 1303 | { |
| 1315 | struct svc_export *exp; | 1304 | struct dentry *saved = dget(path->dentry); |
| 1316 | 1305 | struct svc_export *exp = rqst_exp_get_by_name(rqstp, path); | |
| 1317 | dget(dentry); | 1306 | |
| 1318 | exp = rqst_exp_get_by_name(rqstp, mnt, dentry); | 1307 | while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(path->dentry)) { |
| 1319 | 1308 | struct dentry *parent = dget_parent(path->dentry); | |
| 1320 | while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(dentry)) { | 1309 | dput(path->dentry); |
| 1321 | struct dentry *parent; | 1310 | path->dentry = parent; |
| 1322 | 1311 | exp = rqst_exp_get_by_name(rqstp, path); | |
| 1323 | parent = dget_parent(dentry); | ||
| 1324 | dput(dentry); | ||
| 1325 | dentry = parent; | ||
| 1326 | exp = rqst_exp_get_by_name(rqstp, mnt, dentry); | ||
| 1327 | } | 1312 | } |
| 1328 | dput(dentry); | 1313 | dput(path->dentry); |
| 1314 | path->dentry = saved; | ||
| 1329 | return exp; | 1315 | return exp; |
| 1330 | } | 1316 | } |
| 1331 | 1317 | ||
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index bd584bcf1d9f..99f835753596 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
| @@ -101,36 +101,35 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp, | |||
| 101 | { | 101 | { |
| 102 | struct svc_export *exp = *expp, *exp2 = NULL; | 102 | struct svc_export *exp = *expp, *exp2 = NULL; |
| 103 | struct dentry *dentry = *dpp; | 103 | struct dentry *dentry = *dpp; |
| 104 | struct vfsmount *mnt = mntget(exp->ex_path.mnt); | 104 | struct path path = {.mnt = mntget(exp->ex_path.mnt), |
| 105 | struct dentry *mounts = dget(dentry); | 105 | .dentry = dget(dentry)}; |
| 106 | int err = 0; | 106 | int err = 0; |
| 107 | 107 | ||
| 108 | while (follow_down(&mnt,&mounts)&&d_mountpoint(mounts)); | 108 | while (d_mountpoint(path.dentry) && follow_down(&path)) |
| 109 | ; | ||
| 109 | 110 | ||
| 110 | exp2 = rqst_exp_get_by_name(rqstp, mnt, mounts); | 111 | exp2 = rqst_exp_get_by_name(rqstp, &path); |
| 111 | if (IS_ERR(exp2)) { | 112 | if (IS_ERR(exp2)) { |
| 112 | if (PTR_ERR(exp2) != -ENOENT) | 113 | if (PTR_ERR(exp2) != -ENOENT) |
| 113 | err = PTR_ERR(exp2); | 114 | err = PTR_ERR(exp2); |
| 114 | dput(mounts); | 115 | path_put(&path); |
| 115 | mntput(mnt); | ||
| 116 | goto out; | 116 | goto out; |
| 117 | } | 117 | } |
| 118 | if ((exp->ex_flags & NFSEXP_CROSSMOUNT) || EX_NOHIDE(exp2)) { | 118 | if ((exp->ex_flags & NFSEXP_CROSSMOUNT) || EX_NOHIDE(exp2)) { |
| 119 | /* successfully crossed mount point */ | 119 | /* successfully crossed mount point */ |
| 120 | /* | 120 | /* |
| 121 | * This is subtle: dentry is *not* under mnt at this point. | 121 | * This is subtle: path.dentry is *not* on path.mnt |
| 122 | * The only reason we are safe is that original mnt is pinned | 122 | * at this point. The only reason we are safe is that |
| 123 | * down by exp, so we should dput before putting exp. | 123 | * original mnt is pinned down by exp, so we should |
| 124 | * put path *before* putting exp | ||
| 124 | */ | 125 | */ |
| 125 | dput(dentry); | 126 | *dpp = path.dentry; |
| 126 | *dpp = mounts; | 127 | path.dentry = dentry; |
| 127 | exp_put(exp); | ||
| 128 | *expp = exp2; | 128 | *expp = exp2; |
| 129 | } else { | 129 | exp2 = exp; |
| 130 | exp_put(exp2); | ||
| 131 | dput(mounts); | ||
| 132 | } | 130 | } |
| 133 | mntput(mnt); | 131 | path_put(&path); |
| 132 | exp_put(exp2); | ||
| 134 | out: | 133 | out: |
| 135 | return err; | 134 | return err; |
| 136 | } | 135 | } |
| @@ -169,28 +168,29 @@ nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
| 169 | /* checking mountpoint crossing is very different when stepping up */ | 168 | /* checking mountpoint crossing is very different when stepping up */ |
| 170 | struct svc_export *exp2 = NULL; | 169 | struct svc_export *exp2 = NULL; |
| 171 | struct dentry *dp; | 170 | struct dentry *dp; |
| 172 | struct vfsmount *mnt = mntget(exp->ex_path.mnt); | 171 | struct path path = {.mnt = mntget(exp->ex_path.mnt), |
| 173 | dentry = dget(dparent); | 172 | .dentry = dget(dparent)}; |
| 174 | while(dentry == mnt->mnt_root && follow_up(&mnt, &dentry)) | 173 | |
| 174 | while (path.dentry == path.mnt->mnt_root && | ||
| 175 | follow_up(&path)) | ||
| 175 | ; | 176 | ; |
| 176 | dp = dget_parent(dentry); | 177 | dp = dget_parent(path.dentry); |
| 177 | dput(dentry); | 178 | dput(path.dentry); |
| 178 | dentry = dp; | 179 | path.dentry = dp; |
| 179 | 180 | ||
| 180 | exp2 = rqst_exp_parent(rqstp, mnt, dentry); | 181 | exp2 = rqst_exp_parent(rqstp, &path); |
| 181 | if (PTR_ERR(exp2) == -ENOENT) { | 182 | if (PTR_ERR(exp2) == -ENOENT) { |
| 182 | dput(dentry); | ||
| 183 | dentry = dget(dparent); | 183 | dentry = dget(dparent); |
| 184 | } else if (IS_ERR(exp2)) { | 184 | } else if (IS_ERR(exp2)) { |
| 185 | host_err = PTR_ERR(exp2); | 185 | host_err = PTR_ERR(exp2); |
| 186 | dput(dentry); | 186 | path_put(&path); |
| 187 | mntput(mnt); | ||
| 188 | goto out_nfserr; | 187 | goto out_nfserr; |
| 189 | } else { | 188 | } else { |
| 189 | dentry = dget(path.dentry); | ||
| 190 | exp_put(exp); | 190 | exp_put(exp); |
| 191 | exp = exp2; | 191 | exp = exp2; |
| 192 | } | 192 | } |
| 193 | mntput(mnt); | 193 | path_put(&path); |
| 194 | } | 194 | } |
| 195 | } else { | 195 | } else { |
| 196 | fh_lock(fhp); | 196 | fh_lock(fhp); |
diff --git a/fs/nilfs2/cpfile.c b/fs/nilfs2/cpfile.c index 300f1cdfa862..cadd36b14d07 100644 --- a/fs/nilfs2/cpfile.c +++ b/fs/nilfs2/cpfile.c | |||
| @@ -864,11 +864,11 @@ int nilfs_cpfile_change_cpmode(struct inode *cpfile, __u64 cno, int mode) | |||
| 864 | case NILFS_CHECKPOINT: | 864 | case NILFS_CHECKPOINT: |
| 865 | /* | 865 | /* |
| 866 | * Check for protecting existing snapshot mounts: | 866 | * Check for protecting existing snapshot mounts: |
| 867 | * bd_mount_sem is used to make this operation atomic and | 867 | * ns_mount_mutex is used to make this operation atomic and |
| 868 | * exclusive with a new mount job. Though it doesn't cover | 868 | * exclusive with a new mount job. Though it doesn't cover |
| 869 | * umount, it's enough for the purpose. | 869 | * umount, it's enough for the purpose. |
| 870 | */ | 870 | */ |
| 871 | down(&nilfs->ns_bdev->bd_mount_sem); | 871 | mutex_lock(&nilfs->ns_mount_mutex); |
| 872 | if (nilfs_checkpoint_is_mounted(nilfs, cno, 1)) { | 872 | if (nilfs_checkpoint_is_mounted(nilfs, cno, 1)) { |
| 873 | /* Current implementation does not have to protect | 873 | /* Current implementation does not have to protect |
| 874 | plain read-only mounts since they are exclusive | 874 | plain read-only mounts since they are exclusive |
| @@ -877,7 +877,7 @@ int nilfs_cpfile_change_cpmode(struct inode *cpfile, __u64 cno, int mode) | |||
| 877 | ret = -EBUSY; | 877 | ret = -EBUSY; |
| 878 | } else | 878 | } else |
| 879 | ret = nilfs_cpfile_clear_snapshot(cpfile, cno); | 879 | ret = nilfs_cpfile_clear_snapshot(cpfile, cno); |
| 880 | up(&nilfs->ns_bdev->bd_mount_sem); | 880 | mutex_unlock(&nilfs->ns_mount_mutex); |
| 881 | return ret; | 881 | return ret; |
| 882 | case NILFS_SNAPSHOT: | 882 | case NILFS_SNAPSHOT: |
| 883 | return nilfs_cpfile_set_snapshot(cpfile, cno); | 883 | return nilfs_cpfile_set_snapshot(cpfile, cno); |
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 a91f15b8673c..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); |
| @@ -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) |
diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c index 6aa7c4713536..abaaa1cbf8de 100644 --- a/fs/ntfs/super.c +++ b/fs/ntfs/super.c | |||
| @@ -443,6 +443,8 @@ static int ntfs_remount(struct super_block *sb, int *flags, char *opt) | |||
| 443 | ntfs_volume *vol = NTFS_SB(sb); | 443 | ntfs_volume *vol = NTFS_SB(sb); |
| 444 | 444 | ||
| 445 | ntfs_debug("Entering with remount options string: %s", opt); | 445 | ntfs_debug("Entering with remount options string: %s", opt); |
| 446 | |||
| 447 | lock_kernel(); | ||
| 446 | #ifndef NTFS_RW | 448 | #ifndef NTFS_RW |
| 447 | /* For read-only compiled driver, enforce read-only flag. */ | 449 | /* For read-only compiled driver, enforce read-only flag. */ |
| 448 | *flags |= MS_RDONLY; | 450 | *flags |= MS_RDONLY; |
| @@ -466,15 +468,18 @@ static int ntfs_remount(struct super_block *sb, int *flags, char *opt) | |||
| 466 | if (NVolErrors(vol)) { | 468 | if (NVolErrors(vol)) { |
| 467 | ntfs_error(sb, "Volume has errors and is read-only%s", | 469 | ntfs_error(sb, "Volume has errors and is read-only%s", |
| 468 | es); | 470 | es); |
| 471 | unlock_kernel(); | ||
| 469 | return -EROFS; | 472 | return -EROFS; |
| 470 | } | 473 | } |
| 471 | if (vol->vol_flags & VOLUME_IS_DIRTY) { | 474 | if (vol->vol_flags & VOLUME_IS_DIRTY) { |
| 472 | ntfs_error(sb, "Volume is dirty and read-only%s", es); | 475 | ntfs_error(sb, "Volume is dirty and read-only%s", es); |
| 476 | unlock_kernel(); | ||
| 473 | return -EROFS; | 477 | return -EROFS; |
| 474 | } | 478 | } |
| 475 | if (vol->vol_flags & VOLUME_MODIFIED_BY_CHKDSK) { | 479 | if (vol->vol_flags & VOLUME_MODIFIED_BY_CHKDSK) { |
| 476 | ntfs_error(sb, "Volume has been modified by chkdsk " | 480 | ntfs_error(sb, "Volume has been modified by chkdsk " |
| 477 | "and is read-only%s", es); | 481 | "and is read-only%s", es); |
| 482 | unlock_kernel(); | ||
| 478 | return -EROFS; | 483 | return -EROFS; |
| 479 | } | 484 | } |
| 480 | if (vol->vol_flags & VOLUME_MUST_MOUNT_RO_MASK) { | 485 | if (vol->vol_flags & VOLUME_MUST_MOUNT_RO_MASK) { |
| @@ -482,11 +487,13 @@ static int ntfs_remount(struct super_block *sb, int *flags, char *opt) | |||
| 482 | "(0x%x) and is read-only%s", | 487 | "(0x%x) and is read-only%s", |
| 483 | (unsigned)le16_to_cpu(vol->vol_flags), | 488 | (unsigned)le16_to_cpu(vol->vol_flags), |
| 484 | es); | 489 | es); |
| 490 | unlock_kernel(); | ||
| 485 | return -EROFS; | 491 | return -EROFS; |
| 486 | } | 492 | } |
| 487 | if (ntfs_set_volume_flags(vol, VOLUME_IS_DIRTY)) { | 493 | if (ntfs_set_volume_flags(vol, VOLUME_IS_DIRTY)) { |
| 488 | ntfs_error(sb, "Failed to set dirty bit in volume " | 494 | ntfs_error(sb, "Failed to set dirty bit in volume " |
| 489 | "information flags%s", es); | 495 | "information flags%s", es); |
| 496 | unlock_kernel(); | ||
| 490 | return -EROFS; | 497 | return -EROFS; |
| 491 | } | 498 | } |
| 492 | #if 0 | 499 | #if 0 |
| @@ -506,18 +513,21 @@ static int ntfs_remount(struct super_block *sb, int *flags, char *opt) | |||
| 506 | ntfs_error(sb, "Failed to empty journal $LogFile%s", | 513 | ntfs_error(sb, "Failed to empty journal $LogFile%s", |
| 507 | es); | 514 | es); |
| 508 | NVolSetErrors(vol); | 515 | NVolSetErrors(vol); |
| 516 | unlock_kernel(); | ||
| 509 | return -EROFS; | 517 | return -EROFS; |
| 510 | } | 518 | } |
| 511 | if (!ntfs_mark_quotas_out_of_date(vol)) { | 519 | if (!ntfs_mark_quotas_out_of_date(vol)) { |
| 512 | ntfs_error(sb, "Failed to mark quotas out of date%s", | 520 | ntfs_error(sb, "Failed to mark quotas out of date%s", |
| 513 | es); | 521 | es); |
| 514 | NVolSetErrors(vol); | 522 | NVolSetErrors(vol); |
| 523 | unlock_kernel(); | ||
| 515 | return -EROFS; | 524 | return -EROFS; |
| 516 | } | 525 | } |
| 517 | if (!ntfs_stamp_usnjrnl(vol)) { | 526 | if (!ntfs_stamp_usnjrnl(vol)) { |
| 518 | ntfs_error(sb, "Failed to stamp transation log " | 527 | ntfs_error(sb, "Failed to stamp transation log " |
| 519 | "($UsnJrnl)%s", es); | 528 | "($UsnJrnl)%s", es); |
| 520 | NVolSetErrors(vol); | 529 | NVolSetErrors(vol); |
| 530 | unlock_kernel(); | ||
| 521 | return -EROFS; | 531 | return -EROFS; |
| 522 | } | 532 | } |
| 523 | } else if (!(sb->s_flags & MS_RDONLY) && (*flags & MS_RDONLY)) { | 533 | } else if (!(sb->s_flags & MS_RDONLY) && (*flags & MS_RDONLY)) { |
| @@ -533,8 +543,11 @@ static int ntfs_remount(struct super_block *sb, int *flags, char *opt) | |||
| 533 | 543 | ||
| 534 | // TODO: Deal with *flags. | 544 | // TODO: Deal with *flags. |
| 535 | 545 | ||
| 536 | if (!parse_options(vol, opt)) | 546 | if (!parse_options(vol, opt)) { |
| 547 | unlock_kernel(); | ||
| 537 | return -EINVAL; | 548 | return -EINVAL; |
| 549 | } | ||
| 550 | unlock_kernel(); | ||
| 538 | ntfs_debug("Done."); | 551 | ntfs_debug("Done."); |
| 539 | return 0; | 552 | return 0; |
| 540 | } | 553 | } |
| @@ -2246,6 +2259,9 @@ static void ntfs_put_super(struct super_block *sb) | |||
| 2246 | ntfs_volume *vol = NTFS_SB(sb); | 2259 | ntfs_volume *vol = NTFS_SB(sb); |
| 2247 | 2260 | ||
| 2248 | ntfs_debug("Entering."); | 2261 | ntfs_debug("Entering."); |
| 2262 | |||
| 2263 | lock_kernel(); | ||
| 2264 | |||
| 2249 | #ifdef NTFS_RW | 2265 | #ifdef NTFS_RW |
| 2250 | /* | 2266 | /* |
| 2251 | * Commit all inodes while they are still open in case some of them | 2267 | * Commit all inodes while they are still open in case some of them |
| @@ -2373,39 +2389,12 @@ static void ntfs_put_super(struct super_block *sb) | |||
| 2373 | vol->mftmirr_ino = NULL; | 2389 | vol->mftmirr_ino = NULL; |
| 2374 | } | 2390 | } |
| 2375 | /* | 2391 | /* |
| 2376 | * If any dirty inodes are left, throw away all mft data page cache | 2392 | * We should have no dirty inodes left, due to |
| 2377 | * pages to allow a clean umount. This should never happen any more | 2393 | * mft.c::ntfs_mft_writepage() cleaning all the dirty pages as |
| 2378 | * due to mft.c::ntfs_mft_writepage() cleaning all the dirty pages as | 2394 | * the underlying mft records are written out and cleaned. |
| 2379 | * the underlying mft records are written out and cleaned. If it does, | ||
| 2380 | * happen anyway, we want to know... | ||
| 2381 | */ | 2395 | */ |
| 2382 | ntfs_commit_inode(vol->mft_ino); | 2396 | ntfs_commit_inode(vol->mft_ino); |
| 2383 | write_inode_now(vol->mft_ino, 1); | 2397 | write_inode_now(vol->mft_ino, 1); |
| 2384 | if (sb_has_dirty_inodes(sb)) { | ||
| 2385 | const char *s1, *s2; | ||
| 2386 | |||
| 2387 | mutex_lock(&vol->mft_ino->i_mutex); | ||
| 2388 | truncate_inode_pages(vol->mft_ino->i_mapping, 0); | ||
| 2389 | mutex_unlock(&vol->mft_ino->i_mutex); | ||
| 2390 | write_inode_now(vol->mft_ino, 1); | ||
| 2391 | if (sb_has_dirty_inodes(sb)) { | ||
| 2392 | static const char *_s1 = "inodes"; | ||
| 2393 | static const char *_s2 = ""; | ||
| 2394 | s1 = _s1; | ||
| 2395 | s2 = _s2; | ||
| 2396 | } else { | ||
| 2397 | static const char *_s1 = "mft pages"; | ||
| 2398 | static const char *_s2 = "They have been thrown " | ||
| 2399 | "away. "; | ||
| 2400 | s1 = _s1; | ||
| 2401 | s2 = _s2; | ||
| 2402 | } | ||
| 2403 | ntfs_error(sb, "Dirty %s found at umount time. %sYou should " | ||
| 2404 | "run chkdsk. Please email " | ||
| 2405 | "linux-ntfs-dev@lists.sourceforge.net and say " | ||
| 2406 | "that you saw this message. Thank you.", s1, | ||
| 2407 | s2); | ||
| 2408 | } | ||
| 2409 | #endif /* NTFS_RW */ | 2398 | #endif /* NTFS_RW */ |
| 2410 | 2399 | ||
| 2411 | iput(vol->mft_ino); | 2400 | iput(vol->mft_ino); |
| @@ -2444,7 +2433,8 @@ static void ntfs_put_super(struct super_block *sb) | |||
| 2444 | } | 2433 | } |
| 2445 | sb->s_fs_info = NULL; | 2434 | sb->s_fs_info = NULL; |
| 2446 | kfree(vol); | 2435 | kfree(vol); |
| 2447 | return; | 2436 | |
| 2437 | unlock_kernel(); | ||
| 2448 | } | 2438 | } |
| 2449 | 2439 | ||
| 2450 | /** | 2440 | /** |
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index 5c6163f55039..201b40a441fe 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c | |||
| @@ -42,6 +42,7 @@ | |||
| 42 | #include <linux/mount.h> | 42 | #include <linux/mount.h> |
| 43 | #include <linux/seq_file.h> | 43 | #include <linux/seq_file.h> |
| 44 | #include <linux/quotaops.h> | 44 | #include <linux/quotaops.h> |
| 45 | #include <linux/smp_lock.h> | ||
| 45 | 46 | ||
| 46 | #define MLOG_MASK_PREFIX ML_SUPER | 47 | #define MLOG_MASK_PREFIX ML_SUPER |
| 47 | #include <cluster/masklog.h> | 48 | #include <cluster/masklog.h> |
| @@ -126,7 +127,6 @@ static int ocfs2_get_sector(struct super_block *sb, | |||
| 126 | struct buffer_head **bh, | 127 | struct buffer_head **bh, |
| 127 | int block, | 128 | int block, |
| 128 | int sect_size); | 129 | int sect_size); |
| 129 | static void ocfs2_write_super(struct super_block *sb); | ||
| 130 | static struct inode *ocfs2_alloc_inode(struct super_block *sb); | 130 | static struct inode *ocfs2_alloc_inode(struct super_block *sb); |
| 131 | static void ocfs2_destroy_inode(struct inode *inode); | 131 | static void ocfs2_destroy_inode(struct inode *inode); |
| 132 | static int ocfs2_susp_quotas(struct ocfs2_super *osb, int unsuspend); | 132 | static int ocfs2_susp_quotas(struct ocfs2_super *osb, int unsuspend); |
| @@ -141,7 +141,6 @@ static const struct super_operations ocfs2_sops = { | |||
| 141 | .clear_inode = ocfs2_clear_inode, | 141 | .clear_inode = ocfs2_clear_inode, |
| 142 | .delete_inode = ocfs2_delete_inode, | 142 | .delete_inode = ocfs2_delete_inode, |
| 143 | .sync_fs = ocfs2_sync_fs, | 143 | .sync_fs = ocfs2_sync_fs, |
| 144 | .write_super = ocfs2_write_super, | ||
| 145 | .put_super = ocfs2_put_super, | 144 | .put_super = ocfs2_put_super, |
| 146 | .remount_fs = ocfs2_remount, | 145 | .remount_fs = ocfs2_remount, |
| 147 | .show_options = ocfs2_show_options, | 146 | .show_options = ocfs2_show_options, |
| @@ -365,24 +364,12 @@ static struct file_operations ocfs2_osb_debug_fops = { | |||
| 365 | .llseek = generic_file_llseek, | 364 | .llseek = generic_file_llseek, |
| 366 | }; | 365 | }; |
| 367 | 366 | ||
| 368 | /* | ||
| 369 | * write_super and sync_fs ripped right out of ext3. | ||
| 370 | */ | ||
| 371 | static void ocfs2_write_super(struct super_block *sb) | ||
| 372 | { | ||
| 373 | if (mutex_trylock(&sb->s_lock) != 0) | ||
| 374 | BUG(); | ||
| 375 | sb->s_dirt = 0; | ||
| 376 | } | ||
| 377 | |||
| 378 | static int ocfs2_sync_fs(struct super_block *sb, int wait) | 367 | static int ocfs2_sync_fs(struct super_block *sb, int wait) |
| 379 | { | 368 | { |
| 380 | int status; | 369 | int status; |
| 381 | tid_t target; | 370 | tid_t target; |
| 382 | struct ocfs2_super *osb = OCFS2_SB(sb); | 371 | struct ocfs2_super *osb = OCFS2_SB(sb); |
| 383 | 372 | ||
| 384 | sb->s_dirt = 0; | ||
| 385 | |||
| 386 | if (ocfs2_is_hard_readonly(osb)) | 373 | if (ocfs2_is_hard_readonly(osb)) |
| 387 | return -EROFS; | 374 | return -EROFS; |
| 388 | 375 | ||
| @@ -595,6 +582,8 @@ static int ocfs2_remount(struct super_block *sb, int *flags, char *data) | |||
| 595 | struct mount_options parsed_options; | 582 | struct mount_options parsed_options; |
| 596 | struct ocfs2_super *osb = OCFS2_SB(sb); | 583 | struct ocfs2_super *osb = OCFS2_SB(sb); |
| 597 | 584 | ||
| 585 | lock_kernel(); | ||
| 586 | |||
| 598 | if (!ocfs2_parse_options(sb, data, &parsed_options, 1)) { | 587 | if (!ocfs2_parse_options(sb, data, &parsed_options, 1)) { |
| 599 | ret = -EINVAL; | 588 | ret = -EINVAL; |
| 600 | goto out; | 589 | goto out; |
| @@ -698,6 +687,7 @@ unlock_osb: | |||
| 698 | ocfs2_set_journal_params(osb); | 687 | ocfs2_set_journal_params(osb); |
| 699 | } | 688 | } |
| 700 | out: | 689 | out: |
| 690 | unlock_kernel(); | ||
| 701 | return ret; | 691 | return ret; |
| 702 | } | 692 | } |
| 703 | 693 | ||
| @@ -1550,9 +1540,13 @@ static void ocfs2_put_super(struct super_block *sb) | |||
| 1550 | { | 1540 | { |
| 1551 | mlog_entry("(0x%p)\n", sb); | 1541 | mlog_entry("(0x%p)\n", sb); |
| 1552 | 1542 | ||
| 1543 | lock_kernel(); | ||
| 1544 | |||
| 1553 | ocfs2_sync_blockdev(sb); | 1545 | ocfs2_sync_blockdev(sb); |
| 1554 | ocfs2_dismount_volume(sb, 0); | 1546 | ocfs2_dismount_volume(sb, 0); |
| 1555 | 1547 | ||
| 1548 | unlock_kernel(); | ||
| 1549 | |||
| 1556 | mlog_exit_void(); | 1550 | mlog_exit_void(); |
| 1557 | } | 1551 | } |
| 1558 | 1552 | ||
diff --git a/fs/omfs/file.c b/fs/omfs/file.c index 834b2331f6b3..d17e774eaf45 100644 --- a/fs/omfs/file.c +++ b/fs/omfs/file.c | |||
| @@ -11,21 +11,6 @@ | |||
| 11 | #include <linux/mpage.h> | 11 | #include <linux/mpage.h> |
| 12 | #include "omfs.h" | 12 | #include "omfs.h" |
| 13 | 13 | ||
| 14 | static int omfs_sync_file(struct file *file, struct dentry *dentry, | ||
| 15 | int datasync) | ||
| 16 | { | ||
| 17 | struct inode *inode = dentry->d_inode; | ||
| 18 | int err; | ||
| 19 | |||
| 20 | err = sync_mapping_buffers(inode->i_mapping); | ||
| 21 | if (!(inode->i_state & I_DIRTY)) | ||
| 22 | return err; | ||
| 23 | if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) | ||
| 24 | return err; | ||
| 25 | err |= omfs_sync_inode(inode); | ||
| 26 | return err ? -EIO : 0; | ||
| 27 | } | ||
| 28 | |||
| 29 | static u32 omfs_max_extents(struct omfs_sb_info *sbi, int offset) | 14 | static u32 omfs_max_extents(struct omfs_sb_info *sbi, int offset) |
| 30 | { | 15 | { |
| 31 | return (sbi->s_sys_blocksize - offset - | 16 | return (sbi->s_sys_blocksize - offset - |
| @@ -344,7 +329,7 @@ struct file_operations omfs_file_operations = { | |||
| 344 | .aio_read = generic_file_aio_read, | 329 | .aio_read = generic_file_aio_read, |
| 345 | .aio_write = generic_file_aio_write, | 330 | .aio_write = generic_file_aio_write, |
| 346 | .mmap = generic_file_mmap, | 331 | .mmap = generic_file_mmap, |
| 347 | .fsync = omfs_sync_file, | 332 | .fsync = simple_fsync, |
| 348 | .splice_read = generic_file_splice_read, | 333 | .splice_read = generic_file_splice_read, |
| 349 | }; | 334 | }; |
| 350 | 335 | ||
| @@ -612,7 +612,7 @@ SYSCALL_DEFINE2(fchmod, unsigned int, fd, mode_t, mode) | |||
| 612 | 612 | ||
| 613 | audit_inode(NULL, dentry); | 613 | audit_inode(NULL, dentry); |
| 614 | 614 | ||
| 615 | err = mnt_want_write(file->f_path.mnt); | 615 | err = mnt_want_write_file(file); |
| 616 | if (err) | 616 | if (err) |
| 617 | goto out_putf; | 617 | goto out_putf; |
| 618 | mutex_lock(&inode->i_mutex); | 618 | mutex_lock(&inode->i_mutex); |
| @@ -761,7 +761,7 @@ SYSCALL_DEFINE3(fchown, unsigned int, fd, uid_t, user, gid_t, group) | |||
| 761 | if (!file) | 761 | if (!file) |
| 762 | goto out; | 762 | goto out; |
| 763 | 763 | ||
| 764 | error = mnt_want_write(file->f_path.mnt); | 764 | error = mnt_want_write_file(file); |
| 765 | if (error) | 765 | if (error) |
| 766 | goto out_fput; | 766 | goto out_fput; |
| 767 | dentry = file->f_path.dentry; | 767 | dentry = file->f_path.dentry; |
diff --git a/fs/proc/internal.h b/fs/proc/internal.h index f6db9618a888..753ca37002c8 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h | |||
| @@ -92,3 +92,28 @@ struct pde_opener { | |||
| 92 | struct list_head lh; | 92 | struct list_head lh; |
| 93 | }; | 93 | }; |
| 94 | void pde_users_dec(struct proc_dir_entry *pde); | 94 | void pde_users_dec(struct proc_dir_entry *pde); |
| 95 | |||
| 96 | extern spinlock_t proc_subdir_lock; | ||
| 97 | |||
| 98 | struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *); | ||
| 99 | int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir); | ||
| 100 | unsigned long task_vsize(struct mm_struct *); | ||
| 101 | int task_statm(struct mm_struct *, int *, int *, int *, int *); | ||
| 102 | void task_mem(struct seq_file *, struct mm_struct *); | ||
| 103 | |||
| 104 | struct proc_dir_entry *de_get(struct proc_dir_entry *de); | ||
| 105 | void de_put(struct proc_dir_entry *de); | ||
| 106 | |||
| 107 | extern struct vfsmount *proc_mnt; | ||
| 108 | int proc_fill_super(struct super_block *); | ||
| 109 | struct inode *proc_get_inode(struct super_block *, unsigned int, struct proc_dir_entry *); | ||
| 110 | |||
| 111 | /* | ||
| 112 | * These are generic /proc routines that use the internal | ||
| 113 | * "struct proc_dir_entry" tree to traverse the filesystem. | ||
| 114 | * | ||
| 115 | * The /proc root directory has extended versions to take care | ||
| 116 | * of the /proc/<pid> subdirectories. | ||
| 117 | */ | ||
| 118 | int proc_readdir(struct file *, void *, filldir_t); | ||
| 119 | struct dentry *proc_lookup(struct inode *, struct dentry *, struct nameidata *); | ||
diff --git a/fs/proc/proc_devtree.c b/fs/proc/proc_devtree.c index de2bba5a3440..fc6c3025befd 100644 --- a/fs/proc/proc_devtree.c +++ b/fs/proc/proc_devtree.c | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | #include <linux/string.h> | 11 | #include <linux/string.h> |
| 12 | #include <asm/prom.h> | 12 | #include <asm/prom.h> |
| 13 | #include <asm/uaccess.h> | 13 | #include <asm/uaccess.h> |
| 14 | #include "internal.h" | ||
| 14 | 15 | ||
| 15 | #ifndef HAVE_ARCH_DEVTREE_FIXUPS | 16 | #ifndef HAVE_ARCH_DEVTREE_FIXUPS |
| 16 | static inline void set_node_proc_entry(struct device_node *np, | 17 | static inline void set_node_proc_entry(struct device_node *np, |
diff --git a/fs/qnx4/Makefile b/fs/qnx4/Makefile index 502d7fe98bab..e4d408cc5473 100644 --- a/fs/qnx4/Makefile +++ b/fs/qnx4/Makefile | |||
| @@ -4,4 +4,4 @@ | |||
| 4 | 4 | ||
| 5 | obj-$(CONFIG_QNX4FS_FS) += qnx4.o | 5 | obj-$(CONFIG_QNX4FS_FS) += qnx4.o |
| 6 | 6 | ||
| 7 | qnx4-objs := inode.o dir.o namei.o file.o bitmap.o truncate.o fsync.o | 7 | qnx4-objs := inode.o dir.o namei.o file.o bitmap.o truncate.o |
diff --git a/fs/qnx4/bitmap.c b/fs/qnx4/bitmap.c index 8425cf6e9624..e1cd061a25f7 100644 --- a/fs/qnx4/bitmap.c +++ b/fs/qnx4/bitmap.c | |||
| @@ -13,14 +13,9 @@ | |||
| 13 | * 28-06-1998 by Frank Denis : qnx4_free_inode (to be fixed) . | 13 | * 28-06-1998 by Frank Denis : qnx4_free_inode (to be fixed) . |
| 14 | */ | 14 | */ |
| 15 | 15 | ||
| 16 | #include <linux/time.h> | ||
| 17 | #include <linux/fs.h> | ||
| 18 | #include <linux/qnx4_fs.h> | ||
| 19 | #include <linux/stat.h> | ||
| 20 | #include <linux/kernel.h> | ||
| 21 | #include <linux/string.h> | ||
| 22 | #include <linux/buffer_head.h> | 16 | #include <linux/buffer_head.h> |
| 23 | #include <linux/bitops.h> | 17 | #include <linux/bitops.h> |
| 18 | #include "qnx4.h" | ||
| 24 | 19 | ||
| 25 | #if 0 | 20 | #if 0 |
| 26 | int qnx4_new_block(struct super_block *sb) | 21 | int qnx4_new_block(struct super_block *sb) |
diff --git a/fs/qnx4/dir.c b/fs/qnx4/dir.c index ea9ffefb48ad..003c68f3238b 100644 --- a/fs/qnx4/dir.c +++ b/fs/qnx4/dir.c | |||
| @@ -11,14 +11,9 @@ | |||
| 11 | * 20-06-1998 by Frank Denis : Linux 2.1.99+ & dcache support. | 11 | * 20-06-1998 by Frank Denis : Linux 2.1.99+ & dcache support. |
| 12 | */ | 12 | */ |
| 13 | 13 | ||
| 14 | #include <linux/string.h> | ||
| 15 | #include <linux/errno.h> | ||
| 16 | #include <linux/fs.h> | ||
| 17 | #include <linux/qnx4_fs.h> | ||
| 18 | #include <linux/stat.h> | ||
| 19 | #include <linux/smp_lock.h> | 14 | #include <linux/smp_lock.h> |
| 20 | #include <linux/buffer_head.h> | 15 | #include <linux/buffer_head.h> |
| 21 | 16 | #include "qnx4.h" | |
| 22 | 17 | ||
| 23 | static int qnx4_readdir(struct file *filp, void *dirent, filldir_t filldir) | 18 | static int qnx4_readdir(struct file *filp, void *dirent, filldir_t filldir) |
| 24 | { | 19 | { |
| @@ -84,7 +79,7 @@ const struct file_operations qnx4_dir_operations = | |||
| 84 | { | 79 | { |
| 85 | .read = generic_read_dir, | 80 | .read = generic_read_dir, |
| 86 | .readdir = qnx4_readdir, | 81 | .readdir = qnx4_readdir, |
| 87 | .fsync = file_fsync, | 82 | .fsync = simple_fsync, |
| 88 | }; | 83 | }; |
| 89 | 84 | ||
| 90 | const struct inode_operations qnx4_dir_inode_operations = | 85 | const struct inode_operations qnx4_dir_inode_operations = |
diff --git a/fs/qnx4/file.c b/fs/qnx4/file.c index 867f42b02035..09b170ac936c 100644 --- a/fs/qnx4/file.c +++ b/fs/qnx4/file.c | |||
| @@ -12,8 +12,7 @@ | |||
| 12 | * 27-06-1998 by Frank Denis : file overwriting. | 12 | * 27-06-1998 by Frank Denis : file overwriting. |
| 13 | */ | 13 | */ |
| 14 | 14 | ||
| 15 | #include <linux/fs.h> | 15 | #include "qnx4.h" |
| 16 | #include <linux/qnx4_fs.h> | ||
| 17 | 16 | ||
| 18 | /* | 17 | /* |
| 19 | * We have mostly NULL's here: the current defaults are ok for | 18 | * We have mostly NULL's here: the current defaults are ok for |
| @@ -29,7 +28,7 @@ const struct file_operations qnx4_file_operations = | |||
| 29 | #ifdef CONFIG_QNX4FS_RW | 28 | #ifdef CONFIG_QNX4FS_RW |
| 30 | .write = do_sync_write, | 29 | .write = do_sync_write, |
| 31 | .aio_write = generic_file_aio_write, | 30 | .aio_write = generic_file_aio_write, |
| 32 | .fsync = qnx4_sync_file, | 31 | .fsync = simple_fsync, |
| 33 | #endif | 32 | #endif |
| 34 | }; | 33 | }; |
| 35 | 34 | ||
diff --git a/fs/qnx4/fsync.c b/fs/qnx4/fsync.c deleted file mode 100644 index aa3b19544bee..000000000000 --- a/fs/qnx4/fsync.c +++ /dev/null | |||
| @@ -1,169 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * QNX4 file system, Linux implementation. | ||
| 3 | * | ||
| 4 | * Version : 0.1 | ||
| 5 | * | ||
| 6 | * Using parts of the xiafs filesystem. | ||
| 7 | * | ||
| 8 | * History : | ||
| 9 | * | ||
| 10 | * 24-03-1998 by Richard Frowijn : first release. | ||
| 11 | */ | ||
| 12 | |||
| 13 | #include <linux/errno.h> | ||
| 14 | #include <linux/time.h> | ||
| 15 | #include <linux/stat.h> | ||
| 16 | #include <linux/fcntl.h> | ||
| 17 | #include <linux/smp_lock.h> | ||
| 18 | #include <linux/buffer_head.h> | ||
| 19 | |||
| 20 | #include <linux/fs.h> | ||
| 21 | #include <linux/qnx4_fs.h> | ||
| 22 | |||
| 23 | #include <asm/system.h> | ||
| 24 | |||
| 25 | /* | ||
| 26 | * The functions for qnx4 fs file synchronization. | ||
| 27 | */ | ||
| 28 | |||
| 29 | #ifdef CONFIG_QNX4FS_RW | ||
| 30 | |||
| 31 | static int sync_block(struct inode *inode, unsigned short *block, int wait) | ||
| 32 | { | ||
| 33 | struct buffer_head *bh; | ||
| 34 | unsigned short tmp; | ||
| 35 | |||
| 36 | if (!*block) | ||
| 37 | return 0; | ||
| 38 | tmp = *block; | ||
| 39 | bh = sb_find_get_block(inode->i_sb, *block); | ||
| 40 | if (!bh) | ||
| 41 | return 0; | ||
| 42 | if (*block != tmp) { | ||
| 43 | brelse(bh); | ||
| 44 | return 1; | ||
| 45 | } | ||
| 46 | if (wait && buffer_req(bh) && !buffer_uptodate(bh)) { | ||
| 47 | brelse(bh); | ||
| 48 | return -1; | ||
| 49 | } | ||
| 50 | if (wait || !buffer_uptodate(bh) || !buffer_dirty(bh)) { | ||
| 51 | brelse(bh); | ||
| 52 | return 0; | ||
| 53 | } | ||
| 54 | ll_rw_block(WRITE, 1, &bh); | ||
| 55 | atomic_dec(&bh->b_count); | ||
| 56 | return 0; | ||
| 57 | } | ||
| 58 | |||
| 59 | #ifdef WTF | ||
| 60 | static int sync_iblock(struct inode *inode, unsigned short *iblock, | ||
| 61 | struct buffer_head **bh, int wait) | ||
| 62 | { | ||
| 63 | int rc; | ||
| 64 | unsigned short tmp; | ||
| 65 | |||
| 66 | *bh = NULL; | ||
| 67 | tmp = *iblock; | ||
| 68 | if (!tmp) | ||
| 69 | return 0; | ||
| 70 | rc = sync_block(inode, iblock, wait); | ||
| 71 | if (rc) | ||
| 72 | return rc; | ||
| 73 | *bh = sb_bread(inode->i_sb, tmp); | ||
| 74 | if (tmp != *iblock) { | ||
| 75 | brelse(*bh); | ||
| 76 | *bh = NULL; | ||
| 77 | return 1; | ||
| 78 | } | ||
| 79 | if (!*bh) | ||
| 80 | return -1; | ||
| 81 | return 0; | ||
| 82 | } | ||
| 83 | #endif | ||
| 84 | |||
| 85 | static int sync_direct(struct inode *inode, int wait) | ||
| 86 | { | ||
| 87 | int i; | ||
| 88 | int rc, err = 0; | ||
| 89 | |||
| 90 | for (i = 0; i < 7; i++) { | ||
| 91 | rc = sync_block(inode, | ||
| 92 | (unsigned short *) qnx4_raw_inode(inode)->di_first_xtnt.xtnt_blk + i, wait); | ||
| 93 | if (rc > 0) | ||
| 94 | break; | ||
| 95 | if (rc) | ||
| 96 | err = rc; | ||
| 97 | } | ||
| 98 | return err; | ||
| 99 | } | ||
| 100 | |||
| 101 | #ifdef WTF | ||
| 102 | static int sync_indirect(struct inode *inode, unsigned short *iblock, int wait) | ||
| 103 | { | ||
| 104 | int i; | ||
| 105 | struct buffer_head *ind_bh; | ||
| 106 | int rc, err = 0; | ||
| 107 | |||
| 108 | rc = sync_iblock(inode, iblock, &ind_bh, wait); | ||
| 109 | if (rc || !ind_bh) | ||
| 110 | return rc; | ||
| 111 | |||
| 112 | for (i = 0; i < 512; i++) { | ||
| 113 | rc = sync_block(inode, | ||
| 114 | ((unsigned short *) ind_bh->b_data) + i, | ||
| 115 | wait); | ||
| 116 | if (rc > 0) | ||
| 117 | break; | ||
| 118 | if (rc) | ||
| 119 | err = rc; | ||
| 120 | } | ||
| 121 | brelse(ind_bh); | ||
| 122 | return err; | ||
| 123 | } | ||
| 124 | |||
| 125 | static int sync_dindirect(struct inode *inode, unsigned short *diblock, | ||
| 126 | int wait) | ||
| 127 | { | ||
| 128 | int i; | ||
| 129 | struct buffer_head *dind_bh; | ||
| 130 | int rc, err = 0; | ||
| 131 | |||
| 132 | rc = sync_iblock(inode, diblock, &dind_bh, wait); | ||
| 133 | if (rc || !dind_bh) | ||
| 134 | return rc; | ||
| 135 | |||
| 136 | for (i = 0; i < 512; i++) { | ||
| 137 | rc = sync_indirect(inode, | ||
| 138 | ((unsigned short *) dind_bh->b_data) + i, | ||
| 139 | wait); | ||
| 140 | if (rc > 0) | ||
| 141 | break; | ||
| 142 | if (rc) | ||
| 143 | err = rc; | ||
| 144 | } | ||
| 145 | brelse(dind_bh); | ||
| 146 | return err; | ||
| 147 | } | ||
| 148 | #endif | ||
| 149 | |||
| 150 | int qnx4_sync_file(struct file *file, struct dentry *dentry, int unused) | ||
| 151 | { | ||
| 152 | struct inode *inode = dentry->d_inode; | ||
| 153 | int wait, err = 0; | ||
| 154 | |||
| 155 | (void) file; | ||
| 156 | if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || | ||
| 157 | S_ISLNK(inode->i_mode))) | ||
| 158 | return -EINVAL; | ||
| 159 | |||
| 160 | lock_kernel(); | ||
| 161 | for (wait = 0; wait <= 1; wait++) { | ||
| 162 | err |= sync_direct(inode, wait); | ||
| 163 | } | ||
| 164 | err |= qnx4_sync_inode(inode); | ||
| 165 | unlock_kernel(); | ||
| 166 | return (err < 0) ? -EIO : 0; | ||
| 167 | } | ||
| 168 | |||
| 169 | #endif | ||
diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c index fe1f0f31d11c..681df5fcd161 100644 --- a/fs/qnx4/inode.c +++ b/fs/qnx4/inode.c | |||
| @@ -13,19 +13,15 @@ | |||
| 13 | */ | 13 | */ |
| 14 | 14 | ||
| 15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
| 16 | #include <linux/types.h> | ||
| 17 | #include <linux/string.h> | ||
| 18 | #include <linux/errno.h> | ||
| 19 | #include <linux/slab.h> | ||
| 20 | #include <linux/fs.h> | ||
| 21 | #include <linux/qnx4_fs.h> | ||
| 22 | #include <linux/init.h> | 16 | #include <linux/init.h> |
| 17 | #include <linux/slab.h> | ||
| 23 | #include <linux/highuid.h> | 18 | #include <linux/highuid.h> |
| 24 | #include <linux/smp_lock.h> | 19 | #include <linux/smp_lock.h> |
| 25 | #include <linux/pagemap.h> | 20 | #include <linux/pagemap.h> |
| 26 | #include <linux/buffer_head.h> | 21 | #include <linux/buffer_head.h> |
| 27 | #include <linux/vfs.h> | 22 | #include <linux/writeback.h> |
| 28 | #include <asm/uaccess.h> | 23 | #include <linux/statfs.h> |
| 24 | #include "qnx4.h" | ||
| 29 | 25 | ||
| 30 | #define QNX4_VERSION 4 | 26 | #define QNX4_VERSION 4 |
| 31 | #define QNX4_BMNAME ".bitmap" | 27 | #define QNX4_BMNAME ".bitmap" |
| @@ -34,31 +30,6 @@ static const struct super_operations qnx4_sops; | |||
| 34 | 30 | ||
| 35 | #ifdef CONFIG_QNX4FS_RW | 31 | #ifdef CONFIG_QNX4FS_RW |
| 36 | 32 | ||
| 37 | int qnx4_sync_inode(struct inode *inode) | ||
| 38 | { | ||
| 39 | int err = 0; | ||
| 40 | # if 0 | ||
| 41 | struct buffer_head *bh; | ||
| 42 | |||
| 43 | bh = qnx4_update_inode(inode); | ||
| 44 | if (bh && buffer_dirty(bh)) | ||
| 45 | { | ||
| 46 | sync_dirty_buffer(bh); | ||
| 47 | if (buffer_req(bh) && !buffer_uptodate(bh)) | ||
| 48 | { | ||
| 49 | printk ("IO error syncing qnx4 inode [%s:%08lx]\n", | ||
| 50 | inode->i_sb->s_id, inode->i_ino); | ||
| 51 | err = -1; | ||
| 52 | } | ||
| 53 | brelse (bh); | ||
| 54 | } else if (!bh) { | ||
| 55 | err = -1; | ||
| 56 | } | ||
| 57 | # endif | ||
| 58 | |||
| 59 | return err; | ||
| 60 | } | ||
| 61 | |||
| 62 | static void qnx4_delete_inode(struct inode *inode) | 33 | static void qnx4_delete_inode(struct inode *inode) |
| 63 | { | 34 | { |
| 64 | QNX4DEBUG(("qnx4: deleting inode [%lu]\n", (unsigned long) inode->i_ino)); | 35 | QNX4DEBUG(("qnx4: deleting inode [%lu]\n", (unsigned long) inode->i_ino)); |
| @@ -70,15 +41,7 @@ static void qnx4_delete_inode(struct inode *inode) | |||
| 70 | unlock_kernel(); | 41 | unlock_kernel(); |
| 71 | } | 42 | } |
| 72 | 43 | ||
| 73 | static void qnx4_write_super(struct super_block *sb) | 44 | static int qnx4_write_inode(struct inode *inode, int do_sync) |
| 74 | { | ||
| 75 | lock_kernel(); | ||
| 76 | QNX4DEBUG(("qnx4: write_super\n")); | ||
| 77 | sb->s_dirt = 0; | ||
| 78 | unlock_kernel(); | ||
| 79 | } | ||
| 80 | |||
| 81 | static int qnx4_write_inode(struct inode *inode, int unused) | ||
| 82 | { | 45 | { |
| 83 | struct qnx4_inode_entry *raw_inode; | 46 | struct qnx4_inode_entry *raw_inode; |
| 84 | int block, ino; | 47 | int block, ino; |
| @@ -115,6 +78,16 @@ static int qnx4_write_inode(struct inode *inode, int unused) | |||
| 115 | raw_inode->di_ctime = cpu_to_le32(inode->i_ctime.tv_sec); | 78 | raw_inode->di_ctime = cpu_to_le32(inode->i_ctime.tv_sec); |
| 116 | raw_inode->di_first_xtnt.xtnt_size = cpu_to_le32(inode->i_blocks); | 79 | raw_inode->di_first_xtnt.xtnt_size = cpu_to_le32(inode->i_blocks); |
| 117 | mark_buffer_dirty(bh); | 80 | mark_buffer_dirty(bh); |
| 81 | if (do_sync) { | ||
| 82 | sync_dirty_buffer(bh); | ||
| 83 | if (buffer_req(bh) && !buffer_uptodate(bh)) { | ||
| 84 | printk("qnx4: IO error syncing inode [%s:%08x]\n", | ||
| 85 | inode->i_sb->s_id, ino); | ||
| 86 | brelse(bh); | ||
| 87 | unlock_kernel(); | ||
| 88 | return -EIO; | ||
| 89 | } | ||
| 90 | } | ||
| 118 | brelse(bh); | 91 | brelse(bh); |
| 119 | unlock_kernel(); | 92 | unlock_kernel(); |
| 120 | return 0; | 93 | return 0; |
| @@ -138,7 +111,6 @@ static const struct super_operations qnx4_sops = | |||
| 138 | #ifdef CONFIG_QNX4FS_RW | 111 | #ifdef CONFIG_QNX4FS_RW |
| 139 | .write_inode = qnx4_write_inode, | 112 | .write_inode = qnx4_write_inode, |
| 140 | .delete_inode = qnx4_delete_inode, | 113 | .delete_inode = qnx4_delete_inode, |
| 141 | .write_super = qnx4_write_super, | ||
| 142 | #endif | 114 | #endif |
| 143 | }; | 115 | }; |
| 144 | 116 | ||
diff --git a/fs/qnx4/namei.c b/fs/qnx4/namei.c index 775eed3a4085..5972ed214937 100644 --- a/fs/qnx4/namei.c +++ b/fs/qnx4/namei.c | |||
| @@ -12,16 +12,9 @@ | |||
| 12 | * 04-07-1998 by Frank Denis : first step for rmdir/unlink. | 12 | * 04-07-1998 by Frank Denis : first step for rmdir/unlink. |
| 13 | */ | 13 | */ |
| 14 | 14 | ||
| 15 | #include <linux/time.h> | ||
| 16 | #include <linux/fs.h> | ||
| 17 | #include <linux/qnx4_fs.h> | ||
| 18 | #include <linux/kernel.h> | ||
| 19 | #include <linux/string.h> | ||
| 20 | #include <linux/stat.h> | ||
| 21 | #include <linux/fcntl.h> | ||
| 22 | #include <linux/errno.h> | ||
| 23 | #include <linux/smp_lock.h> | 15 | #include <linux/smp_lock.h> |
| 24 | #include <linux/buffer_head.h> | 16 | #include <linux/buffer_head.h> |
| 17 | #include "qnx4.h" | ||
| 25 | 18 | ||
| 26 | 19 | ||
| 27 | /* | 20 | /* |
| @@ -187,7 +180,7 @@ int qnx4_rmdir(struct inode *dir, struct dentry *dentry) | |||
| 187 | de->di_status = 0; | 180 | de->di_status = 0; |
| 188 | memset(de->di_fname, 0, sizeof de->di_fname); | 181 | memset(de->di_fname, 0, sizeof de->di_fname); |
| 189 | de->di_mode = 0; | 182 | de->di_mode = 0; |
| 190 | mark_buffer_dirty(bh); | 183 | mark_buffer_dirty_inode(bh, dir); |
| 191 | clear_nlink(inode); | 184 | clear_nlink(inode); |
| 192 | mark_inode_dirty(inode); | 185 | mark_inode_dirty(inode); |
| 193 | inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC; | 186 | inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC; |
| @@ -232,7 +225,7 @@ int qnx4_unlink(struct inode *dir, struct dentry *dentry) | |||
| 232 | de->di_status = 0; | 225 | de->di_status = 0; |
| 233 | memset(de->di_fname, 0, sizeof de->di_fname); | 226 | memset(de->di_fname, 0, sizeof de->di_fname); |
| 234 | de->di_mode = 0; | 227 | de->di_mode = 0; |
| 235 | mark_buffer_dirty(bh); | 228 | mark_buffer_dirty_inode(bh, dir); |
| 236 | dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC; | 229 | dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC; |
| 237 | mark_inode_dirty(dir); | 230 | mark_inode_dirty(dir); |
| 238 | inode->i_ctime = dir->i_ctime; | 231 | inode->i_ctime = dir->i_ctime; |
diff --git a/fs/qnx4/qnx4.h b/fs/qnx4/qnx4.h new file mode 100644 index 000000000000..9efc089454f6 --- /dev/null +++ b/fs/qnx4/qnx4.h | |||
| @@ -0,0 +1,57 @@ | |||
| 1 | #include <linux/fs.h> | ||
| 2 | #include <linux/qnx4_fs.h> | ||
| 3 | |||
| 4 | #define QNX4_DEBUG 0 | ||
| 5 | |||
| 6 | #if QNX4_DEBUG | ||
| 7 | #define QNX4DEBUG(X) printk X | ||
| 8 | #else | ||
| 9 | #define QNX4DEBUG(X) (void) 0 | ||
| 10 | #endif | ||
| 11 | |||
| 12 | struct qnx4_sb_info { | ||
| 13 | struct buffer_head *sb_buf; /* superblock buffer */ | ||
| 14 | struct qnx4_super_block *sb; /* our superblock */ | ||
| 15 | unsigned int Version; /* may be useful */ | ||
| 16 | struct qnx4_inode_entry *BitMap; /* useful */ | ||
| 17 | }; | ||
| 18 | |||
| 19 | struct qnx4_inode_info { | ||
| 20 | struct qnx4_inode_entry raw; | ||
| 21 | loff_t mmu_private; | ||
| 22 | struct inode vfs_inode; | ||
| 23 | }; | ||
| 24 | |||
| 25 | extern struct inode *qnx4_iget(struct super_block *, unsigned long); | ||
| 26 | extern struct dentry *qnx4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd); | ||
| 27 | extern unsigned long qnx4_count_free_blocks(struct super_block *sb); | ||
| 28 | extern unsigned long qnx4_block_map(struct inode *inode, long iblock); | ||
| 29 | |||
| 30 | extern struct buffer_head *qnx4_bread(struct inode *, int, int); | ||
| 31 | |||
| 32 | extern const struct inode_operations qnx4_file_inode_operations; | ||
| 33 | extern const struct inode_operations qnx4_dir_inode_operations; | ||
| 34 | extern const struct file_operations qnx4_file_operations; | ||
| 35 | extern const struct file_operations qnx4_dir_operations; | ||
| 36 | extern int qnx4_is_free(struct super_block *sb, long block); | ||
| 37 | extern int qnx4_set_bitmap(struct super_block *sb, long block, int busy); | ||
| 38 | extern int qnx4_create(struct inode *inode, struct dentry *dentry, int mode, struct nameidata *nd); | ||
| 39 | extern void qnx4_truncate(struct inode *inode); | ||
| 40 | extern void qnx4_free_inode(struct inode *inode); | ||
| 41 | extern int qnx4_unlink(struct inode *dir, struct dentry *dentry); | ||
| 42 | extern int qnx4_rmdir(struct inode *dir, struct dentry *dentry); | ||
| 43 | |||
| 44 | static inline struct qnx4_sb_info *qnx4_sb(struct super_block *sb) | ||
| 45 | { | ||
| 46 | return sb->s_fs_info; | ||
| 47 | } | ||
| 48 | |||
| 49 | static inline struct qnx4_inode_info *qnx4_i(struct inode *inode) | ||
| 50 | { | ||
| 51 | return container_of(inode, struct qnx4_inode_info, vfs_inode); | ||
| 52 | } | ||
| 53 | |||
| 54 | static inline struct qnx4_inode_entry *qnx4_raw_inode(struct inode *inode) | ||
| 55 | { | ||
| 56 | return &qnx4_i(inode)->raw; | ||
| 57 | } | ||
diff --git a/fs/qnx4/truncate.c b/fs/qnx4/truncate.c index 6437c1c3d1dd..d94d9ee241fe 100644 --- a/fs/qnx4/truncate.c +++ b/fs/qnx4/truncate.c | |||
| @@ -10,12 +10,8 @@ | |||
| 10 | * 30-06-1998 by Frank DENIS : ugly filler. | 10 | * 30-06-1998 by Frank DENIS : ugly filler. |
| 11 | */ | 11 | */ |
| 12 | 12 | ||
| 13 | #include <linux/types.h> | ||
| 14 | #include <linux/errno.h> | ||
| 15 | #include <linux/fs.h> | ||
| 16 | #include <linux/qnx4_fs.h> | ||
| 17 | #include <linux/smp_lock.h> | 13 | #include <linux/smp_lock.h> |
| 18 | #include <asm/uaccess.h> | 14 | #include "qnx4.h" |
| 19 | 15 | ||
| 20 | #ifdef CONFIG_QNX4FS_RW | 16 | #ifdef CONFIG_QNX4FS_RW |
| 21 | 17 | ||
diff --git a/fs/quota/quota.c b/fs/quota/quota.c index b7f5a468f076..95c5b42384b2 100644 --- a/fs/quota/quota.c +++ b/fs/quota/quota.c | |||
| @@ -159,10 +159,14 @@ static int check_quotactl_valid(struct super_block *sb, int type, int cmd, | |||
| 159 | return error; | 159 | return error; |
| 160 | } | 160 | } |
| 161 | 161 | ||
| 162 | static void quota_sync_sb(struct super_block *sb, int type) | 162 | #ifdef CONFIG_QUOTA |
| 163 | void sync_quota_sb(struct super_block *sb, int type) | ||
| 163 | { | 164 | { |
| 164 | int cnt; | 165 | int cnt; |
| 165 | 166 | ||
| 167 | if (!sb->s_qcop->quota_sync) | ||
| 168 | return; | ||
| 169 | |||
| 166 | sb->s_qcop->quota_sync(sb, type); | 170 | sb->s_qcop->quota_sync(sb, type); |
| 167 | 171 | ||
| 168 | if (sb_dqopt(sb)->flags & DQUOT_QUOTA_SYS_FILE) | 172 | if (sb_dqopt(sb)->flags & DQUOT_QUOTA_SYS_FILE) |
| @@ -191,17 +195,13 @@ static void quota_sync_sb(struct super_block *sb, int type) | |||
| 191 | } | 195 | } |
| 192 | mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex); | 196 | mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex); |
| 193 | } | 197 | } |
| 198 | #endif | ||
| 194 | 199 | ||
| 195 | void sync_dquots(struct super_block *sb, int type) | 200 | static void sync_dquots(int type) |
| 196 | { | 201 | { |
| 202 | struct super_block *sb; | ||
| 197 | int cnt; | 203 | int cnt; |
| 198 | 204 | ||
| 199 | if (sb) { | ||
| 200 | if (sb->s_qcop->quota_sync) | ||
| 201 | quota_sync_sb(sb, type); | ||
| 202 | return; | ||
| 203 | } | ||
| 204 | |||
| 205 | spin_lock(&sb_lock); | 205 | spin_lock(&sb_lock); |
| 206 | restart: | 206 | restart: |
| 207 | list_for_each_entry(sb, &super_blocks, s_list) { | 207 | list_for_each_entry(sb, &super_blocks, s_list) { |
| @@ -222,8 +222,8 @@ restart: | |||
| 222 | sb->s_count++; | 222 | sb->s_count++; |
| 223 | spin_unlock(&sb_lock); | 223 | spin_unlock(&sb_lock); |
| 224 | down_read(&sb->s_umount); | 224 | down_read(&sb->s_umount); |
| 225 | if (sb->s_root && sb->s_qcop->quota_sync) | 225 | if (sb->s_root) |
| 226 | quota_sync_sb(sb, type); | 226 | sync_quota_sb(sb, type); |
| 227 | up_read(&sb->s_umount); | 227 | up_read(&sb->s_umount); |
| 228 | spin_lock(&sb_lock); | 228 | spin_lock(&sb_lock); |
| 229 | if (__put_super_and_need_restart(sb)) | 229 | if (__put_super_and_need_restart(sb)) |
| @@ -301,7 +301,10 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, | |||
| 301 | return sb->s_qcop->set_dqblk(sb, type, id, &idq); | 301 | return sb->s_qcop->set_dqblk(sb, type, id, &idq); |
| 302 | } | 302 | } |
| 303 | case Q_SYNC: | 303 | case Q_SYNC: |
| 304 | sync_dquots(sb, type); | 304 | if (sb) |
| 305 | sync_quota_sb(sb, type); | ||
| 306 | else | ||
| 307 | sync_dquots(type); | ||
| 305 | return 0; | 308 | return 0; |
| 306 | 309 | ||
| 307 | case Q_XQUOTAON: | 310 | case Q_XQUOTAON: |
diff --git a/fs/reiserfs/dir.c b/fs/reiserfs/dir.c index 45ee3d357c70..6d2668fdc384 100644 --- a/fs/reiserfs/dir.c +++ b/fs/reiserfs/dir.c | |||
| @@ -44,13 +44,11 @@ static int reiserfs_dir_fsync(struct file *filp, struct dentry *dentry, | |||
| 44 | static inline bool is_privroot_deh(struct dentry *dir, | 44 | static inline bool is_privroot_deh(struct dentry *dir, |
| 45 | struct reiserfs_de_head *deh) | 45 | struct reiserfs_de_head *deh) |
| 46 | { | 46 | { |
| 47 | int ret = 0; | ||
| 48 | #ifdef CONFIG_REISERFS_FS_XATTR | ||
| 49 | struct dentry *privroot = REISERFS_SB(dir->d_sb)->priv_root; | 47 | struct dentry *privroot = REISERFS_SB(dir->d_sb)->priv_root; |
| 50 | ret = (dir == dir->d_parent && privroot->d_inode && | 48 | if (reiserfs_expose_privroot(dir->d_sb)) |
| 51 | deh->deh_objectid == INODE_PKEY(privroot->d_inode)->k_objectid); | 49 | return 0; |
| 52 | #endif | 50 | return (dir == dir->d_parent && privroot->d_inode && |
| 53 | return ret; | 51 | deh->deh_objectid == INODE_PKEY(privroot->d_inode)->k_objectid); |
| 54 | } | 52 | } |
| 55 | 53 | ||
| 56 | int reiserfs_readdir_dentry(struct dentry *dentry, void *dirent, | 54 | int reiserfs_readdir_dentry(struct dentry *dentry, void *dirent, |
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 3567fb9e3fb1..2969773cfc22 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c | |||
| @@ -28,6 +28,7 @@ | |||
| 28 | #include <linux/mount.h> | 28 | #include <linux/mount.h> |
| 29 | #include <linux/namei.h> | 29 | #include <linux/namei.h> |
| 30 | #include <linux/crc32.h> | 30 | #include <linux/crc32.h> |
| 31 | #include <linux/smp_lock.h> | ||
| 31 | 32 | ||
| 32 | struct file_system_type reiserfs_fs_type; | 33 | struct file_system_type reiserfs_fs_type; |
| 33 | 34 | ||
| @@ -64,18 +65,15 @@ static int reiserfs_statfs(struct dentry *dentry, struct kstatfs *buf); | |||
| 64 | 65 | ||
| 65 | static int reiserfs_sync_fs(struct super_block *s, int wait) | 66 | static int reiserfs_sync_fs(struct super_block *s, int wait) |
| 66 | { | 67 | { |
| 67 | if (!(s->s_flags & MS_RDONLY)) { | 68 | struct reiserfs_transaction_handle th; |
| 68 | struct reiserfs_transaction_handle th; | 69 | |
| 69 | reiserfs_write_lock(s); | 70 | reiserfs_write_lock(s); |
| 70 | if (!journal_begin(&th, s, 1)) | 71 | if (!journal_begin(&th, s, 1)) |
| 71 | if (!journal_end_sync(&th, s, 1)) | 72 | if (!journal_end_sync(&th, s, 1)) |
| 72 | reiserfs_flush_old_commits(s); | 73 | reiserfs_flush_old_commits(s); |
| 73 | s->s_dirt = 0; /* Even if it's not true. | 74 | s->s_dirt = 0; /* Even if it's not true. |
| 74 | * We'll loop forever in sync_supers otherwise */ | 75 | * We'll loop forever in sync_supers otherwise */ |
| 75 | reiserfs_write_unlock(s); | 76 | reiserfs_write_unlock(s); |
| 76 | } else { | ||
| 77 | s->s_dirt = 0; | ||
| 78 | } | ||
| 79 | return 0; | 77 | return 0; |
| 80 | } | 78 | } |
| 81 | 79 | ||
| @@ -468,6 +466,11 @@ static void reiserfs_put_super(struct super_block *s) | |||
| 468 | struct reiserfs_transaction_handle th; | 466 | struct reiserfs_transaction_handle th; |
| 469 | th.t_trans_id = 0; | 467 | th.t_trans_id = 0; |
| 470 | 468 | ||
| 469 | lock_kernel(); | ||
| 470 | |||
| 471 | if (s->s_dirt) | ||
| 472 | reiserfs_write_super(s); | ||
| 473 | |||
| 471 | /* change file system state to current state if it was mounted with read-write permissions */ | 474 | /* change file system state to current state if it was mounted with read-write permissions */ |
| 472 | if (!(s->s_flags & MS_RDONLY)) { | 475 | if (!(s->s_flags & MS_RDONLY)) { |
| 473 | if (!journal_begin(&th, s, 10)) { | 476 | if (!journal_begin(&th, s, 10)) { |
| @@ -500,7 +503,7 @@ static void reiserfs_put_super(struct super_block *s) | |||
| 500 | kfree(s->s_fs_info); | 503 | kfree(s->s_fs_info); |
| 501 | s->s_fs_info = NULL; | 504 | s->s_fs_info = NULL; |
| 502 | 505 | ||
| 503 | return; | 506 | unlock_kernel(); |
| 504 | } | 507 | } |
| 505 | 508 | ||
| 506 | static struct kmem_cache *reiserfs_inode_cachep; | 509 | static struct kmem_cache *reiserfs_inode_cachep; |
| @@ -898,6 +901,7 @@ static int reiserfs_parse_options(struct super_block *s, char *options, /* strin | |||
| 898 | {"conv",.setmask = 1 << REISERFS_CONVERT}, | 901 | {"conv",.setmask = 1 << REISERFS_CONVERT}, |
| 899 | {"attrs",.setmask = 1 << REISERFS_ATTRS}, | 902 | {"attrs",.setmask = 1 << REISERFS_ATTRS}, |
| 900 | {"noattrs",.clrmask = 1 << REISERFS_ATTRS}, | 903 | {"noattrs",.clrmask = 1 << REISERFS_ATTRS}, |
| 904 | {"expose_privroot", .setmask = 1 << REISERFS_EXPOSE_PRIVROOT}, | ||
| 901 | #ifdef CONFIG_REISERFS_FS_XATTR | 905 | #ifdef CONFIG_REISERFS_FS_XATTR |
| 902 | {"user_xattr",.setmask = 1 << REISERFS_XATTRS_USER}, | 906 | {"user_xattr",.setmask = 1 << REISERFS_XATTRS_USER}, |
| 903 | {"nouser_xattr",.clrmask = 1 << REISERFS_XATTRS_USER}, | 907 | {"nouser_xattr",.clrmask = 1 << REISERFS_XATTRS_USER}, |
| @@ -1193,6 +1197,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg) | |||
| 1193 | memcpy(qf_names, REISERFS_SB(s)->s_qf_names, sizeof(qf_names)); | 1197 | memcpy(qf_names, REISERFS_SB(s)->s_qf_names, sizeof(qf_names)); |
| 1194 | #endif | 1198 | #endif |
| 1195 | 1199 | ||
| 1200 | lock_kernel(); | ||
| 1196 | rs = SB_DISK_SUPER_BLOCK(s); | 1201 | rs = SB_DISK_SUPER_BLOCK(s); |
| 1197 | 1202 | ||
| 1198 | if (!reiserfs_parse_options | 1203 | if (!reiserfs_parse_options |
| @@ -1315,10 +1320,12 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg) | |||
| 1315 | 1320 | ||
| 1316 | out_ok: | 1321 | out_ok: |
| 1317 | replace_mount_options(s, new_opts); | 1322 | replace_mount_options(s, new_opts); |
| 1323 | unlock_kernel(); | ||
| 1318 | return 0; | 1324 | return 0; |
| 1319 | 1325 | ||
| 1320 | out_err: | 1326 | out_err: |
| 1321 | kfree(new_opts); | 1327 | kfree(new_opts); |
| 1328 | unlock_kernel(); | ||
| 1322 | return err; | 1329 | return err; |
| 1323 | } | 1330 | } |
| 1324 | 1331 | ||
diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c index 8e7deb0e6964..f3d47d856848 100644 --- a/fs/reiserfs/xattr.c +++ b/fs/reiserfs/xattr.c | |||
| @@ -981,7 +981,8 @@ int reiserfs_lookup_privroot(struct super_block *s) | |||
| 981 | strlen(PRIVROOT_NAME)); | 981 | strlen(PRIVROOT_NAME)); |
| 982 | if (!IS_ERR(dentry)) { | 982 | if (!IS_ERR(dentry)) { |
| 983 | REISERFS_SB(s)->priv_root = dentry; | 983 | REISERFS_SB(s)->priv_root = dentry; |
| 984 | s->s_root->d_op = &xattr_lookup_poison_ops; | 984 | if (!reiserfs_expose_privroot(s)) |
| 985 | s->s_root->d_op = &xattr_lookup_poison_ops; | ||
| 985 | if (dentry->d_inode) | 986 | if (dentry->d_inode) |
| 986 | dentry->d_inode->i_flags |= S_PRIVATE; | 987 | dentry->d_inode->i_flags |= S_PRIVATE; |
| 987 | } else | 988 | } else |
diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c index fc27fbfc5397..1402d2d54f52 100644 --- a/fs/smbfs/inode.c +++ b/fs/smbfs/inode.c | |||
| @@ -474,6 +474,8 @@ smb_put_super(struct super_block *sb) | |||
| 474 | { | 474 | { |
| 475 | struct smb_sb_info *server = SMB_SB(sb); | 475 | struct smb_sb_info *server = SMB_SB(sb); |
| 476 | 476 | ||
| 477 | lock_kernel(); | ||
| 478 | |||
| 477 | smb_lock_server(server); | 479 | smb_lock_server(server); |
| 478 | server->state = CONN_INVALID; | 480 | server->state = CONN_INVALID; |
| 479 | smbiod_unregister_server(server); | 481 | smbiod_unregister_server(server); |
| @@ -489,6 +491,8 @@ smb_put_super(struct super_block *sb) | |||
| 489 | smb_unlock_server(server); | 491 | smb_unlock_server(server); |
| 490 | put_pid(server->conn_pid); | 492 | put_pid(server->conn_pid); |
| 491 | kfree(server); | 493 | kfree(server); |
| 494 | |||
| 495 | unlock_kernel(); | ||
| 492 | } | 496 | } |
| 493 | 497 | ||
| 494 | static int smb_fill_super(struct super_block *sb, void *raw_data, int silent) | 498 | static int smb_fill_super(struct super_block *sb, void *raw_data, int silent) |
diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c index 0adc624c956f..3b52770f46ff 100644 --- a/fs/squashfs/super.c +++ b/fs/squashfs/super.c | |||
| @@ -338,6 +338,8 @@ static int squashfs_remount(struct super_block *sb, int *flags, char *data) | |||
| 338 | 338 | ||
| 339 | static void squashfs_put_super(struct super_block *sb) | 339 | static void squashfs_put_super(struct super_block *sb) |
| 340 | { | 340 | { |
| 341 | lock_kernel(); | ||
| 342 | |||
| 341 | if (sb->s_fs_info) { | 343 | if (sb->s_fs_info) { |
| 342 | struct squashfs_sb_info *sbi = sb->s_fs_info; | 344 | struct squashfs_sb_info *sbi = sb->s_fs_info; |
| 343 | squashfs_cache_delete(sbi->block_cache); | 345 | squashfs_cache_delete(sbi->block_cache); |
| @@ -350,6 +352,8 @@ static void squashfs_put_super(struct super_block *sb) | |||
| 350 | kfree(sb->s_fs_info); | 352 | kfree(sb->s_fs_info); |
| 351 | sb->s_fs_info = NULL; | 353 | sb->s_fs_info = NULL; |
| 352 | } | 354 | } |
| 355 | |||
| 356 | unlock_kernel(); | ||
| 353 | } | 357 | } |
| 354 | 358 | ||
| 355 | 359 | ||
diff --git a/fs/super.c b/fs/super.c index 1943fdf655fa..83b47416d006 100644 --- a/fs/super.c +++ b/fs/super.c | |||
| @@ -28,7 +28,6 @@ | |||
| 28 | #include <linux/blkdev.h> | 28 | #include <linux/blkdev.h> |
| 29 | #include <linux/quotaops.h> | 29 | #include <linux/quotaops.h> |
| 30 | #include <linux/namei.h> | 30 | #include <linux/namei.h> |
| 31 | #include <linux/buffer_head.h> /* for fsync_super() */ | ||
| 32 | #include <linux/mount.h> | 31 | #include <linux/mount.h> |
| 33 | #include <linux/security.h> | 32 | #include <linux/security.h> |
| 34 | #include <linux/syscalls.h> | 33 | #include <linux/syscalls.h> |
| @@ -38,7 +37,6 @@ | |||
| 38 | #include <linux/kobject.h> | 37 | #include <linux/kobject.h> |
| 39 | #include <linux/mutex.h> | 38 | #include <linux/mutex.h> |
| 40 | #include <linux/file.h> | 39 | #include <linux/file.h> |
| 41 | #include <linux/async.h> | ||
| 42 | #include <asm/uaccess.h> | 40 | #include <asm/uaccess.h> |
| 43 | #include "internal.h" | 41 | #include "internal.h" |
| 44 | 42 | ||
| @@ -72,7 +70,6 @@ static struct super_block *alloc_super(struct file_system_type *type) | |||
| 72 | INIT_HLIST_HEAD(&s->s_anon); | 70 | INIT_HLIST_HEAD(&s->s_anon); |
| 73 | INIT_LIST_HEAD(&s->s_inodes); | 71 | INIT_LIST_HEAD(&s->s_inodes); |
| 74 | INIT_LIST_HEAD(&s->s_dentry_lru); | 72 | INIT_LIST_HEAD(&s->s_dentry_lru); |
| 75 | INIT_LIST_HEAD(&s->s_async_list); | ||
| 76 | init_rwsem(&s->s_umount); | 73 | init_rwsem(&s->s_umount); |
| 77 | mutex_init(&s->s_lock); | 74 | mutex_init(&s->s_lock); |
| 78 | lockdep_set_class(&s->s_umount, &type->s_umount_key); | 75 | lockdep_set_class(&s->s_umount, &type->s_umount_key); |
| @@ -285,38 +282,6 @@ void unlock_super(struct super_block * sb) | |||
| 285 | EXPORT_SYMBOL(lock_super); | 282 | EXPORT_SYMBOL(lock_super); |
| 286 | EXPORT_SYMBOL(unlock_super); | 283 | EXPORT_SYMBOL(unlock_super); |
| 287 | 284 | ||
| 288 | /* | ||
| 289 | * Write out and wait upon all dirty data associated with this | ||
| 290 | * superblock. Filesystem data as well as the underlying block | ||
| 291 | * device. Takes the superblock lock. Requires a second blkdev | ||
| 292 | * flush by the caller to complete the operation. | ||
| 293 | */ | ||
| 294 | void __fsync_super(struct super_block *sb) | ||
| 295 | { | ||
| 296 | sync_inodes_sb(sb, 0); | ||
| 297 | vfs_dq_sync(sb); | ||
| 298 | lock_super(sb); | ||
| 299 | if (sb->s_dirt && sb->s_op->write_super) | ||
| 300 | sb->s_op->write_super(sb); | ||
| 301 | unlock_super(sb); | ||
| 302 | if (sb->s_op->sync_fs) | ||
| 303 | sb->s_op->sync_fs(sb, 1); | ||
| 304 | sync_blockdev(sb->s_bdev); | ||
| 305 | sync_inodes_sb(sb, 1); | ||
| 306 | } | ||
| 307 | |||
| 308 | /* | ||
| 309 | * Write out and wait upon all dirty data associated with this | ||
| 310 | * superblock. Filesystem data as well as the underlying block | ||
| 311 | * device. Takes the superblock lock. | ||
| 312 | */ | ||
| 313 | int fsync_super(struct super_block *sb) | ||
| 314 | { | ||
| 315 | __fsync_super(sb); | ||
| 316 | return sync_blockdev(sb->s_bdev); | ||
| 317 | } | ||
| 318 | EXPORT_SYMBOL_GPL(fsync_super); | ||
| 319 | |||
| 320 | /** | 285 | /** |
| 321 | * generic_shutdown_super - common helper for ->kill_sb() | 286 | * generic_shutdown_super - common helper for ->kill_sb() |
| 322 | * @sb: superblock to kill | 287 | * @sb: superblock to kill |
| @@ -338,21 +303,13 @@ void generic_shutdown_super(struct super_block *sb) | |||
| 338 | 303 | ||
| 339 | if (sb->s_root) { | 304 | if (sb->s_root) { |
| 340 | shrink_dcache_for_umount(sb); | 305 | shrink_dcache_for_umount(sb); |
| 341 | fsync_super(sb); | 306 | sync_filesystem(sb); |
| 342 | lock_super(sb); | 307 | get_fs_excl(); |
| 343 | sb->s_flags &= ~MS_ACTIVE; | 308 | sb->s_flags &= ~MS_ACTIVE; |
| 344 | 309 | ||
| 345 | /* | ||
| 346 | * wait for asynchronous fs operations to finish before going further | ||
| 347 | */ | ||
| 348 | async_synchronize_full_domain(&sb->s_async_list); | ||
| 349 | |||
| 350 | /* bad name - it should be evict_inodes() */ | 310 | /* bad name - it should be evict_inodes() */ |
| 351 | invalidate_inodes(sb); | 311 | invalidate_inodes(sb); |
| 352 | lock_kernel(); | ||
| 353 | 312 | ||
| 354 | if (sop->write_super && sb->s_dirt) | ||
| 355 | sop->write_super(sb); | ||
| 356 | if (sop->put_super) | 313 | if (sop->put_super) |
| 357 | sop->put_super(sb); | 314 | sop->put_super(sb); |
| 358 | 315 | ||
| @@ -362,9 +319,7 @@ void generic_shutdown_super(struct super_block *sb) | |||
| 362 | "Self-destruct in 5 seconds. Have a nice day...\n", | 319 | "Self-destruct in 5 seconds. Have a nice day...\n", |
| 363 | sb->s_id); | 320 | sb->s_id); |
| 364 | } | 321 | } |
| 365 | 322 | put_fs_excl(); | |
| 366 | unlock_kernel(); | ||
| 367 | unlock_super(sb); | ||
| 368 | } | 323 | } |
| 369 | spin_lock(&sb_lock); | 324 | spin_lock(&sb_lock); |
| 370 | /* should be initialized for __put_super_and_need_restart() */ | 325 | /* should be initialized for __put_super_and_need_restart() */ |
| @@ -441,16 +396,14 @@ void drop_super(struct super_block *sb) | |||
| 441 | 396 | ||
| 442 | EXPORT_SYMBOL(drop_super); | 397 | EXPORT_SYMBOL(drop_super); |
| 443 | 398 | ||
| 444 | static inline void write_super(struct super_block *sb) | 399 | /** |
| 445 | { | 400 | * sync_supers - helper for periodic superblock writeback |
| 446 | lock_super(sb); | 401 | * |
| 447 | if (sb->s_root && sb->s_dirt) | 402 | * Call the write_super method if present on all dirty superblocks in |
| 448 | if (sb->s_op->write_super) | 403 | * the system. This is for the periodic writeback used by most older |
| 449 | sb->s_op->write_super(sb); | 404 | * filesystems. For data integrity superblock writeback use |
| 450 | unlock_super(sb); | 405 | * sync_filesystems() instead. |
| 451 | } | 406 | * |
| 452 | |||
| 453 | /* | ||
| 454 | * Note: check the dirty flag before waiting, so we don't | 407 | * Note: check the dirty flag before waiting, so we don't |
| 455 | * hold up the sync while mounting a device. (The newly | 408 | * hold up the sync while mounting a device. (The newly |
| 456 | * mounted device won't need syncing.) | 409 | * mounted device won't need syncing.) |
| @@ -462,12 +415,15 @@ void sync_supers(void) | |||
| 462 | spin_lock(&sb_lock); | 415 | spin_lock(&sb_lock); |
| 463 | restart: | 416 | restart: |
| 464 | list_for_each_entry(sb, &super_blocks, s_list) { | 417 | list_for_each_entry(sb, &super_blocks, s_list) { |
| 465 | if (sb->s_dirt) { | 418 | if (sb->s_op->write_super && sb->s_dirt) { |
| 466 | sb->s_count++; | 419 | sb->s_count++; |
| 467 | spin_unlock(&sb_lock); | 420 | spin_unlock(&sb_lock); |
| 421 | |||
| 468 | down_read(&sb->s_umount); | 422 | down_read(&sb->s_umount); |
| 469 | write_super(sb); | 423 | if (sb->s_root && sb->s_dirt) |
| 424 | sb->s_op->write_super(sb); | ||
| 470 | up_read(&sb->s_umount); | 425 | up_read(&sb->s_umount); |
| 426 | |||
| 471 | spin_lock(&sb_lock); | 427 | spin_lock(&sb_lock); |
| 472 | if (__put_super_and_need_restart(sb)) | 428 | if (__put_super_and_need_restart(sb)) |
| 473 | goto restart; | 429 | goto restart; |
| @@ -476,60 +432,6 @@ restart: | |||
| 476 | spin_unlock(&sb_lock); | 432 | spin_unlock(&sb_lock); |
| 477 | } | 433 | } |
| 478 | 434 | ||
| 479 | /* | ||
| 480 | * Call the ->sync_fs super_op against all filesystems which are r/w and | ||
| 481 | * which implement it. | ||
| 482 | * | ||
| 483 | * This operation is careful to avoid the livelock which could easily happen | ||
| 484 | * if two or more filesystems are being continuously dirtied. s_need_sync_fs | ||
| 485 | * is used only here. We set it against all filesystems and then clear it as | ||
| 486 | * we sync them. So redirtied filesystems are skipped. | ||
| 487 | * | ||
| 488 | * But if process A is currently running sync_filesystems and then process B | ||
| 489 | * calls sync_filesystems as well, process B will set all the s_need_sync_fs | ||
| 490 | * flags again, which will cause process A to resync everything. Fix that with | ||
| 491 | * a local mutex. | ||
| 492 | * | ||
| 493 | * (Fabian) Avoid sync_fs with clean fs & wait mode 0 | ||
| 494 | */ | ||
| 495 | void sync_filesystems(int wait) | ||
| 496 | { | ||
| 497 | struct super_block *sb; | ||
| 498 | static DEFINE_MUTEX(mutex); | ||
| 499 | |||
| 500 | mutex_lock(&mutex); /* Could be down_interruptible */ | ||
| 501 | spin_lock(&sb_lock); | ||
| 502 | list_for_each_entry(sb, &super_blocks, s_list) { | ||
| 503 | if (!sb->s_op->sync_fs) | ||
| 504 | continue; | ||
| 505 | if (sb->s_flags & MS_RDONLY) | ||
| 506 | continue; | ||
| 507 | sb->s_need_sync_fs = 1; | ||
| 508 | } | ||
| 509 | |||
| 510 | restart: | ||
| 511 | list_for_each_entry(sb, &super_blocks, s_list) { | ||
| 512 | if (!sb->s_need_sync_fs) | ||
| 513 | continue; | ||
| 514 | sb->s_need_sync_fs = 0; | ||
| 515 | if (sb->s_flags & MS_RDONLY) | ||
| 516 | continue; /* hm. Was remounted r/o meanwhile */ | ||
| 517 | sb->s_count++; | ||
| 518 | spin_unlock(&sb_lock); | ||
| 519 | down_read(&sb->s_umount); | ||
| 520 | async_synchronize_full_domain(&sb->s_async_list); | ||
| 521 | if (sb->s_root && (wait || sb->s_dirt)) | ||
| 522 | sb->s_op->sync_fs(sb, wait); | ||
| 523 | up_read(&sb->s_umount); | ||
| 524 | /* restart only when sb is no longer on the list */ | ||
| 525 | spin_lock(&sb_lock); | ||
| 526 | if (__put_super_and_need_restart(sb)) | ||
| 527 | goto restart; | ||
| 528 | } | ||
| 529 | spin_unlock(&sb_lock); | ||
| 530 | mutex_unlock(&mutex); | ||
| 531 | } | ||
| 532 | |||
| 533 | /** | 435 | /** |
| 534 | * get_super - get the superblock of a device | 436 | * get_super - get the superblock of a device |
| 535 | * @bdev: device to get the superblock for | 437 | * @bdev: device to get the superblock for |
| @@ -616,45 +518,6 @@ out: | |||
| 616 | } | 518 | } |
| 617 | 519 | ||
| 618 | /** | 520 | /** |
| 619 | * mark_files_ro - mark all files read-only | ||
| 620 | * @sb: superblock in question | ||
| 621 | * | ||
| 622 | * All files are marked read-only. We don't care about pending | ||
| 623 | * delete files so this should be used in 'force' mode only. | ||
| 624 | */ | ||
| 625 | |||
| 626 | static void mark_files_ro(struct super_block *sb) | ||
| 627 | { | ||
| 628 | struct file *f; | ||
| 629 | |||
| 630 | retry: | ||
| 631 | file_list_lock(); | ||
| 632 | list_for_each_entry(f, &sb->s_files, f_u.fu_list) { | ||
| 633 | struct vfsmount *mnt; | ||
| 634 | if (!S_ISREG(f->f_path.dentry->d_inode->i_mode)) | ||
| 635 | continue; | ||
| 636 | if (!file_count(f)) | ||
| 637 | continue; | ||
| 638 | if (!(f->f_mode & FMODE_WRITE)) | ||
| 639 | continue; | ||
| 640 | f->f_mode &= ~FMODE_WRITE; | ||
| 641 | if (file_check_writeable(f) != 0) | ||
| 642 | continue; | ||
| 643 | file_release_write(f); | ||
| 644 | mnt = mntget(f->f_path.mnt); | ||
| 645 | file_list_unlock(); | ||
| 646 | /* | ||
| 647 | * This can sleep, so we can't hold | ||
| 648 | * the file_list_lock() spinlock. | ||
| 649 | */ | ||
| 650 | mnt_drop_write(mnt); | ||
| 651 | mntput(mnt); | ||
| 652 | goto retry; | ||
| 653 | } | ||
| 654 | file_list_unlock(); | ||
| 655 | } | ||
| 656 | |||
| 657 | /** | ||
| 658 | * do_remount_sb - asks filesystem to change mount options. | 521 | * do_remount_sb - asks filesystem to change mount options. |
| 659 | * @sb: superblock in question | 522 | * @sb: superblock in question |
| 660 | * @flags: numeric part of options | 523 | * @flags: numeric part of options |
| @@ -675,27 +538,31 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force) | |||
| 675 | if (flags & MS_RDONLY) | 538 | if (flags & MS_RDONLY) |
| 676 | acct_auto_close(sb); | 539 | acct_auto_close(sb); |
| 677 | shrink_dcache_sb(sb); | 540 | shrink_dcache_sb(sb); |
| 678 | fsync_super(sb); | 541 | sync_filesystem(sb); |
| 679 | 542 | ||
| 680 | /* If we are remounting RDONLY and current sb is read/write, | 543 | /* If we are remounting RDONLY and current sb is read/write, |
| 681 | make sure there are no rw files opened */ | 544 | make sure there are no rw files opened */ |
| 682 | if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY)) { | 545 | if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY)) { |
| 683 | if (force) | 546 | if (force) |
| 684 | mark_files_ro(sb); | 547 | mark_files_ro(sb); |
| 685 | else if (!fs_may_remount_ro(sb)) | 548 | else if (!fs_may_remount_ro(sb)) { |
| 549 | unlock_kernel(); | ||
| 686 | return -EBUSY; | 550 | return -EBUSY; |
| 551 | } | ||
| 687 | retval = vfs_dq_off(sb, 1); | 552 | retval = vfs_dq_off(sb, 1); |
| 688 | if (retval < 0 && retval != -ENOSYS) | 553 | if (retval < 0 && retval != -ENOSYS) { |
| 554 | unlock_kernel(); | ||
| 689 | return -EBUSY; | 555 | return -EBUSY; |
| 556 | } | ||
| 690 | } | 557 | } |
| 691 | remount_rw = !(flags & MS_RDONLY) && (sb->s_flags & MS_RDONLY); | 558 | remount_rw = !(flags & MS_RDONLY) && (sb->s_flags & MS_RDONLY); |
| 692 | 559 | ||
| 693 | if (sb->s_op->remount_fs) { | 560 | if (sb->s_op->remount_fs) { |
| 694 | lock_super(sb); | ||
| 695 | retval = sb->s_op->remount_fs(sb, &flags, data); | 561 | retval = sb->s_op->remount_fs(sb, &flags, data); |
| 696 | unlock_super(sb); | 562 | if (retval) { |
| 697 | if (retval) | 563 | unlock_kernel(); |
| 698 | return retval; | 564 | return retval; |
| 565 | } | ||
| 699 | } | 566 | } |
| 700 | sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK); | 567 | sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK); |
| 701 | if (remount_rw) | 568 | if (remount_rw) |
| @@ -711,18 +578,17 @@ static void do_emergency_remount(struct work_struct *work) | |||
| 711 | list_for_each_entry(sb, &super_blocks, s_list) { | 578 | list_for_each_entry(sb, &super_blocks, s_list) { |
| 712 | sb->s_count++; | 579 | sb->s_count++; |
| 713 | spin_unlock(&sb_lock); | 580 | spin_unlock(&sb_lock); |
| 714 | down_read(&sb->s_umount); | 581 | down_write(&sb->s_umount); |
| 715 | if (sb->s_root && sb->s_bdev && !(sb->s_flags & MS_RDONLY)) { | 582 | if (sb->s_root && sb->s_bdev && !(sb->s_flags & MS_RDONLY)) { |
| 716 | /* | 583 | /* |
| 717 | * ->remount_fs needs lock_kernel(). | 584 | * ->remount_fs needs lock_kernel(). |
| 718 | * | 585 | * |
| 719 | * What lock protects sb->s_flags?? | 586 | * What lock protects sb->s_flags?? |
| 720 | */ | 587 | */ |
| 721 | lock_kernel(); | ||
| 722 | do_remount_sb(sb, MS_RDONLY, NULL, 1); | 588 | do_remount_sb(sb, MS_RDONLY, NULL, 1); |
| 723 | unlock_kernel(); | ||
| 724 | } | 589 | } |
| 725 | drop_super(sb); | 590 | up_write(&sb->s_umount); |
| 591 | put_super(sb); | ||
| 726 | spin_lock(&sb_lock); | 592 | spin_lock(&sb_lock); |
| 727 | } | 593 | } |
| 728 | spin_unlock(&sb_lock); | 594 | spin_unlock(&sb_lock); |
| @@ -13,38 +13,123 @@ | |||
| 13 | #include <linux/pagemap.h> | 13 | #include <linux/pagemap.h> |
| 14 | #include <linux/quotaops.h> | 14 | #include <linux/quotaops.h> |
| 15 | #include <linux/buffer_head.h> | 15 | #include <linux/buffer_head.h> |
| 16 | #include "internal.h" | ||
| 16 | 17 | ||
| 17 | #define VALID_FLAGS (SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE| \ | 18 | #define VALID_FLAGS (SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE| \ |
| 18 | SYNC_FILE_RANGE_WAIT_AFTER) | 19 | SYNC_FILE_RANGE_WAIT_AFTER) |
| 19 | 20 | ||
| 20 | /* | 21 | /* |
| 21 | * sync everything. Start out by waking pdflush, because that writes back | 22 | * Do the filesystem syncing work. For simple filesystems sync_inodes_sb(sb, 0) |
| 22 | * all queues in parallel. | 23 | * just dirties buffers with inodes so we have to submit IO for these buffers |
| 24 | * via __sync_blockdev(). This also speeds up the wait == 1 case since in that | ||
| 25 | * case write_inode() functions do sync_dirty_buffer() and thus effectively | ||
| 26 | * write one block at a time. | ||
| 23 | */ | 27 | */ |
| 24 | static void do_sync(unsigned long wait) | 28 | static int __sync_filesystem(struct super_block *sb, int wait) |
| 25 | { | 29 | { |
| 26 | wakeup_pdflush(0); | 30 | /* Avoid doing twice syncing and cache pruning for quota sync */ |
| 27 | sync_inodes(0); /* All mappings, inodes and their blockdevs */ | ||
| 28 | vfs_dq_sync(NULL); | ||
| 29 | sync_supers(); /* Write the superblocks */ | ||
| 30 | sync_filesystems(0); /* Start syncing the filesystems */ | ||
| 31 | sync_filesystems(wait); /* Waitingly sync the filesystems */ | ||
| 32 | sync_inodes(wait); /* Mappings, inodes and blockdevs, again. */ | ||
| 33 | if (!wait) | 31 | if (!wait) |
| 34 | printk("Emergency Sync complete\n"); | 32 | writeout_quota_sb(sb, -1); |
| 35 | if (unlikely(laptop_mode)) | 33 | else |
| 36 | laptop_sync_completion(); | 34 | sync_quota_sb(sb, -1); |
| 35 | sync_inodes_sb(sb, wait); | ||
| 36 | if (sb->s_op->sync_fs) | ||
| 37 | sb->s_op->sync_fs(sb, wait); | ||
| 38 | return __sync_blockdev(sb->s_bdev, wait); | ||
| 39 | } | ||
| 40 | |||
| 41 | /* | ||
| 42 | * Write out and wait upon all dirty data associated with this | ||
| 43 | * superblock. Filesystem data as well as the underlying block | ||
| 44 | * device. Takes the superblock lock. | ||
| 45 | */ | ||
| 46 | int sync_filesystem(struct super_block *sb) | ||
| 47 | { | ||
| 48 | int ret; | ||
| 49 | |||
| 50 | /* | ||
| 51 | * We need to be protected against the filesystem going from | ||
| 52 | * r/o to r/w or vice versa. | ||
| 53 | */ | ||
| 54 | WARN_ON(!rwsem_is_locked(&sb->s_umount)); | ||
| 55 | |||
| 56 | /* | ||
| 57 | * No point in syncing out anything if the filesystem is read-only. | ||
| 58 | */ | ||
| 59 | if (sb->s_flags & MS_RDONLY) | ||
| 60 | return 0; | ||
| 61 | |||
| 62 | ret = __sync_filesystem(sb, 0); | ||
| 63 | if (ret < 0) | ||
| 64 | return ret; | ||
| 65 | return __sync_filesystem(sb, 1); | ||
| 66 | } | ||
| 67 | EXPORT_SYMBOL_GPL(sync_filesystem); | ||
| 68 | |||
| 69 | /* | ||
| 70 | * Sync all the data for all the filesystems (called by sys_sync() and | ||
| 71 | * emergency sync) | ||
| 72 | * | ||
| 73 | * This operation is careful to avoid the livelock which could easily happen | ||
| 74 | * if two or more filesystems are being continuously dirtied. s_need_sync | ||
| 75 | * is used only here. We set it against all filesystems and then clear it as | ||
| 76 | * we sync them. So redirtied filesystems are skipped. | ||
| 77 | * | ||
| 78 | * But if process A is currently running sync_filesystems and then process B | ||
| 79 | * calls sync_filesystems as well, process B will set all the s_need_sync | ||
| 80 | * flags again, which will cause process A to resync everything. Fix that with | ||
| 81 | * a local mutex. | ||
| 82 | */ | ||
| 83 | static void sync_filesystems(int wait) | ||
| 84 | { | ||
| 85 | struct super_block *sb; | ||
| 86 | static DEFINE_MUTEX(mutex); | ||
| 87 | |||
| 88 | mutex_lock(&mutex); /* Could be down_interruptible */ | ||
| 89 | spin_lock(&sb_lock); | ||
| 90 | list_for_each_entry(sb, &super_blocks, s_list) | ||
| 91 | sb->s_need_sync = 1; | ||
| 92 | |||
| 93 | restart: | ||
| 94 | list_for_each_entry(sb, &super_blocks, s_list) { | ||
| 95 | if (!sb->s_need_sync) | ||
| 96 | continue; | ||
| 97 | sb->s_need_sync = 0; | ||
| 98 | sb->s_count++; | ||
| 99 | spin_unlock(&sb_lock); | ||
| 100 | |||
| 101 | down_read(&sb->s_umount); | ||
| 102 | if (!(sb->s_flags & MS_RDONLY) && sb->s_root) | ||
| 103 | __sync_filesystem(sb, wait); | ||
| 104 | up_read(&sb->s_umount); | ||
| 105 | |||
| 106 | /* restart only when sb is no longer on the list */ | ||
| 107 | spin_lock(&sb_lock); | ||
| 108 | if (__put_super_and_need_restart(sb)) | ||
| 109 | goto restart; | ||
| 110 | } | ||
| 111 | spin_unlock(&sb_lock); | ||
| 112 | mutex_unlock(&mutex); | ||
| 37 | } | 113 | } |
| 38 | 114 | ||
| 39 | SYSCALL_DEFINE0(sync) | 115 | SYSCALL_DEFINE0(sync) |
| 40 | { | 116 | { |
| 41 | do_sync(1); | 117 | sync_filesystems(0); |
| 118 | sync_filesystems(1); | ||
| 119 | if (unlikely(laptop_mode)) | ||
| 120 | laptop_sync_completion(); | ||
| 42 | return 0; | 121 | return 0; |
| 43 | } | 122 | } |
| 44 | 123 | ||
| 45 | static void do_sync_work(struct work_struct *work) | 124 | static void do_sync_work(struct work_struct *work) |
| 46 | { | 125 | { |
| 47 | do_sync(0); | 126 | /* |
| 127 | * Sync twice to reduce the possibility we skipped some inodes / pages | ||
| 128 | * because they were temporarily locked | ||
| 129 | */ | ||
| 130 | sync_filesystems(0); | ||
| 131 | sync_filesystems(0); | ||
| 132 | printk("Emergency Sync complete\n"); | ||
| 48 | kfree(work); | 133 | kfree(work); |
| 49 | } | 134 | } |
| 50 | 135 | ||
| @@ -75,10 +160,8 @@ int file_fsync(struct file *filp, struct dentry *dentry, int datasync) | |||
| 75 | 160 | ||
| 76 | /* sync the superblock to buffers */ | 161 | /* sync the superblock to buffers */ |
| 77 | sb = inode->i_sb; | 162 | sb = inode->i_sb; |
| 78 | lock_super(sb); | ||
| 79 | if (sb->s_dirt && sb->s_op->write_super) | 163 | if (sb->s_dirt && sb->s_op->write_super) |
| 80 | sb->s_op->write_super(sb); | 164 | sb->s_op->write_super(sb); |
| 81 | unlock_super(sb); | ||
| 82 | 165 | ||
| 83 | /* .. finally sync the buffers to disk */ | 166 | /* .. finally sync the buffers to disk */ |
| 84 | err = sync_blockdev(sb->s_bdev); | 167 | err = sync_blockdev(sb->s_bdev); |
diff --git a/fs/sysv/dir.c b/fs/sysv/dir.c index 56f655254bfe..c7798079e644 100644 --- a/fs/sysv/dir.c +++ b/fs/sysv/dir.c | |||
| @@ -24,7 +24,7 @@ static int sysv_readdir(struct file *, void *, filldir_t); | |||
| 24 | const struct file_operations sysv_dir_operations = { | 24 | const struct file_operations sysv_dir_operations = { |
| 25 | .read = generic_read_dir, | 25 | .read = generic_read_dir, |
| 26 | .readdir = sysv_readdir, | 26 | .readdir = sysv_readdir, |
| 27 | .fsync = sysv_sync_file, | 27 | .fsync = simple_fsync, |
| 28 | }; | 28 | }; |
| 29 | 29 | ||
| 30 | static inline void dir_put_page(struct page *page) | 30 | static inline void dir_put_page(struct page *page) |
diff --git a/fs/sysv/file.c b/fs/sysv/file.c index 589be21d884e..96340c01f4a7 100644 --- a/fs/sysv/file.c +++ b/fs/sysv/file.c | |||
| @@ -26,7 +26,7 @@ const struct file_operations sysv_file_operations = { | |||
| 26 | .write = do_sync_write, | 26 | .write = do_sync_write, |
| 27 | .aio_write = generic_file_aio_write, | 27 | .aio_write = generic_file_aio_write, |
| 28 | .mmap = generic_file_mmap, | 28 | .mmap = generic_file_mmap, |
| 29 | .fsync = sysv_sync_file, | 29 | .fsync = simple_fsync, |
| 30 | .splice_read = generic_file_splice_read, | 30 | .splice_read = generic_file_splice_read, |
| 31 | }; | 31 | }; |
| 32 | 32 | ||
| @@ -34,18 +34,3 @@ const struct inode_operations sysv_file_inode_operations = { | |||
| 34 | .truncate = sysv_truncate, | 34 | .truncate = sysv_truncate, |
| 35 | .getattr = sysv_getattr, | 35 | .getattr = sysv_getattr, |
| 36 | }; | 36 | }; |
| 37 | |||
| 38 | int sysv_sync_file(struct file * file, struct dentry *dentry, int datasync) | ||
| 39 | { | ||
| 40 | struct inode *inode = dentry->d_inode; | ||
| 41 | int err; | ||
| 42 | |||
| 43 | err = sync_mapping_buffers(inode->i_mapping); | ||
| 44 | if (!(inode->i_state & I_DIRTY)) | ||
| 45 | return err; | ||
| 46 | if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) | ||
| 47 | return err; | ||
| 48 | |||
| 49 | err |= sysv_sync_inode(inode); | ||
| 50 | return err ? -EIO : 0; | ||
| 51 | } | ||
diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c index da20b48d350f..479923456a54 100644 --- a/fs/sysv/inode.c +++ b/fs/sysv/inode.c | |||
| @@ -31,15 +31,13 @@ | |||
| 31 | #include <asm/byteorder.h> | 31 | #include <asm/byteorder.h> |
| 32 | #include "sysv.h" | 32 | #include "sysv.h" |
| 33 | 33 | ||
| 34 | /* This is only called on sync() and umount(), when s_dirt=1. */ | 34 | static int sysv_sync_fs(struct super_block *sb, int wait) |
| 35 | static void sysv_write_super(struct super_block *sb) | ||
| 36 | { | 35 | { |
| 37 | struct sysv_sb_info *sbi = SYSV_SB(sb); | 36 | struct sysv_sb_info *sbi = SYSV_SB(sb); |
| 38 | unsigned long time = get_seconds(), old_time; | 37 | unsigned long time = get_seconds(), old_time; |
| 39 | 38 | ||
| 39 | lock_super(sb); | ||
| 40 | lock_kernel(); | 40 | lock_kernel(); |
| 41 | if (sb->s_flags & MS_RDONLY) | ||
| 42 | goto clean; | ||
| 43 | 41 | ||
| 44 | /* | 42 | /* |
| 45 | * If we are going to write out the super block, | 43 | * If we are going to write out the super block, |
| @@ -53,18 +51,30 @@ static void sysv_write_super(struct super_block *sb) | |||
| 53 | *sbi->s_sb_time = cpu_to_fs32(sbi, time); | 51 | *sbi->s_sb_time = cpu_to_fs32(sbi, time); |
| 54 | mark_buffer_dirty(sbi->s_bh2); | 52 | mark_buffer_dirty(sbi->s_bh2); |
| 55 | } | 53 | } |
| 56 | clean: | 54 | |
| 57 | sb->s_dirt = 0; | ||
| 58 | unlock_kernel(); | 55 | unlock_kernel(); |
| 56 | unlock_super(sb); | ||
| 57 | |||
| 58 | return 0; | ||
| 59 | } | ||
| 60 | |||
| 61 | static void sysv_write_super(struct super_block *sb) | ||
| 62 | { | ||
| 63 | if (!(sb->s_flags & MS_RDONLY)) | ||
| 64 | sysv_sync_fs(sb, 1); | ||
| 65 | else | ||
| 66 | sb->s_dirt = 0; | ||
| 59 | } | 67 | } |
| 60 | 68 | ||
| 61 | static int sysv_remount(struct super_block *sb, int *flags, char *data) | 69 | static int sysv_remount(struct super_block *sb, int *flags, char *data) |
| 62 | { | 70 | { |
| 63 | struct sysv_sb_info *sbi = SYSV_SB(sb); | 71 | struct sysv_sb_info *sbi = SYSV_SB(sb); |
| 72 | lock_super(sb); | ||
| 64 | if (sbi->s_forced_ro) | 73 | if (sbi->s_forced_ro) |
| 65 | *flags |= MS_RDONLY; | 74 | *flags |= MS_RDONLY; |
| 66 | if (!(*flags & MS_RDONLY)) | 75 | if (!(*flags & MS_RDONLY)) |
| 67 | sb->s_dirt = 1; | 76 | sb->s_dirt = 1; |
| 77 | unlock_super(sb); | ||
| 68 | return 0; | 78 | return 0; |
| 69 | } | 79 | } |
| 70 | 80 | ||
| @@ -72,6 +82,11 @@ static void sysv_put_super(struct super_block *sb) | |||
| 72 | { | 82 | { |
| 73 | struct sysv_sb_info *sbi = SYSV_SB(sb); | 83 | struct sysv_sb_info *sbi = SYSV_SB(sb); |
| 74 | 84 | ||
| 85 | lock_kernel(); | ||
| 86 | |||
| 87 | if (sb->s_dirt) | ||
| 88 | sysv_write_super(sb); | ||
| 89 | |||
| 75 | if (!(sb->s_flags & MS_RDONLY)) { | 90 | if (!(sb->s_flags & MS_RDONLY)) { |
| 76 | /* XXX ext2 also updates the state here */ | 91 | /* XXX ext2 also updates the state here */ |
| 77 | mark_buffer_dirty(sbi->s_bh1); | 92 | mark_buffer_dirty(sbi->s_bh1); |
| @@ -84,6 +99,8 @@ static void sysv_put_super(struct super_block *sb) | |||
| 84 | brelse(sbi->s_bh2); | 99 | brelse(sbi->s_bh2); |
| 85 | 100 | ||
| 86 | kfree(sbi); | 101 | kfree(sbi); |
| 102 | |||
| 103 | unlock_kernel(); | ||
| 87 | } | 104 | } |
| 88 | 105 | ||
| 89 | static int sysv_statfs(struct dentry *dentry, struct kstatfs *buf) | 106 | static int sysv_statfs(struct dentry *dentry, struct kstatfs *buf) |
| @@ -236,7 +253,7 @@ bad_inode: | |||
| 236 | return ERR_PTR(-EIO); | 253 | return ERR_PTR(-EIO); |
| 237 | } | 254 | } |
| 238 | 255 | ||
| 239 | static struct buffer_head * sysv_update_inode(struct inode * inode) | 256 | int sysv_write_inode(struct inode *inode, int wait) |
| 240 | { | 257 | { |
| 241 | struct super_block * sb = inode->i_sb; | 258 | struct super_block * sb = inode->i_sb; |
| 242 | struct sysv_sb_info * sbi = SYSV_SB(sb); | 259 | struct sysv_sb_info * sbi = SYSV_SB(sb); |
| @@ -244,19 +261,21 @@ static struct buffer_head * sysv_update_inode(struct inode * inode) | |||
| 244 | struct sysv_inode * raw_inode; | 261 | struct sysv_inode * raw_inode; |
| 245 | struct sysv_inode_info * si; | 262 | struct sysv_inode_info * si; |
| 246 | unsigned int ino, block; | 263 | unsigned int ino, block; |
| 264 | int err = 0; | ||
| 247 | 265 | ||
| 248 | ino = inode->i_ino; | 266 | ino = inode->i_ino; |
| 249 | if (!ino || ino > sbi->s_ninodes) { | 267 | if (!ino || ino > sbi->s_ninodes) { |
| 250 | printk("Bad inode number on dev %s: %d is out of range\n", | 268 | printk("Bad inode number on dev %s: %d is out of range\n", |
| 251 | inode->i_sb->s_id, ino); | 269 | inode->i_sb->s_id, ino); |
| 252 | return NULL; | 270 | return -EIO; |
| 253 | } | 271 | } |
| 254 | raw_inode = sysv_raw_inode(sb, ino, &bh); | 272 | raw_inode = sysv_raw_inode(sb, ino, &bh); |
| 255 | if (!raw_inode) { | 273 | if (!raw_inode) { |
| 256 | printk("unable to read i-node block\n"); | 274 | printk("unable to read i-node block\n"); |
| 257 | return NULL; | 275 | return -EIO; |
| 258 | } | 276 | } |
| 259 | 277 | ||
| 278 | lock_kernel(); | ||
| 260 | raw_inode->i_mode = cpu_to_fs16(sbi, inode->i_mode); | 279 | raw_inode->i_mode = cpu_to_fs16(sbi, inode->i_mode); |
| 261 | raw_inode->i_uid = cpu_to_fs16(sbi, fs_high2lowuid(inode->i_uid)); | 280 | raw_inode->i_uid = cpu_to_fs16(sbi, fs_high2lowuid(inode->i_uid)); |
| 262 | raw_inode->i_gid = cpu_to_fs16(sbi, fs_high2lowgid(inode->i_gid)); | 281 | raw_inode->i_gid = cpu_to_fs16(sbi, fs_high2lowgid(inode->i_gid)); |
| @@ -272,38 +291,23 @@ static struct buffer_head * sysv_update_inode(struct inode * inode) | |||
| 272 | for (block = 0; block < 10+1+1+1; block++) | 291 | for (block = 0; block < 10+1+1+1; block++) |
| 273 | write3byte(sbi, (u8 *)&si->i_data[block], | 292 | write3byte(sbi, (u8 *)&si->i_data[block], |
| 274 | &raw_inode->i_data[3*block]); | 293 | &raw_inode->i_data[3*block]); |
| 294 | unlock_kernel(); | ||
| 275 | mark_buffer_dirty(bh); | 295 | mark_buffer_dirty(bh); |
| 276 | return bh; | 296 | if (wait) { |
| 277 | } | 297 | sync_dirty_buffer(bh); |
| 278 | 298 | if (buffer_req(bh) && !buffer_uptodate(bh)) { | |
| 279 | int sysv_write_inode(struct inode * inode, int wait) | 299 | printk ("IO error syncing sysv inode [%s:%08x]\n", |
| 280 | { | 300 | sb->s_id, ino); |
| 281 | struct buffer_head *bh; | 301 | err = -EIO; |
| 282 | lock_kernel(); | 302 | } |
| 283 | bh = sysv_update_inode(inode); | 303 | } |
| 284 | brelse(bh); | 304 | brelse(bh); |
| 285 | unlock_kernel(); | ||
| 286 | return 0; | 305 | return 0; |
| 287 | } | 306 | } |
| 288 | 307 | ||
| 289 | int sysv_sync_inode(struct inode * inode) | 308 | int sysv_sync_inode(struct inode *inode) |
| 290 | { | 309 | { |
| 291 | int err = 0; | 310 | return sysv_write_inode(inode, 1); |
| 292 | struct buffer_head *bh; | ||
| 293 | |||
| 294 | bh = sysv_update_inode(inode); | ||
| 295 | if (bh && buffer_dirty(bh)) { | ||
| 296 | sync_dirty_buffer(bh); | ||
| 297 | if (buffer_req(bh) && !buffer_uptodate(bh)) { | ||
| 298 | printk ("IO error syncing sysv inode [%s:%08lx]\n", | ||
| 299 | inode->i_sb->s_id, inode->i_ino); | ||
| 300 | err = -1; | ||
| 301 | } | ||
| 302 | } | ||
| 303 | else if (!bh) | ||
| 304 | err = -1; | ||
| 305 | brelse (bh); | ||
| 306 | return err; | ||
| 307 | } | 311 | } |
| 308 | 312 | ||
| 309 | static void sysv_delete_inode(struct inode *inode) | 313 | static void sysv_delete_inode(struct inode *inode) |
| @@ -347,6 +351,7 @@ const struct super_operations sysv_sops = { | |||
| 347 | .delete_inode = sysv_delete_inode, | 351 | .delete_inode = sysv_delete_inode, |
| 348 | .put_super = sysv_put_super, | 352 | .put_super = sysv_put_super, |
| 349 | .write_super = sysv_write_super, | 353 | .write_super = sysv_write_super, |
| 354 | .sync_fs = sysv_sync_fs, | ||
| 350 | .remount_fs = sysv_remount, | 355 | .remount_fs = sysv_remount, |
| 351 | .statfs = sysv_statfs, | 356 | .statfs = sysv_statfs, |
| 352 | }; | 357 | }; |
diff --git a/fs/sysv/sysv.h b/fs/sysv/sysv.h index 5784a318c883..53786eb5cf60 100644 --- a/fs/sysv/sysv.h +++ b/fs/sysv/sysv.h | |||
| @@ -144,7 +144,6 @@ extern int __sysv_write_begin(struct file *file, struct address_space *mapping, | |||
| 144 | extern struct inode *sysv_iget(struct super_block *, unsigned int); | 144 | extern struct inode *sysv_iget(struct super_block *, unsigned int); |
| 145 | extern int sysv_write_inode(struct inode *, int); | 145 | extern int sysv_write_inode(struct inode *, int); |
| 146 | extern int sysv_sync_inode(struct inode *); | 146 | extern int sysv_sync_inode(struct inode *); |
| 147 | extern int sysv_sync_file(struct file *, struct dentry *, int); | ||
| 148 | extern void sysv_set_inode(struct inode *, dev_t); | 147 | extern void sysv_set_inode(struct inode *, dev_t); |
| 149 | extern int sysv_getattr(struct vfsmount *, struct dentry *, struct kstat *); | 148 | extern int sysv_getattr(struct vfsmount *, struct dentry *, struct kstat *); |
| 150 | extern int sysv_init_icache(void); | 149 | extern int sysv_init_icache(void); |
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index e9f7a754c4f7..3589eab02a2f 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c | |||
| @@ -36,6 +36,7 @@ | |||
| 36 | #include <linux/mount.h> | 36 | #include <linux/mount.h> |
| 37 | #include <linux/math64.h> | 37 | #include <linux/math64.h> |
| 38 | #include <linux/writeback.h> | 38 | #include <linux/writeback.h> |
| 39 | #include <linux/smp_lock.h> | ||
| 39 | #include "ubifs.h" | 40 | #include "ubifs.h" |
| 40 | 41 | ||
| 41 | /* | 42 | /* |
| @@ -447,9 +448,6 @@ static int ubifs_sync_fs(struct super_block *sb, int wait) | |||
| 447 | if (!wait) | 448 | if (!wait) |
| 448 | return 0; | 449 | return 0; |
| 449 | 450 | ||
| 450 | if (sb->s_flags & MS_RDONLY) | ||
| 451 | return 0; | ||
| 452 | |||
| 453 | /* | 451 | /* |
| 454 | * VFS calls '->sync_fs()' before synchronizing all dirty inodes and | 452 | * VFS calls '->sync_fs()' before synchronizing all dirty inodes and |
| 455 | * pages, so synchronize them first, then commit the journal. Strictly | 453 | * pages, so synchronize them first, then commit the journal. Strictly |
| @@ -1687,6 +1685,9 @@ static void ubifs_put_super(struct super_block *sb) | |||
| 1687 | 1685 | ||
| 1688 | ubifs_msg("un-mount UBI device %d, volume %d", c->vi.ubi_num, | 1686 | ubifs_msg("un-mount UBI device %d, volume %d", c->vi.ubi_num, |
| 1689 | c->vi.vol_id); | 1687 | c->vi.vol_id); |
| 1688 | |||
| 1689 | lock_kernel(); | ||
| 1690 | |||
| 1690 | /* | 1691 | /* |
| 1691 | * The following asserts are only valid if there has not been a failure | 1692 | * The following asserts are only valid if there has not been a failure |
| 1692 | * of the media. For example, there will be dirty inodes if we failed | 1693 | * of the media. For example, there will be dirty inodes if we failed |
| @@ -1753,6 +1754,8 @@ static void ubifs_put_super(struct super_block *sb) | |||
| 1753 | ubi_close_volume(c->ubi); | 1754 | ubi_close_volume(c->ubi); |
| 1754 | mutex_unlock(&c->umount_mutex); | 1755 | mutex_unlock(&c->umount_mutex); |
| 1755 | kfree(c); | 1756 | kfree(c); |
| 1757 | |||
| 1758 | unlock_kernel(); | ||
| 1756 | } | 1759 | } |
| 1757 | 1760 | ||
| 1758 | static int ubifs_remount_fs(struct super_block *sb, int *flags, char *data) | 1761 | static int ubifs_remount_fs(struct super_block *sb, int *flags, char *data) |
| @@ -1768,17 +1771,22 @@ static int ubifs_remount_fs(struct super_block *sb, int *flags, char *data) | |||
| 1768 | return err; | 1771 | return err; |
| 1769 | } | 1772 | } |
| 1770 | 1773 | ||
| 1774 | lock_kernel(); | ||
| 1771 | if ((sb->s_flags & MS_RDONLY) && !(*flags & MS_RDONLY)) { | 1775 | if ((sb->s_flags & MS_RDONLY) && !(*flags & MS_RDONLY)) { |
| 1772 | if (c->ro_media) { | 1776 | if (c->ro_media) { |
| 1773 | ubifs_msg("cannot re-mount due to prior errors"); | 1777 | ubifs_msg("cannot re-mount due to prior errors"); |
| 1778 | unlock_kernel(); | ||
| 1774 | return -EROFS; | 1779 | return -EROFS; |
| 1775 | } | 1780 | } |
| 1776 | err = ubifs_remount_rw(c); | 1781 | err = ubifs_remount_rw(c); |
| 1777 | if (err) | 1782 | if (err) { |
| 1783 | unlock_kernel(); | ||
| 1778 | return err; | 1784 | return err; |
| 1785 | } | ||
| 1779 | } else if (!(sb->s_flags & MS_RDONLY) && (*flags & MS_RDONLY)) { | 1786 | } else if (!(sb->s_flags & MS_RDONLY) && (*flags & MS_RDONLY)) { |
| 1780 | if (c->ro_media) { | 1787 | if (c->ro_media) { |
| 1781 | ubifs_msg("cannot re-mount due to prior errors"); | 1788 | ubifs_msg("cannot re-mount due to prior errors"); |
| 1789 | unlock_kernel(); | ||
| 1782 | return -EROFS; | 1790 | return -EROFS; |
| 1783 | } | 1791 | } |
| 1784 | ubifs_remount_ro(c); | 1792 | ubifs_remount_ro(c); |
| @@ -1793,6 +1801,7 @@ static int ubifs_remount_fs(struct super_block *sb, int *flags, char *data) | |||
| 1793 | } | 1801 | } |
| 1794 | 1802 | ||
| 1795 | ubifs_assert(c->lst.taken_empty_lebs > 0); | 1803 | ubifs_assert(c->lst.taken_empty_lebs > 0); |
| 1804 | unlock_kernel(); | ||
| 1796 | return 0; | 1805 | return 0; |
| 1797 | } | 1806 | } |
| 1798 | 1807 | ||
diff --git a/fs/udf/Makefile b/fs/udf/Makefile index 0d4503f7446d..eb880f66c23a 100644 --- a/fs/udf/Makefile +++ b/fs/udf/Makefile | |||
| @@ -5,5 +5,5 @@ | |||
| 5 | obj-$(CONFIG_UDF_FS) += udf.o | 5 | obj-$(CONFIG_UDF_FS) += udf.o |
| 6 | 6 | ||
| 7 | udf-objs := balloc.o dir.o file.o ialloc.o inode.o lowlevel.o namei.o \ | 7 | udf-objs := balloc.o dir.o file.o ialloc.o inode.o lowlevel.o namei.o \ |
| 8 | partition.o super.o truncate.o symlink.o fsync.o \ | 8 | partition.o super.o truncate.o symlink.o \ |
| 9 | directory.o misc.o udftime.o unicode.o | 9 | directory.o misc.o udftime.o unicode.o |
diff --git a/fs/udf/dir.c b/fs/udf/dir.c index 2efd4d5291b6..61d9a76a3a69 100644 --- a/fs/udf/dir.c +++ b/fs/udf/dir.c | |||
| @@ -210,5 +210,5 @@ const struct file_operations udf_dir_operations = { | |||
| 210 | .read = generic_read_dir, | 210 | .read = generic_read_dir, |
| 211 | .readdir = udf_readdir, | 211 | .readdir = udf_readdir, |
| 212 | .ioctl = udf_ioctl, | 212 | .ioctl = udf_ioctl, |
| 213 | .fsync = udf_fsync_file, | 213 | .fsync = simple_fsync, |
| 214 | }; | 214 | }; |
diff --git a/fs/udf/file.c b/fs/udf/file.c index eb91f3b70320..7464305382b5 100644 --- a/fs/udf/file.c +++ b/fs/udf/file.c | |||
| @@ -209,7 +209,7 @@ const struct file_operations udf_file_operations = { | |||
| 209 | .write = do_sync_write, | 209 | .write = do_sync_write, |
| 210 | .aio_write = udf_file_aio_write, | 210 | .aio_write = udf_file_aio_write, |
| 211 | .release = udf_release_file, | 211 | .release = udf_release_file, |
| 212 | .fsync = udf_fsync_file, | 212 | .fsync = simple_fsync, |
| 213 | .splice_read = generic_file_splice_read, | 213 | .splice_read = generic_file_splice_read, |
| 214 | .llseek = generic_file_llseek, | 214 | .llseek = generic_file_llseek, |
| 215 | }; | 215 | }; |
diff --git a/fs/udf/fsync.c b/fs/udf/fsync.c deleted file mode 100644 index b2c472b733b8..000000000000 --- a/fs/udf/fsync.c +++ /dev/null | |||
| @@ -1,52 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * fsync.c | ||
| 3 | * | ||
| 4 | * PURPOSE | ||
| 5 | * Fsync handling routines for the OSTA-UDF(tm) filesystem. | ||
| 6 | * | ||
| 7 | * COPYRIGHT | ||
| 8 | * This file is distributed under the terms of the GNU General Public | ||
| 9 | * License (GPL). Copies of the GPL can be obtained from: | ||
| 10 | * ftp://prep.ai.mit.edu/pub/gnu/GPL | ||
| 11 | * Each contributing author retains all rights to their own work. | ||
| 12 | * | ||
| 13 | * (C) 1999-2001 Ben Fennema | ||
| 14 | * (C) 1999-2000 Stelias Computing Inc | ||
| 15 | * | ||
| 16 | * HISTORY | ||
| 17 | * | ||
| 18 | * 05/22/99 blf Created. | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include "udfdecl.h" | ||
| 22 | |||
| 23 | #include <linux/fs.h> | ||
| 24 | |||
| 25 | static int udf_fsync_inode(struct inode *, int); | ||
| 26 | |||
| 27 | /* | ||
| 28 | * File may be NULL when we are called. Perhaps we shouldn't | ||
| 29 | * even pass file to fsync ? | ||
| 30 | */ | ||
| 31 | |||
| 32 | int udf_fsync_file(struct file *file, struct dentry *dentry, int datasync) | ||
| 33 | { | ||
| 34 | struct inode *inode = dentry->d_inode; | ||
| 35 | |||
| 36 | return udf_fsync_inode(inode, datasync); | ||
| 37 | } | ||
| 38 | |||
| 39 | static int udf_fsync_inode(struct inode *inode, int datasync) | ||
| 40 | { | ||
| 41 | int err; | ||
| 42 | |||
| 43 | err = sync_mapping_buffers(inode->i_mapping); | ||
| 44 | if (!(inode->i_state & I_DIRTY)) | ||
| 45 | return err; | ||
| 46 | if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) | ||
| 47 | return err; | ||
| 48 | |||
| 49 | err |= udf_sync_inode(inode); | ||
| 50 | |||
| 51 | return err ? -EIO : 0; | ||
| 52 | } | ||
diff --git a/fs/udf/super.c b/fs/udf/super.c index 0ba44107d8f1..6832135159b6 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c | |||
| @@ -568,6 +568,7 @@ static int udf_remount_fs(struct super_block *sb, int *flags, char *options) | |||
| 568 | if (!udf_parse_options(options, &uopt, true)) | 568 | if (!udf_parse_options(options, &uopt, true)) |
| 569 | return -EINVAL; | 569 | return -EINVAL; |
| 570 | 570 | ||
| 571 | lock_kernel(); | ||
| 571 | sbi->s_flags = uopt.flags; | 572 | sbi->s_flags = uopt.flags; |
| 572 | sbi->s_uid = uopt.uid; | 573 | sbi->s_uid = uopt.uid; |
| 573 | sbi->s_gid = uopt.gid; | 574 | sbi->s_gid = uopt.gid; |
| @@ -581,13 +582,16 @@ static int udf_remount_fs(struct super_block *sb, int *flags, char *options) | |||
| 581 | *flags |= MS_RDONLY; | 582 | *flags |= MS_RDONLY; |
| 582 | } | 583 | } |
| 583 | 584 | ||
| 584 | if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) | 585 | if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) { |
| 586 | unlock_kernel(); | ||
| 585 | return 0; | 587 | return 0; |
| 588 | } | ||
| 586 | if (*flags & MS_RDONLY) | 589 | if (*flags & MS_RDONLY) |
| 587 | udf_close_lvid(sb); | 590 | udf_close_lvid(sb); |
| 588 | else | 591 | else |
| 589 | udf_open_lvid(sb); | 592 | udf_open_lvid(sb); |
| 590 | 593 | ||
| 594 | unlock_kernel(); | ||
| 591 | return 0; | 595 | return 0; |
| 592 | } | 596 | } |
| 593 | 597 | ||
| @@ -2062,6 +2066,9 @@ static void udf_put_super(struct super_block *sb) | |||
| 2062 | struct udf_sb_info *sbi; | 2066 | struct udf_sb_info *sbi; |
| 2063 | 2067 | ||
| 2064 | sbi = UDF_SB(sb); | 2068 | sbi = UDF_SB(sb); |
| 2069 | |||
| 2070 | lock_kernel(); | ||
| 2071 | |||
| 2065 | if (sbi->s_vat_inode) | 2072 | if (sbi->s_vat_inode) |
| 2066 | iput(sbi->s_vat_inode); | 2073 | iput(sbi->s_vat_inode); |
| 2067 | if (sbi->s_partitions) | 2074 | if (sbi->s_partitions) |
| @@ -2077,6 +2084,8 @@ static void udf_put_super(struct super_block *sb) | |||
| 2077 | kfree(sbi->s_partmaps); | 2084 | kfree(sbi->s_partmaps); |
| 2078 | kfree(sb->s_fs_info); | 2085 | kfree(sb->s_fs_info); |
| 2079 | sb->s_fs_info = NULL; | 2086 | sb->s_fs_info = NULL; |
| 2087 | |||
| 2088 | unlock_kernel(); | ||
| 2080 | } | 2089 | } |
| 2081 | 2090 | ||
| 2082 | static int udf_sync_fs(struct super_block *sb, int wait) | 2091 | static int udf_sync_fs(struct super_block *sb, int wait) |
diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h index cac51b77a5d1..8d46f4294ee7 100644 --- a/fs/udf/udfdecl.h +++ b/fs/udf/udfdecl.h | |||
| @@ -223,9 +223,6 @@ extern int udf_prealloc_blocks(struct super_block *, struct inode *, uint16_t, | |||
| 223 | extern int udf_new_block(struct super_block *, struct inode *, uint16_t, | 223 | extern int udf_new_block(struct super_block *, struct inode *, uint16_t, |
| 224 | uint32_t, int *); | 224 | uint32_t, int *); |
| 225 | 225 | ||
| 226 | /* fsync.c */ | ||
| 227 | extern int udf_fsync_file(struct file *, struct dentry *, int); | ||
| 228 | |||
| 229 | /* directory.c */ | 226 | /* directory.c */ |
| 230 | extern struct fileIdentDesc *udf_fileident_read(struct inode *, loff_t *, | 227 | extern struct fileIdentDesc *udf_fileident_read(struct inode *, loff_t *, |
| 231 | struct udf_fileident_bh *, | 228 | struct udf_fileident_bh *, |
diff --git a/fs/ufs/dir.c b/fs/ufs/dir.c index 6321b797061b..6f671f1ac271 100644 --- a/fs/ufs/dir.c +++ b/fs/ufs/dir.c | |||
| @@ -666,6 +666,6 @@ not_empty: | |||
| 666 | const struct file_operations ufs_dir_operations = { | 666 | const struct file_operations ufs_dir_operations = { |
| 667 | .read = generic_read_dir, | 667 | .read = generic_read_dir, |
| 668 | .readdir = ufs_readdir, | 668 | .readdir = ufs_readdir, |
| 669 | .fsync = ufs_sync_file, | 669 | .fsync = simple_fsync, |
| 670 | .llseek = generic_file_llseek, | 670 | .llseek = generic_file_llseek, |
| 671 | }; | 671 | }; |
diff --git a/fs/ufs/file.c b/fs/ufs/file.c index 2bd3a1615714..73655c61240a 100644 --- a/fs/ufs/file.c +++ b/fs/ufs/file.c | |||
| @@ -24,31 +24,10 @@ | |||
| 24 | */ | 24 | */ |
| 25 | 25 | ||
| 26 | #include <linux/fs.h> | 26 | #include <linux/fs.h> |
| 27 | #include <linux/buffer_head.h> /* for sync_mapping_buffers() */ | ||
| 28 | 27 | ||
| 29 | #include "ufs_fs.h" | 28 | #include "ufs_fs.h" |
| 30 | #include "ufs.h" | 29 | #include "ufs.h" |
| 31 | 30 | ||
| 32 | |||
| 33 | int ufs_sync_file(struct file *file, struct dentry *dentry, int datasync) | ||
| 34 | { | ||
| 35 | struct inode *inode = dentry->d_inode; | ||
| 36 | int err; | ||
| 37 | int ret; | ||
| 38 | |||
| 39 | ret = sync_mapping_buffers(inode->i_mapping); | ||
| 40 | if (!(inode->i_state & I_DIRTY)) | ||
| 41 | return ret; | ||
| 42 | if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) | ||
| 43 | return ret; | ||
| 44 | |||
| 45 | err = ufs_sync_inode(inode); | ||
| 46 | if (ret == 0) | ||
| 47 | ret = err; | ||
| 48 | return ret; | ||
| 49 | } | ||
| 50 | |||
| 51 | |||
| 52 | /* | 31 | /* |
| 53 | * We have mostly NULL's here: the current defaults are ok for | 32 | * We have mostly NULL's here: the current defaults are ok for |
| 54 | * the ufs filesystem. | 33 | * the ufs filesystem. |
| @@ -62,6 +41,6 @@ const struct file_operations ufs_file_operations = { | |||
| 62 | .aio_write = generic_file_aio_write, | 41 | .aio_write = generic_file_aio_write, |
| 63 | .mmap = generic_file_mmap, | 42 | .mmap = generic_file_mmap, |
| 64 | .open = generic_file_open, | 43 | .open = generic_file_open, |
| 65 | .fsync = ufs_sync_file, | 44 | .fsync = simple_fsync, |
| 66 | .splice_read = generic_file_splice_read, | 45 | .splice_read = generic_file_splice_read, |
| 67 | }; | 46 | }; |
diff --git a/fs/ufs/super.c b/fs/ufs/super.c index 60359291761f..5faed7954d0a 100644 --- a/fs/ufs/super.c +++ b/fs/ufs/super.c | |||
| @@ -263,6 +263,7 @@ void ufs_panic (struct super_block * sb, const char * function, | |||
| 263 | struct ufs_super_block_first * usb1; | 263 | struct ufs_super_block_first * usb1; |
| 264 | va_list args; | 264 | va_list args; |
| 265 | 265 | ||
| 266 | lock_kernel(); | ||
| 266 | uspi = UFS_SB(sb)->s_uspi; | 267 | uspi = UFS_SB(sb)->s_uspi; |
| 267 | usb1 = ubh_get_usb_first(uspi); | 268 | usb1 = ubh_get_usb_first(uspi); |
| 268 | 269 | ||
| @@ -594,6 +595,9 @@ static void ufs_put_super_internal(struct super_block *sb) | |||
| 594 | 595 | ||
| 595 | 596 | ||
| 596 | UFSD("ENTER\n"); | 597 | UFSD("ENTER\n"); |
| 598 | |||
| 599 | lock_kernel(); | ||
| 600 | |||
| 597 | ufs_put_cstotal(sb); | 601 | ufs_put_cstotal(sb); |
| 598 | size = uspi->s_cssize; | 602 | size = uspi->s_cssize; |
| 599 | blks = (size + uspi->s_fsize - 1) >> uspi->s_fshift; | 603 | blks = (size + uspi->s_fsize - 1) >> uspi->s_fshift; |
| @@ -621,6 +625,9 @@ static void ufs_put_super_internal(struct super_block *sb) | |||
| 621 | brelse (sbi->s_ucg[i]); | 625 | brelse (sbi->s_ucg[i]); |
| 622 | kfree (sbi->s_ucg); | 626 | kfree (sbi->s_ucg); |
| 623 | kfree (base); | 627 | kfree (base); |
| 628 | |||
| 629 | unlock_kernel(); | ||
| 630 | |||
| 624 | UFSD("EXIT\n"); | 631 | UFSD("EXIT\n"); |
| 625 | } | 632 | } |
| 626 | 633 | ||
| @@ -1118,32 +1125,45 @@ failed_nomem: | |||
| 1118 | return -ENOMEM; | 1125 | return -ENOMEM; |
| 1119 | } | 1126 | } |
| 1120 | 1127 | ||
| 1121 | static void ufs_write_super(struct super_block *sb) | 1128 | static int ufs_sync_fs(struct super_block *sb, int wait) |
| 1122 | { | 1129 | { |
| 1123 | struct ufs_sb_private_info * uspi; | 1130 | struct ufs_sb_private_info * uspi; |
| 1124 | struct ufs_super_block_first * usb1; | 1131 | struct ufs_super_block_first * usb1; |
| 1125 | struct ufs_super_block_third * usb3; | 1132 | struct ufs_super_block_third * usb3; |
| 1126 | unsigned flags; | 1133 | unsigned flags; |
| 1127 | 1134 | ||
| 1135 | lock_super(sb); | ||
| 1128 | lock_kernel(); | 1136 | lock_kernel(); |
| 1137 | |||
| 1129 | UFSD("ENTER\n"); | 1138 | UFSD("ENTER\n"); |
| 1139 | |||
| 1130 | flags = UFS_SB(sb)->s_flags; | 1140 | flags = UFS_SB(sb)->s_flags; |
| 1131 | uspi = UFS_SB(sb)->s_uspi; | 1141 | uspi = UFS_SB(sb)->s_uspi; |
| 1132 | usb1 = ubh_get_usb_first(uspi); | 1142 | usb1 = ubh_get_usb_first(uspi); |
| 1133 | usb3 = ubh_get_usb_third(uspi); | 1143 | usb3 = ubh_get_usb_third(uspi); |
| 1134 | 1144 | ||
| 1135 | if (!(sb->s_flags & MS_RDONLY)) { | 1145 | usb1->fs_time = cpu_to_fs32(sb, get_seconds()); |
| 1136 | usb1->fs_time = cpu_to_fs32(sb, get_seconds()); | 1146 | if ((flags & UFS_ST_MASK) == UFS_ST_SUN || |
| 1137 | if ((flags & UFS_ST_MASK) == UFS_ST_SUN | 1147 | (flags & UFS_ST_MASK) == UFS_ST_SUNOS || |
| 1138 | || (flags & UFS_ST_MASK) == UFS_ST_SUNOS | 1148 | (flags & UFS_ST_MASK) == UFS_ST_SUNx86) |
| 1139 | || (flags & UFS_ST_MASK) == UFS_ST_SUNx86) | 1149 | ufs_set_fs_state(sb, usb1, usb3, |
| 1140 | ufs_set_fs_state(sb, usb1, usb3, | 1150 | UFS_FSOK - fs32_to_cpu(sb, usb1->fs_time)); |
| 1141 | UFS_FSOK - fs32_to_cpu(sb, usb1->fs_time)); | 1151 | ufs_put_cstotal(sb); |
| 1142 | ufs_put_cstotal(sb); | ||
| 1143 | } | ||
| 1144 | sb->s_dirt = 0; | 1152 | sb->s_dirt = 0; |
| 1153 | |||
| 1145 | UFSD("EXIT\n"); | 1154 | UFSD("EXIT\n"); |
| 1146 | unlock_kernel(); | 1155 | unlock_kernel(); |
| 1156 | unlock_super(sb); | ||
| 1157 | |||
| 1158 | return 0; | ||
| 1159 | } | ||
| 1160 | |||
| 1161 | static void ufs_write_super(struct super_block *sb) | ||
| 1162 | { | ||
| 1163 | if (!(sb->s_flags & MS_RDONLY)) | ||
| 1164 | ufs_sync_fs(sb, 1); | ||
| 1165 | else | ||
| 1166 | sb->s_dirt = 0; | ||
| 1147 | } | 1167 | } |
| 1148 | 1168 | ||
| 1149 | static void ufs_put_super(struct super_block *sb) | 1169 | static void ufs_put_super(struct super_block *sb) |
| @@ -1152,6 +1172,9 @@ static void ufs_put_super(struct super_block *sb) | |||
| 1152 | 1172 | ||
| 1153 | UFSD("ENTER\n"); | 1173 | UFSD("ENTER\n"); |
| 1154 | 1174 | ||
| 1175 | if (sb->s_dirt) | ||
| 1176 | ufs_write_super(sb); | ||
| 1177 | |||
| 1155 | if (!(sb->s_flags & MS_RDONLY)) | 1178 | if (!(sb->s_flags & MS_RDONLY)) |
| 1156 | ufs_put_super_internal(sb); | 1179 | ufs_put_super_internal(sb); |
| 1157 | 1180 | ||
| @@ -1171,7 +1194,9 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data) | |||
| 1171 | struct ufs_super_block_third * usb3; | 1194 | struct ufs_super_block_third * usb3; |
| 1172 | unsigned new_mount_opt, ufstype; | 1195 | unsigned new_mount_opt, ufstype; |
| 1173 | unsigned flags; | 1196 | unsigned flags; |
| 1174 | 1197 | ||
| 1198 | lock_kernel(); | ||
| 1199 | lock_super(sb); | ||
| 1175 | uspi = UFS_SB(sb)->s_uspi; | 1200 | uspi = UFS_SB(sb)->s_uspi; |
| 1176 | flags = UFS_SB(sb)->s_flags; | 1201 | flags = UFS_SB(sb)->s_flags; |
| 1177 | usb1 = ubh_get_usb_first(uspi); | 1202 | usb1 = ubh_get_usb_first(uspi); |
| @@ -1184,17 +1209,24 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data) | |||
| 1184 | ufstype = UFS_SB(sb)->s_mount_opt & UFS_MOUNT_UFSTYPE; | 1209 | ufstype = UFS_SB(sb)->s_mount_opt & UFS_MOUNT_UFSTYPE; |
| 1185 | new_mount_opt = 0; | 1210 | new_mount_opt = 0; |
| 1186 | ufs_set_opt (new_mount_opt, ONERROR_LOCK); | 1211 | ufs_set_opt (new_mount_opt, ONERROR_LOCK); |
| 1187 | if (!ufs_parse_options (data, &new_mount_opt)) | 1212 | if (!ufs_parse_options (data, &new_mount_opt)) { |
| 1213 | unlock_super(sb); | ||
| 1214 | unlock_kernel(); | ||
| 1188 | return -EINVAL; | 1215 | return -EINVAL; |
| 1216 | } | ||
| 1189 | if (!(new_mount_opt & UFS_MOUNT_UFSTYPE)) { | 1217 | if (!(new_mount_opt & UFS_MOUNT_UFSTYPE)) { |
| 1190 | new_mount_opt |= ufstype; | 1218 | new_mount_opt |= ufstype; |
| 1191 | } else if ((new_mount_opt & UFS_MOUNT_UFSTYPE) != ufstype) { | 1219 | } else if ((new_mount_opt & UFS_MOUNT_UFSTYPE) != ufstype) { |
| 1192 | printk("ufstype can't be changed during remount\n"); | 1220 | printk("ufstype can't be changed during remount\n"); |
| 1221 | unlock_super(sb); | ||
| 1222 | unlock_kernel(); | ||
| 1193 | return -EINVAL; | 1223 | return -EINVAL; |
| 1194 | } | 1224 | } |
| 1195 | 1225 | ||
| 1196 | if ((*mount_flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) { | 1226 | if ((*mount_flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) { |
| 1197 | UFS_SB(sb)->s_mount_opt = new_mount_opt; | 1227 | UFS_SB(sb)->s_mount_opt = new_mount_opt; |
| 1228 | unlock_super(sb); | ||
| 1229 | unlock_kernel(); | ||
| 1198 | return 0; | 1230 | return 0; |
| 1199 | } | 1231 | } |
| 1200 | 1232 | ||
| @@ -1219,6 +1251,8 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data) | |||
| 1219 | #ifndef CONFIG_UFS_FS_WRITE | 1251 | #ifndef CONFIG_UFS_FS_WRITE |
| 1220 | printk("ufs was compiled with read-only support, " | 1252 | printk("ufs was compiled with read-only support, " |
| 1221 | "can't be mounted as read-write\n"); | 1253 | "can't be mounted as read-write\n"); |
| 1254 | unlock_super(sb); | ||
| 1255 | unlock_kernel(); | ||
| 1222 | return -EINVAL; | 1256 | return -EINVAL; |
| 1223 | #else | 1257 | #else |
| 1224 | if (ufstype != UFS_MOUNT_UFSTYPE_SUN && | 1258 | if (ufstype != UFS_MOUNT_UFSTYPE_SUN && |
| @@ -1227,16 +1261,22 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data) | |||
| 1227 | ufstype != UFS_MOUNT_UFSTYPE_SUNx86 && | 1261 | ufstype != UFS_MOUNT_UFSTYPE_SUNx86 && |
| 1228 | ufstype != UFS_MOUNT_UFSTYPE_UFS2) { | 1262 | ufstype != UFS_MOUNT_UFSTYPE_UFS2) { |
| 1229 | printk("this ufstype is read-only supported\n"); | 1263 | printk("this ufstype is read-only supported\n"); |
| 1264 | unlock_super(sb); | ||
| 1265 | unlock_kernel(); | ||
| 1230 | return -EINVAL; | 1266 | return -EINVAL; |
| 1231 | } | 1267 | } |
| 1232 | if (!ufs_read_cylinder_structures(sb)) { | 1268 | if (!ufs_read_cylinder_structures(sb)) { |
| 1233 | printk("failed during remounting\n"); | 1269 | printk("failed during remounting\n"); |
| 1270 | unlock_super(sb); | ||
| 1271 | unlock_kernel(); | ||
| 1234 | return -EPERM; | 1272 | return -EPERM; |
| 1235 | } | 1273 | } |
| 1236 | sb->s_flags &= ~MS_RDONLY; | 1274 | sb->s_flags &= ~MS_RDONLY; |
| 1237 | #endif | 1275 | #endif |
| 1238 | } | 1276 | } |
| 1239 | UFS_SB(sb)->s_mount_opt = new_mount_opt; | 1277 | UFS_SB(sb)->s_mount_opt = new_mount_opt; |
| 1278 | unlock_super(sb); | ||
| 1279 | unlock_kernel(); | ||
| 1240 | return 0; | 1280 | return 0; |
| 1241 | } | 1281 | } |
| 1242 | 1282 | ||
| @@ -1352,6 +1392,7 @@ static const struct super_operations ufs_super_ops = { | |||
| 1352 | .delete_inode = ufs_delete_inode, | 1392 | .delete_inode = ufs_delete_inode, |
| 1353 | .put_super = ufs_put_super, | 1393 | .put_super = ufs_put_super, |
| 1354 | .write_super = ufs_write_super, | 1394 | .write_super = ufs_write_super, |
| 1395 | .sync_fs = ufs_sync_fs, | ||
| 1355 | .statfs = ufs_statfs, | 1396 | .statfs = ufs_statfs, |
| 1356 | .remount_fs = ufs_remount, | 1397 | .remount_fs = ufs_remount, |
| 1357 | .show_options = ufs_show_options, | 1398 | .show_options = ufs_show_options, |
diff --git a/fs/ufs/ufs.h b/fs/ufs/ufs.h index d0c4acd4f1f3..644e77e13599 100644 --- a/fs/ufs/ufs.h +++ b/fs/ufs/ufs.h | |||
| @@ -99,7 +99,6 @@ extern void ufs_set_link(struct inode *dir, struct ufs_dir_entry *de, | |||
| 99 | extern const struct inode_operations ufs_file_inode_operations; | 99 | extern const struct inode_operations ufs_file_inode_operations; |
| 100 | extern const struct file_operations ufs_file_operations; | 100 | extern const struct file_operations ufs_file_operations; |
| 101 | extern const struct address_space_operations ufs_aops; | 101 | extern const struct address_space_operations ufs_aops; |
| 102 | extern int ufs_sync_file(struct file *, struct dentry *, int); | ||
| 103 | 102 | ||
| 104 | /* ialloc.c */ | 103 | /* ialloc.c */ |
| 105 | extern void ufs_free_inode (struct inode *inode); | 104 | extern void ufs_free_inode (struct inode *inode); |
diff --git a/fs/xattr.c b/fs/xattr.c index d51b8f9db921..1c3d0af59ddf 100644 --- a/fs/xattr.c +++ b/fs/xattr.c | |||
| @@ -297,7 +297,7 @@ SYSCALL_DEFINE5(fsetxattr, int, fd, const char __user *, name, | |||
| 297 | return error; | 297 | return error; |
| 298 | dentry = f->f_path.dentry; | 298 | dentry = f->f_path.dentry; |
| 299 | audit_inode(NULL, dentry); | 299 | audit_inode(NULL, dentry); |
| 300 | error = mnt_want_write(f->f_path.mnt); | 300 | error = mnt_want_write_file(f); |
| 301 | if (!error) { | 301 | if (!error) { |
| 302 | error = setxattr(dentry, name, value, size, flags); | 302 | error = setxattr(dentry, name, value, size, flags); |
| 303 | mnt_drop_write(f->f_path.mnt); | 303 | mnt_drop_write(f->f_path.mnt); |
| @@ -524,7 +524,7 @@ SYSCALL_DEFINE2(fremovexattr, int, fd, const char __user *, name) | |||
| 524 | return error; | 524 | return error; |
| 525 | dentry = f->f_path.dentry; | 525 | dentry = f->f_path.dentry; |
| 526 | audit_inode(NULL, dentry); | 526 | audit_inode(NULL, dentry); |
| 527 | error = mnt_want_write(f->f_path.mnt); | 527 | error = mnt_want_write_file(f); |
| 528 | if (!error) { | 528 | if (!error) { |
| 529 | error = removexattr(dentry, name); | 529 | error = removexattr(dentry, name); |
| 530 | mnt_drop_write(f->f_path.mnt); | 530 | mnt_drop_write(f->f_path.mnt); |
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index bb685269f832..08d6bd9a3947 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c | |||
| @@ -1104,15 +1104,6 @@ xfs_fs_put_super( | |||
| 1104 | kfree(mp); | 1104 | kfree(mp); |
| 1105 | } | 1105 | } |
| 1106 | 1106 | ||
| 1107 | STATIC void | ||
| 1108 | xfs_fs_write_super( | ||
| 1109 | struct super_block *sb) | ||
| 1110 | { | ||
| 1111 | if (!(sb->s_flags & MS_RDONLY)) | ||
| 1112 | xfs_sync_fsdata(XFS_M(sb), 0); | ||
| 1113 | sb->s_dirt = 0; | ||
| 1114 | } | ||
| 1115 | |||
| 1116 | STATIC int | 1107 | STATIC int |
| 1117 | xfs_fs_sync_super( | 1108 | xfs_fs_sync_super( |
| 1118 | struct super_block *sb, | 1109 | struct super_block *sb, |
| @@ -1137,7 +1128,6 @@ xfs_fs_sync_super( | |||
| 1137 | error = xfs_quiesce_data(mp); | 1128 | error = xfs_quiesce_data(mp); |
| 1138 | else | 1129 | else |
| 1139 | error = xfs_sync_fsdata(mp, 0); | 1130 | error = xfs_sync_fsdata(mp, 0); |
| 1140 | sb->s_dirt = 0; | ||
| 1141 | 1131 | ||
| 1142 | if (unlikely(laptop_mode)) { | 1132 | if (unlikely(laptop_mode)) { |
| 1143 | int prev_sync_seq = mp->m_sync_seq; | 1133 | int prev_sync_seq = mp->m_sync_seq; |
| @@ -1443,7 +1433,6 @@ xfs_fs_fill_super( | |||
| 1443 | 1433 | ||
| 1444 | XFS_SEND_MOUNT(mp, DM_RIGHT_NULL, mtpt, mp->m_fsname); | 1434 | XFS_SEND_MOUNT(mp, DM_RIGHT_NULL, mtpt, mp->m_fsname); |
| 1445 | 1435 | ||
| 1446 | sb->s_dirt = 1; | ||
| 1447 | sb->s_magic = XFS_SB_MAGIC; | 1436 | sb->s_magic = XFS_SB_MAGIC; |
| 1448 | sb->s_blocksize = mp->m_sb.sb_blocksize; | 1437 | sb->s_blocksize = mp->m_sb.sb_blocksize; |
| 1449 | sb->s_blocksize_bits = ffs(sb->s_blocksize) - 1; | 1438 | sb->s_blocksize_bits = ffs(sb->s_blocksize) - 1; |
| @@ -1533,7 +1522,6 @@ static struct super_operations xfs_super_operations = { | |||
| 1533 | .write_inode = xfs_fs_write_inode, | 1522 | .write_inode = xfs_fs_write_inode, |
| 1534 | .clear_inode = xfs_fs_clear_inode, | 1523 | .clear_inode = xfs_fs_clear_inode, |
| 1535 | .put_super = xfs_fs_put_super, | 1524 | .put_super = xfs_fs_put_super, |
| 1536 | .write_super = xfs_fs_write_super, | ||
| 1537 | .sync_fs = xfs_fs_sync_super, | 1525 | .sync_fs = xfs_fs_sync_super, |
| 1538 | .freeze_fs = xfs_fs_freeze, | 1526 | .freeze_fs = xfs_fs_freeze, |
| 1539 | .statfs = xfs_fs_statfs, | 1527 | .statfs = xfs_fs_statfs, |
diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c index 8570b826fedd..bcc39d358ad3 100644 --- a/fs/xfs/xfs_trans.c +++ b/fs/xfs/xfs_trans.c | |||
| @@ -628,8 +628,6 @@ xfs_trans_apply_sb_deltas( | |||
| 628 | xfs_trans_log_buf(tp, bp, offsetof(xfs_dsb_t, sb_icount), | 628 | xfs_trans_log_buf(tp, bp, offsetof(xfs_dsb_t, sb_icount), |
| 629 | offsetof(xfs_dsb_t, sb_frextents) + | 629 | offsetof(xfs_dsb_t, sb_frextents) + |
| 630 | sizeof(sbp->sb_frextents) - 1); | 630 | sizeof(sbp->sb_frextents) - 1); |
| 631 | |||
| 632 | tp->t_mountp->m_super->s_dirt = 1; | ||
| 633 | } | 631 | } |
| 634 | 632 | ||
| 635 | /* | 633 | /* |
