diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-11 23:05:37 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-11 23:05:37 -0400 |
commit | 4b4f1d017815f96737ca4a62f90e5a1f0b9f02d6 (patch) | |
tree | c95ae92ec01cabf6c2a40d31a31da6a4d9256816 | |
parent | 875287caa067492779670f5fb3b98ec8dcfe2cb0 (diff) | |
parent | aa7dfb8954ccf49e026ba13d12991a4eb7defb96 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6: (87 commits)
nilfs2: get rid of bd_mount_sem use from nilfs
nilfs2: correct exclusion control in nilfs_remount function
nilfs2: simplify remaining sget() use
nilfs2: get rid of sget use for checking if current mount is present
nilfs2: get rid of sget use for acquiring nilfs object
nilfs2: remove meaningless EBUSY case from nilfs_get_sb function
remove the call to ->write_super in __sync_filesystem
nilfs2: call nilfs2_write_super from nilfs2_sync_fs
jffs2: call jffs2_write_super from jffs2_sync_fs
ufs: add ->sync_fs
sysv: add ->sync_fs
hfsplus: add ->sync_fs
hfs: add ->sync_fs
fat: add ->sync_fs
ext2: add ->sync_fs
exofs: add ->sync_fs
bfs: add ->sync_fs
affs: add ->sync_fs
sanitize ->fsync() for affs
repair bfs_write_inode(), switch bfs to simple_fsync()
...
147 files changed, 1707 insertions, 1834 deletions
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index 42ee05981e71..9a3334ae282e 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c | |||
@@ -371,8 +371,6 @@ SYSCALL_DEFINE4(osf_mount, unsigned long, typenr, char __user *, path, | |||
371 | int retval = -EINVAL; | 371 | int retval = -EINVAL; |
372 | char *name; | 372 | char *name; |
373 | 373 | ||
374 | lock_kernel(); | ||
375 | |||
376 | name = getname(path); | 374 | name = getname(path); |
377 | retval = PTR_ERR(name); | 375 | retval = PTR_ERR(name); |
378 | if (IS_ERR(name)) | 376 | if (IS_ERR(name)) |
@@ -392,7 +390,6 @@ SYSCALL_DEFINE4(osf_mount, unsigned long, typenr, char __user *, path, | |||
392 | } | 390 | } |
393 | putname(name); | 391 | putname(name); |
394 | out: | 392 | out: |
395 | unlock_kernel(); | ||
396 | return retval; | 393 | return retval; |
397 | } | 394 | } |
398 | 395 | ||
diff --git a/drivers/ieee1394/dv1394.c b/drivers/ieee1394/dv1394.c index 823a6297a1af..2cd00b5b45b4 100644 --- a/drivers/ieee1394/dv1394.c +++ b/drivers/ieee1394/dv1394.c | |||
@@ -1789,12 +1789,13 @@ static int dv1394_open(struct inode *inode, struct file *file) | |||
1789 | } else { | 1789 | } else { |
1790 | /* look up the card by ID */ | 1790 | /* look up the card by ID */ |
1791 | unsigned long flags; | 1791 | unsigned long flags; |
1792 | int idx = ieee1394_file_to_instance(file); | ||
1792 | 1793 | ||
1793 | spin_lock_irqsave(&dv1394_cards_lock, flags); | 1794 | spin_lock_irqsave(&dv1394_cards_lock, flags); |
1794 | if (!list_empty(&dv1394_cards)) { | 1795 | if (!list_empty(&dv1394_cards)) { |
1795 | struct video_card *p; | 1796 | struct video_card *p; |
1796 | list_for_each_entry(p, &dv1394_cards, list) { | 1797 | list_for_each_entry(p, &dv1394_cards, list) { |
1797 | if ((p->id) == ieee1394_file_to_instance(file)) { | 1798 | if ((p->id) == idx) { |
1798 | video = p; | 1799 | video = p; |
1799 | break; | 1800 | break; |
1800 | } | 1801 | } |
@@ -1803,7 +1804,7 @@ static int dv1394_open(struct inode *inode, struct file *file) | |||
1803 | spin_unlock_irqrestore(&dv1394_cards_lock, flags); | 1804 | spin_unlock_irqrestore(&dv1394_cards_lock, flags); |
1804 | 1805 | ||
1805 | if (!video) { | 1806 | if (!video) { |
1806 | debug_printk("dv1394: OHCI card %d not found", ieee1394_file_to_instance(file)); | 1807 | debug_printk("dv1394: OHCI card %d not found", idx); |
1807 | return -ENODEV; | 1808 | return -ENODEV; |
1808 | } | 1809 | } |
1809 | 1810 | ||
diff --git a/drivers/ieee1394/ieee1394_core.h b/drivers/ieee1394/ieee1394_core.h index 21d50f73a210..28b9f58bafd2 100644 --- a/drivers/ieee1394/ieee1394_core.h +++ b/drivers/ieee1394/ieee1394_core.h | |||
@@ -5,6 +5,7 @@ | |||
5 | #include <linux/fs.h> | 5 | #include <linux/fs.h> |
6 | #include <linux/list.h> | 6 | #include <linux/list.h> |
7 | #include <linux/types.h> | 7 | #include <linux/types.h> |
8 | #include <linux/cdev.h> | ||
8 | #include <asm/atomic.h> | 9 | #include <asm/atomic.h> |
9 | 10 | ||
10 | #include "hosts.h" | 11 | #include "hosts.h" |
@@ -155,7 +156,10 @@ void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size, | |||
155 | */ | 156 | */ |
156 | static inline unsigned char ieee1394_file_to_instance(struct file *file) | 157 | static inline unsigned char ieee1394_file_to_instance(struct file *file) |
157 | { | 158 | { |
158 | return file->f_path.dentry->d_inode->i_cindex; | 159 | int idx = cdev_index(file->f_path.dentry->d_inode); |
160 | if (idx < 0) | ||
161 | idx = 0; | ||
162 | return idx; | ||
159 | } | 163 | } |
160 | 164 | ||
161 | extern int hpsb_disable_irm; | 165 | extern int hpsb_disable_irm; |
diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c index dff5760a37f6..ffe75e83787c 100644 --- a/drivers/usb/core/inode.c +++ b/drivers/usb/core/inode.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <linux/parser.h> | 39 | #include <linux/parser.h> |
40 | #include <linux/notifier.h> | 40 | #include <linux/notifier.h> |
41 | #include <linux/seq_file.h> | 41 | #include <linux/seq_file.h> |
42 | #include <linux/smp_lock.h> | ||
42 | #include <asm/byteorder.h> | 43 | #include <asm/byteorder.h> |
43 | #include "usb.h" | 44 | #include "usb.h" |
44 | #include "hcd.h" | 45 | #include "hcd.h" |
@@ -265,9 +266,13 @@ static int remount(struct super_block *sb, int *flags, char *data) | |||
265 | return -EINVAL; | 266 | return -EINVAL; |
266 | } | 267 | } |
267 | 268 | ||
269 | lock_kernel(); | ||
270 | |||
268 | if (usbfs_mount && usbfs_mount->mnt_sb) | 271 | if (usbfs_mount && usbfs_mount->mnt_sb) |
269 | update_sb(usbfs_mount->mnt_sb); | 272 | update_sb(usbfs_mount->mnt_sb); |
270 | 273 | ||
274 | unlock_kernel(); | ||
275 | |||
271 | return 0; | 276 | return 0; |
272 | } | 277 | } |
273 | 278 | ||
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 | /* |
diff --git a/include/linux/Kbuild b/include/linux/Kbuild index 3f0eaa397ef5..b3afd2219ad2 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild | |||
@@ -135,6 +135,7 @@ header-y += posix_types.h | |||
135 | header-y += ppdev.h | 135 | header-y += ppdev.h |
136 | header-y += prctl.h | 136 | header-y += prctl.h |
137 | header-y += qnxtypes.h | 137 | header-y += qnxtypes.h |
138 | header-y += qnx4_fs.h | ||
138 | header-y += radeonfb.h | 139 | header-y += radeonfb.h |
139 | header-y += raw.h | 140 | header-y += raw.h |
140 | header-y += resource.h | 141 | header-y += resource.h |
@@ -308,7 +309,6 @@ unifdef-y += poll.h | |||
308 | unifdef-y += ppp_defs.h | 309 | unifdef-y += ppp_defs.h |
309 | unifdef-y += ppp-comp.h | 310 | unifdef-y += ppp-comp.h |
310 | unifdef-y += ptrace.h | 311 | unifdef-y += ptrace.h |
311 | unifdef-y += qnx4_fs.h | ||
312 | unifdef-y += quota.h | 312 | unifdef-y += quota.h |
313 | unifdef-y += random.h | 313 | unifdef-y += random.h |
314 | unifdef-y += irqnr.h | 314 | unifdef-y += irqnr.h |
diff --git a/include/linux/cdev.h b/include/linux/cdev.h index fb4591977b03..f389e319a454 100644 --- a/include/linux/cdev.h +++ b/include/linux/cdev.h | |||
@@ -28,6 +28,8 @@ int cdev_add(struct cdev *, dev_t, unsigned); | |||
28 | 28 | ||
29 | void cdev_del(struct cdev *); | 29 | void cdev_del(struct cdev *); |
30 | 30 | ||
31 | int cdev_index(struct inode *inode); | ||
32 | |||
31 | void cd_forget(struct inode *); | 33 | void cd_forget(struct inode *); |
32 | 34 | ||
33 | extern struct backing_dev_info directly_mappable_cdev_bdi; | 35 | extern struct backing_dev_info directly_mappable_cdev_bdi; |
diff --git a/include/linux/cramfs_fs.h b/include/linux/cramfs_fs.h index 3be4e5a27d82..6fc2bed368b8 100644 --- a/include/linux/cramfs_fs.h +++ b/include/linux/cramfs_fs.h | |||
@@ -2,9 +2,8 @@ | |||
2 | #define __CRAMFS_H | 2 | #define __CRAMFS_H |
3 | 3 | ||
4 | #include <linux/types.h> | 4 | #include <linux/types.h> |
5 | #include <linux/magic.h> | ||
5 | 6 | ||
6 | #define CRAMFS_MAGIC 0x28cd3d45 /* some random number */ | ||
7 | #define CRAMFS_MAGIC_WEND 0x453dcd28 /* magic number with the wrong endianess */ | ||
8 | #define CRAMFS_SIGNATURE "Compressed ROMFS" | 7 | #define CRAMFS_SIGNATURE "Compressed ROMFS" |
9 | 8 | ||
10 | /* | 9 | /* |
diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 97978004338d..30b93b2a01a4 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h | |||
@@ -353,6 +353,11 @@ static inline int d_unhashed(struct dentry *dentry) | |||
353 | return (dentry->d_flags & DCACHE_UNHASHED); | 353 | return (dentry->d_flags & DCACHE_UNHASHED); |
354 | } | 354 | } |
355 | 355 | ||
356 | static inline int d_unlinked(struct dentry *dentry) | ||
357 | { | ||
358 | return d_unhashed(dentry) && !IS_ROOT(dentry); | ||
359 | } | ||
360 | |||
356 | static inline struct dentry *dget_parent(struct dentry *dentry) | 361 | static inline struct dentry *dget_parent(struct dentry *dentry) |
357 | { | 362 | { |
358 | struct dentry *ret; | 363 | struct dentry *ret; |
@@ -370,7 +375,7 @@ static inline int d_mountpoint(struct dentry *dentry) | |||
370 | return dentry->d_mounted; | 375 | return dentry->d_mounted; |
371 | } | 376 | } |
372 | 377 | ||
373 | extern struct vfsmount *lookup_mnt(struct vfsmount *, struct dentry *); | 378 | extern struct vfsmount *lookup_mnt(struct path *); |
374 | extern struct dentry *lookup_create(struct nameidata *nd, int is_dir); | 379 | extern struct dentry *lookup_create(struct nameidata *nd, int is_dir); |
375 | 380 | ||
376 | extern int sysctl_vfs_cache_pressure; | 381 | extern int sysctl_vfs_cache_pressure; |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 323b5ce474c1..ede84fa7da5d 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -729,8 +729,8 @@ struct inode { | |||
729 | struct timespec i_atime; | 729 | struct timespec i_atime; |
730 | struct timespec i_mtime; | 730 | struct timespec i_mtime; |
731 | struct timespec i_ctime; | 731 | struct timespec i_ctime; |
732 | unsigned int i_blkbits; | ||
733 | blkcnt_t i_blocks; | 732 | blkcnt_t i_blocks; |
733 | unsigned int i_blkbits; | ||
734 | unsigned short i_bytes; | 734 | unsigned short i_bytes; |
735 | umode_t i_mode; | 735 | umode_t i_mode; |
736 | spinlock_t i_lock; /* i_blocks, i_bytes, maybe i_size */ | 736 | spinlock_t i_lock; /* i_blocks, i_bytes, maybe i_size */ |
@@ -751,7 +751,6 @@ struct inode { | |||
751 | struct block_device *i_bdev; | 751 | struct block_device *i_bdev; |
752 | struct cdev *i_cdev; | 752 | struct cdev *i_cdev; |
753 | }; | 753 | }; |
754 | int i_cindex; | ||
755 | 754 | ||
756 | __u32 i_generation; | 755 | __u32 i_generation; |
757 | 756 | ||
@@ -1321,7 +1320,7 @@ struct super_block { | |||
1321 | struct rw_semaphore s_umount; | 1320 | struct rw_semaphore s_umount; |
1322 | struct mutex s_lock; | 1321 | struct mutex s_lock; |
1323 | int s_count; | 1322 | int s_count; |
1324 | int s_need_sync_fs; | 1323 | int s_need_sync; |
1325 | atomic_t s_active; | 1324 | atomic_t s_active; |
1326 | #ifdef CONFIG_SECURITY | 1325 | #ifdef CONFIG_SECURITY |
1327 | void *s_security; | 1326 | void *s_security; |
@@ -1372,11 +1371,6 @@ struct super_block { | |||
1372 | * generic_show_options() | 1371 | * generic_show_options() |
1373 | */ | 1372 | */ |
1374 | char *s_options; | 1373 | char *s_options; |
1375 | |||
1376 | /* | ||
1377 | * storage for asynchronous operations | ||
1378 | */ | ||
1379 | struct list_head s_async_list; | ||
1380 | }; | 1374 | }; |
1381 | 1375 | ||
1382 | extern struct timespec current_fs_time(struct super_block *sb); | 1376 | extern struct timespec current_fs_time(struct super_block *sb); |
@@ -1800,7 +1794,7 @@ extern struct vfsmount *kern_mount_data(struct file_system_type *, void *data); | |||
1800 | extern int may_umount_tree(struct vfsmount *); | 1794 | extern int may_umount_tree(struct vfsmount *); |
1801 | extern int may_umount(struct vfsmount *); | 1795 | extern int may_umount(struct vfsmount *); |
1802 | extern long do_mount(char *, char *, char *, unsigned long, void *); | 1796 | extern long do_mount(char *, char *, char *, unsigned long, void *); |
1803 | extern struct vfsmount *collect_mounts(struct vfsmount *, struct dentry *); | 1797 | extern struct vfsmount *collect_mounts(struct path *); |
1804 | extern void drop_collected_mounts(struct vfsmount *); | 1798 | extern void drop_collected_mounts(struct vfsmount *); |
1805 | 1799 | ||
1806 | extern int vfs_statfs(struct dentry *, struct kstatfs *); | 1800 | extern int vfs_statfs(struct dentry *, struct kstatfs *); |
@@ -1947,8 +1941,6 @@ extern struct super_block *freeze_bdev(struct block_device *); | |||
1947 | extern void emergency_thaw_all(void); | 1941 | extern void emergency_thaw_all(void); |
1948 | extern int thaw_bdev(struct block_device *bdev, struct super_block *sb); | 1942 | extern int thaw_bdev(struct block_device *bdev, struct super_block *sb); |
1949 | extern int fsync_bdev(struct block_device *); | 1943 | extern int fsync_bdev(struct block_device *); |
1950 | extern int fsync_super(struct super_block *); | ||
1951 | extern int fsync_no_super(struct block_device *); | ||
1952 | #else | 1944 | #else |
1953 | static inline void bd_forget(struct inode *inode) {} | 1945 | static inline void bd_forget(struct inode *inode) {} |
1954 | static inline int sync_blockdev(struct block_device *bdev) { return 0; } | 1946 | static inline int sync_blockdev(struct block_device *bdev) { return 0; } |
@@ -1964,6 +1956,7 @@ static inline int thaw_bdev(struct block_device *bdev, struct super_block *sb) | |||
1964 | return 0; | 1956 | return 0; |
1965 | } | 1957 | } |
1966 | #endif | 1958 | #endif |
1959 | extern int sync_filesystem(struct super_block *); | ||
1967 | extern const struct file_operations def_blk_fops; | 1960 | extern const struct file_operations def_blk_fops; |
1968 | extern const struct file_operations def_chr_fops; | 1961 | extern const struct file_operations def_chr_fops; |
1969 | extern const struct file_operations bad_sock_fops; | 1962 | extern const struct file_operations bad_sock_fops; |
@@ -2082,12 +2075,8 @@ extern int filemap_fdatawrite_range(struct address_space *mapping, | |||
2082 | 2075 | ||
2083 | extern int vfs_fsync(struct file *file, struct dentry *dentry, int datasync); | 2076 | extern int vfs_fsync(struct file *file, struct dentry *dentry, int datasync); |
2084 | extern void sync_supers(void); | 2077 | extern void sync_supers(void); |
2085 | extern void sync_filesystems(int wait); | ||
2086 | extern void __fsync_super(struct super_block *sb); | ||
2087 | extern void emergency_sync(void); | 2078 | extern void emergency_sync(void); |
2088 | extern void emergency_remount(void); | 2079 | extern void emergency_remount(void); |
2089 | extern int do_remount_sb(struct super_block *sb, int flags, | ||
2090 | void *data, int force); | ||
2091 | #ifdef CONFIG_BLOCK | 2080 | #ifdef CONFIG_BLOCK |
2092 | extern sector_t bmap(struct inode *, sector_t); | 2081 | extern sector_t bmap(struct inode *, sector_t); |
2093 | #endif | 2082 | #endif |
@@ -2356,6 +2345,8 @@ extern void simple_release_fs(struct vfsmount **mount, int *count); | |||
2356 | extern ssize_t simple_read_from_buffer(void __user *to, size_t count, | 2345 | extern ssize_t simple_read_from_buffer(void __user *to, size_t count, |
2357 | loff_t *ppos, const void *from, size_t available); | 2346 | loff_t *ppos, const void *from, size_t available); |
2358 | 2347 | ||
2348 | extern int simple_fsync(struct file *, struct dentry *, int); | ||
2349 | |||
2359 | #ifdef CONFIG_MIGRATION | 2350 | #ifdef CONFIG_MIGRATION |
2360 | extern int buffer_migrate_page(struct address_space *, | 2351 | extern int buffer_migrate_page(struct address_space *, |
2361 | struct page *, struct page *); | 2352 | struct page *, struct page *); |
diff --git a/include/linux/magic.h b/include/linux/magic.h index 927138cf3050..1923327b9869 100644 --- a/include/linux/magic.h +++ b/include/linux/magic.h | |||
@@ -6,6 +6,8 @@ | |||
6 | #define AFS_SUPER_MAGIC 0x5346414F | 6 | #define AFS_SUPER_MAGIC 0x5346414F |
7 | #define AUTOFS_SUPER_MAGIC 0x0187 | 7 | #define AUTOFS_SUPER_MAGIC 0x0187 |
8 | #define CODA_SUPER_MAGIC 0x73757245 | 8 | #define CODA_SUPER_MAGIC 0x73757245 |
9 | #define CRAMFS_MAGIC 0x28cd3d45 /* some random number */ | ||
10 | #define CRAMFS_MAGIC_WEND 0x453dcd28 /* magic number with the wrong endianess */ | ||
9 | #define DEBUGFS_MAGIC 0x64626720 | 11 | #define DEBUGFS_MAGIC 0x64626720 |
10 | #define SYSFS_MAGIC 0x62656572 | 12 | #define SYSFS_MAGIC 0x62656572 |
11 | #define SECURITYFS_MAGIC 0x73636673 | 13 | #define SECURITYFS_MAGIC 0x73636673 |
diff --git a/include/linux/mount.h b/include/linux/mount.h index 51f55f903aff..5d5275364867 100644 --- a/include/linux/mount.h +++ b/include/linux/mount.h | |||
@@ -30,7 +30,7 @@ struct mnt_namespace; | |||
30 | #define MNT_STRICTATIME 0x80 | 30 | #define MNT_STRICTATIME 0x80 |
31 | 31 | ||
32 | #define MNT_SHRINKABLE 0x100 | 32 | #define MNT_SHRINKABLE 0x100 |
33 | #define MNT_IMBALANCED_WRITE_COUNT 0x200 /* just for debugging */ | 33 | #define MNT_WRITE_HOLD 0x200 |
34 | 34 | ||
35 | #define MNT_SHARED 0x1000 /* if the vfsmount is a shared mount */ | 35 | #define MNT_SHARED 0x1000 /* if the vfsmount is a shared mount */ |
36 | #define MNT_UNBINDABLE 0x2000 /* if the vfsmount is a unbindable mount */ | 36 | #define MNT_UNBINDABLE 0x2000 /* if the vfsmount is a unbindable mount */ |
@@ -65,13 +65,22 @@ struct vfsmount { | |||
65 | int mnt_expiry_mark; /* true if marked for expiry */ | 65 | int mnt_expiry_mark; /* true if marked for expiry */ |
66 | int mnt_pinned; | 66 | int mnt_pinned; |
67 | int mnt_ghosts; | 67 | int mnt_ghosts; |
68 | /* | 68 | #ifdef CONFIG_SMP |
69 | * This value is not stable unless all of the mnt_writers[] spinlocks | 69 | int *mnt_writers; |
70 | * are held, and all mnt_writer[]s on this mount have 0 as their ->count | 70 | #else |
71 | */ | 71 | int mnt_writers; |
72 | atomic_t __mnt_writers; | 72 | #endif |
73 | }; | 73 | }; |
74 | 74 | ||
75 | static inline int *get_mnt_writers_ptr(struct vfsmount *mnt) | ||
76 | { | ||
77 | #ifdef CONFIG_SMP | ||
78 | return mnt->mnt_writers; | ||
79 | #else | ||
80 | return &mnt->mnt_writers; | ||
81 | #endif | ||
82 | } | ||
83 | |||
75 | static inline struct vfsmount *mntget(struct vfsmount *mnt) | 84 | static inline struct vfsmount *mntget(struct vfsmount *mnt) |
76 | { | 85 | { |
77 | if (mnt) | 86 | if (mnt) |
@@ -79,7 +88,11 @@ static inline struct vfsmount *mntget(struct vfsmount *mnt) | |||
79 | return mnt; | 88 | return mnt; |
80 | } | 89 | } |
81 | 90 | ||
91 | struct file; /* forward dec */ | ||
92 | |||
82 | extern int mnt_want_write(struct vfsmount *mnt); | 93 | extern int mnt_want_write(struct vfsmount *mnt); |
94 | extern int mnt_want_write_file(struct file *file); | ||
95 | extern int mnt_clone_write(struct vfsmount *mnt); | ||
83 | extern void mnt_drop_write(struct vfsmount *mnt); | 96 | extern void mnt_drop_write(struct vfsmount *mnt); |
84 | extern void mntput_no_expire(struct vfsmount *mnt); | 97 | extern void mntput_no_expire(struct vfsmount *mnt); |
85 | extern void mnt_pin(struct vfsmount *mnt); | 98 | extern void mnt_pin(struct vfsmount *mnt); |
diff --git a/include/linux/namei.h b/include/linux/namei.h index 518098fe63af..d870ae2faedc 100644 --- a/include/linux/namei.h +++ b/include/linux/namei.h | |||
@@ -18,6 +18,7 @@ enum { MAX_NESTED_LINKS = 8 }; | |||
18 | struct nameidata { | 18 | struct nameidata { |
19 | struct path path; | 19 | struct path path; |
20 | struct qstr last; | 20 | struct qstr last; |
21 | struct path root; | ||
21 | unsigned int flags; | 22 | unsigned int flags; |
22 | int last_type; | 23 | int last_type; |
23 | unsigned depth; | 24 | unsigned depth; |
@@ -77,8 +78,8 @@ extern void release_open_intent(struct nameidata *); | |||
77 | extern struct dentry *lookup_one_len(const char *, struct dentry *, int); | 78 | extern struct dentry *lookup_one_len(const char *, struct dentry *, int); |
78 | extern struct dentry *lookup_one_noperm(const char *, struct dentry *); | 79 | extern struct dentry *lookup_one_noperm(const char *, struct dentry *); |
79 | 80 | ||
80 | extern int follow_down(struct vfsmount **, struct dentry **); | 81 | extern int follow_down(struct path *); |
81 | extern int follow_up(struct vfsmount **, struct dentry **); | 82 | extern int follow_up(struct path *); |
82 | 83 | ||
83 | extern struct dentry *lock_rename(struct dentry *, struct dentry *); | 84 | extern struct dentry *lock_rename(struct dentry *, struct dentry *); |
84 | extern void unlock_rename(struct dentry *, struct dentry *); | 85 | extern void unlock_rename(struct dentry *, struct dentry *); |
diff --git a/include/linux/nfsd/export.h b/include/linux/nfsd/export.h index bcd0201589f8..a6d9ef2bb34a 100644 --- a/include/linux/nfsd/export.h +++ b/include/linux/nfsd/export.h | |||
@@ -125,11 +125,9 @@ void nfsd_export_flush(void); | |||
125 | void exp_readlock(void); | 125 | void exp_readlock(void); |
126 | void exp_readunlock(void); | 126 | void exp_readunlock(void); |
127 | struct svc_export * rqst_exp_get_by_name(struct svc_rqst *, | 127 | struct svc_export * rqst_exp_get_by_name(struct svc_rqst *, |
128 | struct vfsmount *, | 128 | struct path *); |
129 | struct dentry *); | ||
130 | struct svc_export * rqst_exp_parent(struct svc_rqst *, | 129 | struct svc_export * rqst_exp_parent(struct svc_rqst *, |
131 | struct vfsmount *mnt, | 130 | struct path *); |
132 | struct dentry *dentry); | ||
133 | int exp_rootfh(struct auth_domain *, | 131 | int exp_rootfh(struct auth_domain *, |
134 | char *path, struct knfsd_fh *, int maxsize); | 132 | char *path, struct knfsd_fh *, int maxsize); |
135 | __be32 exp_pseudoroot(struct svc_rqst *, struct svc_fh *); | 133 | __be32 exp_pseudoroot(struct svc_rqst *, struct svc_fh *); |
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index fbfa3d44d33d..e6e77d31c418 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h | |||
@@ -93,20 +93,9 @@ struct vmcore { | |||
93 | 93 | ||
94 | #ifdef CONFIG_PROC_FS | 94 | #ifdef CONFIG_PROC_FS |
95 | 95 | ||
96 | extern spinlock_t proc_subdir_lock; | ||
97 | |||
98 | extern void proc_root_init(void); | 96 | extern void proc_root_init(void); |
99 | 97 | ||
100 | void proc_flush_task(struct task_struct *task); | 98 | void proc_flush_task(struct task_struct *task); |
101 | struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *); | ||
102 | int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir); | ||
103 | unsigned long task_vsize(struct mm_struct *); | ||
104 | int task_statm(struct mm_struct *, int *, int *, int *, int *); | ||
105 | void task_mem(struct seq_file *, struct mm_struct *); | ||
106 | void clear_refs_smap(struct mm_struct *mm); | ||
107 | |||
108 | struct proc_dir_entry *de_get(struct proc_dir_entry *de); | ||
109 | void de_put(struct proc_dir_entry *de); | ||
110 | 99 | ||
111 | extern struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode, | 100 | extern struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode, |
112 | struct proc_dir_entry *parent); | 101 | struct proc_dir_entry *parent); |
@@ -116,20 +105,7 @@ struct proc_dir_entry *proc_create_data(const char *name, mode_t mode, | |||
116 | void *data); | 105 | void *data); |
117 | extern void remove_proc_entry(const char *name, struct proc_dir_entry *parent); | 106 | extern void remove_proc_entry(const char *name, struct proc_dir_entry *parent); |
118 | 107 | ||
119 | extern struct vfsmount *proc_mnt; | ||
120 | struct pid_namespace; | 108 | struct pid_namespace; |
121 | extern int proc_fill_super(struct super_block *); | ||
122 | extern struct inode *proc_get_inode(struct super_block *, unsigned int, struct proc_dir_entry *); | ||
123 | |||
124 | /* | ||
125 | * These are generic /proc routines that use the internal | ||
126 | * "struct proc_dir_entry" tree to traverse the filesystem. | ||
127 | * | ||
128 | * The /proc root directory has extended versions to take care | ||
129 | * of the /proc/<pid> subdirectories. | ||
130 | */ | ||
131 | extern int proc_readdir(struct file *, void *, filldir_t); | ||
132 | extern struct dentry *proc_lookup(struct inode *, struct dentry *, struct nameidata *); | ||
133 | 109 | ||
134 | extern int pid_ns_prepare_proc(struct pid_namespace *ns); | 110 | extern int pid_ns_prepare_proc(struct pid_namespace *ns); |
135 | extern void pid_ns_release_proc(struct pid_namespace *ns); | 111 | extern void pid_ns_release_proc(struct pid_namespace *ns); |
diff --git a/include/linux/qnx4_fs.h b/include/linux/qnx4_fs.h index 787d19ea9f46..8b9aee1a9ce3 100644 --- a/include/linux/qnx4_fs.h +++ b/include/linux/qnx4_fs.h | |||
@@ -85,65 +85,4 @@ struct qnx4_super_block { | |||
85 | struct qnx4_inode_entry AltBoot; | 85 | struct qnx4_inode_entry AltBoot; |
86 | }; | 86 | }; |
87 | 87 | ||
88 | #ifdef __KERNEL__ | ||
89 | |||
90 | #define QNX4_DEBUG 0 | ||
91 | |||
92 | #if QNX4_DEBUG | ||
93 | #define QNX4DEBUG(X) printk X | ||
94 | #else | ||
95 | #define QNX4DEBUG(X) (void) 0 | ||
96 | #endif | ||
97 | |||
98 | struct qnx4_sb_info { | ||
99 | struct buffer_head *sb_buf; /* superblock buffer */ | ||
100 | struct qnx4_super_block *sb; /* our superblock */ | ||
101 | unsigned int Version; /* may be useful */ | ||
102 | struct qnx4_inode_entry *BitMap; /* useful */ | ||
103 | }; | ||
104 | |||
105 | struct qnx4_inode_info { | ||
106 | struct qnx4_inode_entry raw; | ||
107 | loff_t mmu_private; | ||
108 | struct inode vfs_inode; | ||
109 | }; | ||
110 | |||
111 | extern struct inode *qnx4_iget(struct super_block *, unsigned long); | ||
112 | extern struct dentry *qnx4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd); | ||
113 | extern unsigned long qnx4_count_free_blocks(struct super_block *sb); | ||
114 | extern unsigned long qnx4_block_map(struct inode *inode, long iblock); | ||
115 | |||
116 | extern struct buffer_head *qnx4_bread(struct inode *, int, int); | ||
117 | |||
118 | extern const struct inode_operations qnx4_file_inode_operations; | ||
119 | extern const struct inode_operations qnx4_dir_inode_operations; | ||
120 | extern const struct file_operations qnx4_file_operations; | ||
121 | extern const struct file_operations qnx4_dir_operations; | ||
122 | extern int qnx4_is_free(struct super_block *sb, long block); | ||
123 | extern int qnx4_set_bitmap(struct super_block *sb, long block, int busy); | ||
124 | extern int qnx4_create(struct inode *inode, struct dentry *dentry, int mode, struct nameidata *nd); | ||
125 | extern void qnx4_truncate(struct inode *inode); | ||
126 | extern void qnx4_free_inode(struct inode *inode); | ||
127 | extern int qnx4_unlink(struct inode *dir, struct dentry *dentry); | ||
128 | extern int qnx4_rmdir(struct inode *dir, struct dentry *dentry); | ||
129 | extern int qnx4_sync_file(struct file *file, struct dentry *dentry, int); | ||
130 | extern int qnx4_sync_inode(struct inode *inode); | ||
131 | |||
132 | static inline struct qnx4_sb_info *qnx4_sb(struct super_block *sb) | ||
133 | { | ||
134 | return sb->s_fs_info; | ||
135 | } | ||
136 | |||
137 | static inline struct qnx4_inode_info *qnx4_i(struct inode *inode) | ||
138 | { | ||
139 | return container_of(inode, struct qnx4_inode_info, vfs_inode); | ||
140 | } | ||
141 | |||
142 | static inline struct qnx4_inode_entry *qnx4_raw_inode(struct inode *inode) | ||
143 | { | ||
144 | return &qnx4_i(inode)->raw; | ||
145 | } | ||
146 | |||
147 | #endif /* __KERNEL__ */ | ||
148 | |||
149 | #endif | 88 | #endif |
diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h index 36353d95c8db..7bc457593684 100644 --- a/include/linux/quotaops.h +++ b/include/linux/quotaops.h | |||
@@ -20,7 +20,12 @@ static inline struct quota_info *sb_dqopt(struct super_block *sb) | |||
20 | /* | 20 | /* |
21 | * declaration of quota_function calls in kernel. | 21 | * declaration of quota_function calls in kernel. |
22 | */ | 22 | */ |
23 | void sync_dquots(struct super_block *sb, int type); | 23 | void sync_quota_sb(struct super_block *sb, int type); |
24 | static inline void writeout_quota_sb(struct super_block *sb, int type) | ||
25 | { | ||
26 | if (sb->s_qcop->quota_sync) | ||
27 | sb->s_qcop->quota_sync(sb, type); | ||
28 | } | ||
24 | 29 | ||
25 | int dquot_initialize(struct inode *inode, int type); | 30 | int dquot_initialize(struct inode *inode, int type); |
26 | int dquot_drop(struct inode *inode); | 31 | int dquot_drop(struct inode *inode); |
@@ -253,12 +258,7 @@ static inline void vfs_dq_free_inode(struct inode *inode) | |||
253 | inode->i_sb->dq_op->free_inode(inode, 1); | 258 | inode->i_sb->dq_op->free_inode(inode, 1); |
254 | } | 259 | } |
255 | 260 | ||
256 | /* The following two functions cannot be called inside a transaction */ | 261 | /* Cannot be called inside a transaction */ |
257 | static inline void vfs_dq_sync(struct super_block *sb) | ||
258 | { | ||
259 | sync_dquots(sb, -1); | ||
260 | } | ||
261 | |||
262 | static inline int vfs_dq_off(struct super_block *sb, int remount) | 262 | static inline int vfs_dq_off(struct super_block *sb, int remount) |
263 | { | 263 | { |
264 | int ret = -ENOSYS; | 264 | int ret = -ENOSYS; |
@@ -334,7 +334,11 @@ static inline void vfs_dq_free_inode(struct inode *inode) | |||
334 | { | 334 | { |
335 | } | 335 | } |
336 | 336 | ||
337 | static inline void vfs_dq_sync(struct super_block *sb) | 337 | static inline void sync_quota_sb(struct super_block *sb, int type) |
338 | { | ||
339 | } | ||
340 | |||
341 | static inline void writeout_quota_sb(struct super_block *sb, int type) | ||
338 | { | 342 | { |
339 | } | 343 | } |
340 | 344 | ||
diff --git a/include/linux/reiserfs_fs_sb.h b/include/linux/reiserfs_fs_sb.h index 6473650c28f1..dab68bbed675 100644 --- a/include/linux/reiserfs_fs_sb.h +++ b/include/linux/reiserfs_fs_sb.h | |||
@@ -453,6 +453,7 @@ enum reiserfs_mount_options { | |||
453 | REISERFS_ATTRS, | 453 | REISERFS_ATTRS, |
454 | REISERFS_XATTRS_USER, | 454 | REISERFS_XATTRS_USER, |
455 | REISERFS_POSIXACL, | 455 | REISERFS_POSIXACL, |
456 | REISERFS_EXPOSE_PRIVROOT, | ||
456 | REISERFS_BARRIER_NONE, | 457 | REISERFS_BARRIER_NONE, |
457 | REISERFS_BARRIER_FLUSH, | 458 | REISERFS_BARRIER_FLUSH, |
458 | 459 | ||
@@ -490,6 +491,7 @@ enum reiserfs_mount_options { | |||
490 | #define reiserfs_data_writeback(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_DATA_WRITEBACK)) | 491 | #define reiserfs_data_writeback(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_DATA_WRITEBACK)) |
491 | #define reiserfs_xattrs_user(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_XATTRS_USER)) | 492 | #define reiserfs_xattrs_user(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_XATTRS_USER)) |
492 | #define reiserfs_posixacl(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_POSIXACL)) | 493 | #define reiserfs_posixacl(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_POSIXACL)) |
494 | #define reiserfs_expose_privroot(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_EXPOSE_PRIVROOT)) | ||
493 | #define reiserfs_xattrs_optional(s) (reiserfs_xattrs_user(s) || reiserfs_posixacl(s)) | 495 | #define reiserfs_xattrs_optional(s) (reiserfs_xattrs_user(s) || reiserfs_posixacl(s)) |
494 | #define reiserfs_barrier_none(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_BARRIER_NONE)) | 496 | #define reiserfs_barrier_none(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_BARRIER_NONE)) |
495 | #define reiserfs_barrier_flush(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_BARRIER_FLUSH)) | 497 | #define reiserfs_barrier_flush(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_BARRIER_FLUSH)) |
diff --git a/include/linux/writeback.h b/include/linux/writeback.h index 93445477f86a..3224820c8514 100644 --- a/include/linux/writeback.h +++ b/include/linux/writeback.h | |||
@@ -79,7 +79,6 @@ struct writeback_control { | |||
79 | void writeback_inodes(struct writeback_control *wbc); | 79 | void writeback_inodes(struct writeback_control *wbc); |
80 | int inode_wait(void *); | 80 | int inode_wait(void *); |
81 | void sync_inodes_sb(struct super_block *, int wait); | 81 | void sync_inodes_sb(struct super_block *, int wait); |
82 | void sync_inodes(int wait); | ||
83 | 82 | ||
84 | /* writeback.h requires fs.h; it, too, is not included from here. */ | 83 | /* writeback.h requires fs.h; it, too, is not included from here. */ |
85 | static inline void wait_on_inode(struct inode *inode) | 84 | static inline void wait_on_inode(struct inode *inode) |
diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c index 6e7351739a82..1f6396d76687 100644 --- a/kernel/audit_tree.c +++ b/kernel/audit_tree.c | |||
@@ -568,7 +568,7 @@ void audit_trim_trees(void) | |||
568 | if (err) | 568 | if (err) |
569 | goto skip_it; | 569 | goto skip_it; |
570 | 570 | ||
571 | root_mnt = collect_mounts(path.mnt, path.dentry); | 571 | root_mnt = collect_mounts(&path); |
572 | path_put(&path); | 572 | path_put(&path); |
573 | if (!root_mnt) | 573 | if (!root_mnt) |
574 | goto skip_it; | 574 | goto skip_it; |
@@ -660,7 +660,7 @@ int audit_add_tree_rule(struct audit_krule *rule) | |||
660 | err = kern_path(tree->pathname, 0, &path); | 660 | err = kern_path(tree->pathname, 0, &path); |
661 | if (err) | 661 | if (err) |
662 | goto Err; | 662 | goto Err; |
663 | mnt = collect_mounts(path.mnt, path.dentry); | 663 | mnt = collect_mounts(&path); |
664 | path_put(&path); | 664 | path_put(&path); |
665 | if (!mnt) { | 665 | if (!mnt) { |
666 | err = -ENOMEM; | 666 | err = -ENOMEM; |
@@ -720,7 +720,7 @@ int audit_tag_tree(char *old, char *new) | |||
720 | err = kern_path(new, 0, &path); | 720 | err = kern_path(new, 0, &path); |
721 | if (err) | 721 | if (err) |
722 | return err; | 722 | return err; |
723 | tagged = collect_mounts(path.mnt, path.dentry); | 723 | tagged = collect_mounts(&path); |
724 | path_put(&path); | 724 | path_put(&path); |
725 | if (!tagged) | 725 | if (!tagged) |
726 | return -ENOMEM; | 726 | return -ENOMEM; |
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index a7267bfd3765..3fb789f6df94 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
@@ -46,6 +46,7 @@ | |||
46 | #include <linux/cgroupstats.h> | 46 | #include <linux/cgroupstats.h> |
47 | #include <linux/hash.h> | 47 | #include <linux/hash.h> |
48 | #include <linux/namei.h> | 48 | #include <linux/namei.h> |
49 | #include <linux/smp_lock.h> | ||
49 | 50 | ||
50 | #include <asm/atomic.h> | 51 | #include <asm/atomic.h> |
51 | 52 | ||
@@ -900,6 +901,7 @@ static int cgroup_remount(struct super_block *sb, int *flags, char *data) | |||
900 | struct cgroup *cgrp = &root->top_cgroup; | 901 | struct cgroup *cgrp = &root->top_cgroup; |
901 | struct cgroup_sb_opts opts; | 902 | struct cgroup_sb_opts opts; |
902 | 903 | ||
904 | lock_kernel(); | ||
903 | mutex_lock(&cgrp->dentry->d_inode->i_mutex); | 905 | mutex_lock(&cgrp->dentry->d_inode->i_mutex); |
904 | mutex_lock(&cgroup_mutex); | 906 | mutex_lock(&cgroup_mutex); |
905 | 907 | ||
@@ -927,6 +929,7 @@ static int cgroup_remount(struct super_block *sb, int *flags, char *data) | |||
927 | kfree(opts.release_agent); | 929 | kfree(opts.release_agent); |
928 | mutex_unlock(&cgroup_mutex); | 930 | mutex_unlock(&cgroup_mutex); |
929 | mutex_unlock(&cgrp->dentry->d_inode->i_mutex); | 931 | mutex_unlock(&cgrp->dentry->d_inode->i_mutex); |
932 | unlock_kernel(); | ||
930 | return ret; | 933 | return ret; |
931 | } | 934 | } |
932 | 935 | ||