diff options
author | Paul Mackerras <paulus@samba.org> | 2007-05-10 07:08:37 -0400 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2007-05-10 07:08:37 -0400 |
commit | 2ecf042ef530dd0943e41d84b6344f507941af3e (patch) | |
tree | 73100361dd74e3f80f14c7c81ba4675948983f44 /fs | |
parent | 32a56ebb24f23da1bbaf24292acf85b6c04526ab (diff) | |
parent | de5603748af8bf7deac403e6ba92887f8d18e812 (diff) |
Merge branch 'linux-2.6'
Diffstat (limited to 'fs')
65 files changed, 1868 insertions, 530 deletions
diff --git a/fs/Kconfig b/fs/Kconfig index 4622dabb2253..0fa0c1193e81 100644 --- a/fs/Kconfig +++ b/fs/Kconfig | |||
@@ -724,10 +724,6 @@ config FAT_FS | |||
724 | file system and use GNU tar's M option. GNU tar is a program | 724 | file system and use GNU tar's M option. GNU tar is a program |
725 | available for Unix and DOS ("man tar" or "info tar"). | 725 | available for Unix and DOS ("man tar" or "info tar"). |
726 | 726 | ||
727 | It is now also becoming possible to read and write compressed FAT | ||
728 | file systems; read <file:Documentation/filesystems/fat_cvf.txt> for | ||
729 | details. | ||
730 | |||
731 | The FAT support will enlarge your kernel by about 37 KB. If unsure, | 727 | The FAT support will enlarge your kernel by about 37 KB. If unsure, |
732 | say Y. | 728 | say Y. |
733 | 729 | ||
diff --git a/fs/affs/file.c b/fs/affs/file.c index 4aa8079e71be..c8796906f584 100644 --- a/fs/affs/file.c +++ b/fs/affs/file.c | |||
@@ -628,11 +628,7 @@ static int affs_prepare_write_ofs(struct file *file, struct page *page, unsigned | |||
628 | return err; | 628 | return err; |
629 | } | 629 | } |
630 | if (to < PAGE_CACHE_SIZE) { | 630 | if (to < PAGE_CACHE_SIZE) { |
631 | char *kaddr = kmap_atomic(page, KM_USER0); | 631 | zero_user_page(page, to, PAGE_CACHE_SIZE - to, KM_USER0); |
632 | |||
633 | memset(kaddr + to, 0, PAGE_CACHE_SIZE - to); | ||
634 | flush_dcache_page(page); | ||
635 | kunmap_atomic(kaddr, KM_USER0); | ||
636 | if (size > offset + to) { | 632 | if (size > offset + to) { |
637 | if (size < offset + PAGE_CACHE_SIZE) | 633 | if (size < offset + PAGE_CACHE_SIZE) |
638 | tmp = size & ~PAGE_CACHE_MASK; | 634 | tmp = size & ~PAGE_CACHE_MASK; |
diff --git a/fs/afs/Makefile b/fs/afs/Makefile index cf83e5d63512..73ce561f3ea0 100644 --- a/fs/afs/Makefile +++ b/fs/afs/Makefile | |||
@@ -22,6 +22,7 @@ kafs-objs := \ | |||
22 | vlclient.o \ | 22 | vlclient.o \ |
23 | vlocation.o \ | 23 | vlocation.o \ |
24 | vnode.o \ | 24 | vnode.o \ |
25 | volume.o | 25 | volume.o \ |
26 | write.o | ||
26 | 27 | ||
27 | obj-$(CONFIG_AFS_FS) := kafs.o | 28 | obj-$(CONFIG_AFS_FS) := kafs.o |
diff --git a/fs/afs/afs_fs.h b/fs/afs/afs_fs.h index 89e0d1650a72..2198006d2d03 100644 --- a/fs/afs/afs_fs.h +++ b/fs/afs/afs_fs.h | |||
@@ -18,6 +18,8 @@ | |||
18 | enum AFS_FS_Operations { | 18 | enum AFS_FS_Operations { |
19 | FSFETCHDATA = 130, /* AFS Fetch file data */ | 19 | FSFETCHDATA = 130, /* AFS Fetch file data */ |
20 | FSFETCHSTATUS = 132, /* AFS Fetch file status */ | 20 | FSFETCHSTATUS = 132, /* AFS Fetch file status */ |
21 | FSSTOREDATA = 133, /* AFS Store file data */ | ||
22 | FSSTORESTATUS = 135, /* AFS Store file status */ | ||
21 | FSREMOVEFILE = 136, /* AFS Remove a file */ | 23 | FSREMOVEFILE = 136, /* AFS Remove a file */ |
22 | FSCREATEFILE = 137, /* AFS Create a file */ | 24 | FSCREATEFILE = 137, /* AFS Create a file */ |
23 | FSRENAME = 138, /* AFS Rename or move a file or directory */ | 25 | FSRENAME = 138, /* AFS Rename or move a file or directory */ |
diff --git a/fs/afs/callback.c b/fs/afs/callback.c index 9bdbf36a9aa9..f64e40fefc02 100644 --- a/fs/afs/callback.c +++ b/fs/afs/callback.c | |||
@@ -44,7 +44,7 @@ void afs_init_callback_state(struct afs_server *server) | |||
44 | while (!RB_EMPTY_ROOT(&server->cb_promises)) { | 44 | while (!RB_EMPTY_ROOT(&server->cb_promises)) { |
45 | vnode = rb_entry(server->cb_promises.rb_node, | 45 | vnode = rb_entry(server->cb_promises.rb_node, |
46 | struct afs_vnode, cb_promise); | 46 | struct afs_vnode, cb_promise); |
47 | _debug("UNPROMISE { vid=%x vn=%u uq=%u}", | 47 | _debug("UNPROMISE { vid=%x:%u uq=%u}", |
48 | vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique); | 48 | vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique); |
49 | rb_erase(&vnode->cb_promise, &server->cb_promises); | 49 | rb_erase(&vnode->cb_promise, &server->cb_promises); |
50 | vnode->cb_promised = false; | 50 | vnode->cb_promised = false; |
@@ -84,11 +84,8 @@ void afs_broken_callback_work(struct work_struct *work) | |||
84 | 84 | ||
85 | /* if the vnode's data version number changed then its contents | 85 | /* if the vnode's data version number changed then its contents |
86 | * are different */ | 86 | * are different */ |
87 | if (test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) { | 87 | if (test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) |
88 | _debug("zap data {%x:%u}", | 88 | afs_zap_data(vnode); |
89 | vnode->fid.vid, vnode->fid.vnode); | ||
90 | invalidate_remote_inode(&vnode->vfs_inode); | ||
91 | } | ||
92 | } | 89 | } |
93 | 90 | ||
94 | out: | 91 | out: |
diff --git a/fs/afs/dir.c b/fs/afs/dir.c index 0c1e902f17a3..2fb31276196b 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c | |||
@@ -55,7 +55,8 @@ const struct inode_operations afs_dir_inode_operations = { | |||
55 | .rmdir = afs_rmdir, | 55 | .rmdir = afs_rmdir, |
56 | .rename = afs_rename, | 56 | .rename = afs_rename, |
57 | .permission = afs_permission, | 57 | .permission = afs_permission, |
58 | .getattr = afs_inode_getattr, | 58 | .getattr = afs_getattr, |
59 | .setattr = afs_setattr, | ||
59 | }; | 60 | }; |
60 | 61 | ||
61 | static struct dentry_operations afs_fs_dentry_operations = { | 62 | static struct dentry_operations afs_fs_dentry_operations = { |
@@ -491,7 +492,7 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry, | |||
491 | 492 | ||
492 | vnode = AFS_FS_I(dir); | 493 | vnode = AFS_FS_I(dir); |
493 | 494 | ||
494 | _enter("{%x:%d},%p{%s},", | 495 | _enter("{%x:%u},%p{%s},", |
495 | vnode->fid.vid, vnode->fid.vnode, dentry, dentry->d_name.name); | 496 | vnode->fid.vid, vnode->fid.vnode, dentry, dentry->d_name.name); |
496 | 497 | ||
497 | ASSERTCMP(dentry->d_inode, ==, NULL); | 498 | ASSERTCMP(dentry->d_inode, ==, NULL); |
@@ -731,7 +732,7 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
731 | 732 | ||
732 | dvnode = AFS_FS_I(dir); | 733 | dvnode = AFS_FS_I(dir); |
733 | 734 | ||
734 | _enter("{%x:%d},{%s},%o", | 735 | _enter("{%x:%u},{%s},%o", |
735 | dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name, mode); | 736 | dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name, mode); |
736 | 737 | ||
737 | ret = -ENAMETOOLONG; | 738 | ret = -ENAMETOOLONG; |
@@ -796,7 +797,7 @@ static int afs_rmdir(struct inode *dir, struct dentry *dentry) | |||
796 | 797 | ||
797 | dvnode = AFS_FS_I(dir); | 798 | dvnode = AFS_FS_I(dir); |
798 | 799 | ||
799 | _enter("{%x:%d},{%s}", | 800 | _enter("{%x:%u},{%s}", |
800 | dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name); | 801 | dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name); |
801 | 802 | ||
802 | ret = -ENAMETOOLONG; | 803 | ret = -ENAMETOOLONG; |
@@ -842,7 +843,7 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry) | |||
842 | 843 | ||
843 | dvnode = AFS_FS_I(dir); | 844 | dvnode = AFS_FS_I(dir); |
844 | 845 | ||
845 | _enter("{%x:%d},{%s}", | 846 | _enter("{%x:%u},{%s}", |
846 | dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name); | 847 | dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name); |
847 | 848 | ||
848 | ret = -ENAMETOOLONG; | 849 | ret = -ENAMETOOLONG; |
@@ -916,7 +917,7 @@ static int afs_create(struct inode *dir, struct dentry *dentry, int mode, | |||
916 | 917 | ||
917 | dvnode = AFS_FS_I(dir); | 918 | dvnode = AFS_FS_I(dir); |
918 | 919 | ||
919 | _enter("{%x:%d},{%s},%o,", | 920 | _enter("{%x:%u},{%s},%o,", |
920 | dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name, mode); | 921 | dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name, mode); |
921 | 922 | ||
922 | ret = -ENAMETOOLONG; | 923 | ret = -ENAMETOOLONG; |
@@ -983,7 +984,7 @@ static int afs_link(struct dentry *from, struct inode *dir, | |||
983 | vnode = AFS_FS_I(from->d_inode); | 984 | vnode = AFS_FS_I(from->d_inode); |
984 | dvnode = AFS_FS_I(dir); | 985 | dvnode = AFS_FS_I(dir); |
985 | 986 | ||
986 | _enter("{%x:%d},{%x:%d},{%s}", | 987 | _enter("{%x:%u},{%x:%u},{%s}", |
987 | vnode->fid.vid, vnode->fid.vnode, | 988 | vnode->fid.vid, vnode->fid.vnode, |
988 | dvnode->fid.vid, dvnode->fid.vnode, | 989 | dvnode->fid.vid, dvnode->fid.vnode, |
989 | dentry->d_name.name); | 990 | dentry->d_name.name); |
@@ -1032,7 +1033,7 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry, | |||
1032 | 1033 | ||
1033 | dvnode = AFS_FS_I(dir); | 1034 | dvnode = AFS_FS_I(dir); |
1034 | 1035 | ||
1035 | _enter("{%x:%d},{%s},%s", | 1036 | _enter("{%x:%u},{%s},%s", |
1036 | dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name, | 1037 | dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name, |
1037 | content); | 1038 | content); |
1038 | 1039 | ||
@@ -1104,7 +1105,7 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
1104 | orig_dvnode = AFS_FS_I(old_dir); | 1105 | orig_dvnode = AFS_FS_I(old_dir); |
1105 | new_dvnode = AFS_FS_I(new_dir); | 1106 | new_dvnode = AFS_FS_I(new_dir); |
1106 | 1107 | ||
1107 | _enter("{%x:%d},{%x:%d},{%x:%d},{%s}", | 1108 | _enter("{%x:%u},{%x:%u},{%x:%u},{%s}", |
1108 | orig_dvnode->fid.vid, orig_dvnode->fid.vnode, | 1109 | orig_dvnode->fid.vid, orig_dvnode->fid.vnode, |
1109 | vnode->fid.vid, vnode->fid.vnode, | 1110 | vnode->fid.vid, vnode->fid.vnode, |
1110 | new_dvnode->fid.vid, new_dvnode->fid.vnode, | 1111 | new_dvnode->fid.vid, new_dvnode->fid.vnode, |
diff --git a/fs/afs/file.c b/fs/afs/file.c index ae256498f4f7..3e25795e5a42 100644 --- a/fs/afs/file.c +++ b/fs/afs/file.c | |||
@@ -15,32 +15,43 @@ | |||
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | #include <linux/fs.h> | 16 | #include <linux/fs.h> |
17 | #include <linux/pagemap.h> | 17 | #include <linux/pagemap.h> |
18 | #include <linux/writeback.h> | ||
18 | #include "internal.h" | 19 | #include "internal.h" |
19 | 20 | ||
20 | static int afs_file_readpage(struct file *file, struct page *page); | 21 | static int afs_readpage(struct file *file, struct page *page); |
21 | static void afs_file_invalidatepage(struct page *page, unsigned long offset); | 22 | static void afs_invalidatepage(struct page *page, unsigned long offset); |
22 | static int afs_file_releasepage(struct page *page, gfp_t gfp_flags); | 23 | static int afs_releasepage(struct page *page, gfp_t gfp_flags); |
24 | static int afs_launder_page(struct page *page); | ||
23 | 25 | ||
24 | const struct file_operations afs_file_operations = { | 26 | const struct file_operations afs_file_operations = { |
25 | .open = afs_open, | 27 | .open = afs_open, |
26 | .release = afs_release, | 28 | .release = afs_release, |
27 | .llseek = generic_file_llseek, | 29 | .llseek = generic_file_llseek, |
28 | .read = do_sync_read, | 30 | .read = do_sync_read, |
31 | .write = do_sync_write, | ||
29 | .aio_read = generic_file_aio_read, | 32 | .aio_read = generic_file_aio_read, |
33 | .aio_write = afs_file_write, | ||
30 | .mmap = generic_file_readonly_mmap, | 34 | .mmap = generic_file_readonly_mmap, |
31 | .sendfile = generic_file_sendfile, | 35 | .sendfile = generic_file_sendfile, |
36 | .fsync = afs_fsync, | ||
32 | }; | 37 | }; |
33 | 38 | ||
34 | const struct inode_operations afs_file_inode_operations = { | 39 | const struct inode_operations afs_file_inode_operations = { |
35 | .getattr = afs_inode_getattr, | 40 | .getattr = afs_getattr, |
41 | .setattr = afs_setattr, | ||
36 | .permission = afs_permission, | 42 | .permission = afs_permission, |
37 | }; | 43 | }; |
38 | 44 | ||
39 | const struct address_space_operations afs_fs_aops = { | 45 | const struct address_space_operations afs_fs_aops = { |
40 | .readpage = afs_file_readpage, | 46 | .readpage = afs_readpage, |
41 | .set_page_dirty = __set_page_dirty_nobuffers, | 47 | .set_page_dirty = afs_set_page_dirty, |
42 | .releasepage = afs_file_releasepage, | 48 | .launder_page = afs_launder_page, |
43 | .invalidatepage = afs_file_invalidatepage, | 49 | .releasepage = afs_releasepage, |
50 | .invalidatepage = afs_invalidatepage, | ||
51 | .prepare_write = afs_prepare_write, | ||
52 | .commit_write = afs_commit_write, | ||
53 | .writepage = afs_writepage, | ||
54 | .writepages = afs_writepages, | ||
44 | }; | 55 | }; |
45 | 56 | ||
46 | /* | 57 | /* |
@@ -52,7 +63,7 @@ int afs_open(struct inode *inode, struct file *file) | |||
52 | struct key *key; | 63 | struct key *key; |
53 | int ret; | 64 | int ret; |
54 | 65 | ||
55 | _enter("{%x:%x},", vnode->fid.vid, vnode->fid.vnode); | 66 | _enter("{%x:%u},", vnode->fid.vid, vnode->fid.vnode); |
56 | 67 | ||
57 | key = afs_request_key(vnode->volume->cell); | 68 | key = afs_request_key(vnode->volume->cell); |
58 | if (IS_ERR(key)) { | 69 | if (IS_ERR(key)) { |
@@ -78,7 +89,7 @@ int afs_release(struct inode *inode, struct file *file) | |||
78 | { | 89 | { |
79 | struct afs_vnode *vnode = AFS_FS_I(inode); | 90 | struct afs_vnode *vnode = AFS_FS_I(inode); |
80 | 91 | ||
81 | _enter("{%x:%x},", vnode->fid.vid, vnode->fid.vnode); | 92 | _enter("{%x:%u},", vnode->fid.vid, vnode->fid.vnode); |
82 | 93 | ||
83 | key_put(file->private_data); | 94 | key_put(file->private_data); |
84 | _leave(" = 0"); | 95 | _leave(" = 0"); |
@@ -89,10 +100,10 @@ int afs_release(struct inode *inode, struct file *file) | |||
89 | * deal with notification that a page was read from the cache | 100 | * deal with notification that a page was read from the cache |
90 | */ | 101 | */ |
91 | #ifdef AFS_CACHING_SUPPORT | 102 | #ifdef AFS_CACHING_SUPPORT |
92 | static void afs_file_readpage_read_complete(void *cookie_data, | 103 | static void afs_readpage_read_complete(void *cookie_data, |
93 | struct page *page, | 104 | struct page *page, |
94 | void *data, | 105 | void *data, |
95 | int error) | 106 | int error) |
96 | { | 107 | { |
97 | _enter("%p,%p,%p,%d", cookie_data, page, data, error); | 108 | _enter("%p,%p,%p,%d", cookie_data, page, data, error); |
98 | 109 | ||
@@ -109,10 +120,10 @@ static void afs_file_readpage_read_complete(void *cookie_data, | |||
109 | * deal with notification that a page was written to the cache | 120 | * deal with notification that a page was written to the cache |
110 | */ | 121 | */ |
111 | #ifdef AFS_CACHING_SUPPORT | 122 | #ifdef AFS_CACHING_SUPPORT |
112 | static void afs_file_readpage_write_complete(void *cookie_data, | 123 | static void afs_readpage_write_complete(void *cookie_data, |
113 | struct page *page, | 124 | struct page *page, |
114 | void *data, | 125 | void *data, |
115 | int error) | 126 | int error) |
116 | { | 127 | { |
117 | _enter("%p,%p,%p,%d", cookie_data, page, data, error); | 128 | _enter("%p,%p,%p,%d", cookie_data, page, data, error); |
118 | 129 | ||
@@ -121,9 +132,9 @@ static void afs_file_readpage_write_complete(void *cookie_data, | |||
121 | #endif | 132 | #endif |
122 | 133 | ||
123 | /* | 134 | /* |
124 | * AFS read page from file (or symlink) | 135 | * AFS read page from file, directory or symlink |
125 | */ | 136 | */ |
126 | static int afs_file_readpage(struct file *file, struct page *page) | 137 | static int afs_readpage(struct file *file, struct page *page) |
127 | { | 138 | { |
128 | struct afs_vnode *vnode; | 139 | struct afs_vnode *vnode; |
129 | struct inode *inode; | 140 | struct inode *inode; |
@@ -219,39 +230,17 @@ error: | |||
219 | } | 230 | } |
220 | 231 | ||
221 | /* | 232 | /* |
222 | * get a page cookie for the specified page | ||
223 | */ | ||
224 | #ifdef AFS_CACHING_SUPPORT | ||
225 | int afs_cache_get_page_cookie(struct page *page, | ||
226 | struct cachefs_page **_page_cookie) | ||
227 | { | ||
228 | int ret; | ||
229 | |||
230 | _enter(""); | ||
231 | ret = cachefs_page_get_private(page,_page_cookie, GFP_NOIO); | ||
232 | |||
233 | _leave(" = %d", ret); | ||
234 | return ret; | ||
235 | } | ||
236 | #endif | ||
237 | |||
238 | /* | ||
239 | * invalidate part or all of a page | 233 | * invalidate part or all of a page |
240 | */ | 234 | */ |
241 | static void afs_file_invalidatepage(struct page *page, unsigned long offset) | 235 | static void afs_invalidatepage(struct page *page, unsigned long offset) |
242 | { | 236 | { |
243 | int ret = 1; | 237 | int ret = 1; |
244 | 238 | ||
245 | _enter("{%lu},%lu", page->index, offset); | 239 | kenter("{%lu},%lu", page->index, offset); |
246 | 240 | ||
247 | BUG_ON(!PageLocked(page)); | 241 | BUG_ON(!PageLocked(page)); |
248 | 242 | ||
249 | if (PagePrivate(page)) { | 243 | if (PagePrivate(page)) { |
250 | #ifdef AFS_CACHING_SUPPORT | ||
251 | struct afs_vnode *vnode = AFS_FS_I(page->mapping->host); | ||
252 | cachefs_uncache_page(vnode->cache,page); | ||
253 | #endif | ||
254 | |||
255 | /* We release buffers only if the entire page is being | 244 | /* We release buffers only if the entire page is being |
256 | * invalidated. | 245 | * invalidated. |
257 | * The get_block cached value has been unconditionally | 246 | * The get_block cached value has been unconditionally |
@@ -272,25 +261,33 @@ static void afs_file_invalidatepage(struct page *page, unsigned long offset) | |||
272 | } | 261 | } |
273 | 262 | ||
274 | /* | 263 | /* |
264 | * write back a dirty page | ||
265 | */ | ||
266 | static int afs_launder_page(struct page *page) | ||
267 | { | ||
268 | _enter("{%lu}", page->index); | ||
269 | |||
270 | return 0; | ||
271 | } | ||
272 | |||
273 | /* | ||
275 | * release a page and cleanup its private data | 274 | * release a page and cleanup its private data |
276 | */ | 275 | */ |
277 | static int afs_file_releasepage(struct page *page, gfp_t gfp_flags) | 276 | static int afs_releasepage(struct page *page, gfp_t gfp_flags) |
278 | { | 277 | { |
279 | struct cachefs_page *pageio; | 278 | struct afs_vnode *vnode = AFS_FS_I(page->mapping->host); |
279 | struct afs_writeback *wb; | ||
280 | 280 | ||
281 | _enter("{%lu},%x", page->index, gfp_flags); | 281 | _enter("{{%x:%u}[%lu],%lx},%x", |
282 | vnode->fid.vid, vnode->fid.vnode, page->index, page->flags, | ||
283 | gfp_flags); | ||
282 | 284 | ||
283 | if (PagePrivate(page)) { | 285 | if (PagePrivate(page)) { |
284 | #ifdef AFS_CACHING_SUPPORT | 286 | wb = (struct afs_writeback *) page_private(page); |
285 | struct afs_vnode *vnode = AFS_FS_I(page->mapping->host); | 287 | ASSERT(wb != NULL); |
286 | cachefs_uncache_page(vnode->cache, page); | ||
287 | #endif | ||
288 | |||
289 | pageio = (struct cachefs_page *) page_private(page); | ||
290 | set_page_private(page, 0); | 288 | set_page_private(page, 0); |
291 | ClearPagePrivate(page); | 289 | ClearPagePrivate(page); |
292 | 290 | afs_put_writeback(wb); | |
293 | kfree(pageio); | ||
294 | } | 291 | } |
295 | 292 | ||
296 | _leave(" = 0"); | 293 | _leave(" = 0"); |
diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c index e54e6c2ad343..025b1903d9e1 100644 --- a/fs/afs/fsclient.c +++ b/fs/afs/fsclient.c | |||
@@ -33,8 +33,10 @@ static void xdr_decode_AFSFid(const __be32 **_bp, struct afs_fid *fid) | |||
33 | */ | 33 | */ |
34 | static void xdr_decode_AFSFetchStatus(const __be32 **_bp, | 34 | static void xdr_decode_AFSFetchStatus(const __be32 **_bp, |
35 | struct afs_file_status *status, | 35 | struct afs_file_status *status, |
36 | struct afs_vnode *vnode) | 36 | struct afs_vnode *vnode, |
37 | afs_dataversion_t *store_version) | ||
37 | { | 38 | { |
39 | afs_dataversion_t expected_version; | ||
38 | const __be32 *bp = *_bp; | 40 | const __be32 *bp = *_bp; |
39 | umode_t mode; | 41 | umode_t mode; |
40 | u64 data_version, size; | 42 | u64 data_version, size; |
@@ -101,7 +103,11 @@ static void xdr_decode_AFSFetchStatus(const __be32 **_bp, | |||
101 | vnode->vfs_inode.i_atime = vnode->vfs_inode.i_ctime; | 103 | vnode->vfs_inode.i_atime = vnode->vfs_inode.i_ctime; |
102 | } | 104 | } |
103 | 105 | ||
104 | if (status->data_version != data_version) { | 106 | expected_version = status->data_version; |
107 | if (store_version) | ||
108 | expected_version = *store_version; | ||
109 | |||
110 | if (expected_version != data_version) { | ||
105 | status->data_version = data_version; | 111 | status->data_version = data_version; |
106 | if (vnode && !test_bit(AFS_VNODE_UNSET, &vnode->flags)) { | 112 | if (vnode && !test_bit(AFS_VNODE_UNSET, &vnode->flags)) { |
107 | _debug("vnode modified %llx on {%x:%u}", | 113 | _debug("vnode modified %llx on {%x:%u}", |
@@ -110,6 +116,8 @@ static void xdr_decode_AFSFetchStatus(const __be32 **_bp, | |||
110 | set_bit(AFS_VNODE_MODIFIED, &vnode->flags); | 116 | set_bit(AFS_VNODE_MODIFIED, &vnode->flags); |
111 | set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags); | 117 | set_bit(AFS_VNODE_ZAP_DATA, &vnode->flags); |
112 | } | 118 | } |
119 | } else if (store_version) { | ||
120 | status->data_version = data_version; | ||
113 | } | 121 | } |
114 | } | 122 | } |
115 | 123 | ||
@@ -156,6 +164,44 @@ static void xdr_decode_AFSVolSync(const __be32 **_bp, | |||
156 | } | 164 | } |
157 | 165 | ||
158 | /* | 166 | /* |
167 | * encode the requested attributes into an AFSStoreStatus block | ||
168 | */ | ||
169 | static void xdr_encode_AFS_StoreStatus(__be32 **_bp, struct iattr *attr) | ||
170 | { | ||
171 | __be32 *bp = *_bp; | ||
172 | u32 mask = 0, mtime = 0, owner = 0, group = 0, mode = 0; | ||
173 | |||
174 | mask = 0; | ||
175 | if (attr->ia_valid & ATTR_MTIME) { | ||
176 | mask |= AFS_SET_MTIME; | ||
177 | mtime = attr->ia_mtime.tv_sec; | ||
178 | } | ||
179 | |||
180 | if (attr->ia_valid & ATTR_UID) { | ||
181 | mask |= AFS_SET_OWNER; | ||
182 | owner = attr->ia_uid; | ||
183 | } | ||
184 | |||
185 | if (attr->ia_valid & ATTR_GID) { | ||
186 | mask |= AFS_SET_GROUP; | ||
187 | group = attr->ia_gid; | ||
188 | } | ||
189 | |||
190 | if (attr->ia_valid & ATTR_MODE) { | ||
191 | mask |= AFS_SET_MODE; | ||
192 | mode = attr->ia_mode & S_IALLUGO; | ||
193 | } | ||
194 | |||
195 | *bp++ = htonl(mask); | ||
196 | *bp++ = htonl(mtime); | ||
197 | *bp++ = htonl(owner); | ||
198 | *bp++ = htonl(group); | ||
199 | *bp++ = htonl(mode); | ||
200 | *bp++ = 0; /* segment size */ | ||
201 | *_bp = bp; | ||
202 | } | ||
203 | |||
204 | /* | ||
159 | * deliver reply data to an FS.FetchStatus | 205 | * deliver reply data to an FS.FetchStatus |
160 | */ | 206 | */ |
161 | static int afs_deliver_fs_fetch_status(struct afs_call *call, | 207 | static int afs_deliver_fs_fetch_status(struct afs_call *call, |
@@ -175,7 +221,7 @@ static int afs_deliver_fs_fetch_status(struct afs_call *call, | |||
175 | 221 | ||
176 | /* unmarshall the reply once we've received all of it */ | 222 | /* unmarshall the reply once we've received all of it */ |
177 | bp = call->buffer; | 223 | bp = call->buffer; |
178 | xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode); | 224 | xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL); |
179 | xdr_decode_AFSCallBack(&bp, vnode); | 225 | xdr_decode_AFSCallBack(&bp, vnode); |
180 | if (call->reply2) | 226 | if (call->reply2) |
181 | xdr_decode_AFSVolSync(&bp, call->reply2); | 227 | xdr_decode_AFSVolSync(&bp, call->reply2); |
@@ -206,7 +252,7 @@ int afs_fs_fetch_file_status(struct afs_server *server, | |||
206 | struct afs_call *call; | 252 | struct afs_call *call; |
207 | __be32 *bp; | 253 | __be32 *bp; |
208 | 254 | ||
209 | _enter(",%x,{%x:%d},,", | 255 | _enter(",%x,{%x:%u},,", |
210 | key_serial(key), vnode->fid.vid, vnode->fid.vnode); | 256 | key_serial(key), vnode->fid.vid, vnode->fid.vnode); |
211 | 257 | ||
212 | call = afs_alloc_flat_call(&afs_RXFSFetchStatus, 16, (21 + 3 + 6) * 4); | 258 | call = afs_alloc_flat_call(&afs_RXFSFetchStatus, 16, (21 + 3 + 6) * 4); |
@@ -265,25 +311,20 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call, | |||
265 | call->offset = 0; | 311 | call->offset = 0; |
266 | call->unmarshall++; | 312 | call->unmarshall++; |
267 | 313 | ||
268 | if (call->count < PAGE_SIZE) { | ||
269 | page = call->reply3; | ||
270 | buffer = kmap_atomic(page, KM_USER0); | ||
271 | memset(buffer + PAGE_SIZE - call->count, 0, | ||
272 | call->count); | ||
273 | kunmap_atomic(buffer, KM_USER0); | ||
274 | } | ||
275 | |||
276 | /* extract the returned data */ | 314 | /* extract the returned data */ |
277 | case 2: | 315 | case 2: |
278 | _debug("extract data"); | 316 | _debug("extract data"); |
279 | page = call->reply3; | 317 | if (call->count > 0) { |
280 | buffer = kmap_atomic(page, KM_USER0); | 318 | page = call->reply3; |
281 | ret = afs_extract_data(call, skb, last, buffer, call->count); | 319 | buffer = kmap_atomic(page, KM_USER0); |
282 | kunmap_atomic(buffer, KM_USER0); | 320 | ret = afs_extract_data(call, skb, last, buffer, |
283 | switch (ret) { | 321 | call->count); |
284 | case 0: break; | 322 | kunmap_atomic(buffer, KM_USER0); |
285 | case -EAGAIN: return 0; | 323 | switch (ret) { |
286 | default: return ret; | 324 | case 0: break; |
325 | case -EAGAIN: return 0; | ||
326 | default: return ret; | ||
327 | } | ||
287 | } | 328 | } |
288 | 329 | ||
289 | call->offset = 0; | 330 | call->offset = 0; |
@@ -300,7 +341,7 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call, | |||
300 | } | 341 | } |
301 | 342 | ||
302 | bp = call->buffer; | 343 | bp = call->buffer; |
303 | xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode); | 344 | xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL); |
304 | xdr_decode_AFSCallBack(&bp, vnode); | 345 | xdr_decode_AFSCallBack(&bp, vnode); |
305 | if (call->reply2) | 346 | if (call->reply2) |
306 | xdr_decode_AFSVolSync(&bp, call->reply2); | 347 | xdr_decode_AFSVolSync(&bp, call->reply2); |
@@ -318,6 +359,14 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call, | |||
318 | if (!last) | 359 | if (!last) |
319 | return 0; | 360 | return 0; |
320 | 361 | ||
362 | if (call->count < PAGE_SIZE) { | ||
363 | _debug("clear"); | ||
364 | page = call->reply3; | ||
365 | buffer = kmap_atomic(page, KM_USER0); | ||
366 | memset(buffer + call->count, 0, PAGE_SIZE - call->count); | ||
367 | kunmap_atomic(buffer, KM_USER0); | ||
368 | } | ||
369 | |||
321 | _leave(" = 0 [done]"); | 370 | _leave(" = 0 [done]"); |
322 | return 0; | 371 | return 0; |
323 | } | 372 | } |
@@ -476,8 +525,8 @@ static int afs_deliver_fs_create_vnode(struct afs_call *call, | |||
476 | /* unmarshall the reply once we've received all of it */ | 525 | /* unmarshall the reply once we've received all of it */ |
477 | bp = call->buffer; | 526 | bp = call->buffer; |
478 | xdr_decode_AFSFid(&bp, call->reply2); | 527 | xdr_decode_AFSFid(&bp, call->reply2); |
479 | xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL); | 528 | xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL, NULL); |
480 | xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode); | 529 | xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL); |
481 | xdr_decode_AFSCallBack_raw(&bp, call->reply4); | 530 | xdr_decode_AFSCallBack_raw(&bp, call->reply4); |
482 | /* xdr_decode_AFSVolSync(&bp, call->replyX); */ | 531 | /* xdr_decode_AFSVolSync(&bp, call->replyX); */ |
483 | 532 | ||
@@ -574,7 +623,7 @@ static int afs_deliver_fs_remove(struct afs_call *call, | |||
574 | 623 | ||
575 | /* unmarshall the reply once we've received all of it */ | 624 | /* unmarshall the reply once we've received all of it */ |
576 | bp = call->buffer; | 625 | bp = call->buffer; |
577 | xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode); | 626 | xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL); |
578 | /* xdr_decode_AFSVolSync(&bp, call->replyX); */ | 627 | /* xdr_decode_AFSVolSync(&bp, call->replyX); */ |
579 | 628 | ||
580 | _leave(" = 0 [done]"); | 629 | _leave(" = 0 [done]"); |
@@ -657,8 +706,8 @@ static int afs_deliver_fs_link(struct afs_call *call, | |||
657 | 706 | ||
658 | /* unmarshall the reply once we've received all of it */ | 707 | /* unmarshall the reply once we've received all of it */ |
659 | bp = call->buffer; | 708 | bp = call->buffer; |
660 | xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode); | 709 | xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL); |
661 | xdr_decode_AFSFetchStatus(&bp, &dvnode->status, dvnode); | 710 | xdr_decode_AFSFetchStatus(&bp, &dvnode->status, dvnode, NULL); |
662 | /* xdr_decode_AFSVolSync(&bp, call->replyX); */ | 711 | /* xdr_decode_AFSVolSync(&bp, call->replyX); */ |
663 | 712 | ||
664 | _leave(" = 0 [done]"); | 713 | _leave(" = 0 [done]"); |
@@ -746,8 +795,8 @@ static int afs_deliver_fs_symlink(struct afs_call *call, | |||
746 | /* unmarshall the reply once we've received all of it */ | 795 | /* unmarshall the reply once we've received all of it */ |
747 | bp = call->buffer; | 796 | bp = call->buffer; |
748 | xdr_decode_AFSFid(&bp, call->reply2); | 797 | xdr_decode_AFSFid(&bp, call->reply2); |
749 | xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL); | 798 | xdr_decode_AFSFetchStatus(&bp, call->reply3, NULL, NULL); |
750 | xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode); | 799 | xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, NULL); |
751 | /* xdr_decode_AFSVolSync(&bp, call->replyX); */ | 800 | /* xdr_decode_AFSVolSync(&bp, call->replyX); */ |
752 | 801 | ||
753 | _leave(" = 0 [done]"); | 802 | _leave(" = 0 [done]"); |
@@ -852,9 +901,10 @@ static int afs_deliver_fs_rename(struct afs_call *call, | |||
852 | 901 | ||
853 | /* unmarshall the reply once we've received all of it */ | 902 | /* unmarshall the reply once we've received all of it */ |
854 | bp = call->buffer; | 903 | bp = call->buffer; |
855 | xdr_decode_AFSFetchStatus(&bp, &orig_dvnode->status, orig_dvnode); | 904 | xdr_decode_AFSFetchStatus(&bp, &orig_dvnode->status, orig_dvnode, NULL); |
856 | if (new_dvnode != orig_dvnode) | 905 | if (new_dvnode != orig_dvnode) |
857 | xdr_decode_AFSFetchStatus(&bp, &new_dvnode->status, new_dvnode); | 906 | xdr_decode_AFSFetchStatus(&bp, &new_dvnode->status, new_dvnode, |
907 | NULL); | ||
858 | /* xdr_decode_AFSVolSync(&bp, call->replyX); */ | 908 | /* xdr_decode_AFSVolSync(&bp, call->replyX); */ |
859 | 909 | ||
860 | _leave(" = 0 [done]"); | 910 | _leave(" = 0 [done]"); |
@@ -936,3 +986,262 @@ int afs_fs_rename(struct afs_server *server, | |||
936 | 986 | ||
937 | return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); | 987 | return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); |
938 | } | 988 | } |
989 | |||
990 | /* | ||
991 | * deliver reply data to an FS.StoreData | ||
992 | */ | ||
993 | static int afs_deliver_fs_store_data(struct afs_call *call, | ||
994 | struct sk_buff *skb, bool last) | ||
995 | { | ||
996 | struct afs_vnode *vnode = call->reply; | ||
997 | const __be32 *bp; | ||
998 | |||
999 | _enter(",,%u", last); | ||
1000 | |||
1001 | afs_transfer_reply(call, skb); | ||
1002 | if (!last) { | ||
1003 | _leave(" = 0 [more]"); | ||
1004 | return 0; | ||
1005 | } | ||
1006 | |||
1007 | if (call->reply_size != call->reply_max) { | ||
1008 | _leave(" = -EBADMSG [%u != %u]", | ||
1009 | call->reply_size, call->reply_max); | ||
1010 | return -EBADMSG; | ||
1011 | } | ||
1012 | |||
1013 | /* unmarshall the reply once we've received all of it */ | ||
1014 | bp = call->buffer; | ||
1015 | xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, | ||
1016 | &call->store_version); | ||
1017 | /* xdr_decode_AFSVolSync(&bp, call->replyX); */ | ||
1018 | |||
1019 | afs_pages_written_back(vnode, call); | ||
1020 | |||
1021 | _leave(" = 0 [done]"); | ||
1022 | return 0; | ||
1023 | } | ||
1024 | |||
1025 | /* | ||
1026 | * FS.StoreData operation type | ||
1027 | */ | ||
1028 | static const struct afs_call_type afs_RXFSStoreData = { | ||
1029 | .name = "FS.StoreData", | ||
1030 | .deliver = afs_deliver_fs_store_data, | ||
1031 | .abort_to_error = afs_abort_to_error, | ||
1032 | .destructor = afs_flat_call_destructor, | ||
1033 | }; | ||
1034 | |||
1035 | /* | ||
1036 | * store a set of pages | ||
1037 | */ | ||
1038 | int afs_fs_store_data(struct afs_server *server, struct afs_writeback *wb, | ||
1039 | pgoff_t first, pgoff_t last, | ||
1040 | unsigned offset, unsigned to, | ||
1041 | const struct afs_wait_mode *wait_mode) | ||
1042 | { | ||
1043 | struct afs_vnode *vnode = wb->vnode; | ||
1044 | struct afs_call *call; | ||
1045 | loff_t size, pos, i_size; | ||
1046 | __be32 *bp; | ||
1047 | |||
1048 | _enter(",%x,{%x:%u},,", | ||
1049 | key_serial(wb->key), vnode->fid.vid, vnode->fid.vnode); | ||
1050 | |||
1051 | size = to - offset; | ||
1052 | if (first != last) | ||
1053 | size += (loff_t)(last - first) << PAGE_SHIFT; | ||
1054 | pos = (loff_t)first << PAGE_SHIFT; | ||
1055 | pos += offset; | ||
1056 | |||
1057 | i_size = i_size_read(&vnode->vfs_inode); | ||
1058 | if (pos + size > i_size) | ||
1059 | i_size = size + pos; | ||
1060 | |||
1061 | _debug("size %llx, at %llx, i_size %llx", | ||
1062 | (unsigned long long) size, (unsigned long long) pos, | ||
1063 | (unsigned long long) i_size); | ||
1064 | |||
1065 | BUG_ON(i_size > 0xffffffff); // TODO: use 64-bit store | ||
1066 | |||
1067 | call = afs_alloc_flat_call(&afs_RXFSStoreData, | ||
1068 | (4 + 6 + 3) * 4, | ||
1069 | (21 + 6) * 4); | ||
1070 | if (!call) | ||
1071 | return -ENOMEM; | ||
1072 | |||
1073 | call->wb = wb; | ||
1074 | call->key = wb->key; | ||
1075 | call->reply = vnode; | ||
1076 | call->service_id = FS_SERVICE; | ||
1077 | call->port = htons(AFS_FS_PORT); | ||
1078 | call->mapping = vnode->vfs_inode.i_mapping; | ||
1079 | call->first = first; | ||
1080 | call->last = last; | ||
1081 | call->first_offset = offset; | ||
1082 | call->last_to = to; | ||
1083 | call->send_pages = true; | ||
1084 | call->store_version = vnode->status.data_version + 1; | ||
1085 | |||
1086 | /* marshall the parameters */ | ||
1087 | bp = call->request; | ||
1088 | *bp++ = htonl(FSSTOREDATA); | ||
1089 | *bp++ = htonl(vnode->fid.vid); | ||
1090 | *bp++ = htonl(vnode->fid.vnode); | ||
1091 | *bp++ = htonl(vnode->fid.unique); | ||
1092 | |||
1093 | *bp++ = 0; /* mask */ | ||
1094 | *bp++ = 0; /* mtime */ | ||
1095 | *bp++ = 0; /* owner */ | ||
1096 | *bp++ = 0; /* group */ | ||
1097 | *bp++ = 0; /* unix mode */ | ||
1098 | *bp++ = 0; /* segment size */ | ||
1099 | |||
1100 | *bp++ = htonl(pos); | ||
1101 | *bp++ = htonl(size); | ||
1102 | *bp++ = htonl(i_size); | ||
1103 | |||
1104 | return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); | ||
1105 | } | ||
1106 | |||
1107 | /* | ||
1108 | * deliver reply data to an FS.StoreStatus | ||
1109 | */ | ||
1110 | static int afs_deliver_fs_store_status(struct afs_call *call, | ||
1111 | struct sk_buff *skb, bool last) | ||
1112 | { | ||
1113 | afs_dataversion_t *store_version; | ||
1114 | struct afs_vnode *vnode = call->reply; | ||
1115 | const __be32 *bp; | ||
1116 | |||
1117 | _enter(",,%u", last); | ||
1118 | |||
1119 | afs_transfer_reply(call, skb); | ||
1120 | if (!last) { | ||
1121 | _leave(" = 0 [more]"); | ||
1122 | return 0; | ||
1123 | } | ||
1124 | |||
1125 | if (call->reply_size != call->reply_max) { | ||
1126 | _leave(" = -EBADMSG [%u != %u]", | ||
1127 | call->reply_size, call->reply_max); | ||
1128 | return -EBADMSG; | ||
1129 | } | ||
1130 | |||
1131 | /* unmarshall the reply once we've received all of it */ | ||
1132 | store_version = NULL; | ||
1133 | if (call->operation_ID == FSSTOREDATA) | ||
1134 | store_version = &call->store_version; | ||
1135 | |||
1136 | bp = call->buffer; | ||
1137 | xdr_decode_AFSFetchStatus(&bp, &vnode->status, vnode, store_version); | ||
1138 | /* xdr_decode_AFSVolSync(&bp, call->replyX); */ | ||
1139 | |||
1140 | _leave(" = 0 [done]"); | ||
1141 | return 0; | ||
1142 | } | ||
1143 | |||
1144 | /* | ||
1145 | * FS.StoreStatus operation type | ||
1146 | */ | ||
1147 | static const struct afs_call_type afs_RXFSStoreStatus = { | ||
1148 | .name = "FS.StoreStatus", | ||
1149 | .deliver = afs_deliver_fs_store_status, | ||
1150 | .abort_to_error = afs_abort_to_error, | ||
1151 | .destructor = afs_flat_call_destructor, | ||
1152 | }; | ||
1153 | |||
1154 | static const struct afs_call_type afs_RXFSStoreData_as_Status = { | ||
1155 | .name = "FS.StoreData", | ||
1156 | .deliver = afs_deliver_fs_store_status, | ||
1157 | .abort_to_error = afs_abort_to_error, | ||
1158 | .destructor = afs_flat_call_destructor, | ||
1159 | }; | ||
1160 | |||
1161 | /* | ||
1162 | * set the attributes on a file, using FS.StoreData rather than FS.StoreStatus | ||
1163 | * so as to alter the file size also | ||
1164 | */ | ||
1165 | static int afs_fs_setattr_size(struct afs_server *server, struct key *key, | ||
1166 | struct afs_vnode *vnode, struct iattr *attr, | ||
1167 | const struct afs_wait_mode *wait_mode) | ||
1168 | { | ||
1169 | struct afs_call *call; | ||
1170 | __be32 *bp; | ||
1171 | |||
1172 | _enter(",%x,{%x:%u},,", | ||
1173 | key_serial(key), vnode->fid.vid, vnode->fid.vnode); | ||
1174 | |||
1175 | ASSERT(attr->ia_valid & ATTR_SIZE); | ||
1176 | ASSERTCMP(attr->ia_size, <=, 0xffffffff); // TODO: use 64-bit store | ||
1177 | |||
1178 | call = afs_alloc_flat_call(&afs_RXFSStoreData_as_Status, | ||
1179 | (4 + 6 + 3) * 4, | ||
1180 | (21 + 6) * 4); | ||
1181 | if (!call) | ||
1182 | return -ENOMEM; | ||
1183 | |||
1184 | call->key = key; | ||
1185 | call->reply = vnode; | ||
1186 | call->service_id = FS_SERVICE; | ||
1187 | call->port = htons(AFS_FS_PORT); | ||
1188 | call->store_version = vnode->status.data_version + 1; | ||
1189 | call->operation_ID = FSSTOREDATA; | ||
1190 | |||
1191 | /* marshall the parameters */ | ||
1192 | bp = call->request; | ||
1193 | *bp++ = htonl(FSSTOREDATA); | ||
1194 | *bp++ = htonl(vnode->fid.vid); | ||
1195 | *bp++ = htonl(vnode->fid.vnode); | ||
1196 | *bp++ = htonl(vnode->fid.unique); | ||
1197 | |||
1198 | xdr_encode_AFS_StoreStatus(&bp, attr); | ||
1199 | |||
1200 | *bp++ = 0; /* position of start of write */ | ||
1201 | *bp++ = 0; /* size of write */ | ||
1202 | *bp++ = htonl(attr->ia_size); /* new file length */ | ||
1203 | |||
1204 | return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); | ||
1205 | } | ||
1206 | |||
1207 | /* | ||
1208 | * set the attributes on a file, using FS.StoreData if there's a change in file | ||
1209 | * size, and FS.StoreStatus otherwise | ||
1210 | */ | ||
1211 | int afs_fs_setattr(struct afs_server *server, struct key *key, | ||
1212 | struct afs_vnode *vnode, struct iattr *attr, | ||
1213 | const struct afs_wait_mode *wait_mode) | ||
1214 | { | ||
1215 | struct afs_call *call; | ||
1216 | __be32 *bp; | ||
1217 | |||
1218 | if (attr->ia_valid & ATTR_SIZE) | ||
1219 | return afs_fs_setattr_size(server, key, vnode, attr, | ||
1220 | wait_mode); | ||
1221 | |||
1222 | _enter(",%x,{%x:%u},,", | ||
1223 | key_serial(key), vnode->fid.vid, vnode->fid.vnode); | ||
1224 | |||
1225 | call = afs_alloc_flat_call(&afs_RXFSStoreStatus, | ||
1226 | (4 + 6) * 4, | ||
1227 | (21 + 6) * 4); | ||
1228 | if (!call) | ||
1229 | return -ENOMEM; | ||
1230 | |||
1231 | call->key = key; | ||
1232 | call->reply = vnode; | ||
1233 | call->service_id = FS_SERVICE; | ||
1234 | call->port = htons(AFS_FS_PORT); | ||
1235 | call->operation_ID = FSSTORESTATUS; | ||
1236 | |||
1237 | /* marshall the parameters */ | ||
1238 | bp = call->request; | ||
1239 | *bp++ = htonl(FSSTORESTATUS); | ||
1240 | *bp++ = htonl(vnode->fid.vid); | ||
1241 | *bp++ = htonl(vnode->fid.vnode); | ||
1242 | *bp++ = htonl(vnode->fid.unique); | ||
1243 | |||
1244 | xdr_encode_AFS_StoreStatus(&bp, attr); | ||
1245 | |||
1246 | return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode); | ||
1247 | } | ||
diff --git a/fs/afs/inode.c b/fs/afs/inode.c index c184a4ee5995..515a5d12d8fb 100644 --- a/fs/afs/inode.c +++ b/fs/afs/inode.c | |||
@@ -125,7 +125,7 @@ struct inode *afs_iget(struct super_block *sb, struct key *key, | |||
125 | struct inode *inode; | 125 | struct inode *inode; |
126 | int ret; | 126 | int ret; |
127 | 127 | ||
128 | _enter(",{%u,%u,%u},,", fid->vid, fid->vnode, fid->unique); | 128 | _enter(",{%x:%u.%u},,", fid->vid, fid->vnode, fid->unique); |
129 | 129 | ||
130 | as = sb->s_fs_info; | 130 | as = sb->s_fs_info; |
131 | data.volume = as->volume; | 131 | data.volume = as->volume; |
@@ -204,6 +204,19 @@ bad_inode: | |||
204 | } | 204 | } |
205 | 205 | ||
206 | /* | 206 | /* |
207 | * mark the data attached to an inode as obsolete due to a write on the server | ||
208 | * - might also want to ditch all the outstanding writes and dirty pages | ||
209 | */ | ||
210 | void afs_zap_data(struct afs_vnode *vnode) | ||
211 | { | ||
212 | _enter("zap data {%x:%u}", vnode->fid.vid, vnode->fid.vnode); | ||
213 | |||
214 | /* nuke all the non-dirty pages that aren't locked, mapped or being | ||
215 | * written back */ | ||
216 | invalidate_remote_inode(&vnode->vfs_inode); | ||
217 | } | ||
218 | |||
219 | /* | ||
207 | * validate a vnode/inode | 220 | * validate a vnode/inode |
208 | * - there are several things we need to check | 221 | * - there are several things we need to check |
209 | * - parent dir data changes (rm, rmdir, rename, mkdir, create, link, | 222 | * - parent dir data changes (rm, rmdir, rename, mkdir, create, link, |
@@ -258,10 +271,8 @@ int afs_validate(struct afs_vnode *vnode, struct key *key) | |||
258 | 271 | ||
259 | /* if the vnode's data version number changed then its contents are | 272 | /* if the vnode's data version number changed then its contents are |
260 | * different */ | 273 | * different */ |
261 | if (test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) { | 274 | if (test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) |
262 | _debug("zap data {%x:%d}", vnode->fid.vid, vnode->fid.vnode); | 275 | afs_zap_data(vnode); |
263 | invalidate_remote_inode(&vnode->vfs_inode); | ||
264 | } | ||
265 | 276 | ||
266 | clear_bit(AFS_VNODE_MODIFIED, &vnode->flags); | 277 | clear_bit(AFS_VNODE_MODIFIED, &vnode->flags); |
267 | mutex_unlock(&vnode->validate_lock); | 278 | mutex_unlock(&vnode->validate_lock); |
@@ -278,7 +289,7 @@ error_unlock: | |||
278 | /* | 289 | /* |
279 | * read the attributes of an inode | 290 | * read the attributes of an inode |
280 | */ | 291 | */ |
281 | int afs_inode_getattr(struct vfsmount *mnt, struct dentry *dentry, | 292 | int afs_getattr(struct vfsmount *mnt, struct dentry *dentry, |
282 | struct kstat *stat) | 293 | struct kstat *stat) |
283 | { | 294 | { |
284 | struct inode *inode; | 295 | struct inode *inode; |
@@ -301,7 +312,7 @@ void afs_clear_inode(struct inode *inode) | |||
301 | 312 | ||
302 | vnode = AFS_FS_I(inode); | 313 | vnode = AFS_FS_I(inode); |
303 | 314 | ||
304 | _enter("{%x:%d.%d} v=%u x=%u t=%u }", | 315 | _enter("{%x:%u.%d} v=%u x=%u t=%u }", |
305 | vnode->fid.vid, | 316 | vnode->fid.vid, |
306 | vnode->fid.vnode, | 317 | vnode->fid.vnode, |
307 | vnode->fid.unique, | 318 | vnode->fid.unique, |
@@ -323,6 +334,7 @@ void afs_clear_inode(struct inode *inode) | |||
323 | vnode->server = NULL; | 334 | vnode->server = NULL; |
324 | } | 335 | } |
325 | 336 | ||
337 | ASSERT(list_empty(&vnode->writebacks)); | ||
326 | ASSERT(!vnode->cb_promised); | 338 | ASSERT(!vnode->cb_promised); |
327 | 339 | ||
328 | #ifdef AFS_CACHING_SUPPORT | 340 | #ifdef AFS_CACHING_SUPPORT |
@@ -339,3 +351,47 @@ void afs_clear_inode(struct inode *inode) | |||
339 | 351 | ||
340 | _leave(""); | 352 | _leave(""); |
341 | } | 353 | } |
354 | |||
355 | /* | ||
356 | * set the attributes of an inode | ||
357 | */ | ||
358 | int afs_setattr(struct dentry *dentry, struct iattr *attr) | ||
359 | { | ||
360 | struct afs_vnode *vnode = AFS_FS_I(dentry->d_inode); | ||
361 | struct key *key; | ||
362 | int ret; | ||
363 | |||
364 | _enter("{%x:%u},{n=%s},%x", | ||
365 | vnode->fid.vid, vnode->fid.vnode, dentry->d_name.name, | ||
366 | attr->ia_valid); | ||
367 | |||
368 | if (!(attr->ia_valid & (ATTR_SIZE | ATTR_MODE | ATTR_UID | ATTR_GID | | ||
369 | ATTR_MTIME))) { | ||
370 | _leave(" = 0 [unsupported]"); | ||
371 | return 0; | ||
372 | } | ||
373 | |||
374 | /* flush any dirty data outstanding on a regular file */ | ||
375 | if (S_ISREG(vnode->vfs_inode.i_mode)) { | ||
376 | filemap_write_and_wait(vnode->vfs_inode.i_mapping); | ||
377 | afs_writeback_all(vnode); | ||
378 | } | ||
379 | |||
380 | if (attr->ia_valid & ATTR_FILE) { | ||
381 | key = attr->ia_file->private_data; | ||
382 | } else { | ||
383 | key = afs_request_key(vnode->volume->cell); | ||
384 | if (IS_ERR(key)) { | ||
385 | ret = PTR_ERR(key); | ||
386 | goto error; | ||
387 | } | ||
388 | } | ||
389 | |||
390 | ret = afs_vnode_setattr(vnode, key, attr); | ||
391 | if (!(attr->ia_valid & ATTR_FILE)) | ||
392 | key_put(key); | ||
393 | |||
394 | error: | ||
395 | _leave(" = %d", ret); | ||
396 | return ret; | ||
397 | } | ||
diff --git a/fs/afs/internal.h b/fs/afs/internal.h index d90c158cd934..a30d4fa768e3 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h | |||
@@ -21,6 +21,7 @@ | |||
21 | 21 | ||
22 | #define AFS_CELL_MAX_ADDRS 15 | 22 | #define AFS_CELL_MAX_ADDRS 15 |
23 | 23 | ||
24 | struct pagevec; | ||
24 | struct afs_call; | 25 | struct afs_call; |
25 | 26 | ||
26 | typedef enum { | 27 | typedef enum { |
@@ -75,12 +76,15 @@ struct afs_call { | |||
75 | struct key *key; /* security for this call */ | 76 | struct key *key; /* security for this call */ |
76 | struct afs_server *server; /* server affected by incoming CM call */ | 77 | struct afs_server *server; /* server affected by incoming CM call */ |
77 | void *request; /* request data (first part) */ | 78 | void *request; /* request data (first part) */ |
78 | void *request2; /* request data (second part) */ | 79 | struct address_space *mapping; /* page set */ |
80 | struct afs_writeback *wb; /* writeback being performed */ | ||
79 | void *buffer; /* reply receive buffer */ | 81 | void *buffer; /* reply receive buffer */ |
80 | void *reply; /* reply buffer (first part) */ | 82 | void *reply; /* reply buffer (first part) */ |
81 | void *reply2; /* reply buffer (second part) */ | 83 | void *reply2; /* reply buffer (second part) */ |
82 | void *reply3; /* reply buffer (third part) */ | 84 | void *reply3; /* reply buffer (third part) */ |
83 | void *reply4; /* reply buffer (fourth part) */ | 85 | void *reply4; /* reply buffer (fourth part) */ |
86 | pgoff_t first; /* first page in mapping to deal with */ | ||
87 | pgoff_t last; /* last page in mapping to deal with */ | ||
84 | enum { /* call state */ | 88 | enum { /* call state */ |
85 | AFS_CALL_REQUESTING, /* request is being sent for outgoing call */ | 89 | AFS_CALL_REQUESTING, /* request is being sent for outgoing call */ |
86 | AFS_CALL_AWAIT_REPLY, /* awaiting reply to outgoing call */ | 90 | AFS_CALL_AWAIT_REPLY, /* awaiting reply to outgoing call */ |
@@ -97,14 +101,18 @@ struct afs_call { | |||
97 | unsigned request_size; /* size of request data */ | 101 | unsigned request_size; /* size of request data */ |
98 | unsigned reply_max; /* maximum size of reply */ | 102 | unsigned reply_max; /* maximum size of reply */ |
99 | unsigned reply_size; /* current size of reply */ | 103 | unsigned reply_size; /* current size of reply */ |
104 | unsigned first_offset; /* offset into mapping[first] */ | ||
105 | unsigned last_to; /* amount of mapping[last] */ | ||
100 | unsigned short offset; /* offset into received data store */ | 106 | unsigned short offset; /* offset into received data store */ |
101 | unsigned char unmarshall; /* unmarshalling phase */ | 107 | unsigned char unmarshall; /* unmarshalling phase */ |
102 | bool incoming; /* T if incoming call */ | 108 | bool incoming; /* T if incoming call */ |
109 | bool send_pages; /* T if data from mapping should be sent */ | ||
103 | u16 service_id; /* RxRPC service ID to call */ | 110 | u16 service_id; /* RxRPC service ID to call */ |
104 | __be16 port; /* target UDP port */ | 111 | __be16 port; /* target UDP port */ |
105 | __be32 operation_ID; /* operation ID for an incoming call */ | 112 | __be32 operation_ID; /* operation ID for an incoming call */ |
106 | u32 count; /* count for use in unmarshalling */ | 113 | u32 count; /* count for use in unmarshalling */ |
107 | __be32 tmp; /* place to extract temporary data */ | 114 | __be32 tmp; /* place to extract temporary data */ |
115 | afs_dataversion_t store_version; /* updated version expected from store */ | ||
108 | }; | 116 | }; |
109 | 117 | ||
110 | struct afs_call_type { | 118 | struct afs_call_type { |
@@ -124,6 +132,32 @@ struct afs_call_type { | |||
124 | }; | 132 | }; |
125 | 133 | ||
126 | /* | 134 | /* |
135 | * record of an outstanding writeback on a vnode | ||
136 | */ | ||
137 | struct afs_writeback { | ||
138 | struct list_head link; /* link in vnode->writebacks */ | ||
139 | struct work_struct writer; /* work item to perform the writeback */ | ||
140 | struct afs_vnode *vnode; /* vnode to which this write applies */ | ||
141 | struct key *key; /* owner of this write */ | ||
142 | wait_queue_head_t waitq; /* completion and ready wait queue */ | ||
143 | pgoff_t first; /* first page in batch */ | ||
144 | pgoff_t point; /* last page in current store op */ | ||
145 | pgoff_t last; /* last page in batch (inclusive) */ | ||
146 | unsigned offset_first; /* offset into first page of start of write */ | ||
147 | unsigned to_last; /* offset into last page of end of write */ | ||
148 | int num_conflicts; /* count of conflicting writes in list */ | ||
149 | int usage; | ||
150 | bool conflicts; /* T if has dependent conflicts */ | ||
151 | enum { | ||
152 | AFS_WBACK_SYNCING, /* synchronisation being performed */ | ||
153 | AFS_WBACK_PENDING, /* write pending */ | ||
154 | AFS_WBACK_CONFLICTING, /* conflicting writes posted */ | ||
155 | AFS_WBACK_WRITING, /* writing back */ | ||
156 | AFS_WBACK_COMPLETE /* the writeback record has been unlinked */ | ||
157 | } state __attribute__((packed)); | ||
158 | }; | ||
159 | |||
160 | /* | ||
127 | * AFS superblock private data | 161 | * AFS superblock private data |
128 | * - there's one superblock per volume | 162 | * - there's one superblock per volume |
129 | */ | 163 | */ |
@@ -305,6 +339,7 @@ struct afs_vnode { | |||
305 | wait_queue_head_t update_waitq; /* status fetch waitqueue */ | 339 | wait_queue_head_t update_waitq; /* status fetch waitqueue */ |
306 | int update_cnt; /* number of outstanding ops that will update the | 340 | int update_cnt; /* number of outstanding ops that will update the |
307 | * status */ | 341 | * status */ |
342 | spinlock_t writeback_lock; /* lock for writebacks */ | ||
308 | spinlock_t lock; /* waitqueue/flags lock */ | 343 | spinlock_t lock; /* waitqueue/flags lock */ |
309 | unsigned long flags; | 344 | unsigned long flags; |
310 | #define AFS_VNODE_CB_BROKEN 0 /* set if vnode's callback was broken */ | 345 | #define AFS_VNODE_CB_BROKEN 0 /* set if vnode's callback was broken */ |
@@ -316,6 +351,8 @@ struct afs_vnode { | |||
316 | 351 | ||
317 | long acl_order; /* ACL check count (callback break count) */ | 352 | long acl_order; /* ACL check count (callback break count) */ |
318 | 353 | ||
354 | struct list_head writebacks; /* alterations in pagecache that need writing */ | ||
355 | |||
319 | /* outstanding callback notification on this file */ | 356 | /* outstanding callback notification on this file */ |
320 | struct rb_node server_rb; /* link in server->fs_vnodes */ | 357 | struct rb_node server_rb; /* link in server->fs_vnodes */ |
321 | struct rb_node cb_promise; /* link in server->cb_promises */ | 358 | struct rb_node cb_promise; /* link in server->cb_promises */ |
@@ -433,10 +470,6 @@ extern const struct file_operations afs_file_operations; | |||
433 | extern int afs_open(struct inode *, struct file *); | 470 | extern int afs_open(struct inode *, struct file *); |
434 | extern int afs_release(struct inode *, struct file *); | 471 | extern int afs_release(struct inode *, struct file *); |
435 | 472 | ||
436 | #ifdef AFS_CACHING_SUPPORT | ||
437 | extern int afs_cache_get_page_cookie(struct page *, struct cachefs_page **); | ||
438 | #endif | ||
439 | |||
440 | /* | 473 | /* |
441 | * fsclient.c | 474 | * fsclient.c |
442 | */ | 475 | */ |
@@ -467,6 +500,12 @@ extern int afs_fs_rename(struct afs_server *, struct key *, | |||
467 | struct afs_vnode *, const char *, | 500 | struct afs_vnode *, const char *, |
468 | struct afs_vnode *, const char *, | 501 | struct afs_vnode *, const char *, |
469 | const struct afs_wait_mode *); | 502 | const struct afs_wait_mode *); |
503 | extern int afs_fs_store_data(struct afs_server *, struct afs_writeback *, | ||
504 | pgoff_t, pgoff_t, unsigned, unsigned, | ||
505 | const struct afs_wait_mode *); | ||
506 | extern int afs_fs_setattr(struct afs_server *, struct key *, | ||
507 | struct afs_vnode *, struct iattr *, | ||
508 | const struct afs_wait_mode *); | ||
470 | 509 | ||
471 | /* | 510 | /* |
472 | * inode.c | 511 | * inode.c |
@@ -474,10 +513,10 @@ extern int afs_fs_rename(struct afs_server *, struct key *, | |||
474 | extern struct inode *afs_iget(struct super_block *, struct key *, | 513 | extern struct inode *afs_iget(struct super_block *, struct key *, |
475 | struct afs_fid *, struct afs_file_status *, | 514 | struct afs_fid *, struct afs_file_status *, |
476 | struct afs_callback *); | 515 | struct afs_callback *); |
516 | extern void afs_zap_data(struct afs_vnode *); | ||
477 | extern int afs_validate(struct afs_vnode *, struct key *); | 517 | extern int afs_validate(struct afs_vnode *, struct key *); |
478 | extern int afs_inode_getattr(struct vfsmount *, struct dentry *, | 518 | extern int afs_getattr(struct vfsmount *, struct dentry *, struct kstat *); |
479 | struct kstat *); | 519 | extern int afs_setattr(struct dentry *, struct iattr *); |
480 | extern void afs_zap_permits(struct rcu_head *); | ||
481 | extern void afs_clear_inode(struct inode *); | 520 | extern void afs_clear_inode(struct inode *); |
482 | 521 | ||
483 | /* | 522 | /* |
@@ -533,6 +572,7 @@ extern int afs_extract_data(struct afs_call *, struct sk_buff *, bool, void *, | |||
533 | */ | 572 | */ |
534 | extern void afs_clear_permits(struct afs_vnode *); | 573 | extern void afs_clear_permits(struct afs_vnode *); |
535 | extern void afs_cache_permit(struct afs_vnode *, struct key *, long); | 574 | extern void afs_cache_permit(struct afs_vnode *, struct key *, long); |
575 | extern void afs_zap_permits(struct rcu_head *); | ||
536 | extern struct key *afs_request_key(struct afs_cell *); | 576 | extern struct key *afs_request_key(struct afs_cell *); |
537 | extern int afs_permission(struct inode *, int, struct nameidata *); | 577 | extern int afs_permission(struct inode *, int, struct nameidata *); |
538 | 578 | ||
@@ -629,6 +669,9 @@ extern int afs_vnode_symlink(struct afs_vnode *, struct key *, const char *, | |||
629 | struct afs_file_status *, struct afs_server **); | 669 | struct afs_file_status *, struct afs_server **); |
630 | extern int afs_vnode_rename(struct afs_vnode *, struct afs_vnode *, | 670 | extern int afs_vnode_rename(struct afs_vnode *, struct afs_vnode *, |
631 | struct key *, const char *, const char *); | 671 | struct key *, const char *, const char *); |
672 | extern int afs_vnode_store_data(struct afs_writeback *, pgoff_t, pgoff_t, | ||
673 | unsigned, unsigned); | ||
674 | extern int afs_vnode_setattr(struct afs_vnode *, struct key *, struct iattr *); | ||
632 | 675 | ||
633 | /* | 676 | /* |
634 | * volume.c | 677 | * volume.c |
@@ -645,6 +688,23 @@ extern struct afs_server *afs_volume_pick_fileserver(struct afs_vnode *); | |||
645 | extern int afs_volume_release_fileserver(struct afs_vnode *, | 688 | extern int afs_volume_release_fileserver(struct afs_vnode *, |
646 | struct afs_server *, int); | 689 | struct afs_server *, int); |
647 | 690 | ||
691 | /* | ||
692 | * write.c | ||
693 | */ | ||
694 | extern int afs_set_page_dirty(struct page *); | ||
695 | extern void afs_put_writeback(struct afs_writeback *); | ||
696 | extern int afs_prepare_write(struct file *, struct page *, unsigned, unsigned); | ||
697 | extern int afs_commit_write(struct file *, struct page *, unsigned, unsigned); | ||
698 | extern int afs_writepage(struct page *, struct writeback_control *); | ||
699 | extern int afs_writepages(struct address_space *, struct writeback_control *); | ||
700 | extern int afs_write_inode(struct inode *, int); | ||
701 | extern void afs_pages_written_back(struct afs_vnode *, struct afs_call *); | ||
702 | extern ssize_t afs_file_write(struct kiocb *, const struct iovec *, | ||
703 | unsigned long, loff_t); | ||
704 | extern int afs_writeback_all(struct afs_vnode *); | ||
705 | extern int afs_fsync(struct file *, struct dentry *, int); | ||
706 | |||
707 | |||
648 | /*****************************************************************************/ | 708 | /*****************************************************************************/ |
649 | /* | 709 | /* |
650 | * debug tracing | 710 | * debug tracing |
@@ -726,6 +786,21 @@ do { \ | |||
726 | } \ | 786 | } \ |
727 | } while(0) | 787 | } while(0) |
728 | 788 | ||
789 | #define ASSERTRANGE(L, OP1, N, OP2, H) \ | ||
790 | do { \ | ||
791 | if (unlikely(!((L) OP1 (N)) || !((N) OP2 (H)))) { \ | ||
792 | printk(KERN_ERR "\n"); \ | ||
793 | printk(KERN_ERR "AFS: Assertion failed\n"); \ | ||
794 | printk(KERN_ERR "%lu "#OP1" %lu "#OP2" %lu is false\n", \ | ||
795 | (unsigned long)(L), (unsigned long)(N), \ | ||
796 | (unsigned long)(H)); \ | ||
797 | printk(KERN_ERR "0x%lx "#OP1" 0x%lx "#OP2" 0x%lx is false\n", \ | ||
798 | (unsigned long)(L), (unsigned long)(N), \ | ||
799 | (unsigned long)(H)); \ | ||
800 | BUG(); \ | ||
801 | } \ | ||
802 | } while(0) | ||
803 | |||
729 | #define ASSERTIF(C, X) \ | 804 | #define ASSERTIF(C, X) \ |
730 | do { \ | 805 | do { \ |
731 | if (unlikely((C) && !(X))) { \ | 806 | if (unlikely((C) && !(X))) { \ |
@@ -758,6 +833,10 @@ do { \ | |||
758 | do { \ | 833 | do { \ |
759 | } while(0) | 834 | } while(0) |
760 | 835 | ||
836 | #define ASSERTRANGE(L, OP1, N, OP2, H) \ | ||
837 | do { \ | ||
838 | } while(0) | ||
839 | |||
761 | #define ASSERTIF(C, X) \ | 840 | #define ASSERTIF(C, X) \ |
762 | do { \ | 841 | do { \ |
763 | } while(0) | 842 | } while(0) |
diff --git a/fs/afs/main.c b/fs/afs/main.c index 80ec6fd19a73..f1f71ff7d5c6 100644 --- a/fs/afs/main.c +++ b/fs/afs/main.c | |||
@@ -149,6 +149,7 @@ error_cache: | |||
149 | afs_vlocation_purge(); | 149 | afs_vlocation_purge(); |
150 | afs_cell_purge(); | 150 | afs_cell_purge(); |
151 | afs_proc_cleanup(); | 151 | afs_proc_cleanup(); |
152 | rcu_barrier(); | ||
152 | printk(KERN_ERR "kAFS: failed to register: %d\n", ret); | 153 | printk(KERN_ERR "kAFS: failed to register: %d\n", ret); |
153 | return ret; | 154 | return ret; |
154 | } | 155 | } |
@@ -176,6 +177,7 @@ static void __exit afs_exit(void) | |||
176 | cachefs_unregister_netfs(&afs_cache_netfs); | 177 | cachefs_unregister_netfs(&afs_cache_netfs); |
177 | #endif | 178 | #endif |
178 | afs_proc_cleanup(); | 179 | afs_proc_cleanup(); |
180 | rcu_barrier(); | ||
179 | } | 181 | } |
180 | 182 | ||
181 | module_exit(afs_exit); | 183 | module_exit(afs_exit); |
diff --git a/fs/afs/misc.c b/fs/afs/misc.c index cdb9792d8161..d1a889c40742 100644 --- a/fs/afs/misc.c +++ b/fs/afs/misc.c | |||
@@ -22,6 +22,7 @@ int afs_abort_to_error(u32 abort_code) | |||
22 | { | 22 | { |
23 | switch (abort_code) { | 23 | switch (abort_code) { |
24 | case 13: return -EACCES; | 24 | case 13: return -EACCES; |
25 | case 27: return -EFBIG; | ||
25 | case 30: return -EROFS; | 26 | case 30: return -EROFS; |
26 | case VSALVAGE: return -EIO; | 27 | case VSALVAGE: return -EIO; |
27 | case VNOVNODE: return -ENOENT; | 28 | case VNOVNODE: return -ENOENT; |
diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c index 034fcfd4e330..a3684dcc76e7 100644 --- a/fs/afs/mntpt.c +++ b/fs/afs/mntpt.c | |||
@@ -36,7 +36,7 @@ const struct inode_operations afs_mntpt_inode_operations = { | |||
36 | .lookup = afs_mntpt_lookup, | 36 | .lookup = afs_mntpt_lookup, |
37 | .follow_link = afs_mntpt_follow_link, | 37 | .follow_link = afs_mntpt_follow_link, |
38 | .readlink = page_readlink, | 38 | .readlink = page_readlink, |
39 | .getattr = afs_inode_getattr, | 39 | .getattr = afs_getattr, |
40 | }; | 40 | }; |
41 | 41 | ||
42 | static LIST_HEAD(afs_vfsmounts); | 42 | static LIST_HEAD(afs_vfsmounts); |
@@ -58,7 +58,8 @@ int afs_mntpt_check_symlink(struct afs_vnode *vnode, struct key *key) | |||
58 | char *buf; | 58 | char *buf; |
59 | int ret; | 59 | int ret; |
60 | 60 | ||
61 | _enter("{%u,%u}", vnode->fid.vnode, vnode->fid.unique); | 61 | _enter("{%x:%u,%u}", |
62 | vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique); | ||
62 | 63 | ||
63 | /* read the contents of the symlink into the pagecache */ | 64 | /* read the contents of the symlink into the pagecache */ |
64 | page = read_mapping_page(AFS_VNODE_TO_I(vnode)->i_mapping, 0, &file); | 65 | page = read_mapping_page(AFS_VNODE_TO_I(vnode)->i_mapping, 0, &file); |
diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c index 222c1a3abbb8..04189c47d6a0 100644 --- a/fs/afs/rxrpc.c +++ b/fs/afs/rxrpc.c | |||
@@ -237,6 +237,70 @@ void afs_flat_call_destructor(struct afs_call *call) | |||
237 | } | 237 | } |
238 | 238 | ||
239 | /* | 239 | /* |
240 | * attach the data from a bunch of pages on an inode to a call | ||
241 | */ | ||
242 | int afs_send_pages(struct afs_call *call, struct msghdr *msg, struct kvec *iov) | ||
243 | { | ||
244 | struct page *pages[8]; | ||
245 | unsigned count, n, loop, offset, to; | ||
246 | pgoff_t first = call->first, last = call->last; | ||
247 | int ret; | ||
248 | |||
249 | _enter(""); | ||
250 | |||
251 | offset = call->first_offset; | ||
252 | call->first_offset = 0; | ||
253 | |||
254 | do { | ||
255 | _debug("attach %lx-%lx", first, last); | ||
256 | |||
257 | count = last - first + 1; | ||
258 | if (count > ARRAY_SIZE(pages)) | ||
259 | count = ARRAY_SIZE(pages); | ||
260 | n = find_get_pages_contig(call->mapping, first, count, pages); | ||
261 | ASSERTCMP(n, ==, count); | ||
262 | |||
263 | loop = 0; | ||
264 | do { | ||
265 | msg->msg_flags = 0; | ||
266 | to = PAGE_SIZE; | ||
267 | if (first + loop >= last) | ||
268 | to = call->last_to; | ||
269 | else | ||
270 | msg->msg_flags = MSG_MORE; | ||
271 | iov->iov_base = kmap(pages[loop]) + offset; | ||
272 | iov->iov_len = to - offset; | ||
273 | offset = 0; | ||
274 | |||
275 | _debug("- range %u-%u%s", | ||
276 | offset, to, msg->msg_flags ? " [more]" : ""); | ||
277 | msg->msg_iov = (struct iovec *) iov; | ||
278 | msg->msg_iovlen = 1; | ||
279 | |||
280 | /* have to change the state *before* sending the last | ||
281 | * packet as RxRPC might give us the reply before it | ||
282 | * returns from sending the request */ | ||
283 | if (first + loop >= last) | ||
284 | call->state = AFS_CALL_AWAIT_REPLY; | ||
285 | ret = rxrpc_kernel_send_data(call->rxcall, msg, | ||
286 | to - offset); | ||
287 | kunmap(pages[loop]); | ||
288 | if (ret < 0) | ||
289 | break; | ||
290 | } while (++loop < count); | ||
291 | first += count; | ||
292 | |||
293 | for (loop = 0; loop < count; loop++) | ||
294 | put_page(pages[loop]); | ||
295 | if (ret < 0) | ||
296 | break; | ||
297 | } while (first < last); | ||
298 | |||
299 | _leave(" = %d", ret); | ||
300 | return ret; | ||
301 | } | ||
302 | |||
303 | /* | ||
240 | * initiate a call | 304 | * initiate a call |
241 | */ | 305 | */ |
242 | int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp, | 306 | int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp, |
@@ -253,8 +317,9 @@ int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp, | |||
253 | ASSERT(call->type != NULL); | 317 | ASSERT(call->type != NULL); |
254 | ASSERT(call->type->name != NULL); | 318 | ASSERT(call->type->name != NULL); |
255 | 319 | ||
256 | _debug("MAKE %p{%s} [%d]", | 320 | _debug("____MAKE %p{%s,%x} [%d]____", |
257 | call, call->type->name, atomic_read(&afs_outstanding_calls)); | 321 | call, call->type->name, key_serial(call->key), |
322 | atomic_read(&afs_outstanding_calls)); | ||
258 | 323 | ||
259 | call->wait_mode = wait_mode; | 324 | call->wait_mode = wait_mode; |
260 | INIT_WORK(&call->async_work, afs_process_async_call); | 325 | INIT_WORK(&call->async_work, afs_process_async_call); |
@@ -289,16 +354,23 @@ int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp, | |||
289 | msg.msg_iovlen = 1; | 354 | msg.msg_iovlen = 1; |
290 | msg.msg_control = NULL; | 355 | msg.msg_control = NULL; |
291 | msg.msg_controllen = 0; | 356 | msg.msg_controllen = 0; |
292 | msg.msg_flags = 0; | 357 | msg.msg_flags = (call->send_pages ? MSG_MORE : 0); |
293 | 358 | ||
294 | /* have to change the state *before* sending the last packet as RxRPC | 359 | /* have to change the state *before* sending the last packet as RxRPC |
295 | * might give us the reply before it returns from sending the | 360 | * might give us the reply before it returns from sending the |
296 | * request */ | 361 | * request */ |
297 | call->state = AFS_CALL_AWAIT_REPLY; | 362 | if (!call->send_pages) |
363 | call->state = AFS_CALL_AWAIT_REPLY; | ||
298 | ret = rxrpc_kernel_send_data(rxcall, &msg, call->request_size); | 364 | ret = rxrpc_kernel_send_data(rxcall, &msg, call->request_size); |
299 | if (ret < 0) | 365 | if (ret < 0) |
300 | goto error_do_abort; | 366 | goto error_do_abort; |
301 | 367 | ||
368 | if (call->send_pages) { | ||
369 | ret = afs_send_pages(call, &msg, iov); | ||
370 | if (ret < 0) | ||
371 | goto error_do_abort; | ||
372 | } | ||
373 | |||
302 | /* at this point, an async call may no longer exist as it may have | 374 | /* at this point, an async call may no longer exist as it may have |
303 | * already completed */ | 375 | * already completed */ |
304 | return wait_mode->wait(call); | 376 | return wait_mode->wait(call); |
diff --git a/fs/afs/security.c b/fs/afs/security.c index f9f424d80458..e0ea88b63ebf 100644 --- a/fs/afs/security.c +++ b/fs/afs/security.c | |||
@@ -109,7 +109,7 @@ void afs_clear_permits(struct afs_vnode *vnode) | |||
109 | { | 109 | { |
110 | struct afs_permits *permits; | 110 | struct afs_permits *permits; |
111 | 111 | ||
112 | _enter("{%x}", vnode->fid.vnode); | 112 | _enter("{%x:%u}", vnode->fid.vid, vnode->fid.vnode); |
113 | 113 | ||
114 | mutex_lock(&vnode->permits_lock); | 114 | mutex_lock(&vnode->permits_lock); |
115 | permits = vnode->permits; | 115 | permits = vnode->permits; |
@@ -132,7 +132,8 @@ void afs_cache_permit(struct afs_vnode *vnode, struct key *key, long acl_order) | |||
132 | struct afs_vnode *auth_vnode; | 132 | struct afs_vnode *auth_vnode; |
133 | int count, loop; | 133 | int count, loop; |
134 | 134 | ||
135 | _enter("{%x},%x,%lx", vnode->fid.vnode, key_serial(key), acl_order); | 135 | _enter("{%x:%u},%x,%lx", |
136 | vnode->fid.vid, vnode->fid.vnode, key_serial(key), acl_order); | ||
136 | 137 | ||
137 | auth_vnode = afs_get_auth_inode(vnode, key); | 138 | auth_vnode = afs_get_auth_inode(vnode, key); |
138 | if (IS_ERR(auth_vnode)) { | 139 | if (IS_ERR(auth_vnode)) { |
@@ -220,7 +221,8 @@ static int afs_check_permit(struct afs_vnode *vnode, struct key *key, | |||
220 | bool valid; | 221 | bool valid; |
221 | int loop, ret; | 222 | int loop, ret; |
222 | 223 | ||
223 | _enter(""); | 224 | _enter("{%x:%u},%x", |
225 | vnode->fid.vid, vnode->fid.vnode, key_serial(key)); | ||
224 | 226 | ||
225 | auth_vnode = afs_get_auth_inode(vnode, key); | 227 | auth_vnode = afs_get_auth_inode(vnode, key); |
226 | if (IS_ERR(auth_vnode)) { | 228 | if (IS_ERR(auth_vnode)) { |
@@ -268,9 +270,9 @@ static int afs_check_permit(struct afs_vnode *vnode, struct key *key, | |||
268 | _leave(" = %d", ret); | 270 | _leave(" = %d", ret); |
269 | return ret; | 271 | return ret; |
270 | } | 272 | } |
273 | *_access = vnode->status.caller_access; | ||
271 | } | 274 | } |
272 | 275 | ||
273 | *_access = vnode->status.caller_access; | ||
274 | iput(&auth_vnode->vfs_inode); | 276 | iput(&auth_vnode->vfs_inode); |
275 | _leave(" = 0 [access %x]", *_access); | 277 | _leave(" = 0 [access %x]", *_access); |
276 | return 0; | 278 | return 0; |
@@ -288,7 +290,7 @@ int afs_permission(struct inode *inode, int mask, struct nameidata *nd) | |||
288 | struct key *key; | 290 | struct key *key; |
289 | int ret; | 291 | int ret; |
290 | 292 | ||
291 | _enter("{{%x:%x},%lx},%x,", | 293 | _enter("{{%x:%u},%lx},%x,", |
292 | vnode->fid.vid, vnode->fid.vnode, vnode->flags, mask); | 294 | vnode->fid.vid, vnode->fid.vnode, vnode->flags, mask); |
293 | 295 | ||
294 | key = afs_request_key(vnode->volume->cell); | 296 | key = afs_request_key(vnode->volume->cell); |
diff --git a/fs/afs/server.c b/fs/afs/server.c index 96bb23b476a2..231ae4150279 100644 --- a/fs/afs/server.c +++ b/fs/afs/server.c | |||
@@ -252,6 +252,9 @@ static void afs_destroy_server(struct afs_server *server) | |||
252 | { | 252 | { |
253 | _enter("%p", server); | 253 | _enter("%p", server); |
254 | 254 | ||
255 | ASSERTIF(server->cb_break_head != server->cb_break_tail, | ||
256 | delayed_work_pending(&server->cb_break_work)); | ||
257 | |||
255 | ASSERTCMP(server->fs_vnodes.rb_node, ==, NULL); | 258 | ASSERTCMP(server->fs_vnodes.rb_node, ==, NULL); |
256 | ASSERTCMP(server->cb_promises.rb_node, ==, NULL); | 259 | ASSERTCMP(server->cb_promises.rb_node, ==, NULL); |
257 | ASSERTCMP(server->cb_break_head, ==, server->cb_break_tail); | 260 | ASSERTCMP(server->cb_break_head, ==, server->cb_break_tail); |
diff --git a/fs/afs/super.c b/fs/afs/super.c index 7030d76155fc..d24be334b608 100644 --- a/fs/afs/super.c +++ b/fs/afs/super.c | |||
@@ -50,6 +50,7 @@ static const struct super_operations afs_super_ops = { | |||
50 | .statfs = simple_statfs, | 50 | .statfs = simple_statfs, |
51 | .alloc_inode = afs_alloc_inode, | 51 | .alloc_inode = afs_alloc_inode, |
52 | .drop_inode = generic_delete_inode, | 52 | .drop_inode = generic_delete_inode, |
53 | .write_inode = afs_write_inode, | ||
53 | .destroy_inode = afs_destroy_inode, | 54 | .destroy_inode = afs_destroy_inode, |
54 | .clear_inode = afs_clear_inode, | 55 | .clear_inode = afs_clear_inode, |
55 | .umount_begin = afs_umount_begin, | 56 | .umount_begin = afs_umount_begin, |
@@ -66,7 +67,7 @@ enum { | |||
66 | afs_opt_vol, | 67 | afs_opt_vol, |
67 | }; | 68 | }; |
68 | 69 | ||
69 | static const match_table_t afs_options_list = { | 70 | static match_table_t afs_options_list = { |
70 | { afs_opt_cell, "cell=%s" }, | 71 | { afs_opt_cell, "cell=%s" }, |
71 | { afs_opt_rwpath, "rwpath" }, | 72 | { afs_opt_rwpath, "rwpath" }, |
72 | { afs_opt_vol, "vol=%s" }, | 73 | { afs_opt_vol, "vol=%s" }, |
@@ -459,7 +460,9 @@ static void afs_i_init_once(void *_vnode, struct kmem_cache *cachep, | |||
459 | init_waitqueue_head(&vnode->update_waitq); | 460 | init_waitqueue_head(&vnode->update_waitq); |
460 | mutex_init(&vnode->permits_lock); | 461 | mutex_init(&vnode->permits_lock); |
461 | mutex_init(&vnode->validate_lock); | 462 | mutex_init(&vnode->validate_lock); |
463 | spin_lock_init(&vnode->writeback_lock); | ||
462 | spin_lock_init(&vnode->lock); | 464 | spin_lock_init(&vnode->lock); |
465 | INIT_LIST_HEAD(&vnode->writebacks); | ||
463 | INIT_WORK(&vnode->cb_broken_work, afs_broken_callback_work); | 466 | INIT_WORK(&vnode->cb_broken_work, afs_broken_callback_work); |
464 | } | 467 | } |
465 | } | 468 | } |
diff --git a/fs/afs/vnode.c b/fs/afs/vnode.c index a1904ab8426a..ec814660209f 100644 --- a/fs/afs/vnode.c +++ b/fs/afs/vnode.c | |||
@@ -261,7 +261,7 @@ int afs_vnode_fetch_status(struct afs_vnode *vnode, | |||
261 | 261 | ||
262 | DECLARE_WAITQUEUE(myself, current); | 262 | DECLARE_WAITQUEUE(myself, current); |
263 | 263 | ||
264 | _enter("%s,{%u,%u,%u}", | 264 | _enter("%s,{%x:%u.%u}", |
265 | vnode->volume->vlocation->vldb.name, | 265 | vnode->volume->vlocation->vldb.name, |
266 | vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique); | 266 | vnode->fid.vid, vnode->fid.vnode, vnode->fid.unique); |
267 | 267 | ||
@@ -389,7 +389,7 @@ int afs_vnode_fetch_data(struct afs_vnode *vnode, struct key *key, | |||
389 | struct afs_server *server; | 389 | struct afs_server *server; |
390 | int ret; | 390 | int ret; |
391 | 391 | ||
392 | _enter("%s{%u,%u,%u},%x,,,", | 392 | _enter("%s{%x:%u.%u},%x,,,", |
393 | vnode->volume->vlocation->vldb.name, | 393 | vnode->volume->vlocation->vldb.name, |
394 | vnode->fid.vid, | 394 | vnode->fid.vid, |
395 | vnode->fid.vnode, | 395 | vnode->fid.vnode, |
@@ -446,7 +446,7 @@ int afs_vnode_create(struct afs_vnode *vnode, struct key *key, | |||
446 | struct afs_server *server; | 446 | struct afs_server *server; |
447 | int ret; | 447 | int ret; |
448 | 448 | ||
449 | _enter("%s{%u,%u,%u},%x,%s,,", | 449 | _enter("%s{%x:%u.%u},%x,%s,,", |
450 | vnode->volume->vlocation->vldb.name, | 450 | vnode->volume->vlocation->vldb.name, |
451 | vnode->fid.vid, | 451 | vnode->fid.vid, |
452 | vnode->fid.vnode, | 452 | vnode->fid.vnode, |
@@ -502,7 +502,7 @@ int afs_vnode_remove(struct afs_vnode *vnode, struct key *key, const char *name, | |||
502 | struct afs_server *server; | 502 | struct afs_server *server; |
503 | int ret; | 503 | int ret; |
504 | 504 | ||
505 | _enter("%s{%u,%u,%u},%x,%s", | 505 | _enter("%s{%x:%u.%u},%x,%s", |
506 | vnode->volume->vlocation->vldb.name, | 506 | vnode->volume->vlocation->vldb.name, |
507 | vnode->fid.vid, | 507 | vnode->fid.vid, |
508 | vnode->fid.vnode, | 508 | vnode->fid.vnode, |
@@ -557,7 +557,7 @@ extern int afs_vnode_link(struct afs_vnode *dvnode, struct afs_vnode *vnode, | |||
557 | struct afs_server *server; | 557 | struct afs_server *server; |
558 | int ret; | 558 | int ret; |
559 | 559 | ||
560 | _enter("%s{%u,%u,%u},%s{%u,%u,%u},%x,%s", | 560 | _enter("%s{%x:%u.%u},%s{%x:%u.%u},%x,%s", |
561 | dvnode->volume->vlocation->vldb.name, | 561 | dvnode->volume->vlocation->vldb.name, |
562 | dvnode->fid.vid, | 562 | dvnode->fid.vid, |
563 | dvnode->fid.vnode, | 563 | dvnode->fid.vnode, |
@@ -628,7 +628,7 @@ int afs_vnode_symlink(struct afs_vnode *vnode, struct key *key, | |||
628 | struct afs_server *server; | 628 | struct afs_server *server; |
629 | int ret; | 629 | int ret; |
630 | 630 | ||
631 | _enter("%s{%u,%u,%u},%x,%s,%s,,,", | 631 | _enter("%s{%x:%u.%u},%x,%s,%s,,,", |
632 | vnode->volume->vlocation->vldb.name, | 632 | vnode->volume->vlocation->vldb.name, |
633 | vnode->fid.vid, | 633 | vnode->fid.vid, |
634 | vnode->fid.vnode, | 634 | vnode->fid.vnode, |
@@ -687,7 +687,7 @@ int afs_vnode_rename(struct afs_vnode *orig_dvnode, | |||
687 | struct afs_server *server; | 687 | struct afs_server *server; |
688 | int ret; | 688 | int ret; |
689 | 689 | ||
690 | _enter("%s{%u,%u,%u},%s{%u,%u,%u},%x,%s,%s", | 690 | _enter("%s{%x:%u.%u},%s{%u,%u,%u},%x,%s,%s", |
691 | orig_dvnode->volume->vlocation->vldb.name, | 691 | orig_dvnode->volume->vlocation->vldb.name, |
692 | orig_dvnode->fid.vid, | 692 | orig_dvnode->fid.vid, |
693 | orig_dvnode->fid.vnode, | 693 | orig_dvnode->fid.vnode, |
@@ -753,3 +753,110 @@ no_server: | |||
753 | _leave(" = %ld [cnt %d]", PTR_ERR(server), orig_dvnode->update_cnt); | 753 | _leave(" = %ld [cnt %d]", PTR_ERR(server), orig_dvnode->update_cnt); |
754 | return PTR_ERR(server); | 754 | return PTR_ERR(server); |
755 | } | 755 | } |
756 | |||
757 | /* | ||
758 | * write to a file | ||
759 | */ | ||
760 | int afs_vnode_store_data(struct afs_writeback *wb, pgoff_t first, pgoff_t last, | ||
761 | unsigned offset, unsigned to) | ||
762 | { | ||
763 | struct afs_server *server; | ||
764 | struct afs_vnode *vnode = wb->vnode; | ||
765 | int ret; | ||
766 | |||
767 | _enter("%s{%x:%u.%u},%x,%lx,%lx,%x,%x", | ||
768 | vnode->volume->vlocation->vldb.name, | ||
769 | vnode->fid.vid, | ||
770 | vnode->fid.vnode, | ||
771 | vnode->fid.unique, | ||
772 | key_serial(wb->key), | ||
773 | first, last, offset, to); | ||
774 | |||
775 | /* this op will fetch the status */ | ||
776 | spin_lock(&vnode->lock); | ||
777 | vnode->update_cnt++; | ||
778 | spin_unlock(&vnode->lock); | ||
779 | |||
780 | do { | ||
781 | /* pick a server to query */ | ||
782 | server = afs_volume_pick_fileserver(vnode); | ||
783 | if (IS_ERR(server)) | ||
784 | goto no_server; | ||
785 | |||
786 | _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); | ||
787 | |||
788 | ret = afs_fs_store_data(server, wb, first, last, offset, to, | ||
789 | &afs_sync_call); | ||
790 | |||
791 | } while (!afs_volume_release_fileserver(vnode, server, ret)); | ||
792 | |||
793 | /* adjust the flags */ | ||
794 | if (ret == 0) { | ||
795 | afs_vnode_finalise_status_update(vnode, server); | ||
796 | afs_put_server(server); | ||
797 | } else { | ||
798 | afs_vnode_status_update_failed(vnode, ret); | ||
799 | } | ||
800 | |||
801 | _leave(" = %d", ret); | ||
802 | return ret; | ||
803 | |||
804 | no_server: | ||
805 | spin_lock(&vnode->lock); | ||
806 | vnode->update_cnt--; | ||
807 | ASSERTCMP(vnode->update_cnt, >=, 0); | ||
808 | spin_unlock(&vnode->lock); | ||
809 | return PTR_ERR(server); | ||
810 | } | ||
811 | |||
812 | /* | ||
813 | * set the attributes on a file | ||
814 | */ | ||
815 | int afs_vnode_setattr(struct afs_vnode *vnode, struct key *key, | ||
816 | struct iattr *attr) | ||
817 | { | ||
818 | struct afs_server *server; | ||
819 | int ret; | ||
820 | |||
821 | _enter("%s{%x:%u.%u},%x", | ||
822 | vnode->volume->vlocation->vldb.name, | ||
823 | vnode->fid.vid, | ||
824 | vnode->fid.vnode, | ||
825 | vnode->fid.unique, | ||
826 | key_serial(key)); | ||
827 | |||
828 | /* this op will fetch the status */ | ||
829 | spin_lock(&vnode->lock); | ||
830 | vnode->update_cnt++; | ||
831 | spin_unlock(&vnode->lock); | ||
832 | |||
833 | do { | ||
834 | /* pick a server to query */ | ||
835 | server = afs_volume_pick_fileserver(vnode); | ||
836 | if (IS_ERR(server)) | ||
837 | goto no_server; | ||
838 | |||
839 | _debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr)); | ||
840 | |||
841 | ret = afs_fs_setattr(server, key, vnode, attr, &afs_sync_call); | ||
842 | |||
843 | } while (!afs_volume_release_fileserver(vnode, server, ret)); | ||
844 | |||
845 | /* adjust the flags */ | ||
846 | if (ret == 0) { | ||
847 | afs_vnode_finalise_status_update(vnode, server); | ||
848 | afs_put_server(server); | ||
849 | } else { | ||
850 | afs_vnode_status_update_failed(vnode, ret); | ||
851 | } | ||
852 | |||
853 | _leave(" = %d", ret); | ||
854 | return ret; | ||
855 | |||
856 | no_server: | ||
857 | spin_lock(&vnode->lock); | ||
858 | vnode->update_cnt--; | ||
859 | ASSERTCMP(vnode->update_cnt, >=, 0); | ||
860 | spin_unlock(&vnode->lock); | ||
861 | return PTR_ERR(server); | ||
862 | } | ||
diff --git a/fs/afs/write.c b/fs/afs/write.c new file mode 100644 index 000000000000..83ff29262816 --- /dev/null +++ b/fs/afs/write.c | |||
@@ -0,0 +1,835 @@ | |||
1 | /* handling of writes to regular files and writing back to the server | ||
2 | * | ||
3 | * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the License, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <linux/slab.h> | ||
13 | #include <linux/fs.h> | ||
14 | #include <linux/pagemap.h> | ||
15 | #include <linux/writeback.h> | ||
16 | #include <linux/pagevec.h> | ||
17 | #include "internal.h" | ||
18 | |||
19 | static int afs_write_back_from_locked_page(struct afs_writeback *wb, | ||
20 | struct page *page); | ||
21 | |||
22 | /* | ||
23 | * mark a page as having been made dirty and thus needing writeback | ||
24 | */ | ||
25 | int afs_set_page_dirty(struct page *page) | ||
26 | { | ||
27 | _enter(""); | ||
28 | return __set_page_dirty_nobuffers(page); | ||
29 | } | ||
30 | |||
31 | /* | ||
32 | * unlink a writeback record because its usage has reached zero | ||
33 | * - must be called with the wb->vnode->writeback_lock held | ||
34 | */ | ||
35 | static void afs_unlink_writeback(struct afs_writeback *wb) | ||
36 | { | ||
37 | struct afs_writeback *front; | ||
38 | struct afs_vnode *vnode = wb->vnode; | ||
39 | |||
40 | list_del_init(&wb->link); | ||
41 | if (!list_empty(&vnode->writebacks)) { | ||
42 | /* if an fsync rises to the front of the queue then wake it | ||
43 | * up */ | ||
44 | front = list_entry(vnode->writebacks.next, | ||
45 | struct afs_writeback, link); | ||
46 | if (front->state == AFS_WBACK_SYNCING) { | ||
47 | _debug("wake up sync"); | ||
48 | front->state = AFS_WBACK_COMPLETE; | ||
49 | wake_up(&front->waitq); | ||
50 | } | ||
51 | } | ||
52 | } | ||
53 | |||
54 | /* | ||
55 | * free a writeback record | ||
56 | */ | ||
57 | static void afs_free_writeback(struct afs_writeback *wb) | ||
58 | { | ||
59 | _enter(""); | ||
60 | key_put(wb->key); | ||
61 | kfree(wb); | ||
62 | } | ||
63 | |||
64 | /* | ||
65 | * dispose of a reference to a writeback record | ||
66 | */ | ||
67 | void afs_put_writeback(struct afs_writeback *wb) | ||
68 | { | ||
69 | struct afs_vnode *vnode = wb->vnode; | ||
70 | |||
71 | _enter("{%d}", wb->usage); | ||
72 | |||
73 | spin_lock(&vnode->writeback_lock); | ||
74 | if (--wb->usage == 0) | ||
75 | afs_unlink_writeback(wb); | ||
76 | else | ||
77 | wb = NULL; | ||
78 | spin_unlock(&vnode->writeback_lock); | ||
79 | if (wb) | ||
80 | afs_free_writeback(wb); | ||
81 | } | ||
82 | |||
83 | /* | ||
84 | * partly or wholly fill a page that's under preparation for writing | ||
85 | */ | ||
86 | static int afs_fill_page(struct afs_vnode *vnode, struct key *key, | ||
87 | unsigned start, unsigned len, struct page *page) | ||
88 | { | ||
89 | int ret; | ||
90 | |||
91 | _enter(",,%u,%u", start, len); | ||
92 | |||
93 | ASSERTCMP(start + len, <=, PAGE_SIZE); | ||
94 | |||
95 | ret = afs_vnode_fetch_data(vnode, key, start, len, page); | ||
96 | if (ret < 0) { | ||
97 | if (ret == -ENOENT) { | ||
98 | _debug("got NOENT from server" | ||
99 | " - marking file deleted and stale"); | ||
100 | set_bit(AFS_VNODE_DELETED, &vnode->flags); | ||
101 | ret = -ESTALE; | ||
102 | } | ||
103 | } | ||
104 | |||
105 | _leave(" = %d", ret); | ||
106 | return ret; | ||
107 | } | ||
108 | |||
109 | /* | ||
110 | * prepare a page for being written to | ||
111 | */ | ||
112 | static int afs_prepare_page(struct afs_vnode *vnode, struct page *page, | ||
113 | struct key *key, unsigned offset, unsigned to) | ||
114 | { | ||
115 | unsigned eof, tail, start, stop, len; | ||
116 | loff_t i_size, pos; | ||
117 | void *p; | ||
118 | int ret; | ||
119 | |||
120 | _enter(""); | ||
121 | |||
122 | if (offset == 0 && to == PAGE_SIZE) | ||
123 | return 0; | ||
124 | |||
125 | p = kmap(page); | ||
126 | |||
127 | i_size = i_size_read(&vnode->vfs_inode); | ||
128 | pos = (loff_t) page->index << PAGE_SHIFT; | ||
129 | if (pos >= i_size) { | ||
130 | /* partial write, page beyond EOF */ | ||
131 | _debug("beyond"); | ||
132 | if (offset > 0) | ||
133 | memset(p, 0, offset); | ||
134 | if (to < PAGE_SIZE) | ||
135 | memset(p + to, 0, PAGE_SIZE - to); | ||
136 | kunmap(page); | ||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | if (i_size - pos >= PAGE_SIZE) { | ||
141 | /* partial write, page entirely before EOF */ | ||
142 | _debug("before"); | ||
143 | tail = eof = PAGE_SIZE; | ||
144 | } else { | ||
145 | /* partial write, page overlaps EOF */ | ||
146 | eof = i_size - pos; | ||
147 | _debug("overlap %u", eof); | ||
148 | tail = max(eof, to); | ||
149 | if (tail < PAGE_SIZE) | ||
150 | memset(p + tail, 0, PAGE_SIZE - tail); | ||
151 | if (offset > eof) | ||
152 | memset(p + eof, 0, PAGE_SIZE - eof); | ||
153 | } | ||
154 | |||
155 | kunmap(p); | ||
156 | |||
157 | ret = 0; | ||
158 | if (offset > 0 || eof > to) { | ||
159 | /* need to fill one or two bits that aren't going to be written | ||
160 | * (cover both fillers in one read if there are two) */ | ||
161 | start = (offset > 0) ? 0 : to; | ||
162 | stop = (eof > to) ? eof : offset; | ||
163 | len = stop - start; | ||
164 | _debug("wr=%u-%u av=0-%u rd=%u@%u", | ||
165 | offset, to, eof, start, len); | ||
166 | ret = afs_fill_page(vnode, key, start, len, page); | ||
167 | } | ||
168 | |||
169 | _leave(" = %d", ret); | ||
170 | return ret; | ||
171 | } | ||
172 | |||
173 | /* | ||
174 | * prepare to perform part of a write to a page | ||
175 | * - the caller holds the page locked, preventing it from being written out or | ||
176 | * modified by anyone else | ||
177 | */ | ||
178 | int afs_prepare_write(struct file *file, struct page *page, | ||
179 | unsigned offset, unsigned to) | ||
180 | { | ||
181 | struct afs_writeback *candidate, *wb; | ||
182 | struct afs_vnode *vnode = AFS_FS_I(file->f_dentry->d_inode); | ||
183 | struct key *key = file->private_data; | ||
184 | pgoff_t index; | ||
185 | int ret; | ||
186 | |||
187 | _enter("{%x:%u},{%lx},%u,%u", | ||
188 | vnode->fid.vid, vnode->fid.vnode, page->index, offset, to); | ||
189 | |||
190 | candidate = kzalloc(sizeof(*candidate), GFP_KERNEL); | ||
191 | if (!candidate) | ||
192 | return -ENOMEM; | ||
193 | candidate->vnode = vnode; | ||
194 | candidate->first = candidate->last = page->index; | ||
195 | candidate->offset_first = offset; | ||
196 | candidate->to_last = to; | ||
197 | candidate->usage = 1; | ||
198 | candidate->state = AFS_WBACK_PENDING; | ||
199 | init_waitqueue_head(&candidate->waitq); | ||
200 | |||
201 | if (!PageUptodate(page)) { | ||
202 | _debug("not up to date"); | ||
203 | ret = afs_prepare_page(vnode, page, key, offset, to); | ||
204 | if (ret < 0) { | ||
205 | kfree(candidate); | ||
206 | _leave(" = %d [prep]", ret); | ||
207 | return ret; | ||
208 | } | ||
209 | SetPageUptodate(page); | ||
210 | } | ||
211 | |||
212 | try_again: | ||
213 | index = page->index; | ||
214 | spin_lock(&vnode->writeback_lock); | ||
215 | |||
216 | /* see if this page is already pending a writeback under a suitable key | ||
217 | * - if so we can just join onto that one */ | ||
218 | wb = (struct afs_writeback *) page_private(page); | ||
219 | if (wb) { | ||
220 | if (wb->key == key && wb->state == AFS_WBACK_PENDING) | ||
221 | goto subsume_in_current_wb; | ||
222 | goto flush_conflicting_wb; | ||
223 | } | ||
224 | |||
225 | if (index > 0) { | ||
226 | /* see if we can find an already pending writeback that we can | ||
227 | * append this page to */ | ||
228 | list_for_each_entry(wb, &vnode->writebacks, link) { | ||
229 | if (wb->last == index - 1 && wb->key == key && | ||
230 | wb->state == AFS_WBACK_PENDING) | ||
231 | goto append_to_previous_wb; | ||
232 | } | ||
233 | } | ||
234 | |||
235 | list_add_tail(&candidate->link, &vnode->writebacks); | ||
236 | candidate->key = key_get(key); | ||
237 | spin_unlock(&vnode->writeback_lock); | ||
238 | SetPagePrivate(page); | ||
239 | set_page_private(page, (unsigned long) candidate); | ||
240 | _leave(" = 0 [new]"); | ||
241 | return 0; | ||
242 | |||
243 | subsume_in_current_wb: | ||
244 | _debug("subsume"); | ||
245 | ASSERTRANGE(wb->first, <=, index, <=, wb->last); | ||
246 | if (index == wb->first && offset < wb->offset_first) | ||
247 | wb->offset_first = offset; | ||
248 | if (index == wb->last && to > wb->to_last) | ||
249 | wb->to_last = to; | ||
250 | spin_unlock(&vnode->writeback_lock); | ||
251 | kfree(candidate); | ||
252 | _leave(" = 0 [sub]"); | ||
253 | return 0; | ||
254 | |||
255 | append_to_previous_wb: | ||
256 | _debug("append into %lx-%lx", wb->first, wb->last); | ||
257 | wb->usage++; | ||
258 | wb->last++; | ||
259 | wb->to_last = to; | ||
260 | spin_unlock(&vnode->writeback_lock); | ||
261 | SetPagePrivate(page); | ||
262 | set_page_private(page, (unsigned long) wb); | ||
263 | kfree(candidate); | ||
264 | _leave(" = 0 [app]"); | ||
265 | return 0; | ||
266 | |||
267 | /* the page is currently bound to another context, so if it's dirty we | ||
268 | * need to flush it before we can use the new context */ | ||
269 | flush_conflicting_wb: | ||
270 | _debug("flush conflict"); | ||
271 | if (wb->state == AFS_WBACK_PENDING) | ||
272 | wb->state = AFS_WBACK_CONFLICTING; | ||
273 | spin_unlock(&vnode->writeback_lock); | ||
274 | if (PageDirty(page)) { | ||
275 | ret = afs_write_back_from_locked_page(wb, page); | ||
276 | if (ret < 0) { | ||
277 | afs_put_writeback(candidate); | ||
278 | _leave(" = %d", ret); | ||
279 | return ret; | ||
280 | } | ||
281 | } | ||
282 | |||
283 | /* the page holds a ref on the writeback record */ | ||
284 | afs_put_writeback(wb); | ||
285 | set_page_private(page, 0); | ||
286 | ClearPagePrivate(page); | ||
287 | goto try_again; | ||
288 | } | ||
289 | |||
290 | /* | ||
291 | * finalise part of a write to a page | ||
292 | */ | ||
293 | int afs_commit_write(struct file *file, struct page *page, | ||
294 | unsigned offset, unsigned to) | ||
295 | { | ||
296 | struct afs_vnode *vnode = AFS_FS_I(file->f_dentry->d_inode); | ||
297 | loff_t i_size, maybe_i_size; | ||
298 | |||
299 | _enter("{%x:%u},{%lx},%u,%u", | ||
300 | vnode->fid.vid, vnode->fid.vnode, page->index, offset, to); | ||
301 | |||
302 | maybe_i_size = (loff_t) page->index << PAGE_SHIFT; | ||
303 | maybe_i_size += to; | ||
304 | |||
305 | i_size = i_size_read(&vnode->vfs_inode); | ||
306 | if (maybe_i_size > i_size) { | ||
307 | spin_lock(&vnode->writeback_lock); | ||
308 | i_size = i_size_read(&vnode->vfs_inode); | ||
309 | if (maybe_i_size > i_size) | ||
310 | i_size_write(&vnode->vfs_inode, maybe_i_size); | ||
311 | spin_unlock(&vnode->writeback_lock); | ||
312 | } | ||
313 | |||
314 | set_page_dirty(page); | ||
315 | |||
316 | if (PageDirty(page)) | ||
317 | _debug("dirtied"); | ||
318 | |||
319 | return 0; | ||
320 | } | ||
321 | |||
322 | /* | ||
323 | * kill all the pages in the given range | ||
324 | */ | ||
325 | static void afs_kill_pages(struct afs_vnode *vnode, bool error, | ||
326 | pgoff_t first, pgoff_t last) | ||
327 | { | ||
328 | struct pagevec pv; | ||
329 | unsigned count, loop; | ||
330 | |||
331 | _enter("{%x:%u},%lx-%lx", | ||
332 | vnode->fid.vid, vnode->fid.vnode, first, last); | ||
333 | |||
334 | pagevec_init(&pv, 0); | ||
335 | |||
336 | do { | ||
337 | _debug("kill %lx-%lx", first, last); | ||
338 | |||
339 | count = last - first + 1; | ||
340 | if (count > PAGEVEC_SIZE) | ||
341 | count = PAGEVEC_SIZE; | ||
342 | pv.nr = find_get_pages_contig(vnode->vfs_inode.i_mapping, | ||
343 | first, count, pv.pages); | ||
344 | ASSERTCMP(pv.nr, ==, count); | ||
345 | |||
346 | for (loop = 0; loop < count; loop++) { | ||
347 | ClearPageUptodate(pv.pages[loop]); | ||
348 | if (error) | ||
349 | SetPageError(pv.pages[loop]); | ||
350 | end_page_writeback(pv.pages[loop]); | ||
351 | } | ||
352 | |||
353 | __pagevec_release(&pv); | ||
354 | } while (first < last); | ||
355 | |||
356 | _leave(""); | ||
357 | } | ||
358 | |||
359 | /* | ||
360 | * synchronously write back the locked page and any subsequent non-locked dirty | ||
361 | * pages also covered by the same writeback record | ||
362 | */ | ||
363 | static int afs_write_back_from_locked_page(struct afs_writeback *wb, | ||
364 | struct page *primary_page) | ||
365 | { | ||
366 | struct page *pages[8], *page; | ||
367 | unsigned long count; | ||
368 | unsigned n, offset, to; | ||
369 | pgoff_t start, first, last; | ||
370 | int loop, ret; | ||
371 | |||
372 | _enter(",%lx", primary_page->index); | ||
373 | |||
374 | count = 1; | ||
375 | if (!clear_page_dirty_for_io(primary_page)) | ||
376 | BUG(); | ||
377 | if (test_set_page_writeback(primary_page)) | ||
378 | BUG(); | ||
379 | |||
380 | /* find all consecutive lockable dirty pages, stopping when we find a | ||
381 | * page that is not immediately lockable, is not dirty or is missing, | ||
382 | * or we reach the end of the range */ | ||
383 | start = primary_page->index; | ||
384 | if (start >= wb->last) | ||
385 | goto no_more; | ||
386 | start++; | ||
387 | do { | ||
388 | _debug("more %lx [%lx]", start, count); | ||
389 | n = wb->last - start + 1; | ||
390 | if (n > ARRAY_SIZE(pages)) | ||
391 | n = ARRAY_SIZE(pages); | ||
392 | n = find_get_pages_contig(wb->vnode->vfs_inode.i_mapping, | ||
393 | start, n, pages); | ||
394 | _debug("fgpc %u", n); | ||
395 | if (n == 0) | ||
396 | goto no_more; | ||
397 | if (pages[0]->index != start) { | ||
398 | for (n--; n >= 0; n--) | ||
399 | put_page(pages[n]); | ||
400 | goto no_more; | ||
401 | } | ||
402 | |||
403 | for (loop = 0; loop < n; loop++) { | ||
404 | page = pages[loop]; | ||
405 | if (page->index > wb->last) | ||
406 | break; | ||
407 | if (TestSetPageLocked(page)) | ||
408 | break; | ||
409 | if (!PageDirty(page) || | ||
410 | page_private(page) != (unsigned long) wb) { | ||
411 | unlock_page(page); | ||
412 | break; | ||
413 | } | ||
414 | if (!clear_page_dirty_for_io(page)) | ||
415 | BUG(); | ||
416 | if (test_set_page_writeback(page)) | ||
417 | BUG(); | ||
418 | unlock_page(page); | ||
419 | put_page(page); | ||
420 | } | ||
421 | count += loop; | ||
422 | if (loop < n) { | ||
423 | for (; loop < n; loop++) | ||
424 | put_page(pages[loop]); | ||
425 | goto no_more; | ||
426 | } | ||
427 | |||
428 | start += loop; | ||
429 | } while (start <= wb->last && count < 65536); | ||
430 | |||
431 | no_more: | ||
432 | /* we now have a contiguous set of dirty pages, each with writeback set | ||
433 | * and the dirty mark cleared; the first page is locked and must remain | ||
434 | * so, all the rest are unlocked */ | ||
435 | first = primary_page->index; | ||
436 | last = first + count - 1; | ||
437 | |||
438 | offset = (first == wb->first) ? wb->offset_first : 0; | ||
439 | to = (last == wb->last) ? wb->to_last : PAGE_SIZE; | ||
440 | |||
441 | _debug("write back %lx[%u..] to %lx[..%u]", first, offset, last, to); | ||
442 | |||
443 | ret = afs_vnode_store_data(wb, first, last, offset, to); | ||
444 | if (ret < 0) { | ||
445 | switch (ret) { | ||
446 | case -EDQUOT: | ||
447 | case -ENOSPC: | ||
448 | set_bit(AS_ENOSPC, | ||
449 | &wb->vnode->vfs_inode.i_mapping->flags); | ||
450 | break; | ||
451 | case -EROFS: | ||
452 | case -EIO: | ||
453 | case -EREMOTEIO: | ||
454 | case -EFBIG: | ||
455 | case -ENOENT: | ||
456 | case -ENOMEDIUM: | ||
457 | case -ENXIO: | ||
458 | afs_kill_pages(wb->vnode, true, first, last); | ||
459 | set_bit(AS_EIO, &wb->vnode->vfs_inode.i_mapping->flags); | ||
460 | break; | ||
461 | case -EACCES: | ||
462 | case -EPERM: | ||
463 | case -ENOKEY: | ||
464 | case -EKEYEXPIRED: | ||
465 | case -EKEYREJECTED: | ||
466 | case -EKEYREVOKED: | ||
467 | afs_kill_pages(wb->vnode, false, first, last); | ||
468 | break; | ||
469 | default: | ||
470 | break; | ||
471 | } | ||
472 | } else { | ||
473 | ret = count; | ||
474 | } | ||
475 | |||
476 | _leave(" = %d", ret); | ||
477 | return ret; | ||
478 | } | ||
479 | |||
480 | /* | ||
481 | * write a page back to the server | ||
482 | * - the caller locked the page for us | ||
483 | */ | ||
484 | int afs_writepage(struct page *page, struct writeback_control *wbc) | ||
485 | { | ||
486 | struct backing_dev_info *bdi = page->mapping->backing_dev_info; | ||
487 | struct afs_writeback *wb; | ||
488 | int ret; | ||
489 | |||
490 | _enter("{%lx},", page->index); | ||
491 | |||
492 | if (wbc->sync_mode != WB_SYNC_NONE) | ||
493 | wait_on_page_writeback(page); | ||
494 | |||
495 | if (PageWriteback(page) || !PageDirty(page)) { | ||
496 | unlock_page(page); | ||
497 | return 0; | ||
498 | } | ||
499 | |||
500 | wb = (struct afs_writeback *) page_private(page); | ||
501 | ASSERT(wb != NULL); | ||
502 | |||
503 | ret = afs_write_back_from_locked_page(wb, page); | ||
504 | unlock_page(page); | ||
505 | if (ret < 0) { | ||
506 | _leave(" = %d", ret); | ||
507 | return 0; | ||
508 | } | ||
509 | |||
510 | wbc->nr_to_write -= ret; | ||
511 | if (wbc->nonblocking && bdi_write_congested(bdi)) | ||
512 | wbc->encountered_congestion = 1; | ||
513 | |||
514 | _leave(" = 0"); | ||
515 | return 0; | ||
516 | } | ||
517 | |||
518 | /* | ||
519 | * write a region of pages back to the server | ||
520 | */ | ||
521 | int afs_writepages_region(struct address_space *mapping, | ||
522 | struct writeback_control *wbc, | ||
523 | pgoff_t index, pgoff_t end, pgoff_t *_next) | ||
524 | { | ||
525 | struct backing_dev_info *bdi = mapping->backing_dev_info; | ||
526 | struct afs_writeback *wb; | ||
527 | struct page *page; | ||
528 | int ret, n; | ||
529 | |||
530 | _enter(",,%lx,%lx,", index, end); | ||
531 | |||
532 | do { | ||
533 | n = find_get_pages_tag(mapping, &index, PAGECACHE_TAG_DIRTY, | ||
534 | 1, &page); | ||
535 | if (!n) | ||
536 | break; | ||
537 | |||
538 | _debug("wback %lx", page->index); | ||
539 | |||
540 | if (page->index > end) { | ||
541 | *_next = index; | ||
542 | page_cache_release(page); | ||
543 | _leave(" = 0 [%lx]", *_next); | ||
544 | return 0; | ||
545 | } | ||
546 | |||
547 | /* at this point we hold neither mapping->tree_lock nor lock on | ||
548 | * the page itself: the page may be truncated or invalidated | ||
549 | * (changing page->mapping to NULL), or even swizzled back from | ||
550 | * swapper_space to tmpfs file mapping | ||
551 | */ | ||
552 | lock_page(page); | ||
553 | |||
554 | if (page->mapping != mapping) { | ||
555 | unlock_page(page); | ||
556 | page_cache_release(page); | ||
557 | continue; | ||
558 | } | ||
559 | |||
560 | if (wbc->sync_mode != WB_SYNC_NONE) | ||
561 | wait_on_page_writeback(page); | ||
562 | |||
563 | if (PageWriteback(page) || !PageDirty(page)) { | ||
564 | unlock_page(page); | ||
565 | continue; | ||
566 | } | ||
567 | |||
568 | wb = (struct afs_writeback *) page_private(page); | ||
569 | ASSERT(wb != NULL); | ||
570 | |||
571 | spin_lock(&wb->vnode->writeback_lock); | ||
572 | wb->state = AFS_WBACK_WRITING; | ||
573 | spin_unlock(&wb->vnode->writeback_lock); | ||
574 | |||
575 | ret = afs_write_back_from_locked_page(wb, page); | ||
576 | unlock_page(page); | ||
577 | page_cache_release(page); | ||
578 | if (ret < 0) { | ||
579 | _leave(" = %d", ret); | ||
580 | return ret; | ||
581 | } | ||
582 | |||
583 | wbc->nr_to_write -= ret; | ||
584 | |||
585 | if (wbc->nonblocking && bdi_write_congested(bdi)) { | ||
586 | wbc->encountered_congestion = 1; | ||
587 | break; | ||
588 | } | ||
589 | |||
590 | cond_resched(); | ||
591 | } while (index < end && wbc->nr_to_write > 0); | ||
592 | |||
593 | *_next = index; | ||
594 | _leave(" = 0 [%lx]", *_next); | ||
595 | return 0; | ||
596 | } | ||
597 | |||
598 | /* | ||
599 | * write some of the pending data back to the server | ||
600 | */ | ||
601 | int afs_writepages(struct address_space *mapping, | ||
602 | struct writeback_control *wbc) | ||
603 | { | ||
604 | struct backing_dev_info *bdi = mapping->backing_dev_info; | ||
605 | pgoff_t start, end, next; | ||
606 | int ret; | ||
607 | |||
608 | _enter(""); | ||
609 | |||
610 | if (wbc->nonblocking && bdi_write_congested(bdi)) { | ||
611 | wbc->encountered_congestion = 1; | ||
612 | _leave(" = 0 [congest]"); | ||
613 | return 0; | ||
614 | } | ||
615 | |||
616 | if (wbc->range_cyclic) { | ||
617 | start = mapping->writeback_index; | ||
618 | end = -1; | ||
619 | ret = afs_writepages_region(mapping, wbc, start, end, &next); | ||
620 | if (start > 0 && wbc->nr_to_write > 0 && ret == 0 && | ||
621 | !(wbc->nonblocking && wbc->encountered_congestion)) | ||
622 | ret = afs_writepages_region(mapping, wbc, 0, start, | ||
623 | &next); | ||
624 | mapping->writeback_index = next; | ||
625 | } else if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX) { | ||
626 | end = (pgoff_t)(LLONG_MAX >> PAGE_CACHE_SHIFT); | ||
627 | ret = afs_writepages_region(mapping, wbc, 0, end, &next); | ||
628 | if (wbc->nr_to_write > 0) | ||
629 | mapping->writeback_index = next; | ||
630 | } else { | ||
631 | start = wbc->range_start >> PAGE_CACHE_SHIFT; | ||
632 | end = wbc->range_end >> PAGE_CACHE_SHIFT; | ||
633 | ret = afs_writepages_region(mapping, wbc, start, end, &next); | ||
634 | } | ||
635 | |||
636 | _leave(" = %d", ret); | ||
637 | return ret; | ||
638 | } | ||
639 | |||
640 | /* | ||
641 | * write an inode back | ||
642 | */ | ||
643 | int afs_write_inode(struct inode *inode, int sync) | ||
644 | { | ||
645 | struct afs_vnode *vnode = AFS_FS_I(inode); | ||
646 | int ret; | ||
647 | |||
648 | _enter("{%x:%u},", vnode->fid.vid, vnode->fid.vnode); | ||
649 | |||
650 | ret = 0; | ||
651 | if (sync) { | ||
652 | ret = filemap_fdatawait(inode->i_mapping); | ||
653 | if (ret < 0) | ||
654 | __mark_inode_dirty(inode, I_DIRTY_DATASYNC); | ||
655 | } | ||
656 | |||
657 | _leave(" = %d", ret); | ||
658 | return ret; | ||
659 | } | ||
660 | |||
661 | /* | ||
662 | * completion of write to server | ||
663 | */ | ||
664 | void afs_pages_written_back(struct afs_vnode *vnode, struct afs_call *call) | ||
665 | { | ||
666 | struct afs_writeback *wb = call->wb; | ||
667 | struct pagevec pv; | ||
668 | unsigned count, loop; | ||
669 | pgoff_t first = call->first, last = call->last; | ||
670 | bool free_wb; | ||
671 | |||
672 | _enter("{%x:%u},{%lx-%lx}", | ||
673 | vnode->fid.vid, vnode->fid.vnode, first, last); | ||
674 | |||
675 | ASSERT(wb != NULL); | ||
676 | |||
677 | pagevec_init(&pv, 0); | ||
678 | |||
679 | do { | ||
680 | _debug("attach %lx-%lx", first, last); | ||
681 | |||
682 | count = last - first + 1; | ||
683 | if (count > PAGEVEC_SIZE) | ||
684 | count = PAGEVEC_SIZE; | ||
685 | pv.nr = find_get_pages_contig(call->mapping, first, count, | ||
686 | pv.pages); | ||
687 | ASSERTCMP(pv.nr, ==, count); | ||
688 | |||
689 | spin_lock(&vnode->writeback_lock); | ||
690 | for (loop = 0; loop < count; loop++) { | ||
691 | struct page *page = pv.pages[loop]; | ||
692 | end_page_writeback(page); | ||
693 | if (page_private(page) == (unsigned long) wb) { | ||
694 | set_page_private(page, 0); | ||
695 | ClearPagePrivate(page); | ||
696 | wb->usage--; | ||
697 | } | ||
698 | } | ||
699 | free_wb = false; | ||
700 | if (wb->usage == 0) { | ||
701 | afs_unlink_writeback(wb); | ||
702 | free_wb = true; | ||
703 | } | ||
704 | spin_unlock(&vnode->writeback_lock); | ||
705 | first += count; | ||
706 | if (free_wb) { | ||
707 | afs_free_writeback(wb); | ||
708 | wb = NULL; | ||
709 | } | ||
710 | |||
711 | __pagevec_release(&pv); | ||
712 | } while (first < last); | ||
713 | |||
714 | _leave(""); | ||
715 | } | ||
716 | |||
717 | /* | ||
718 | * write to an AFS file | ||
719 | */ | ||
720 | ssize_t afs_file_write(struct kiocb *iocb, const struct iovec *iov, | ||
721 | unsigned long nr_segs, loff_t pos) | ||
722 | { | ||
723 | struct dentry *dentry = iocb->ki_filp->f_path.dentry; | ||
724 | struct afs_vnode *vnode = AFS_FS_I(dentry->d_inode); | ||
725 | ssize_t result; | ||
726 | size_t count = iov_length(iov, nr_segs); | ||
727 | int ret; | ||
728 | |||
729 | _enter("{%x.%u},{%zu},%lu,", | ||
730 | vnode->fid.vid, vnode->fid.vnode, count, nr_segs); | ||
731 | |||
732 | if (IS_SWAPFILE(&vnode->vfs_inode)) { | ||
733 | printk(KERN_INFO | ||
734 | "AFS: Attempt to write to active swap file!\n"); | ||
735 | return -EBUSY; | ||
736 | } | ||
737 | |||
738 | if (!count) | ||
739 | return 0; | ||
740 | |||
741 | result = generic_file_aio_write(iocb, iov, nr_segs, pos); | ||
742 | if (IS_ERR_VALUE(result)) { | ||
743 | _leave(" = %zd", result); | ||
744 | return result; | ||
745 | } | ||
746 | |||
747 | /* return error values for O_SYNC and IS_SYNC() */ | ||
748 | if (IS_SYNC(&vnode->vfs_inode) || iocb->ki_filp->f_flags & O_SYNC) { | ||
749 | ret = afs_fsync(iocb->ki_filp, dentry, 1); | ||
750 | if (ret < 0) | ||
751 | result = ret; | ||
752 | } | ||
753 | |||
754 | _leave(" = %zd", result); | ||
755 | return result; | ||
756 | } | ||
757 | |||
758 | /* | ||
759 | * flush the vnode to the fileserver | ||
760 | */ | ||
761 | int afs_writeback_all(struct afs_vnode *vnode) | ||
762 | { | ||
763 | struct address_space *mapping = vnode->vfs_inode.i_mapping; | ||
764 | struct writeback_control wbc = { | ||
765 | .bdi = mapping->backing_dev_info, | ||
766 | .sync_mode = WB_SYNC_ALL, | ||
767 | .nr_to_write = LONG_MAX, | ||
768 | .for_writepages = 1, | ||
769 | .range_cyclic = 1, | ||
770 | }; | ||
771 | int ret; | ||
772 | |||
773 | _enter(""); | ||
774 | |||
775 | ret = mapping->a_ops->writepages(mapping, &wbc); | ||
776 | __mark_inode_dirty(mapping->host, I_DIRTY_PAGES); | ||
777 | |||
778 | _leave(" = %d", ret); | ||
779 | return ret; | ||
780 | } | ||
781 | |||
782 | /* | ||
783 | * flush any dirty pages for this process, and check for write errors. | ||
784 | * - the return status from this call provides a reliable indication of | ||
785 | * whether any write errors occurred for this process. | ||
786 | */ | ||
787 | int afs_fsync(struct file *file, struct dentry *dentry, int datasync) | ||
788 | { | ||
789 | struct afs_writeback *wb, *xwb; | ||
790 | struct afs_vnode *vnode = AFS_FS_I(dentry->d_inode); | ||
791 | int ret; | ||
792 | |||
793 | _enter("{%x:%u},{n=%s},%d", | ||
794 | vnode->fid.vid, vnode->fid.vnode, dentry->d_name.name, | ||
795 | datasync); | ||
796 | |||
797 | /* use a writeback record as a marker in the queue - when this reaches | ||
798 | * the front of the queue, all the outstanding writes are either | ||
799 | * completed or rejected */ | ||
800 | wb = kzalloc(sizeof(*wb), GFP_KERNEL); | ||
801 | if (!wb) | ||
802 | return -ENOMEM; | ||
803 | wb->vnode = vnode; | ||
804 | wb->first = 0; | ||
805 | wb->last = -1; | ||
806 | wb->offset_first = 0; | ||
807 | wb->to_last = PAGE_SIZE; | ||
808 | wb->usage = 1; | ||
809 | wb->state = AFS_WBACK_SYNCING; | ||
810 | init_waitqueue_head(&wb->waitq); | ||
811 | |||
812 | spin_lock(&vnode->writeback_lock); | ||
813 | list_for_each_entry(xwb, &vnode->writebacks, link) { | ||
814 | if (xwb->state == AFS_WBACK_PENDING) | ||
815 | xwb->state = AFS_WBACK_CONFLICTING; | ||
816 | } | ||
817 | list_add_tail(&wb->link, &vnode->writebacks); | ||
818 | spin_unlock(&vnode->writeback_lock); | ||
819 | |||
820 | /* push all the outstanding writebacks to the server */ | ||
821 | ret = afs_writeback_all(vnode); | ||
822 | if (ret < 0) { | ||
823 | afs_put_writeback(wb); | ||
824 | _leave(" = %d [wb]", ret); | ||
825 | return ret; | ||
826 | } | ||
827 | |||
828 | /* wait for the preceding writes to actually complete */ | ||
829 | ret = wait_event_interruptible(wb->waitq, | ||
830 | wb->state == AFS_WBACK_COMPLETE || | ||
831 | vnode->writebacks.next == &wb->link); | ||
832 | afs_put_writeback(wb); | ||
833 | _leave(" = %d", ret); | ||
834 | return ret; | ||
835 | } | ||
@@ -346,10 +346,9 @@ void fastcall exit_aio(struct mm_struct *mm) | |||
346 | 346 | ||
347 | wait_for_all_aios(ctx); | 347 | wait_for_all_aios(ctx); |
348 | /* | 348 | /* |
349 | * this is an overkill, but ensures we don't leave | 349 | * Ensure we don't leave the ctx on the aio_wq |
350 | * the ctx on the aio_wq | ||
351 | */ | 350 | */ |
352 | flush_workqueue(aio_wq); | 351 | cancel_work_sync(&ctx->wq.work); |
353 | 352 | ||
354 | if (1 != atomic_read(&ctx->users)) | 353 | if (1 != atomic_read(&ctx->users)) |
355 | printk(KERN_DEBUG | 354 | printk(KERN_DEBUG |
@@ -372,7 +371,7 @@ void fastcall __put_ioctx(struct kioctx *ctx) | |||
372 | BUG_ON(ctx->reqs_active); | 371 | BUG_ON(ctx->reqs_active); |
373 | 372 | ||
374 | cancel_delayed_work(&ctx->wq); | 373 | cancel_delayed_work(&ctx->wq); |
375 | flush_workqueue(aio_wq); | 374 | cancel_work_sync(&ctx->wq.work); |
376 | aio_free_ring(ctx); | 375 | aio_free_ring(ctx); |
377 | mmdrop(ctx->mm); | 376 | mmdrop(ctx->mm); |
378 | ctx->mm = NULL; | 377 | ctx->mm = NULL; |
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c index 18657f001b43..72d0b412c376 100644 --- a/fs/binfmt_misc.c +++ b/fs/binfmt_misc.c | |||
@@ -675,19 +675,8 @@ static ssize_t | |||
675 | bm_status_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) | 675 | bm_status_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) |
676 | { | 676 | { |
677 | char *s = enabled ? "enabled" : "disabled"; | 677 | char *s = enabled ? "enabled" : "disabled"; |
678 | int len = strlen(s); | ||
679 | loff_t pos = *ppos; | ||
680 | 678 | ||
681 | if (pos < 0) | 679 | return simple_read_from_buffer(buf, nbytes, ppos, s, strlen(s)); |
682 | return -EINVAL; | ||
683 | if (pos >= len) | ||
684 | return 0; | ||
685 | if (len < pos + nbytes) | ||
686 | nbytes = len - pos; | ||
687 | if (copy_to_user(buf, s + pos, nbytes)) | ||
688 | return -EFAULT; | ||
689 | *ppos = pos + nbytes; | ||
690 | return nbytes; | ||
691 | } | 680 | } |
692 | 681 | ||
693 | static ssize_t bm_status_write(struct file * file, const char __user * buffer, | 682 | static ssize_t bm_status_write(struct file * file, const char __user * buffer, |
diff --git a/fs/buffer.c b/fs/buffer.c index eb820b82a636..aecd057cd0e0 100644 --- a/fs/buffer.c +++ b/fs/buffer.c | |||
@@ -1846,13 +1846,8 @@ static int __block_prepare_write(struct inode *inode, struct page *page, | |||
1846 | if (block_start >= to) | 1846 | if (block_start >= to) |
1847 | break; | 1847 | break; |
1848 | if (buffer_new(bh)) { | 1848 | if (buffer_new(bh)) { |
1849 | void *kaddr; | ||
1850 | |||
1851 | clear_buffer_new(bh); | 1849 | clear_buffer_new(bh); |
1852 | kaddr = kmap_atomic(page, KM_USER0); | 1850 | zero_user_page(page, block_start, bh->b_size, KM_USER0); |
1853 | memset(kaddr+block_start, 0, bh->b_size); | ||
1854 | flush_dcache_page(page); | ||
1855 | kunmap_atomic(kaddr, KM_USER0); | ||
1856 | set_buffer_uptodate(bh); | 1851 | set_buffer_uptodate(bh); |
1857 | mark_buffer_dirty(bh); | 1852 | mark_buffer_dirty(bh); |
1858 | } | 1853 | } |
@@ -1940,10 +1935,8 @@ int block_read_full_page(struct page *page, get_block_t *get_block) | |||
1940 | SetPageError(page); | 1935 | SetPageError(page); |
1941 | } | 1936 | } |
1942 | if (!buffer_mapped(bh)) { | 1937 | if (!buffer_mapped(bh)) { |
1943 | void *kaddr = kmap_atomic(page, KM_USER0); | 1938 | zero_user_page(page, i * blocksize, blocksize, |
1944 | memset(kaddr + i * blocksize, 0, blocksize); | 1939 | KM_USER0); |
1945 | flush_dcache_page(page); | ||
1946 | kunmap_atomic(kaddr, KM_USER0); | ||
1947 | if (!err) | 1940 | if (!err) |
1948 | set_buffer_uptodate(bh); | 1941 | set_buffer_uptodate(bh); |
1949 | continue; | 1942 | continue; |
@@ -2086,7 +2079,6 @@ int cont_prepare_write(struct page *page, unsigned offset, | |||
2086 | long status; | 2079 | long status; |
2087 | unsigned zerofrom; | 2080 | unsigned zerofrom; |
2088 | unsigned blocksize = 1 << inode->i_blkbits; | 2081 | unsigned blocksize = 1 << inode->i_blkbits; |
2089 | void *kaddr; | ||
2090 | 2082 | ||
2091 | while(page->index > (pgpos = *bytes>>PAGE_CACHE_SHIFT)) { | 2083 | while(page->index > (pgpos = *bytes>>PAGE_CACHE_SHIFT)) { |
2092 | status = -ENOMEM; | 2084 | status = -ENOMEM; |
@@ -2108,10 +2100,8 @@ int cont_prepare_write(struct page *page, unsigned offset, | |||
2108 | PAGE_CACHE_SIZE, get_block); | 2100 | PAGE_CACHE_SIZE, get_block); |
2109 | if (status) | 2101 | if (status) |
2110 | goto out_unmap; | 2102 | goto out_unmap; |
2111 | kaddr = kmap_atomic(new_page, KM_USER0); | 2103 | zero_user_page(page, zerofrom, PAGE_CACHE_SIZE - zerofrom, |
2112 | memset(kaddr+zerofrom, 0, PAGE_CACHE_SIZE-zerofrom); | 2104 | KM_USER0); |
2113 | flush_dcache_page(new_page); | ||
2114 | kunmap_atomic(kaddr, KM_USER0); | ||
2115 | generic_commit_write(NULL, new_page, zerofrom, PAGE_CACHE_SIZE); | 2105 | generic_commit_write(NULL, new_page, zerofrom, PAGE_CACHE_SIZE); |
2116 | unlock_page(new_page); | 2106 | unlock_page(new_page); |
2117 | page_cache_release(new_page); | 2107 | page_cache_release(new_page); |
@@ -2138,10 +2128,7 @@ int cont_prepare_write(struct page *page, unsigned offset, | |||
2138 | if (status) | 2128 | if (status) |
2139 | goto out1; | 2129 | goto out1; |
2140 | if (zerofrom < offset) { | 2130 | if (zerofrom < offset) { |
2141 | kaddr = kmap_atomic(page, KM_USER0); | 2131 | zero_user_page(page, zerofrom, offset - zerofrom, KM_USER0); |
2142 | memset(kaddr+zerofrom, 0, offset-zerofrom); | ||
2143 | flush_dcache_page(page); | ||
2144 | kunmap_atomic(kaddr, KM_USER0); | ||
2145 | __block_commit_write(inode, page, zerofrom, offset); | 2132 | __block_commit_write(inode, page, zerofrom, offset); |
2146 | } | 2133 | } |
2147 | return 0; | 2134 | return 0; |
@@ -2340,10 +2327,7 @@ failed: | |||
2340 | * Error recovery is pretty slack. Clear the page and mark it dirty | 2327 | * Error recovery is pretty slack. Clear the page and mark it dirty |
2341 | * so we'll later zero out any blocks which _were_ allocated. | 2328 | * so we'll later zero out any blocks which _were_ allocated. |
2342 | */ | 2329 | */ |
2343 | kaddr = kmap_atomic(page, KM_USER0); | 2330 | zero_user_page(page, 0, PAGE_CACHE_SIZE, KM_USER0); |
2344 | memset(kaddr, 0, PAGE_CACHE_SIZE); | ||
2345 | flush_dcache_page(page); | ||
2346 | kunmap_atomic(kaddr, KM_USER0); | ||
2347 | SetPageUptodate(page); | 2331 | SetPageUptodate(page); |
2348 | set_page_dirty(page); | 2332 | set_page_dirty(page); |
2349 | return ret; | 2333 | return ret; |
@@ -2382,7 +2366,6 @@ int nobh_writepage(struct page *page, get_block_t *get_block, | |||
2382 | loff_t i_size = i_size_read(inode); | 2366 | loff_t i_size = i_size_read(inode); |
2383 | const pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT; | 2367 | const pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT; |
2384 | unsigned offset; | 2368 | unsigned offset; |
2385 | void *kaddr; | ||
2386 | int ret; | 2369 | int ret; |
2387 | 2370 | ||
2388 | /* Is the page fully inside i_size? */ | 2371 | /* Is the page fully inside i_size? */ |
@@ -2413,10 +2396,7 @@ int nobh_writepage(struct page *page, get_block_t *get_block, | |||
2413 | * the page size, the remaining memory is zeroed when mapped, and | 2396 | * the page size, the remaining memory is zeroed when mapped, and |
2414 | * writes to that region are not written out to the file." | 2397 | * writes to that region are not written out to the file." |
2415 | */ | 2398 | */ |
2416 | kaddr = kmap_atomic(page, KM_USER0); | 2399 | zero_user_page(page, offset, PAGE_CACHE_SIZE - offset, KM_USER0); |
2417 | memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset); | ||
2418 | flush_dcache_page(page); | ||
2419 | kunmap_atomic(kaddr, KM_USER0); | ||
2420 | out: | 2400 | out: |
2421 | ret = mpage_writepage(page, get_block, wbc); | 2401 | ret = mpage_writepage(page, get_block, wbc); |
2422 | if (ret == -EAGAIN) | 2402 | if (ret == -EAGAIN) |
@@ -2437,7 +2417,6 @@ int nobh_truncate_page(struct address_space *mapping, loff_t from) | |||
2437 | unsigned to; | 2417 | unsigned to; |
2438 | struct page *page; | 2418 | struct page *page; |
2439 | const struct address_space_operations *a_ops = mapping->a_ops; | 2419 | const struct address_space_operations *a_ops = mapping->a_ops; |
2440 | char *kaddr; | ||
2441 | int ret = 0; | 2420 | int ret = 0; |
2442 | 2421 | ||
2443 | if ((offset & (blocksize - 1)) == 0) | 2422 | if ((offset & (blocksize - 1)) == 0) |
@@ -2451,10 +2430,8 @@ int nobh_truncate_page(struct address_space *mapping, loff_t from) | |||
2451 | to = (offset + blocksize) & ~(blocksize - 1); | 2430 | to = (offset + blocksize) & ~(blocksize - 1); |
2452 | ret = a_ops->prepare_write(NULL, page, offset, to); | 2431 | ret = a_ops->prepare_write(NULL, page, offset, to); |
2453 | if (ret == 0) { | 2432 | if (ret == 0) { |
2454 | kaddr = kmap_atomic(page, KM_USER0); | 2433 | zero_user_page(page, offset, PAGE_CACHE_SIZE - offset, |
2455 | memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset); | 2434 | KM_USER0); |
2456 | flush_dcache_page(page); | ||
2457 | kunmap_atomic(kaddr, KM_USER0); | ||
2458 | /* | 2435 | /* |
2459 | * It would be more correct to call aops->commit_write() | 2436 | * It would be more correct to call aops->commit_write() |
2460 | * here, but this is more efficient. | 2437 | * here, but this is more efficient. |
@@ -2480,7 +2457,6 @@ int block_truncate_page(struct address_space *mapping, | |||
2480 | struct inode *inode = mapping->host; | 2457 | struct inode *inode = mapping->host; |
2481 | struct page *page; | 2458 | struct page *page; |
2482 | struct buffer_head *bh; | 2459 | struct buffer_head *bh; |
2483 | void *kaddr; | ||
2484 | int err; | 2460 | int err; |
2485 | 2461 | ||
2486 | blocksize = 1 << inode->i_blkbits; | 2462 | blocksize = 1 << inode->i_blkbits; |
@@ -2534,11 +2510,7 @@ int block_truncate_page(struct address_space *mapping, | |||
2534 | goto unlock; | 2510 | goto unlock; |
2535 | } | 2511 | } |
2536 | 2512 | ||
2537 | kaddr = kmap_atomic(page, KM_USER0); | 2513 | zero_user_page(page, offset, length, KM_USER0); |
2538 | memset(kaddr + offset, 0, length); | ||
2539 | flush_dcache_page(page); | ||
2540 | kunmap_atomic(kaddr, KM_USER0); | ||
2541 | |||
2542 | mark_buffer_dirty(bh); | 2514 | mark_buffer_dirty(bh); |
2543 | err = 0; | 2515 | err = 0; |
2544 | 2516 | ||
@@ -2559,7 +2531,6 @@ int block_write_full_page(struct page *page, get_block_t *get_block, | |||
2559 | loff_t i_size = i_size_read(inode); | 2531 | loff_t i_size = i_size_read(inode); |
2560 | const pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT; | 2532 | const pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT; |
2561 | unsigned offset; | 2533 | unsigned offset; |
2562 | void *kaddr; | ||
2563 | 2534 | ||
2564 | /* Is the page fully inside i_size? */ | 2535 | /* Is the page fully inside i_size? */ |
2565 | if (page->index < end_index) | 2536 | if (page->index < end_index) |
@@ -2585,10 +2556,7 @@ int block_write_full_page(struct page *page, get_block_t *get_block, | |||
2585 | * the page size, the remaining memory is zeroed when mapped, and | 2556 | * the page size, the remaining memory is zeroed when mapped, and |
2586 | * writes to that region are not written out to the file." | 2557 | * writes to that region are not written out to the file." |
2587 | */ | 2558 | */ |
2588 | kaddr = kmap_atomic(page, KM_USER0); | 2559 | zero_user_page(page, offset, PAGE_CACHE_SIZE - offset, KM_USER0); |
2589 | memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset); | ||
2590 | flush_dcache_page(page); | ||
2591 | kunmap_atomic(kaddr, KM_USER0); | ||
2592 | return __block_write_full_page(inode, page, get_block, wbc); | 2560 | return __block_write_full_page(inode, page, get_block, wbc); |
2593 | } | 2561 | } |
2594 | 2562 | ||
@@ -2978,7 +2946,7 @@ static void buffer_exit_cpu(int cpu) | |||
2978 | static int buffer_cpu_notify(struct notifier_block *self, | 2946 | static int buffer_cpu_notify(struct notifier_block *self, |
2979 | unsigned long action, void *hcpu) | 2947 | unsigned long action, void *hcpu) |
2980 | { | 2948 | { |
2981 | if (action == CPU_DEAD) | 2949 | if (action == CPU_DEAD || action == CPU_DEAD_FROZEN) |
2982 | buffer_exit_cpu((unsigned long)hcpu); | 2950 | buffer_exit_cpu((unsigned long)hcpu); |
2983 | return NOTIFY_OK; | 2951 | return NOTIFY_OK; |
2984 | } | 2952 | } |
diff --git a/fs/configfs/file.c b/fs/configfs/file.c index d98be5e01328..3527c7c6def8 100644 --- a/fs/configfs/file.c +++ b/fs/configfs/file.c | |||
@@ -77,36 +77,6 @@ static int fill_read_buffer(struct dentry * dentry, struct configfs_buffer * buf | |||
77 | return ret; | 77 | return ret; |
78 | } | 78 | } |
79 | 79 | ||
80 | |||
81 | /** | ||
82 | * flush_read_buffer - push buffer to userspace. | ||
83 | * @buffer: data buffer for file. | ||
84 | * @userbuf: user-passed buffer. | ||
85 | * @count: number of bytes requested. | ||
86 | * @ppos: file position. | ||
87 | * | ||
88 | * Copy the buffer we filled in fill_read_buffer() to userspace. | ||
89 | * This is done at the reader's leisure, copying and advancing | ||
90 | * the amount they specify each time. | ||
91 | * This may be called continuously until the buffer is empty. | ||
92 | */ | ||
93 | static int flush_read_buffer(struct configfs_buffer * buffer, char __user * buf, | ||
94 | size_t count, loff_t * ppos) | ||
95 | { | ||
96 | int error; | ||
97 | |||
98 | if (*ppos > buffer->count) | ||
99 | return 0; | ||
100 | |||
101 | if (count > (buffer->count - *ppos)) | ||
102 | count = buffer->count - *ppos; | ||
103 | |||
104 | error = copy_to_user(buf,buffer->page + *ppos,count); | ||
105 | if (!error) | ||
106 | *ppos += count; | ||
107 | return error ? -EFAULT : count; | ||
108 | } | ||
109 | |||
110 | /** | 80 | /** |
111 | * configfs_read_file - read an attribute. | 81 | * configfs_read_file - read an attribute. |
112 | * @file: file pointer. | 82 | * @file: file pointer. |
@@ -139,7 +109,8 @@ configfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *pp | |||
139 | } | 109 | } |
140 | pr_debug("%s: count = %zd, ppos = %lld, buf = %s\n", | 110 | pr_debug("%s: count = %zd, ppos = %lld, buf = %s\n", |
141 | __FUNCTION__, count, *ppos, buffer->page); | 111 | __FUNCTION__, count, *ppos, buffer->page); |
142 | retval = flush_read_buffer(buffer,buf,count,ppos); | 112 | retval = simple_read_from_buffer(buf, count, ppos, buffer->page, |
113 | buffer->count); | ||
143 | out: | 114 | out: |
144 | up(&buffer->sem); | 115 | up(&buffer->sem); |
145 | return retval; | 116 | return retval; |
diff --git a/fs/direct-io.c b/fs/direct-io.c index d9d0833444f5..8593f3dfd299 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c | |||
@@ -439,7 +439,7 @@ static int dio_bio_complete(struct dio *dio, struct bio *bio) | |||
439 | * Wait on and process all in-flight BIOs. This must only be called once | 439 | * Wait on and process all in-flight BIOs. This must only be called once |
440 | * all bios have been issued so that the refcount can only decrease. | 440 | * all bios have been issued so that the refcount can only decrease. |
441 | * This just waits for all bios to make it through dio_bio_complete. IO | 441 | * This just waits for all bios to make it through dio_bio_complete. IO |
442 | * errors are propogated through dio->io_error and should be propogated via | 442 | * errors are propagated through dio->io_error and should be propagated via |
443 | * dio_complete(). | 443 | * dio_complete(). |
444 | */ | 444 | */ |
445 | static void dio_await_completion(struct dio *dio) | 445 | static void dio_await_completion(struct dio *dio) |
@@ -867,7 +867,6 @@ static int do_direct_IO(struct dio *dio) | |||
867 | do_holes: | 867 | do_holes: |
868 | /* Handle holes */ | 868 | /* Handle holes */ |
869 | if (!buffer_mapped(map_bh)) { | 869 | if (!buffer_mapped(map_bh)) { |
870 | char *kaddr; | ||
871 | loff_t i_size_aligned; | 870 | loff_t i_size_aligned; |
872 | 871 | ||
873 | /* AKPM: eargh, -ENOTBLK is a hack */ | 872 | /* AKPM: eargh, -ENOTBLK is a hack */ |
@@ -888,11 +887,8 @@ do_holes: | |||
888 | page_cache_release(page); | 887 | page_cache_release(page); |
889 | goto out; | 888 | goto out; |
890 | } | 889 | } |
891 | kaddr = kmap_atomic(page, KM_USER0); | 890 | zero_user_page(page, block_in_page << blkbits, |
892 | memset(kaddr + (block_in_page << blkbits), | 891 | 1 << blkbits, KM_USER0); |
893 | 0, 1 << blkbits); | ||
894 | flush_dcache_page(page); | ||
895 | kunmap_atomic(kaddr, KM_USER0); | ||
896 | dio->block_in_file++; | 892 | dio->block_in_file++; |
897 | block_in_page++; | 893 | block_in_page++; |
898 | goto next_block; | 894 | goto next_block; |
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index e1bb03171986..a6cb6171c3af 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c | |||
@@ -1767,7 +1767,6 @@ static int ext3_block_truncate_page(handle_t *handle, struct page *page, | |||
1767 | struct inode *inode = mapping->host; | 1767 | struct inode *inode = mapping->host; |
1768 | struct buffer_head *bh; | 1768 | struct buffer_head *bh; |
1769 | int err = 0; | 1769 | int err = 0; |
1770 | void *kaddr; | ||
1771 | 1770 | ||
1772 | blocksize = inode->i_sb->s_blocksize; | 1771 | blocksize = inode->i_sb->s_blocksize; |
1773 | length = blocksize - (offset & (blocksize - 1)); | 1772 | length = blocksize - (offset & (blocksize - 1)); |
@@ -1779,10 +1778,7 @@ static int ext3_block_truncate_page(handle_t *handle, struct page *page, | |||
1779 | */ | 1778 | */ |
1780 | if (!page_has_buffers(page) && test_opt(inode->i_sb, NOBH) && | 1779 | if (!page_has_buffers(page) && test_opt(inode->i_sb, NOBH) && |
1781 | ext3_should_writeback_data(inode) && PageUptodate(page)) { | 1780 | ext3_should_writeback_data(inode) && PageUptodate(page)) { |
1782 | kaddr = kmap_atomic(page, KM_USER0); | 1781 | zero_user_page(page, offset, length, KM_USER0); |
1783 | memset(kaddr + offset, 0, length); | ||
1784 | flush_dcache_page(page); | ||
1785 | kunmap_atomic(kaddr, KM_USER0); | ||
1786 | set_page_dirty(page); | 1782 | set_page_dirty(page); |
1787 | goto unlock; | 1783 | goto unlock; |
1788 | } | 1784 | } |
@@ -1835,11 +1831,7 @@ static int ext3_block_truncate_page(handle_t *handle, struct page *page, | |||
1835 | goto unlock; | 1831 | goto unlock; |
1836 | } | 1832 | } |
1837 | 1833 | ||
1838 | kaddr = kmap_atomic(page, KM_USER0); | 1834 | zero_user_page(page, offset, length, KM_USER0); |
1839 | memset(kaddr + offset, 0, length); | ||
1840 | flush_dcache_page(page); | ||
1841 | kunmap_atomic(kaddr, KM_USER0); | ||
1842 | |||
1843 | BUFFER_TRACE(bh, "zeroed end of block"); | 1835 | BUFFER_TRACE(bh, "zeroed end of block"); |
1844 | 1836 | ||
1845 | err = 0; | 1837 | err = 0; |
diff --git a/fs/jbd/checkpoint.c b/fs/jbd/checkpoint.c index 0208cc7ac5d0..47552d4a6324 100644 --- a/fs/jbd/checkpoint.c +++ b/fs/jbd/checkpoint.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * linux/fs/checkpoint.c | 2 | * linux/fs/jbd/checkpoint.c |
3 | * | 3 | * |
4 | * Written by Stephen C. Tweedie <sct@redhat.com>, 1999 | 4 | * Written by Stephen C. Tweedie <sct@redhat.com>, 1999 |
5 | * | 5 | * |
diff --git a/fs/jbd/recovery.c b/fs/jbd/recovery.c index 11563fe2a52b..2a5f4b833e35 100644 --- a/fs/jbd/recovery.c +++ b/fs/jbd/recovery.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * linux/fs/recovery.c | 2 | * linux/fs/jbd/recovery.c |
3 | * | 3 | * |
4 | * Written by Stephen C. Tweedie <sct@redhat.com>, 1999 | 4 | * Written by Stephen C. Tweedie <sct@redhat.com>, 1999 |
5 | * | 5 | * |
diff --git a/fs/jbd/revoke.c b/fs/jbd/revoke.c index a68cbb605022..824e3b7d4ec1 100644 --- a/fs/jbd/revoke.c +++ b/fs/jbd/revoke.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * linux/fs/revoke.c | 2 | * linux/fs/jbd/revoke.c |
3 | * | 3 | * |
4 | * Written by Stephen C. Tweedie <sct@redhat.com>, 2000 | 4 | * Written by Stephen C. Tweedie <sct@redhat.com>, 2000 |
5 | * | 5 | * |
diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c index f9822fc07851..772b6531a2a2 100644 --- a/fs/jbd/transaction.c +++ b/fs/jbd/transaction.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * linux/fs/transaction.c | 2 | * linux/fs/jbd/transaction.c |
3 | * | 3 | * |
4 | * Written by Stephen C. Tweedie <sct@redhat.com>, 1998 | 4 | * Written by Stephen C. Tweedie <sct@redhat.com>, 1998 |
5 | * | 5 | * |
diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c index 68039fa9a566..3fccde7ba008 100644 --- a/fs/jbd2/checkpoint.c +++ b/fs/jbd2/checkpoint.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * linux/fs/checkpoint.c | 2 | * linux/fs/jbd2/checkpoint.c |
3 | * | 3 | * |
4 | * Written by Stephen C. Tweedie <sct@redhat.com>, 1999 | 4 | * Written by Stephen C. Tweedie <sct@redhat.com>, 1999 |
5 | * | 5 | * |
diff --git a/fs/jbd2/recovery.c b/fs/jbd2/recovery.c index 9f10acafaf70..395c92a04ac9 100644 --- a/fs/jbd2/recovery.c +++ b/fs/jbd2/recovery.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * linux/fs/recovery.c | 2 | * linux/fs/jbd2/recovery.c |
3 | * | 3 | * |
4 | * Written by Stephen C. Tweedie <sct@redhat.com>, 1999 | 4 | * Written by Stephen C. Tweedie <sct@redhat.com>, 1999 |
5 | * | 5 | * |
diff --git a/fs/jbd2/revoke.c b/fs/jbd2/revoke.c index 1e864dcc49ea..9246e763da78 100644 --- a/fs/jbd2/revoke.c +++ b/fs/jbd2/revoke.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * linux/fs/revoke.c | 2 | * linux/fs/jbd2/revoke.c |
3 | * | 3 | * |
4 | * Written by Stephen C. Tweedie <sct@redhat.com>, 2000 | 4 | * Written by Stephen C. Tweedie <sct@redhat.com>, 2000 |
5 | * | 5 | * |
diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index e347d8c078bc..7946ff43fc40 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * linux/fs/transaction.c | 2 | * linux/fs/jbd2/transaction.c |
3 | * | 3 | * |
4 | * Written by Stephen C. Tweedie <sct@redhat.com>, 1998 | 4 | * Written by Stephen C. Tweedie <sct@redhat.com>, 1998 |
5 | * | 5 | * |
diff --git a/fs/jffs2/histo_mips.h b/fs/jffs2/histo_mips.h deleted file mode 100644 index fa3dac19a109..000000000000 --- a/fs/jffs2/histo_mips.h +++ /dev/null | |||
@@ -1,2 +0,0 @@ | |||
1 | #define BIT_DIVIDER_MIPS 1043 | ||
2 | static int bits_mips[8] = { 277,249,290,267,229,341,212,241}; /* mips32 */ | ||
diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c index 6aff38930b50..4884d5edfe65 100644 --- a/fs/jffs2/readinode.c +++ b/fs/jffs2/readinode.c | |||
@@ -219,9 +219,9 @@ static int jffs2_add_tn_to_tree(struct jffs2_sb_info *c, | |||
219 | struct jffs2_tmp_dnode_info *tn) | 219 | struct jffs2_tmp_dnode_info *tn) |
220 | { | 220 | { |
221 | uint32_t fn_end = tn->fn->ofs + tn->fn->size; | 221 | uint32_t fn_end = tn->fn->ofs + tn->fn->size; |
222 | struct jffs2_tmp_dnode_info *insert_point = NULL, *this; | 222 | struct jffs2_tmp_dnode_info *this; |
223 | 223 | ||
224 | dbg_readinode("insert fragment %#04x-%#04x, ver %u\n", tn->fn->ofs, fn_end, tn->version); | 224 | dbg_readinode("insert fragment %#04x-%#04x, ver %u at %08x\n", tn->fn->ofs, fn_end, tn->version, ref_offset(tn->fn->raw)); |
225 | 225 | ||
226 | /* If a node has zero dsize, we only have to keep if it if it might be the | 226 | /* If a node has zero dsize, we only have to keep if it if it might be the |
227 | node with highest version -- i.e. the one which will end up as f->metadata. | 227 | node with highest version -- i.e. the one which will end up as f->metadata. |
@@ -240,23 +240,16 @@ static int jffs2_add_tn_to_tree(struct jffs2_sb_info *c, | |||
240 | 240 | ||
241 | /* Find the earliest node which _may_ be relevant to this one */ | 241 | /* Find the earliest node which _may_ be relevant to this one */ |
242 | this = jffs2_lookup_tn(&rii->tn_root, tn->fn->ofs); | 242 | this = jffs2_lookup_tn(&rii->tn_root, tn->fn->ofs); |
243 | if (!this) { | 243 | if (this) { |
244 | /* First addition to empty tree. $DEITY how I love the easy cases */ | 244 | /* If the node is coincident with another at a lower address, |
245 | rb_link_node(&tn->rb, NULL, &rii->tn_root.rb_node); | 245 | back up until the other node is found. It may be relevant */ |
246 | rb_insert_color(&tn->rb, &rii->tn_root); | 246 | while (this->overlapped) |
247 | dbg_readinode("keep new frag\n"); | 247 | this = tn_prev(this); |
248 | return 0; | ||
249 | } | ||
250 | |||
251 | /* If we add a new node it'll be somewhere under here. */ | ||
252 | insert_point = this; | ||
253 | |||
254 | /* If the node is coincident with another at a lower address, | ||
255 | back up until the other node is found. It may be relevant */ | ||
256 | while (tn->overlapped) | ||
257 | tn = tn_prev(tn); | ||
258 | 248 | ||
259 | dbg_readinode("'this' found %#04x-%#04x (%s)\n", this->fn->ofs, this->fn->ofs + this->fn->size, this->fn ? "data" : "hole"); | 249 | /* First node should never be marked overlapped */ |
250 | BUG_ON(!this); | ||
251 | dbg_readinode("'this' found %#04x-%#04x (%s)\n", this->fn->ofs, this->fn->ofs + this->fn->size, this->fn ? "data" : "hole"); | ||
252 | } | ||
260 | 253 | ||
261 | while (this) { | 254 | while (this) { |
262 | if (this->fn->ofs > fn_end) | 255 | if (this->fn->ofs > fn_end) |
@@ -274,11 +267,10 @@ static int jffs2_add_tn_to_tree(struct jffs2_sb_info *c, | |||
274 | return 0; | 267 | return 0; |
275 | } else { | 268 | } else { |
276 | /* Who cares if the new one is good; keep it for now anyway. */ | 269 | /* Who cares if the new one is good; keep it for now anyway. */ |
270 | dbg_readinode("Like new node. Throw away old\n"); | ||
277 | rb_replace_node(&this->rb, &tn->rb, &rii->tn_root); | 271 | rb_replace_node(&this->rb, &tn->rb, &rii->tn_root); |
278 | /* Same overlapping from in front and behind */ | ||
279 | tn->overlapped = this->overlapped; | ||
280 | jffs2_kill_tn(c, this); | 272 | jffs2_kill_tn(c, this); |
281 | dbg_readinode("Like new node. Throw away old\n"); | 273 | /* Same overlapping from in front and behind */ |
282 | return 0; | 274 | return 0; |
283 | } | 275 | } |
284 | } | 276 | } |
@@ -291,13 +283,8 @@ static int jffs2_add_tn_to_tree(struct jffs2_sb_info *c, | |||
291 | jffs2_kill_tn(c, tn); | 283 | jffs2_kill_tn(c, tn); |
292 | return 0; | 284 | return 0; |
293 | } | 285 | } |
294 | /* ... and is good. Kill 'this'... */ | 286 | /* ... and is good. Kill 'this' and any subsequent nodes which are also overlapped */ |
295 | rb_replace_node(&this->rb, &tn->rb, &rii->tn_root); | 287 | while (this && this->fn->ofs + this->fn->size <= fn_end) { |
296 | tn->overlapped = this->overlapped; | ||
297 | jffs2_kill_tn(c, this); | ||
298 | /* ... and any subsequent nodes which are also overlapped */ | ||
299 | this = tn_next(tn); | ||
300 | while (this && this->fn->ofs + this->fn->size < fn_end) { | ||
301 | struct jffs2_tmp_dnode_info *next = tn_next(this); | 288 | struct jffs2_tmp_dnode_info *next = tn_next(this); |
302 | if (this->version < tn->version) { | 289 | if (this->version < tn->version) { |
303 | tn_erase(this, &rii->tn_root); | 290 | tn_erase(this, &rii->tn_root); |
@@ -308,8 +295,8 @@ static int jffs2_add_tn_to_tree(struct jffs2_sb_info *c, | |||
308 | } | 295 | } |
309 | this = next; | 296 | this = next; |
310 | } | 297 | } |
311 | dbg_readinode("Done inserting new\n"); | 298 | dbg_readinode("Done killing overlapped nodes\n"); |
312 | return 0; | 299 | continue; |
313 | } | 300 | } |
314 | if (this->version > tn->version && | 301 | if (this->version > tn->version && |
315 | this->fn->ofs <= tn->fn->ofs && | 302 | this->fn->ofs <= tn->fn->ofs && |
@@ -321,29 +308,21 @@ static int jffs2_add_tn_to_tree(struct jffs2_sb_info *c, | |||
321 | return 0; | 308 | return 0; |
322 | } | 309 | } |
323 | /* ... but 'this' was bad. Replace it... */ | 310 | /* ... but 'this' was bad. Replace it... */ |
324 | rb_replace_node(&this->rb, &tn->rb, &rii->tn_root); | ||
325 | dbg_readinode("Bad CRC on old overlapping node. Kill it\n"); | 311 | dbg_readinode("Bad CRC on old overlapping node. Kill it\n"); |
312 | tn_erase(this, &rii->tn_root); | ||
326 | jffs2_kill_tn(c, this); | 313 | jffs2_kill_tn(c, this); |
327 | return 0; | 314 | break; |
328 | } | 315 | } |
329 | /* We want to be inserted under the last node which is | ||
330 | either at a lower offset _or_ has a smaller range */ | ||
331 | if (this->fn->ofs < tn->fn->ofs || | ||
332 | (this->fn->ofs == tn->fn->ofs && | ||
333 | this->fn->size <= tn->fn->size)) | ||
334 | insert_point = this; | ||
335 | 316 | ||
336 | this = tn_next(this); | 317 | this = tn_next(this); |
337 | } | 318 | } |
338 | dbg_readinode("insert_point %p, ver %d, 0x%x-0x%x, ov %d\n", | 319 | |
339 | insert_point, insert_point->version, insert_point->fn->ofs, | ||
340 | insert_point->fn->ofs+insert_point->fn->size, | ||
341 | insert_point->overlapped); | ||
342 | /* We neither completely obsoleted nor were completely | 320 | /* We neither completely obsoleted nor were completely |
343 | obsoleted by an earlier node. Insert under insert_point */ | 321 | obsoleted by an earlier node. Insert into the tree */ |
344 | { | 322 | { |
345 | struct rb_node *parent = &insert_point->rb; | 323 | struct rb_node *parent; |
346 | struct rb_node **link = &parent; | 324 | struct rb_node **link = &rii->tn_root.rb_node; |
325 | struct jffs2_tmp_dnode_info *insert_point = NULL; | ||
347 | 326 | ||
348 | while (*link) { | 327 | while (*link) { |
349 | parent = *link; | 328 | parent = *link; |
@@ -359,6 +338,7 @@ static int jffs2_add_tn_to_tree(struct jffs2_sb_info *c, | |||
359 | rb_link_node(&tn->rb, &insert_point->rb, link); | 338 | rb_link_node(&tn->rb, &insert_point->rb, link); |
360 | rb_insert_color(&tn->rb, &rii->tn_root); | 339 | rb_insert_color(&tn->rb, &rii->tn_root); |
361 | } | 340 | } |
341 | |||
362 | /* If there's anything behind that overlaps us, note it */ | 342 | /* If there's anything behind that overlaps us, note it */ |
363 | this = tn_prev(tn); | 343 | this = tn_prev(tn); |
364 | if (this) { | 344 | if (this) { |
@@ -457,7 +437,7 @@ static int jffs2_build_inode_fragtree(struct jffs2_sb_info *c, | |||
457 | this = tn_last(&rii->tn_root); | 437 | this = tn_last(&rii->tn_root); |
458 | while (this) { | 438 | while (this) { |
459 | dbg_readinode("tn %p ver %d range 0x%x-0x%x ov %d\n", this, this->version, this->fn->ofs, | 439 | dbg_readinode("tn %p ver %d range 0x%x-0x%x ov %d\n", this, this->version, this->fn->ofs, |
460 | this->fn->ofs+this->fn->size, this->overlapped); | 440 | this->fn->ofs+this->fn->size, this->overlapped); |
461 | this = tn_prev(this); | 441 | this = tn_prev(this); |
462 | } | 442 | } |
463 | #endif | 443 | #endif |
@@ -483,7 +463,7 @@ static int jffs2_build_inode_fragtree(struct jffs2_sb_info *c, | |||
483 | vers_next = tn_prev(this); | 463 | vers_next = tn_prev(this); |
484 | eat_last(&ver_root, &this->rb); | 464 | eat_last(&ver_root, &this->rb); |
485 | if (check_tn_node(c, this)) { | 465 | if (check_tn_node(c, this)) { |
486 | dbg_readinode("node ver %x, 0x%x-0x%x failed CRC\n", | 466 | dbg_readinode("node ver %d, 0x%x-0x%x failed CRC\n", |
487 | this->version, this->fn->ofs, | 467 | this->version, this->fn->ofs, |
488 | this->fn->ofs+this->fn->size); | 468 | this->fn->ofs+this->fn->size); |
489 | jffs2_kill_tn(c, this); | 469 | jffs2_kill_tn(c, this); |
@@ -496,7 +476,7 @@ static int jffs2_build_inode_fragtree(struct jffs2_sb_info *c, | |||
496 | high_ver = this->version; | 476 | high_ver = this->version; |
497 | rii->latest_ref = this->fn->raw; | 477 | rii->latest_ref = this->fn->raw; |
498 | } | 478 | } |
499 | dbg_readinode("Add %p (v %x, 0x%x-0x%x, ov %d) to fragtree\n", | 479 | dbg_readinode("Add %p (v %d, 0x%x-0x%x, ov %d) to fragtree\n", |
500 | this, this->version, this->fn->ofs, | 480 | this, this->version, this->fn->ofs, |
501 | this->fn->ofs+this->fn->size, this->overlapped); | 481 | this->fn->ofs+this->fn->size, this->overlapped); |
502 | 482 | ||
@@ -850,7 +830,7 @@ static inline int read_dnode(struct jffs2_sb_info *c, struct jffs2_raw_node_ref | |||
850 | return ret; | 830 | return ret; |
851 | } | 831 | } |
852 | #ifdef JFFS2_DBG_READINODE_MESSAGES | 832 | #ifdef JFFS2_DBG_READINODE_MESSAGES |
853 | dbg_readinode("After adding ver %d:\n", tn->version); | 833 | dbg_readinode("After adding ver %d:\n", je32_to_cpu(rd->version)); |
854 | tn = tn_first(&rii->tn_root); | 834 | tn = tn_first(&rii->tn_root); |
855 | while (tn) { | 835 | while (tn) { |
856 | dbg_readinode("%p: v %d r 0x%x-0x%x ov %d\n", | 836 | dbg_readinode("%p: v %d r 0x%x-0x%x ov %d\n", |
diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index c556e85a565c..91d1d0f1c66c 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c | |||
@@ -637,7 +637,10 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) | |||
637 | 637 | ||
638 | memset(c->wbuf,0xff,c->wbuf_pagesize); | 638 | memset(c->wbuf,0xff,c->wbuf_pagesize); |
639 | /* adjust write buffer offset, else we get a non contiguous write bug */ | 639 | /* adjust write buffer offset, else we get a non contiguous write bug */ |
640 | c->wbuf_ofs += c->wbuf_pagesize; | 640 | if (SECTOR_ADDR(c->wbuf_ofs) == SECTOR_ADDR(c->wbuf_ofs+c->wbuf_pagesize)) |
641 | c->wbuf_ofs += c->wbuf_pagesize; | ||
642 | else | ||
643 | c->wbuf_ofs = 0xffffffff; | ||
641 | c->wbuf_len = 0; | 644 | c->wbuf_len = 0; |
642 | return 0; | 645 | return 0; |
643 | } | 646 | } |
diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c index 82b0544bd76d..f3b1ebb22280 100644 --- a/fs/jfs/jfs_dmap.c +++ b/fs/jfs/jfs_dmap.c | |||
@@ -1507,7 +1507,7 @@ dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb, s64 * results) | |||
1507 | if (l2nb < budmin) { | 1507 | if (l2nb < budmin) { |
1508 | 1508 | ||
1509 | /* search the lower level dmap control pages to get | 1509 | /* search the lower level dmap control pages to get |
1510 | * the starting block number of the the dmap that | 1510 | * the starting block number of the dmap that |
1511 | * contains or starts off the free space. | 1511 | * contains or starts off the free space. |
1512 | */ | 1512 | */ |
1513 | if ((rc = | 1513 | if ((rc = |
diff --git a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c index c465607be991..c6530227cda6 100644 --- a/fs/jfs/jfs_imap.c +++ b/fs/jfs/jfs_imap.c | |||
@@ -386,7 +386,7 @@ int diRead(struct inode *ip) | |||
386 | return -EIO; | 386 | return -EIO; |
387 | } | 387 | } |
388 | 388 | ||
389 | /* locate the the disk inode requested */ | 389 | /* locate the disk inode requested */ |
390 | dp = (struct dinode *) mp->data; | 390 | dp = (struct dinode *) mp->data; |
391 | dp += rel_inode; | 391 | dp += rel_inode; |
392 | 392 | ||
@@ -1407,7 +1407,7 @@ int diAlloc(struct inode *pip, bool dir, struct inode *ip) | |||
1407 | inum = pip->i_ino + 1; | 1407 | inum = pip->i_ino + 1; |
1408 | ino = inum & (INOSPERIAG - 1); | 1408 | ino = inum & (INOSPERIAG - 1); |
1409 | 1409 | ||
1410 | /* back off the the hint if it is outside of the iag */ | 1410 | /* back off the hint if it is outside of the iag */ |
1411 | if (ino == 0) | 1411 | if (ino == 0) |
1412 | inum = pip->i_ino; | 1412 | inum = pip->i_ino; |
1413 | 1413 | ||
diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c index 6a3f00dc8c83..44a2f33cb98d 100644 --- a/fs/jfs/jfs_logmgr.c +++ b/fs/jfs/jfs_logmgr.c | |||
@@ -1960,7 +1960,7 @@ static void lbmfree(struct lbuf * bp) | |||
1960 | /* | 1960 | /* |
1961 | * NAME: lbmRedrive | 1961 | * NAME: lbmRedrive |
1962 | * | 1962 | * |
1963 | * FUNCTION: add a log buffer to the the log redrive list | 1963 | * FUNCTION: add a log buffer to the log redrive list |
1964 | * | 1964 | * |
1965 | * PARAMETER: | 1965 | * PARAMETER: |
1966 | * bp - log buffer | 1966 | * bp - log buffer |
diff --git a/fs/libfs.c b/fs/libfs.c index 1247ee90253a..5294de1f40c4 100644 --- a/fs/libfs.c +++ b/fs/libfs.c | |||
@@ -159,7 +159,10 @@ int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir) | |||
159 | continue; | 159 | continue; |
160 | 160 | ||
161 | spin_unlock(&dcache_lock); | 161 | spin_unlock(&dcache_lock); |
162 | if (filldir(dirent, next->d_name.name, next->d_name.len, filp->f_pos, next->d_inode->i_ino, dt_type(next->d_inode)) < 0) | 162 | if (filldir(dirent, next->d_name.name, |
163 | next->d_name.len, filp->f_pos, | ||
164 | next->d_inode->i_ino, | ||
165 | dt_type(next->d_inode)) < 0) | ||
163 | return 0; | 166 | return 0; |
164 | spin_lock(&dcache_lock); | 167 | spin_lock(&dcache_lock); |
165 | /* next is still alive */ | 168 | /* next is still alive */ |
diff --git a/fs/mpage.c b/fs/mpage.c index fa2441f57b41..0fb914fc2ee0 100644 --- a/fs/mpage.c +++ b/fs/mpage.c | |||
@@ -284,11 +284,9 @@ do_mpage_readpage(struct bio *bio, struct page *page, unsigned nr_pages, | |||
284 | } | 284 | } |
285 | 285 | ||
286 | if (first_hole != blocks_per_page) { | 286 | if (first_hole != blocks_per_page) { |
287 | char *kaddr = kmap_atomic(page, KM_USER0); | 287 | zero_user_page(page, first_hole << blkbits, |
288 | memset(kaddr + (first_hole << blkbits), 0, | 288 | PAGE_CACHE_SIZE - (first_hole << blkbits), |
289 | PAGE_CACHE_SIZE - (first_hole << blkbits)); | 289 | KM_USER0); |
290 | flush_dcache_page(page); | ||
291 | kunmap_atomic(kaddr, KM_USER0); | ||
292 | if (first_hole == 0) { | 290 | if (first_hole == 0) { |
293 | SetPageUptodate(page); | 291 | SetPageUptodate(page); |
294 | unlock_page(page); | 292 | unlock_page(page); |
@@ -576,14 +574,11 @@ page_is_mapped: | |||
576 | * written out to the file." | 574 | * written out to the file." |
577 | */ | 575 | */ |
578 | unsigned offset = i_size & (PAGE_CACHE_SIZE - 1); | 576 | unsigned offset = i_size & (PAGE_CACHE_SIZE - 1); |
579 | char *kaddr; | ||
580 | 577 | ||
581 | if (page->index > end_index || !offset) | 578 | if (page->index > end_index || !offset) |
582 | goto confused; | 579 | goto confused; |
583 | kaddr = kmap_atomic(page, KM_USER0); | 580 | zero_user_page(page, offset, PAGE_CACHE_SIZE - offset, |
584 | memset(kaddr + offset, 0, PAGE_CACHE_SIZE - offset); | 581 | KM_USER0); |
585 | flush_dcache_page(page); | ||
586 | kunmap_atomic(kaddr, KM_USER0); | ||
587 | } | 582 | } |
588 | 583 | ||
589 | /* | 584 | /* |
diff --git a/fs/namei.c b/fs/namei.c index 856b2f5da51d..b3780e3fc88e 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -1152,14 +1152,12 @@ static int fastcall do_path_lookup(int dfd, const char *name, | |||
1152 | 1152 | ||
1153 | fput_light(file, fput_needed); | 1153 | fput_light(file, fput_needed); |
1154 | } | 1154 | } |
1155 | current->total_link_count = 0; | 1155 | |
1156 | retval = link_path_walk(name, nd); | 1156 | retval = path_walk(name, nd); |
1157 | out: | 1157 | out: |
1158 | if (likely(retval == 0)) { | 1158 | if (unlikely(!retval && !audit_dummy_context() && nd->dentry && |
1159 | if (unlikely(!audit_dummy_context() && nd && nd->dentry && | ||
1160 | nd->dentry->d_inode)) | 1159 | nd->dentry->d_inode)) |
1161 | audit_inode(name, nd->dentry->d_inode); | 1160 | audit_inode(name, nd->dentry->d_inode); |
1162 | } | ||
1163 | out_fail: | 1161 | out_fail: |
1164 | return retval; | 1162 | return retval; |
1165 | 1163 | ||
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 625d8e5fb39d..3df428816559 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
@@ -38,7 +38,6 @@ | |||
38 | #include "delegation.h" | 38 | #include "delegation.h" |
39 | #include "iostat.h" | 39 | #include "iostat.h" |
40 | 40 | ||
41 | #define NFS_PARANOIA 1 | ||
42 | /* #define NFS_DEBUG_VERBOSE 1 */ | 41 | /* #define NFS_DEBUG_VERBOSE 1 */ |
43 | 42 | ||
44 | static int nfs_opendir(struct inode *, struct file *); | 43 | static int nfs_opendir(struct inode *, struct file *); |
@@ -650,12 +649,15 @@ int nfs_fsync_dir(struct file *filp, struct dentry *dentry, int datasync) | |||
650 | */ | 649 | */ |
651 | static int nfs_check_verifier(struct inode *dir, struct dentry *dentry) | 650 | static int nfs_check_verifier(struct inode *dir, struct dentry *dentry) |
652 | { | 651 | { |
652 | unsigned long verf; | ||
653 | |||
653 | if (IS_ROOT(dentry)) | 654 | if (IS_ROOT(dentry)) |
654 | return 1; | 655 | return 1; |
655 | if ((NFS_I(dir)->cache_validity & NFS_INO_INVALID_ATTR) != 0 | 656 | verf = (unsigned long)dentry->d_fsdata; |
656 | || nfs_attribute_timeout(dir)) | 657 | if (nfs_caches_unstable(dir) |
658 | || verf != NFS_I(dir)->cache_change_attribute) | ||
657 | return 0; | 659 | return 0; |
658 | return nfs_verify_change_attribute(dir, (unsigned long)dentry->d_fsdata); | 660 | return 1; |
659 | } | 661 | } |
660 | 662 | ||
661 | static inline void nfs_set_verifier(struct dentry * dentry, unsigned long verf) | 663 | static inline void nfs_set_verifier(struct dentry * dentry, unsigned long verf) |
@@ -665,8 +667,7 @@ static inline void nfs_set_verifier(struct dentry * dentry, unsigned long verf) | |||
665 | 667 | ||
666 | static void nfs_refresh_verifier(struct dentry * dentry, unsigned long verf) | 668 | static void nfs_refresh_verifier(struct dentry * dentry, unsigned long verf) |
667 | { | 669 | { |
668 | if (time_after(verf, (unsigned long)dentry->d_fsdata)) | 670 | nfs_set_verifier(dentry, verf); |
669 | nfs_set_verifier(dentry, verf); | ||
670 | } | 671 | } |
671 | 672 | ||
672 | /* | 673 | /* |
@@ -765,6 +766,10 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd) | |||
765 | nfs_inc_stats(dir, NFSIOS_DENTRYREVALIDATE); | 766 | nfs_inc_stats(dir, NFSIOS_DENTRYREVALIDATE); |
766 | inode = dentry->d_inode; | 767 | inode = dentry->d_inode; |
767 | 768 | ||
769 | /* Revalidate parent directory attribute cache */ | ||
770 | if (nfs_revalidate_inode(NFS_SERVER(dir), dir) < 0) | ||
771 | goto out_zap_parent; | ||
772 | |||
768 | if (!inode) { | 773 | if (!inode) { |
769 | if (nfs_neg_need_reval(dir, dentry, nd)) | 774 | if (nfs_neg_need_reval(dir, dentry, nd)) |
770 | goto out_bad; | 775 | goto out_bad; |
@@ -778,10 +783,6 @@ static int nfs_lookup_revalidate(struct dentry * dentry, struct nameidata *nd) | |||
778 | goto out_bad; | 783 | goto out_bad; |
779 | } | 784 | } |
780 | 785 | ||
781 | /* Revalidate parent directory attribute cache */ | ||
782 | if (nfs_revalidate_inode(NFS_SERVER(dir), dir) < 0) | ||
783 | goto out_zap_parent; | ||
784 | |||
785 | /* Force a full look up iff the parent directory has changed */ | 786 | /* Force a full look up iff the parent directory has changed */ |
786 | if (nfs_check_verifier(dir, dentry)) { | 787 | if (nfs_check_verifier(dir, dentry)) { |
787 | if (nfs_lookup_verify_inode(inode, nd)) | 788 | if (nfs_lookup_verify_inode(inode, nd)) |
@@ -1360,11 +1361,6 @@ static int nfs_sillyrename(struct inode *dir, struct dentry *dentry) | |||
1360 | atomic_read(&dentry->d_count)); | 1361 | atomic_read(&dentry->d_count)); |
1361 | nfs_inc_stats(dir, NFSIOS_SILLYRENAME); | 1362 | nfs_inc_stats(dir, NFSIOS_SILLYRENAME); |
1362 | 1363 | ||
1363 | #ifdef NFS_PARANOIA | ||
1364 | if (!dentry->d_inode) | ||
1365 | printk("NFS: silly-renaming %s/%s, negative dentry??\n", | ||
1366 | dentry->d_parent->d_name.name, dentry->d_name.name); | ||
1367 | #endif | ||
1368 | /* | 1364 | /* |
1369 | * We don't allow a dentry to be silly-renamed twice. | 1365 | * We don't allow a dentry to be silly-renamed twice. |
1370 | */ | 1366 | */ |
@@ -1681,16 +1677,9 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
1681 | new_inode = NULL; | 1677 | new_inode = NULL; |
1682 | /* instantiate the replacement target */ | 1678 | /* instantiate the replacement target */ |
1683 | d_instantiate(new_dentry, NULL); | 1679 | d_instantiate(new_dentry, NULL); |
1684 | } else if (atomic_read(&new_dentry->d_count) > 1) { | 1680 | } else if (atomic_read(&new_dentry->d_count) > 1) |
1685 | /* dentry still busy? */ | 1681 | /* dentry still busy? */ |
1686 | #ifdef NFS_PARANOIA | ||
1687 | printk("nfs_rename: target %s/%s busy, d_count=%d\n", | ||
1688 | new_dentry->d_parent->d_name.name, | ||
1689 | new_dentry->d_name.name, | ||
1690 | atomic_read(&new_dentry->d_count)); | ||
1691 | #endif | ||
1692 | goto out; | 1682 | goto out; |
1693 | } | ||
1694 | } else | 1683 | } else |
1695 | drop_nlink(new_inode); | 1684 | drop_nlink(new_inode); |
1696 | 1685 | ||
diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c index 234778576f09..d1cbf0a0fbb2 100644 --- a/fs/nfs/getroot.c +++ b/fs/nfs/getroot.c | |||
@@ -41,7 +41,6 @@ | |||
41 | #include "internal.h" | 41 | #include "internal.h" |
42 | 42 | ||
43 | #define NFSDBG_FACILITY NFSDBG_CLIENT | 43 | #define NFSDBG_FACILITY NFSDBG_CLIENT |
44 | #define NFS_PARANOIA 1 | ||
45 | 44 | ||
46 | /* | 45 | /* |
47 | * get an NFS2/NFS3 root dentry from the root filehandle | 46 | * get an NFS2/NFS3 root dentry from the root filehandle |
diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c index 9d4a6b2d1996..d11eb055265c 100644 --- a/fs/nfs/idmap.c +++ b/fs/nfs/idmap.c | |||
@@ -272,7 +272,7 @@ nfs_idmap_id(struct idmap *idmap, struct idmap_hashtable *h, | |||
272 | set_current_state(TASK_UNINTERRUPTIBLE); | 272 | set_current_state(TASK_UNINTERRUPTIBLE); |
273 | mutex_unlock(&idmap->idmap_im_lock); | 273 | mutex_unlock(&idmap->idmap_im_lock); |
274 | schedule(); | 274 | schedule(); |
275 | current->state = TASK_RUNNING; | 275 | __set_current_state(TASK_RUNNING); |
276 | remove_wait_queue(&idmap->idmap_wq, &wq); | 276 | remove_wait_queue(&idmap->idmap_wq, &wq); |
277 | mutex_lock(&idmap->idmap_im_lock); | 277 | mutex_lock(&idmap->idmap_im_lock); |
278 | 278 | ||
@@ -333,7 +333,7 @@ nfs_idmap_name(struct idmap *idmap, struct idmap_hashtable *h, | |||
333 | set_current_state(TASK_UNINTERRUPTIBLE); | 333 | set_current_state(TASK_UNINTERRUPTIBLE); |
334 | mutex_unlock(&idmap->idmap_im_lock); | 334 | mutex_unlock(&idmap->idmap_im_lock); |
335 | schedule(); | 335 | schedule(); |
336 | current->state = TASK_RUNNING; | 336 | __set_current_state(TASK_RUNNING); |
337 | remove_wait_queue(&idmap->idmap_wq, &wq); | 337 | remove_wait_queue(&idmap->idmap_wq, &wq); |
338 | mutex_lock(&idmap->idmap_im_lock); | 338 | mutex_lock(&idmap->idmap_im_lock); |
339 | 339 | ||
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 1e9a915d1fea..2a3fd9573207 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -48,7 +48,6 @@ | |||
48 | #include "internal.h" | 48 | #include "internal.h" |
49 | 49 | ||
50 | #define NFSDBG_FACILITY NFSDBG_VFS | 50 | #define NFSDBG_FACILITY NFSDBG_VFS |
51 | #define NFS_PARANOIA 1 | ||
52 | 51 | ||
53 | static void nfs_invalidate_inode(struct inode *); | 52 | static void nfs_invalidate_inode(struct inode *); |
54 | static int nfs_update_inode(struct inode *, struct nfs_fattr *); | 53 | static int nfs_update_inode(struct inode *, struct nfs_fattr *); |
@@ -1075,10 +1074,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
1075 | /* | 1074 | /* |
1076 | * Big trouble! The inode has become a different object. | 1075 | * Big trouble! The inode has become a different object. |
1077 | */ | 1076 | */ |
1078 | #ifdef NFS_PARANOIA | ||
1079 | printk(KERN_DEBUG "%s: inode %ld mode changed, %07o to %07o\n", | 1077 | printk(KERN_DEBUG "%s: inode %ld mode changed, %07o to %07o\n", |
1080 | __FUNCTION__, inode->i_ino, inode->i_mode, fattr->mode); | 1078 | __FUNCTION__, inode->i_ino, inode->i_mode, fattr->mode); |
1081 | #endif | ||
1082 | out_err: | 1079 | out_err: |
1083 | /* | 1080 | /* |
1084 | * No need to worry about unhashing the dentry, as the | 1081 | * No need to worry about unhashing the dentry, as the |
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c index abd9f8b48943..cd3ca7b5d3db 100644 --- a/fs/nfs/nfs2xdr.c +++ b/fs/nfs/nfs2xdr.c | |||
@@ -26,7 +26,6 @@ | |||
26 | #include "internal.h" | 26 | #include "internal.h" |
27 | 27 | ||
28 | #define NFSDBG_FACILITY NFSDBG_XDR | 28 | #define NFSDBG_FACILITY NFSDBG_XDR |
29 | /* #define NFS_PARANOIA 1 */ | ||
30 | 29 | ||
31 | /* Mapping from NFS error code to "errno" error code. */ | 30 | /* Mapping from NFS error code to "errno" error code. */ |
32 | #define errno_NFSERR_IO EIO | 31 | #define errno_NFSERR_IO EIO |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index b8c28f2380a5..938f37166788 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
@@ -224,7 +224,8 @@ static int nfs4_stat_to_errno(int); | |||
224 | encode_getattr_maxsz) | 224 | encode_getattr_maxsz) |
225 | #define NFS4_dec_setattr_sz (compound_decode_hdr_maxsz + \ | 225 | #define NFS4_dec_setattr_sz (compound_decode_hdr_maxsz + \ |
226 | decode_putfh_maxsz + \ | 226 | decode_putfh_maxsz + \ |
227 | op_decode_hdr_maxsz + 3) | 227 | op_decode_hdr_maxsz + 3 + \ |
228 | nfs4_fattr_maxsz) | ||
228 | #define NFS4_enc_fsinfo_sz (compound_encode_hdr_maxsz + \ | 229 | #define NFS4_enc_fsinfo_sz (compound_encode_hdr_maxsz + \ |
229 | encode_putfh_maxsz + \ | 230 | encode_putfh_maxsz + \ |
230 | encode_fsinfo_maxsz) | 231 | encode_fsinfo_maxsz) |
@@ -2079,9 +2080,11 @@ out: | |||
2079 | 2080 | ||
2080 | #define READ_BUF(nbytes) do { \ | 2081 | #define READ_BUF(nbytes) do { \ |
2081 | p = xdr_inline_decode(xdr, nbytes); \ | 2082 | p = xdr_inline_decode(xdr, nbytes); \ |
2082 | if (!p) { \ | 2083 | if (unlikely(!p)) { \ |
2083 | printk(KERN_WARNING "%s: reply buffer overflowed in line %d.", \ | 2084 | printk(KERN_INFO "%s: prematurely hit end of receive" \ |
2084 | __FUNCTION__, __LINE__); \ | 2085 | " buffer\n", __FUNCTION__); \ |
2086 | printk(KERN_INFO "%s: xdr->p=%p, bytes=%u, xdr->end=%p\n", \ | ||
2087 | __FUNCTION__, xdr->p, nbytes, xdr->end); \ | ||
2085 | return -EIO; \ | 2088 | return -EIO; \ |
2086 | } \ | 2089 | } \ |
2087 | } while (0) | 2090 | } while (0) |
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 388950118f59..e12054c86d0d 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c | |||
@@ -20,8 +20,6 @@ | |||
20 | 20 | ||
21 | #include "internal.h" | 21 | #include "internal.h" |
22 | 22 | ||
23 | #define NFS_PARANOIA 1 | ||
24 | |||
25 | static struct kmem_cache *nfs_page_cachep; | 23 | static struct kmem_cache *nfs_page_cachep; |
26 | 24 | ||
27 | static inline struct nfs_page * | 25 | static inline struct nfs_page * |
@@ -167,11 +165,6 @@ nfs_release_request(struct nfs_page *req) | |||
167 | if (!atomic_dec_and_test(&req->wb_count)) | 165 | if (!atomic_dec_and_test(&req->wb_count)) |
168 | return; | 166 | return; |
169 | 167 | ||
170 | #ifdef NFS_PARANOIA | ||
171 | BUG_ON (!list_empty(&req->wb_list)); | ||
172 | BUG_ON (NFS_WBACK_BUSY(req)); | ||
173 | #endif | ||
174 | |||
175 | /* Release struct file or cached credential */ | 168 | /* Release struct file or cached credential */ |
176 | nfs_clear_request(req); | 169 | nfs_clear_request(req); |
177 | put_nfs_open_context(req->wb_context); | 170 | put_nfs_open_context(req->wb_context); |
diff --git a/fs/nfsd/Makefile b/fs/nfsd/Makefile index ce341dc76d5e..9b118ee20193 100644 --- a/fs/nfsd/Makefile +++ b/fs/nfsd/Makefile | |||
@@ -11,4 +11,3 @@ nfsd-$(CONFIG_NFSD_V3) += nfs3proc.o nfs3xdr.o | |||
11 | nfsd-$(CONFIG_NFSD_V3_ACL) += nfs3acl.o | 11 | nfsd-$(CONFIG_NFSD_V3_ACL) += nfs3acl.o |
12 | nfsd-$(CONFIG_NFSD_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4idmap.o \ | 12 | nfsd-$(CONFIG_NFSD_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4idmap.o \ |
13 | nfs4acl.o nfs4callback.o nfs4recover.o | 13 | nfs4acl.o nfs4callback.o nfs4recover.o |
14 | nfsd-objs := $(nfsd-y) | ||
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 6f24768272a1..79bd03b8bbf8 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c | |||
@@ -469,6 +469,13 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) | |||
469 | nd.dentry = NULL; | 469 | nd.dentry = NULL; |
470 | exp.ex_path = NULL; | 470 | exp.ex_path = NULL; |
471 | 471 | ||
472 | /* fs locations */ | ||
473 | exp.ex_fslocs.locations = NULL; | ||
474 | exp.ex_fslocs.locations_count = 0; | ||
475 | exp.ex_fslocs.migrated = 0; | ||
476 | |||
477 | exp.ex_uuid = NULL; | ||
478 | |||
472 | if (mesg[mlen-1] != '\n') | 479 | if (mesg[mlen-1] != '\n') |
473 | return -EINVAL; | 480 | return -EINVAL; |
474 | mesg[mlen-1] = 0; | 481 | mesg[mlen-1] = 0; |
@@ -509,13 +516,6 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) | |||
509 | if (exp.h.expiry_time == 0) | 516 | if (exp.h.expiry_time == 0) |
510 | goto out; | 517 | goto out; |
511 | 518 | ||
512 | /* fs locations */ | ||
513 | exp.ex_fslocs.locations = NULL; | ||
514 | exp.ex_fslocs.locations_count = 0; | ||
515 | exp.ex_fslocs.migrated = 0; | ||
516 | |||
517 | exp.ex_uuid = NULL; | ||
518 | |||
519 | /* flags */ | 519 | /* flags */ |
520 | err = get_int(&mesg, &an_int); | 520 | err = get_int(&mesg, &an_int); |
521 | if (err == -ENOENT) | 521 | if (err == -ENOENT) |
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c index 7f5bad0393b1..eac82830bfd7 100644 --- a/fs/nfsd/nfs3proc.c +++ b/fs/nfsd/nfs3proc.c | |||
@@ -177,7 +177,7 @@ nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp, | |||
177 | if (max_blocksize < resp->count) | 177 | if (max_blocksize < resp->count) |
178 | resp->count = max_blocksize; | 178 | resp->count = max_blocksize; |
179 | 179 | ||
180 | svc_reserve(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3)<<2) + resp->count +4); | 180 | svc_reserve_auth(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3)<<2) + resp->count +4); |
181 | 181 | ||
182 | fh_copy(&resp->fh, &argp->fh); | 182 | fh_copy(&resp->fh, &argp->fh); |
183 | nfserr = nfsd_read(rqstp, &resp->fh, NULL, | 183 | nfserr = nfsd_read(rqstp, &resp->fh, NULL, |
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index 7e4bb0af24d7..10f6e7dcf633 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c | |||
@@ -239,7 +239,7 @@ static __be32 * | |||
239 | encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp) | 239 | encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp) |
240 | { | 240 | { |
241 | struct dentry *dentry = fhp->fh_dentry; | 241 | struct dentry *dentry = fhp->fh_dentry; |
242 | if (dentry && dentry->d_inode != NULL) { | 242 | if (dentry && dentry->d_inode) { |
243 | int err; | 243 | int err; |
244 | struct kstat stat; | 244 | struct kstat stat; |
245 | 245 | ||
@@ -300,9 +300,9 @@ int | |||
300 | nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p, | 300 | nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p, |
301 | struct nfsd3_sattrargs *args) | 301 | struct nfsd3_sattrargs *args) |
302 | { | 302 | { |
303 | if (!(p = decode_fh(p, &args->fh)) | 303 | if (!(p = decode_fh(p, &args->fh))) |
304 | || !(p = decode_sattr3(p, &args->attrs))) | ||
305 | return 0; | 304 | return 0; |
305 | p = decode_sattr3(p, &args->attrs); | ||
306 | 306 | ||
307 | if ((args->check_guard = ntohl(*p++)) != 0) { | 307 | if ((args->check_guard = ntohl(*p++)) != 0) { |
308 | struct timespec time; | 308 | struct timespec time; |
@@ -343,9 +343,9 @@ nfs3svc_decode_readargs(struct svc_rqst *rqstp, __be32 *p, | |||
343 | int v,pn; | 343 | int v,pn; |
344 | u32 max_blocksize = svc_max_payload(rqstp); | 344 | u32 max_blocksize = svc_max_payload(rqstp); |
345 | 345 | ||
346 | if (!(p = decode_fh(p, &args->fh)) | 346 | if (!(p = decode_fh(p, &args->fh))) |
347 | || !(p = xdr_decode_hyper(p, &args->offset))) | ||
348 | return 0; | 347 | return 0; |
348 | p = xdr_decode_hyper(p, &args->offset); | ||
349 | 349 | ||
350 | len = args->count = ntohl(*p++); | 350 | len = args->count = ntohl(*p++); |
351 | 351 | ||
@@ -369,28 +369,44 @@ int | |||
369 | nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p, | 369 | nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p, |
370 | struct nfsd3_writeargs *args) | 370 | struct nfsd3_writeargs *args) |
371 | { | 371 | { |
372 | unsigned int len, v, hdr; | 372 | unsigned int len, v, hdr, dlen; |
373 | u32 max_blocksize = svc_max_payload(rqstp); | 373 | u32 max_blocksize = svc_max_payload(rqstp); |
374 | 374 | ||
375 | if (!(p = decode_fh(p, &args->fh)) | 375 | if (!(p = decode_fh(p, &args->fh))) |
376 | || !(p = xdr_decode_hyper(p, &args->offset))) | ||
377 | return 0; | 376 | return 0; |
377 | p = xdr_decode_hyper(p, &args->offset); | ||
378 | 378 | ||
379 | args->count = ntohl(*p++); | 379 | args->count = ntohl(*p++); |
380 | args->stable = ntohl(*p++); | 380 | args->stable = ntohl(*p++); |
381 | len = args->len = ntohl(*p++); | 381 | len = args->len = ntohl(*p++); |
382 | /* | ||
383 | * The count must equal the amount of data passed. | ||
384 | */ | ||
385 | if (args->count != args->len) | ||
386 | return 0; | ||
382 | 387 | ||
388 | /* | ||
389 | * Check to make sure that we got the right number of | ||
390 | * bytes. | ||
391 | */ | ||
383 | hdr = (void*)p - rqstp->rq_arg.head[0].iov_base; | 392 | hdr = (void*)p - rqstp->rq_arg.head[0].iov_base; |
384 | if (rqstp->rq_arg.len < hdr || | 393 | dlen = rqstp->rq_arg.head[0].iov_len + rqstp->rq_arg.page_len |
385 | rqstp->rq_arg.len - hdr < len) | 394 | - hdr; |
395 | /* | ||
396 | * Round the length of the data which was specified up to | ||
397 | * the next multiple of XDR units and then compare that | ||
398 | * against the length which was actually received. | ||
399 | */ | ||
400 | if (dlen != XDR_QUADLEN(len)*4) | ||
386 | return 0; | 401 | return 0; |
387 | 402 | ||
403 | if (args->count > max_blocksize) { | ||
404 | args->count = max_blocksize; | ||
405 | len = args->len = max_blocksize; | ||
406 | } | ||
388 | rqstp->rq_vec[0].iov_base = (void*)p; | 407 | rqstp->rq_vec[0].iov_base = (void*)p; |
389 | rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - hdr; | 408 | rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - hdr; |
390 | 409 | v = 0; | |
391 | if (len > max_blocksize) | ||
392 | len = max_blocksize; | ||
393 | v= 0; | ||
394 | while (len > rqstp->rq_vec[v].iov_len) { | 410 | while (len > rqstp->rq_vec[v].iov_len) { |
395 | len -= rqstp->rq_vec[v].iov_len; | 411 | len -= rqstp->rq_vec[v].iov_len; |
396 | v++; | 412 | v++; |
@@ -398,9 +414,8 @@ nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p, | |||
398 | rqstp->rq_vec[v].iov_len = PAGE_SIZE; | 414 | rqstp->rq_vec[v].iov_len = PAGE_SIZE; |
399 | } | 415 | } |
400 | rqstp->rq_vec[v].iov_len = len; | 416 | rqstp->rq_vec[v].iov_len = len; |
401 | args->vlen = v+1; | 417 | args->vlen = v + 1; |
402 | 418 | return 1; | |
403 | return args->count == args->len && rqstp->rq_vec[0].iov_len > 0; | ||
404 | } | 419 | } |
405 | 420 | ||
406 | int | 421 | int |
@@ -414,8 +429,7 @@ nfs3svc_decode_createargs(struct svc_rqst *rqstp, __be32 *p, | |||
414 | switch (args->createmode = ntohl(*p++)) { | 429 | switch (args->createmode = ntohl(*p++)) { |
415 | case NFS3_CREATE_UNCHECKED: | 430 | case NFS3_CREATE_UNCHECKED: |
416 | case NFS3_CREATE_GUARDED: | 431 | case NFS3_CREATE_GUARDED: |
417 | if (!(p = decode_sattr3(p, &args->attrs))) | 432 | p = decode_sattr3(p, &args->attrs); |
418 | return 0; | ||
419 | break; | 433 | break; |
420 | case NFS3_CREATE_EXCLUSIVE: | 434 | case NFS3_CREATE_EXCLUSIVE: |
421 | args->verf = p; | 435 | args->verf = p; |
@@ -431,10 +445,10 @@ int | |||
431 | nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, __be32 *p, | 445 | nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, __be32 *p, |
432 | struct nfsd3_createargs *args) | 446 | struct nfsd3_createargs *args) |
433 | { | 447 | { |
434 | if (!(p = decode_fh(p, &args->fh)) | 448 | if (!(p = decode_fh(p, &args->fh)) || |
435 | || !(p = decode_filename(p, &args->name, &args->len)) | 449 | !(p = decode_filename(p, &args->name, &args->len))) |
436 | || !(p = decode_sattr3(p, &args->attrs))) | ||
437 | return 0; | 450 | return 0; |
451 | p = decode_sattr3(p, &args->attrs); | ||
438 | 452 | ||
439 | return xdr_argsize_check(rqstp, p); | 453 | return xdr_argsize_check(rqstp, p); |
440 | } | 454 | } |
@@ -448,11 +462,12 @@ nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p, | |||
448 | char *old, *new; | 462 | char *old, *new; |
449 | struct kvec *vec; | 463 | struct kvec *vec; |
450 | 464 | ||
451 | if (!(p = decode_fh(p, &args->ffh)) | 465 | if (!(p = decode_fh(p, &args->ffh)) || |
452 | || !(p = decode_filename(p, &args->fname, &args->flen)) | 466 | !(p = decode_filename(p, &args->fname, &args->flen)) |
453 | || !(p = decode_sattr3(p, &args->attrs)) | ||
454 | ) | 467 | ) |
455 | return 0; | 468 | return 0; |
469 | p = decode_sattr3(p, &args->attrs); | ||
470 | |||
456 | /* now decode the pathname, which might be larger than the first page. | 471 | /* now decode the pathname, which might be larger than the first page. |
457 | * As we have to check for nul's anyway, we copy it into a new page | 472 | * As we have to check for nul's anyway, we copy it into a new page |
458 | * This page appears in the rq_res.pages list, but as pages_len is always | 473 | * This page appears in the rq_res.pages list, but as pages_len is always |
@@ -502,10 +517,8 @@ nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, __be32 *p, | |||
502 | args->ftype = ntohl(*p++); | 517 | args->ftype = ntohl(*p++); |
503 | 518 | ||
504 | if (args->ftype == NF3BLK || args->ftype == NF3CHR | 519 | if (args->ftype == NF3BLK || args->ftype == NF3CHR |
505 | || args->ftype == NF3SOCK || args->ftype == NF3FIFO) { | 520 | || args->ftype == NF3SOCK || args->ftype == NF3FIFO) |
506 | if (!(p = decode_sattr3(p, &args->attrs))) | 521 | p = decode_sattr3(p, &args->attrs); |
507 | return 0; | ||
508 | } | ||
509 | 522 | ||
510 | if (args->ftype == NF3BLK || args->ftype == NF3CHR) { | 523 | if (args->ftype == NF3BLK || args->ftype == NF3CHR) { |
511 | args->major = ntohl(*p++); | 524 | args->major = ntohl(*p++); |
diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c index 673a53c014a3..cc3b7badd486 100644 --- a/fs/nfsd/nfs4acl.c +++ b/fs/nfsd/nfs4acl.c | |||
@@ -137,7 +137,6 @@ struct ace_container { | |||
137 | static short ace2type(struct nfs4_ace *); | 137 | static short ace2type(struct nfs4_ace *); |
138 | static void _posix_to_nfsv4_one(struct posix_acl *, struct nfs4_acl *, | 138 | static void _posix_to_nfsv4_one(struct posix_acl *, struct nfs4_acl *, |
139 | unsigned int); | 139 | unsigned int); |
140 | void nfs4_acl_add_ace(struct nfs4_acl *, u32, u32, u32, int, uid_t); | ||
141 | 140 | ||
142 | struct nfs4_acl * | 141 | struct nfs4_acl * |
143 | nfs4_acl_posix_to_nfsv4(struct posix_acl *pacl, struct posix_acl *dpacl, | 142 | nfs4_acl_posix_to_nfsv4(struct posix_acl *pacl, struct posix_acl *dpacl, |
@@ -785,21 +784,6 @@ nfs4_acl_new(int n) | |||
785 | return acl; | 784 | return acl; |
786 | } | 785 | } |
787 | 786 | ||
788 | void | ||
789 | nfs4_acl_add_ace(struct nfs4_acl *acl, u32 type, u32 flag, u32 access_mask, | ||
790 | int whotype, uid_t who) | ||
791 | { | ||
792 | struct nfs4_ace *ace = acl->aces + acl->naces; | ||
793 | |||
794 | ace->type = type; | ||
795 | ace->flag = flag; | ||
796 | ace->access_mask = access_mask; | ||
797 | ace->whotype = whotype; | ||
798 | ace->who = who; | ||
799 | |||
800 | acl->naces++; | ||
801 | } | ||
802 | |||
803 | static struct { | 787 | static struct { |
804 | char *string; | 788 | char *string; |
805 | int stringlen; | 789 | int stringlen; |
@@ -851,6 +835,5 @@ nfs4_acl_write_who(int who, char *p) | |||
851 | } | 835 | } |
852 | 836 | ||
853 | EXPORT_SYMBOL(nfs4_acl_new); | 837 | EXPORT_SYMBOL(nfs4_acl_new); |
854 | EXPORT_SYMBOL(nfs4_acl_add_ace); | ||
855 | EXPORT_SYMBOL(nfs4_acl_get_whotype); | 838 | EXPORT_SYMBOL(nfs4_acl_get_whotype); |
856 | EXPORT_SYMBOL(nfs4_acl_write_who); | 839 | EXPORT_SYMBOL(nfs4_acl_write_who); |
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 678f3be88ac0..3cc8ce422ab1 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -1326,8 +1326,6 @@ do_recall(void *__dp) | |||
1326 | { | 1326 | { |
1327 | struct nfs4_delegation *dp = __dp; | 1327 | struct nfs4_delegation *dp = __dp; |
1328 | 1328 | ||
1329 | daemonize("nfsv4-recall"); | ||
1330 | |||
1331 | nfsd4_cb_recall(dp); | 1329 | nfsd4_cb_recall(dp); |
1332 | return 0; | 1330 | return 0; |
1333 | } | 1331 | } |
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index 739dd3c5c3b2..6ca2d24fc216 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c | |||
@@ -323,7 +323,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, | |||
323 | * | 323 | * |
324 | */ | 324 | */ |
325 | 325 | ||
326 | u8 version = 1; | 326 | u8 version; |
327 | u8 fsid_type = 0; | 327 | u8 fsid_type = 0; |
328 | struct inode * inode = dentry->d_inode; | 328 | struct inode * inode = dentry->d_inode; |
329 | struct dentry *parent = dentry->d_parent; | 329 | struct dentry *parent = dentry->d_parent; |
@@ -341,15 +341,59 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, | |||
341 | * the reference filehandle (if it is in the same export) | 341 | * the reference filehandle (if it is in the same export) |
342 | * or the export options. | 342 | * or the export options. |
343 | */ | 343 | */ |
344 | retry: | ||
345 | version = 1; | ||
344 | if (ref_fh && ref_fh->fh_export == exp) { | 346 | if (ref_fh && ref_fh->fh_export == exp) { |
345 | version = ref_fh->fh_handle.fh_version; | 347 | version = ref_fh->fh_handle.fh_version; |
346 | if (version == 0xca) | 348 | fsid_type = ref_fh->fh_handle.fh_fsid_type; |
349 | |||
350 | if (ref_fh == fhp) | ||
351 | fh_put(ref_fh); | ||
352 | ref_fh = NULL; | ||
353 | |||
354 | switch (version) { | ||
355 | case 0xca: | ||
347 | fsid_type = FSID_DEV; | 356 | fsid_type = FSID_DEV; |
348 | else | 357 | break; |
349 | fsid_type = ref_fh->fh_handle.fh_fsid_type; | 358 | case 1: |
350 | /* We know this version/type works for this export | 359 | break; |
351 | * so there is no need for further checks. | 360 | default: |
361 | goto retry; | ||
362 | } | ||
363 | |||
364 | /* Need to check that this type works for this | ||
365 | * export point. As the fsid -> filesystem mapping | ||
366 | * was guided by user-space, there is no guarantee | ||
367 | * that the filesystem actually supports that fsid | ||
368 | * type. If it doesn't we loop around again without | ||
369 | * ref_fh set. | ||
352 | */ | 370 | */ |
371 | switch(fsid_type) { | ||
372 | case FSID_DEV: | ||
373 | if (!old_valid_dev(ex_dev)) | ||
374 | goto retry; | ||
375 | /* FALL THROUGH */ | ||
376 | case FSID_MAJOR_MINOR: | ||
377 | case FSID_ENCODE_DEV: | ||
378 | if (!(exp->ex_dentry->d_inode->i_sb->s_type->fs_flags | ||
379 | & FS_REQUIRES_DEV)) | ||
380 | goto retry; | ||
381 | break; | ||
382 | case FSID_NUM: | ||
383 | if (! (exp->ex_flags & NFSEXP_FSID)) | ||
384 | goto retry; | ||
385 | break; | ||
386 | case FSID_UUID8: | ||
387 | case FSID_UUID16: | ||
388 | if (!root_export) | ||
389 | goto retry; | ||
390 | /* fall through */ | ||
391 | case FSID_UUID4_INUM: | ||
392 | case FSID_UUID16_INUM: | ||
393 | if (exp->ex_uuid == NULL) | ||
394 | goto retry; | ||
395 | break; | ||
396 | } | ||
353 | } else if (exp->ex_uuid) { | 397 | } else if (exp->ex_uuid) { |
354 | if (fhp->fh_maxsize >= 64) { | 398 | if (fhp->fh_maxsize >= 64) { |
355 | if (root_export) | 399 | if (root_export) |
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index 5cc2eec981b8..b2c7147aa921 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c | |||
@@ -155,7 +155,7 @@ nfsd_proc_read(struct svc_rqst *rqstp, struct nfsd_readargs *argp, | |||
155 | argp->count); | 155 | argp->count); |
156 | argp->count = NFSSVC_MAXBLKSIZE_V2; | 156 | argp->count = NFSSVC_MAXBLKSIZE_V2; |
157 | } | 157 | } |
158 | svc_reserve(rqstp, (19<<2) + argp->count + 4); | 158 | svc_reserve_auth(rqstp, (19<<2) + argp->count + 4); |
159 | 159 | ||
160 | resp->count = argp->count; | 160 | resp->count = argp->count; |
161 | nfserr = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh), NULL, | 161 | nfserr = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh), NULL, |
diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c index 0c24b9e24fe8..cb3e7fadb772 100644 --- a/fs/nfsd/nfsxdr.c +++ b/fs/nfsd/nfsxdr.c | |||
@@ -231,9 +231,10 @@ int | |||
231 | nfssvc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p, | 231 | nfssvc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p, |
232 | struct nfsd_sattrargs *args) | 232 | struct nfsd_sattrargs *args) |
233 | { | 233 | { |
234 | if (!(p = decode_fh(p, &args->fh)) | 234 | p = decode_fh(p, &args->fh); |
235 | || !(p = decode_sattr(p, &args->attrs))) | 235 | if (!p) |
236 | return 0; | 236 | return 0; |
237 | p = decode_sattr(p, &args->attrs); | ||
237 | 238 | ||
238 | return xdr_argsize_check(rqstp, p); | 239 | return xdr_argsize_check(rqstp, p); |
239 | } | 240 | } |
@@ -284,8 +285,9 @@ int | |||
284 | nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p, | 285 | nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p, |
285 | struct nfsd_writeargs *args) | 286 | struct nfsd_writeargs *args) |
286 | { | 287 | { |
287 | unsigned int len; | 288 | unsigned int len, hdr, dlen; |
288 | int v; | 289 | int v; |
290 | |||
289 | if (!(p = decode_fh(p, &args->fh))) | 291 | if (!(p = decode_fh(p, &args->fh))) |
290 | return 0; | 292 | return 0; |
291 | 293 | ||
@@ -293,11 +295,30 @@ nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p, | |||
293 | args->offset = ntohl(*p++); /* offset */ | 295 | args->offset = ntohl(*p++); /* offset */ |
294 | p++; /* totalcount */ | 296 | p++; /* totalcount */ |
295 | len = args->len = ntohl(*p++); | 297 | len = args->len = ntohl(*p++); |
296 | rqstp->rq_vec[0].iov_base = (void*)p; | 298 | /* |
297 | rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - | 299 | * The protocol specifies a maximum of 8192 bytes. |
298 | (((void*)p) - rqstp->rq_arg.head[0].iov_base); | 300 | */ |
299 | if (len > NFSSVC_MAXBLKSIZE_V2) | 301 | if (len > NFSSVC_MAXBLKSIZE_V2) |
300 | len = NFSSVC_MAXBLKSIZE_V2; | 302 | return 0; |
303 | |||
304 | /* | ||
305 | * Check to make sure that we got the right number of | ||
306 | * bytes. | ||
307 | */ | ||
308 | hdr = (void*)p - rqstp->rq_arg.head[0].iov_base; | ||
309 | dlen = rqstp->rq_arg.head[0].iov_len + rqstp->rq_arg.page_len | ||
310 | - hdr; | ||
311 | |||
312 | /* | ||
313 | * Round the length of the data which was specified up to | ||
314 | * the next multiple of XDR units and then compare that | ||
315 | * against the length which was actually received. | ||
316 | */ | ||
317 | if (dlen != XDR_QUADLEN(len)*4) | ||
318 | return 0; | ||
319 | |||
320 | rqstp->rq_vec[0].iov_base = (void*)p; | ||
321 | rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - hdr; | ||
301 | v = 0; | 322 | v = 0; |
302 | while (len > rqstp->rq_vec[v].iov_len) { | 323 | while (len > rqstp->rq_vec[v].iov_len) { |
303 | len -= rqstp->rq_vec[v].iov_len; | 324 | len -= rqstp->rq_vec[v].iov_len; |
@@ -306,18 +327,18 @@ nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p, | |||
306 | rqstp->rq_vec[v].iov_len = PAGE_SIZE; | 327 | rqstp->rq_vec[v].iov_len = PAGE_SIZE; |
307 | } | 328 | } |
308 | rqstp->rq_vec[v].iov_len = len; | 329 | rqstp->rq_vec[v].iov_len = len; |
309 | args->vlen = v+1; | 330 | args->vlen = v + 1; |
310 | return rqstp->rq_vec[0].iov_len > 0; | 331 | return 1; |
311 | } | 332 | } |
312 | 333 | ||
313 | int | 334 | int |
314 | nfssvc_decode_createargs(struct svc_rqst *rqstp, __be32 *p, | 335 | nfssvc_decode_createargs(struct svc_rqst *rqstp, __be32 *p, |
315 | struct nfsd_createargs *args) | 336 | struct nfsd_createargs *args) |
316 | { | 337 | { |
317 | if (!(p = decode_fh(p, &args->fh)) | 338 | if ( !(p = decode_fh(p, &args->fh)) |
318 | || !(p = decode_filename(p, &args->name, &args->len)) | 339 | || !(p = decode_filename(p, &args->name, &args->len))) |
319 | || !(p = decode_sattr(p, &args->attrs))) | ||
320 | return 0; | 340 | return 0; |
341 | p = decode_sattr(p, &args->attrs); | ||
321 | 342 | ||
322 | return xdr_argsize_check(rqstp, p); | 343 | return xdr_argsize_check(rqstp, p); |
323 | } | 344 | } |
@@ -361,11 +382,11 @@ int | |||
361 | nfssvc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p, | 382 | nfssvc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p, |
362 | struct nfsd_symlinkargs *args) | 383 | struct nfsd_symlinkargs *args) |
363 | { | 384 | { |
364 | if (!(p = decode_fh(p, &args->ffh)) | 385 | if ( !(p = decode_fh(p, &args->ffh)) |
365 | || !(p = decode_filename(p, &args->fname, &args->flen)) | 386 | || !(p = decode_filename(p, &args->fname, &args->flen)) |
366 | || !(p = decode_pathname(p, &args->tname, &args->tlen)) | 387 | || !(p = decode_pathname(p, &args->tname, &args->tlen))) |
367 | || !(p = decode_sattr(p, &args->attrs))) | ||
368 | return 0; | 388 | return 0; |
389 | p = decode_sattr(p, &args->attrs); | ||
369 | 390 | ||
370 | return xdr_argsize_check(rqstp, p); | 391 | return xdr_argsize_check(rqstp, p); |
371 | } | 392 | } |
diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c index ab45db529c80..9e451a68580f 100644 --- a/fs/reiserfs/file.c +++ b/fs/reiserfs/file.c | |||
@@ -1059,20 +1059,12 @@ static int reiserfs_prepare_file_region_for_write(struct inode *inode | |||
1059 | maping blocks, since there is none, so we just zero out remaining | 1059 | maping blocks, since there is none, so we just zero out remaining |
1060 | parts of first and last pages in write area (if needed) */ | 1060 | parts of first and last pages in write area (if needed) */ |
1061 | if ((pos & ~((loff_t) PAGE_CACHE_SIZE - 1)) > inode->i_size) { | 1061 | if ((pos & ~((loff_t) PAGE_CACHE_SIZE - 1)) > inode->i_size) { |
1062 | if (from != 0) { /* First page needs to be partially zeroed */ | 1062 | if (from != 0) /* First page needs to be partially zeroed */ |
1063 | char *kaddr = kmap_atomic(prepared_pages[0], KM_USER0); | 1063 | zero_user_page(prepared_pages[0], 0, from, KM_USER0); |
1064 | memset(kaddr, 0, from); | 1064 | |
1065 | kunmap_atomic(kaddr, KM_USER0); | 1065 | if (to != PAGE_CACHE_SIZE) /* Last page needs to be partially zeroed */ |
1066 | flush_dcache_page(prepared_pages[0]); | 1066 | zero_user_page(prepared_pages[num_pages-1], to, |
1067 | } | 1067 | PAGE_CACHE_SIZE - to, KM_USER0); |
1068 | if (to != PAGE_CACHE_SIZE) { /* Last page needs to be partially zeroed */ | ||
1069 | char *kaddr = | ||
1070 | kmap_atomic(prepared_pages[num_pages - 1], | ||
1071 | KM_USER0); | ||
1072 | memset(kaddr + to, 0, PAGE_CACHE_SIZE - to); | ||
1073 | kunmap_atomic(kaddr, KM_USER0); | ||
1074 | flush_dcache_page(prepared_pages[num_pages - 1]); | ||
1075 | } | ||
1076 | 1068 | ||
1077 | /* Since all blocks are new - use already calculated value */ | 1069 | /* Since all blocks are new - use already calculated value */ |
1078 | return blocks; | 1070 | return blocks; |
@@ -1199,13 +1191,9 @@ static int reiserfs_prepare_file_region_for_write(struct inode *inode | |||
1199 | ll_rw_block(READ, 1, &bh); | 1191 | ll_rw_block(READ, 1, &bh); |
1200 | *wait_bh++ = bh; | 1192 | *wait_bh++ = bh; |
1201 | } else { /* Not mapped, zero it */ | 1193 | } else { /* Not mapped, zero it */ |
1202 | char *kaddr = | 1194 | zero_user_page(prepared_pages[0], |
1203 | kmap_atomic(prepared_pages[0], | 1195 | block_start, |
1204 | KM_USER0); | 1196 | from - block_start, KM_USER0); |
1205 | memset(kaddr + block_start, 0, | ||
1206 | from - block_start); | ||
1207 | kunmap_atomic(kaddr, KM_USER0); | ||
1208 | flush_dcache_page(prepared_pages[0]); | ||
1209 | set_buffer_uptodate(bh); | 1197 | set_buffer_uptodate(bh); |
1210 | } | 1198 | } |
1211 | } | 1199 | } |
@@ -1237,13 +1225,8 @@ static int reiserfs_prepare_file_region_for_write(struct inode *inode | |||
1237 | ll_rw_block(READ, 1, &bh); | 1225 | ll_rw_block(READ, 1, &bh); |
1238 | *wait_bh++ = bh; | 1226 | *wait_bh++ = bh; |
1239 | } else { /* Not mapped, zero it */ | 1227 | } else { /* Not mapped, zero it */ |
1240 | char *kaddr = | 1228 | zero_user_page(prepared_pages[num_pages-1], |
1241 | kmap_atomic(prepared_pages | 1229 | to, block_end - to, KM_USER0); |
1242 | [num_pages - 1], | ||
1243 | KM_USER0); | ||
1244 | memset(kaddr + to, 0, block_end - to); | ||
1245 | kunmap_atomic(kaddr, KM_USER0); | ||
1246 | flush_dcache_page(prepared_pages[num_pages - 1]); | ||
1247 | set_buffer_uptodate(bh); | 1230 | set_buffer_uptodate(bh); |
1248 | } | 1231 | } |
1249 | } | 1232 | } |
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index 9fcbfe316977..1272d11399fb 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c | |||
@@ -2148,13 +2148,8 @@ int reiserfs_truncate_file(struct inode *p_s_inode, int update_timestamps) | |||
2148 | length = offset & (blocksize - 1); | 2148 | length = offset & (blocksize - 1); |
2149 | /* if we are not on a block boundary */ | 2149 | /* if we are not on a block boundary */ |
2150 | if (length) { | 2150 | if (length) { |
2151 | char *kaddr; | ||
2152 | |||
2153 | length = blocksize - length; | 2151 | length = blocksize - length; |
2154 | kaddr = kmap_atomic(page, KM_USER0); | 2152 | zero_user_page(page, offset, length, KM_USER0); |
2155 | memset(kaddr + offset, 0, length); | ||
2156 | flush_dcache_page(page); | ||
2157 | kunmap_atomic(kaddr, KM_USER0); | ||
2158 | if (buffer_mapped(bh) && bh->b_blocknr != 0) { | 2153 | if (buffer_mapped(bh) && bh->b_blocknr != 0) { |
2159 | mark_buffer_dirty(bh); | 2154 | mark_buffer_dirty(bh); |
2160 | } | 2155 | } |
@@ -2370,7 +2365,6 @@ static int reiserfs_write_full_page(struct page *page, | |||
2370 | ** last byte in the file | 2365 | ** last byte in the file |
2371 | */ | 2366 | */ |
2372 | if (page->index >= end_index) { | 2367 | if (page->index >= end_index) { |
2373 | char *kaddr; | ||
2374 | unsigned last_offset; | 2368 | unsigned last_offset; |
2375 | 2369 | ||
2376 | last_offset = inode->i_size & (PAGE_CACHE_SIZE - 1); | 2370 | last_offset = inode->i_size & (PAGE_CACHE_SIZE - 1); |
@@ -2379,10 +2373,7 @@ static int reiserfs_write_full_page(struct page *page, | |||
2379 | unlock_page(page); | 2373 | unlock_page(page); |
2380 | return 0; | 2374 | return 0; |
2381 | } | 2375 | } |
2382 | kaddr = kmap_atomic(page, KM_USER0); | 2376 | zero_user_page(page, last_offset, PAGE_CACHE_SIZE - last_offset, KM_USER0); |
2383 | memset(kaddr + last_offset, 0, PAGE_CACHE_SIZE - last_offset); | ||
2384 | flush_dcache_page(page); | ||
2385 | kunmap_atomic(kaddr, KM_USER0); | ||
2386 | } | 2377 | } |
2387 | bh = head; | 2378 | bh = head; |
2388 | block = page->index << (PAGE_CACHE_SHIFT - s->s_blocksize_bits); | 2379 | block = page->index << (PAGE_CACHE_SHIFT - s->s_blocksize_bits); |
diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c index e073fd86cf60..f25086aeef5f 100644 --- a/fs/reiserfs/journal.c +++ b/fs/reiserfs/journal.c | |||
@@ -1110,7 +1110,7 @@ static int flush_commit_list(struct super_block *s, | |||
1110 | if (!barrier) { | 1110 | if (!barrier) { |
1111 | /* If there was a write error in the journal - we can't commit | 1111 | /* If there was a write error in the journal - we can't commit |
1112 | * this transaction - it will be invalid and, if successful, | 1112 | * this transaction - it will be invalid and, if successful, |
1113 | * will just end up propogating the write error out to | 1113 | * will just end up propagating the write error out to |
1114 | * the file system. */ | 1114 | * the file system. */ |
1115 | if (likely(!retval && !reiserfs_is_journal_aborted (journal))) { | 1115 | if (likely(!retval && !reiserfs_is_journal_aborted (journal))) { |
1116 | if (buffer_dirty(jl->j_commit_bh)) | 1116 | if (buffer_dirty(jl->j_commit_bh)) |
@@ -1125,7 +1125,7 @@ static int flush_commit_list(struct super_block *s, | |||
1125 | 1125 | ||
1126 | /* If there was a write error in the journal - we can't commit this | 1126 | /* If there was a write error in the journal - we can't commit this |
1127 | * transaction - it will be invalid and, if successful, will just end | 1127 | * transaction - it will be invalid and, if successful, will just end |
1128 | * up propogating the write error out to the filesystem. */ | 1128 | * up propagating the write error out to the filesystem. */ |
1129 | if (unlikely(!buffer_uptodate(jl->j_commit_bh))) { | 1129 | if (unlikely(!buffer_uptodate(jl->j_commit_bh))) { |
1130 | #ifdef CONFIG_REISERFS_CHECK | 1130 | #ifdef CONFIG_REISERFS_CHECK |
1131 | reiserfs_warning(s, "journal-615: buffer write failed"); | 1131 | reiserfs_warning(s, "journal-615: buffer write failed"); |
diff --git a/fs/select.c b/fs/select.c index d86224154dec..a974082b0824 100644 --- a/fs/select.c +++ b/fs/select.c | |||
@@ -64,7 +64,7 @@ EXPORT_SYMBOL(poll_initwait); | |||
64 | 64 | ||
65 | static void free_poll_entry(struct poll_table_entry *entry) | 65 | static void free_poll_entry(struct poll_table_entry *entry) |
66 | { | 66 | { |
67 | remove_wait_queue(entry->wait_address,&entry->wait); | 67 | remove_wait_queue(entry->wait_address, &entry->wait); |
68 | fput(entry->filp); | 68 | fput(entry->filp); |
69 | } | 69 | } |
70 | 70 | ||
@@ -128,7 +128,7 @@ static void __pollwait(struct file *filp, wait_queue_head_t *wait_address, | |||
128 | entry->filp = filp; | 128 | entry->filp = filp; |
129 | entry->wait_address = wait_address; | 129 | entry->wait_address = wait_address; |
130 | init_waitqueue_entry(&entry->wait, current); | 130 | init_waitqueue_entry(&entry->wait, current); |
131 | add_wait_queue(wait_address,&entry->wait); | 131 | add_wait_queue(wait_address, &entry->wait); |
132 | } | 132 | } |
133 | 133 | ||
134 | #define FDS_IN(fds, n) (fds->in + n) | 134 | #define FDS_IN(fds, n) (fds->in + n) |
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index 0e637adc2b87..b502c7197ec0 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c | |||
@@ -111,36 +111,6 @@ static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer | |||
111 | return ret; | 111 | return ret; |
112 | } | 112 | } |
113 | 113 | ||
114 | |||
115 | /** | ||
116 | * flush_read_buffer - push buffer to userspace. | ||
117 | * @buffer: data buffer for file. | ||
118 | * @buf: user-passed buffer. | ||
119 | * @count: number of bytes requested. | ||
120 | * @ppos: file position. | ||
121 | * | ||
122 | * Copy the buffer we filled in fill_read_buffer() to userspace. | ||
123 | * This is done at the reader's leisure, copying and advancing | ||
124 | * the amount they specify each time. | ||
125 | * This may be called continuously until the buffer is empty. | ||
126 | */ | ||
127 | static int flush_read_buffer(struct sysfs_buffer * buffer, char __user * buf, | ||
128 | size_t count, loff_t * ppos) | ||
129 | { | ||
130 | int error; | ||
131 | |||
132 | if (*ppos > buffer->count) | ||
133 | return 0; | ||
134 | |||
135 | if (count > (buffer->count - *ppos)) | ||
136 | count = buffer->count - *ppos; | ||
137 | |||
138 | error = copy_to_user(buf,buffer->page + *ppos,count); | ||
139 | if (!error) | ||
140 | *ppos += count; | ||
141 | return error ? -EFAULT : count; | ||
142 | } | ||
143 | |||
144 | /** | 114 | /** |
145 | * sysfs_read_file - read an attribute. | 115 | * sysfs_read_file - read an attribute. |
146 | * @file: file pointer. | 116 | * @file: file pointer. |
@@ -177,7 +147,8 @@ sysfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos) | |||
177 | } | 147 | } |
178 | pr_debug("%s: count = %zd, ppos = %lld, buf = %s\n", | 148 | pr_debug("%s: count = %zd, ppos = %lld, buf = %s\n", |
179 | __FUNCTION__, count, *ppos, buffer->page); | 149 | __FUNCTION__, count, *ppos, buffer->page); |
180 | retval = flush_read_buffer(buffer,buf,count,ppos); | 150 | retval = simple_read_from_buffer(buf, count, ppos, buffer->page, |
151 | buffer->count); | ||
181 | out: | 152 | out: |
182 | up(&buffer->sem); | 153 | up(&buffer->sem); |
183 | return retval; | 154 | return retval; |
diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c index 7775ddc0b3c6..e725ddd3de5f 100644 --- a/fs/xfs/xfs_itable.c +++ b/fs/xfs/xfs_itable.c | |||
@@ -809,7 +809,7 @@ xfs_inumbers( | |||
809 | xfs_buf_relse(agbp); | 809 | xfs_buf_relse(agbp); |
810 | agbp = NULL; | 810 | agbp = NULL; |
811 | /* | 811 | /* |
812 | * Move up the the last inode in the current | 812 | * Move up the last inode in the current |
813 | * chunk. The lookup_ge will always get | 813 | * chunk. The lookup_ge will always get |
814 | * us the first inode in the next chunk. | 814 | * us the first inode in the next chunk. |
815 | */ | 815 | */ |
diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index f5aa3ef855fb..a96bde6df96d 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c | |||
@@ -1734,11 +1734,13 @@ xfs_icsb_cpu_notify( | |||
1734 | per_cpu_ptr(mp->m_sb_cnts, (unsigned long)hcpu); | 1734 | per_cpu_ptr(mp->m_sb_cnts, (unsigned long)hcpu); |
1735 | switch (action) { | 1735 | switch (action) { |
1736 | case CPU_UP_PREPARE: | 1736 | case CPU_UP_PREPARE: |
1737 | case CPU_UP_PREPARE_FROZEN: | ||
1737 | /* Easy Case - initialize the area and locks, and | 1738 | /* Easy Case - initialize the area and locks, and |
1738 | * then rebalance when online does everything else for us. */ | 1739 | * then rebalance when online does everything else for us. */ |
1739 | memset(cntp, 0, sizeof(xfs_icsb_cnts_t)); | 1740 | memset(cntp, 0, sizeof(xfs_icsb_cnts_t)); |
1740 | break; | 1741 | break; |
1741 | case CPU_ONLINE: | 1742 | case CPU_ONLINE: |
1743 | case CPU_ONLINE_FROZEN: | ||
1742 | xfs_icsb_lock(mp); | 1744 | xfs_icsb_lock(mp); |
1743 | xfs_icsb_balance_counter(mp, XFS_SBS_ICOUNT, 0, 0); | 1745 | xfs_icsb_balance_counter(mp, XFS_SBS_ICOUNT, 0, 0); |
1744 | xfs_icsb_balance_counter(mp, XFS_SBS_IFREE, 0, 0); | 1746 | xfs_icsb_balance_counter(mp, XFS_SBS_IFREE, 0, 0); |
@@ -1746,6 +1748,7 @@ xfs_icsb_cpu_notify( | |||
1746 | xfs_icsb_unlock(mp); | 1748 | xfs_icsb_unlock(mp); |
1747 | break; | 1749 | break; |
1748 | case CPU_DEAD: | 1750 | case CPU_DEAD: |
1751 | case CPU_DEAD_FROZEN: | ||
1749 | /* Disable all the counters, then fold the dead cpu's | 1752 | /* Disable all the counters, then fold the dead cpu's |
1750 | * count into the total on the global superblock and | 1753 | * count into the total on the global superblock and |
1751 | * re-enable the counters. */ | 1754 | * re-enable the counters. */ |