diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-20 21:14:31 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-20 21:14:31 -0500 |
commit | 1f0377ff088ed2971c57debc9b0c3b846ec431fd (patch) | |
tree | cd53c8981269e57e38e4285abd71cc990e1cfc67 /fs | |
parent | 54d46ea993744c5408e39ce0cb4851e13cbea716 (diff) | |
parent | b729d75d19777a5dd34672020516eada43ff026f (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull VFS update from Al Viro:
"fscache fixes, ESTALE patchset, vmtruncate removal series, assorted
misc stuff."
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (79 commits)
vfs: make lremovexattr retry once on ESTALE error
vfs: make removexattr retry once on ESTALE
vfs: make llistxattr retry once on ESTALE error
vfs: make listxattr retry once on ESTALE error
vfs: make lgetxattr retry once on ESTALE
vfs: make getxattr retry once on an ESTALE error
vfs: allow lsetxattr() to retry once on ESTALE errors
vfs: allow setxattr to retry once on ESTALE errors
vfs: allow utimensat() calls to retry once on an ESTALE error
vfs: fix user_statfs to retry once on ESTALE errors
vfs: make fchownat retry once on ESTALE errors
vfs: make fchmodat retry once on ESTALE errors
vfs: have chroot retry once on ESTALE error
vfs: have chdir retry lookup and call once on ESTALE error
vfs: have faccessat retry once on an ESTALE error
vfs: have do_sys_truncate retry once on an ESTALE error
vfs: fix renameat to retry on ESTALE errors
vfs: make do_unlinkat retry once on ESTALE errors
vfs: make do_rmdir retry once on ESTALE errors
vfs: add a flags argument to user_path_parent
...
Diffstat (limited to 'fs')
64 files changed, 1096 insertions, 435 deletions
diff --git a/fs/adfs/inode.c b/fs/adfs/inode.c index e9bad5093a3f..5f95d1ed9c6d 100644 --- a/fs/adfs/inode.c +++ b/fs/adfs/inode.c | |||
@@ -45,6 +45,14 @@ static int adfs_readpage(struct file *file, struct page *page) | |||
45 | return block_read_full_page(page, adfs_get_block); | 45 | return block_read_full_page(page, adfs_get_block); |
46 | } | 46 | } |
47 | 47 | ||
48 | static void adfs_write_failed(struct address_space *mapping, loff_t to) | ||
49 | { | ||
50 | struct inode *inode = mapping->host; | ||
51 | |||
52 | if (to > inode->i_size) | ||
53 | truncate_pagecache(inode, to, inode->i_size); | ||
54 | } | ||
55 | |||
48 | static int adfs_write_begin(struct file *file, struct address_space *mapping, | 56 | static int adfs_write_begin(struct file *file, struct address_space *mapping, |
49 | loff_t pos, unsigned len, unsigned flags, | 57 | loff_t pos, unsigned len, unsigned flags, |
50 | struct page **pagep, void **fsdata) | 58 | struct page **pagep, void **fsdata) |
@@ -55,11 +63,8 @@ static int adfs_write_begin(struct file *file, struct address_space *mapping, | |||
55 | ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, | 63 | ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, |
56 | adfs_get_block, | 64 | adfs_get_block, |
57 | &ADFS_I(mapping->host)->mmu_private); | 65 | &ADFS_I(mapping->host)->mmu_private); |
58 | if (unlikely(ret)) { | 66 | if (unlikely(ret)) |
59 | loff_t isize = mapping->host->i_size; | 67 | adfs_write_failed(mapping, pos + len); |
60 | if (pos + len > isize) | ||
61 | vmtruncate(mapping->host, isize); | ||
62 | } | ||
63 | 68 | ||
64 | return ret; | 69 | return ret; |
65 | } | 70 | } |
diff --git a/fs/affs/file.c b/fs/affs/file.c index 2f4c935cb327..af3261b78102 100644 --- a/fs/affs/file.c +++ b/fs/affs/file.c | |||
@@ -39,7 +39,6 @@ const struct file_operations affs_file_operations = { | |||
39 | }; | 39 | }; |
40 | 40 | ||
41 | const struct inode_operations affs_file_inode_operations = { | 41 | const struct inode_operations affs_file_inode_operations = { |
42 | .truncate = affs_truncate, | ||
43 | .setattr = affs_notify_change, | 42 | .setattr = affs_notify_change, |
44 | }; | 43 | }; |
45 | 44 | ||
@@ -402,6 +401,16 @@ static int affs_readpage(struct file *file, struct page *page) | |||
402 | return block_read_full_page(page, affs_get_block); | 401 | return block_read_full_page(page, affs_get_block); |
403 | } | 402 | } |
404 | 403 | ||
404 | static void affs_write_failed(struct address_space *mapping, loff_t to) | ||
405 | { | ||
406 | struct inode *inode = mapping->host; | ||
407 | |||
408 | if (to > inode->i_size) { | ||
409 | truncate_pagecache(inode, to, inode->i_size); | ||
410 | affs_truncate(inode); | ||
411 | } | ||
412 | } | ||
413 | |||
405 | static int affs_write_begin(struct file *file, struct address_space *mapping, | 414 | static int affs_write_begin(struct file *file, struct address_space *mapping, |
406 | loff_t pos, unsigned len, unsigned flags, | 415 | loff_t pos, unsigned len, unsigned flags, |
407 | struct page **pagep, void **fsdata) | 416 | struct page **pagep, void **fsdata) |
@@ -412,11 +421,8 @@ static int affs_write_begin(struct file *file, struct address_space *mapping, | |||
412 | ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, | 421 | ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, |
413 | affs_get_block, | 422 | affs_get_block, |
414 | &AFFS_I(mapping->host)->mmu_private); | 423 | &AFFS_I(mapping->host)->mmu_private); |
415 | if (unlikely(ret)) { | 424 | if (unlikely(ret)) |
416 | loff_t isize = mapping->host->i_size; | 425 | affs_write_failed(mapping, pos + len); |
417 | if (pos + len > isize) | ||
418 | vmtruncate(mapping->host, isize); | ||
419 | } | ||
420 | 426 | ||
421 | return ret; | 427 | return ret; |
422 | } | 428 | } |
diff --git a/fs/affs/inode.c b/fs/affs/inode.c index 15c484268229..0e092d08680e 100644 --- a/fs/affs/inode.c +++ b/fs/affs/inode.c | |||
@@ -237,9 +237,12 @@ affs_notify_change(struct dentry *dentry, struct iattr *attr) | |||
237 | 237 | ||
238 | if ((attr->ia_valid & ATTR_SIZE) && | 238 | if ((attr->ia_valid & ATTR_SIZE) && |
239 | attr->ia_size != i_size_read(inode)) { | 239 | attr->ia_size != i_size_read(inode)) { |
240 | error = vmtruncate(inode, attr->ia_size); | 240 | error = inode_newsize_ok(inode, attr->ia_size); |
241 | if (error) | 241 | if (error) |
242 | return error; | 242 | return error; |
243 | |||
244 | truncate_setsize(inode, attr->ia_size); | ||
245 | affs_truncate(inode); | ||
243 | } | 246 | } |
244 | 247 | ||
245 | setattr_copy(inode, attr); | 248 | setattr_copy(inode, attr); |
diff --git a/fs/bfs/file.c b/fs/bfs/file.c index f20e8a71062f..ad3ea1497cc3 100644 --- a/fs/bfs/file.c +++ b/fs/bfs/file.c | |||
@@ -161,6 +161,14 @@ static int bfs_readpage(struct file *file, struct page *page) | |||
161 | return block_read_full_page(page, bfs_get_block); | 161 | return block_read_full_page(page, bfs_get_block); |
162 | } | 162 | } |
163 | 163 | ||
164 | static void bfs_write_failed(struct address_space *mapping, loff_t to) | ||
165 | { | ||
166 | struct inode *inode = mapping->host; | ||
167 | |||
168 | if (to > inode->i_size) | ||
169 | truncate_pagecache(inode, to, inode->i_size); | ||
170 | } | ||
171 | |||
164 | static int bfs_write_begin(struct file *file, struct address_space *mapping, | 172 | static int bfs_write_begin(struct file *file, struct address_space *mapping, |
165 | loff_t pos, unsigned len, unsigned flags, | 173 | loff_t pos, unsigned len, unsigned flags, |
166 | struct page **pagep, void **fsdata) | 174 | struct page **pagep, void **fsdata) |
@@ -169,11 +177,8 @@ static int bfs_write_begin(struct file *file, struct address_space *mapping, | |||
169 | 177 | ||
170 | ret = block_write_begin(mapping, pos, len, flags, pagep, | 178 | ret = block_write_begin(mapping, pos, len, flags, pagep, |
171 | bfs_get_block); | 179 | bfs_get_block); |
172 | if (unlikely(ret)) { | 180 | if (unlikely(ret)) |
173 | loff_t isize = mapping->host->i_size; | 181 | bfs_write_failed(mapping, pos + len); |
174 | if (pos + len > isize) | ||
175 | vmtruncate(mapping->host, isize); | ||
176 | } | ||
177 | 182 | ||
178 | return ret; | 183 | return ret; |
179 | } | 184 | } |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 67ed24ae86bb..16d9e8e191e6 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -4262,16 +4262,7 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry) | |||
4262 | if (dentry->d_name.len > BTRFS_NAME_LEN) | 4262 | if (dentry->d_name.len > BTRFS_NAME_LEN) |
4263 | return ERR_PTR(-ENAMETOOLONG); | 4263 | return ERR_PTR(-ENAMETOOLONG); |
4264 | 4264 | ||
4265 | if (unlikely(d_need_lookup(dentry))) { | 4265 | ret = btrfs_inode_by_name(dir, dentry, &location); |
4266 | memcpy(&location, dentry->d_fsdata, sizeof(struct btrfs_key)); | ||
4267 | kfree(dentry->d_fsdata); | ||
4268 | dentry->d_fsdata = NULL; | ||
4269 | /* This thing is hashed, drop it for now */ | ||
4270 | d_drop(dentry); | ||
4271 | } else { | ||
4272 | ret = btrfs_inode_by_name(dir, dentry, &location); | ||
4273 | } | ||
4274 | |||
4275 | if (ret < 0) | 4266 | if (ret < 0) |
4276 | return ERR_PTR(ret); | 4267 | return ERR_PTR(ret); |
4277 | 4268 | ||
@@ -4341,11 +4332,6 @@ static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry, | |||
4341 | struct dentry *ret; | 4332 | struct dentry *ret; |
4342 | 4333 | ||
4343 | ret = d_splice_alias(btrfs_lookup_dentry(dir, dentry), dentry); | 4334 | ret = d_splice_alias(btrfs_lookup_dentry(dir, dentry), dentry); |
4344 | if (unlikely(d_need_lookup(dentry))) { | ||
4345 | spin_lock(&dentry->d_lock); | ||
4346 | dentry->d_flags &= ~DCACHE_NEED_LOOKUP; | ||
4347 | spin_unlock(&dentry->d_lock); | ||
4348 | } | ||
4349 | return ret; | 4335 | return ret; |
4350 | } | 4336 | } |
4351 | 4337 | ||
diff --git a/fs/cachefiles/interface.c b/fs/cachefiles/interface.c index 67bef6d01484..746ce532e130 100644 --- a/fs/cachefiles/interface.c +++ b/fs/cachefiles/interface.c | |||
@@ -41,12 +41,12 @@ static struct fscache_object *cachefiles_alloc_object( | |||
41 | 41 | ||
42 | _enter("{%s},%p,", cache->cache.identifier, cookie); | 42 | _enter("{%s},%p,", cache->cache.identifier, cookie); |
43 | 43 | ||
44 | lookup_data = kmalloc(sizeof(*lookup_data), GFP_KERNEL); | 44 | lookup_data = kmalloc(sizeof(*lookup_data), cachefiles_gfp); |
45 | if (!lookup_data) | 45 | if (!lookup_data) |
46 | goto nomem_lookup_data; | 46 | goto nomem_lookup_data; |
47 | 47 | ||
48 | /* create a new object record and a temporary leaf image */ | 48 | /* create a new object record and a temporary leaf image */ |
49 | object = kmem_cache_alloc(cachefiles_object_jar, GFP_KERNEL); | 49 | object = kmem_cache_alloc(cachefiles_object_jar, cachefiles_gfp); |
50 | if (!object) | 50 | if (!object) |
51 | goto nomem_object; | 51 | goto nomem_object; |
52 | 52 | ||
@@ -63,7 +63,7 @@ static struct fscache_object *cachefiles_alloc_object( | |||
63 | * - stick the length on the front and leave space on the back for the | 63 | * - stick the length on the front and leave space on the back for the |
64 | * encoder | 64 | * encoder |
65 | */ | 65 | */ |
66 | buffer = kmalloc((2 + 512) + 3, GFP_KERNEL); | 66 | buffer = kmalloc((2 + 512) + 3, cachefiles_gfp); |
67 | if (!buffer) | 67 | if (!buffer) |
68 | goto nomem_buffer; | 68 | goto nomem_buffer; |
69 | 69 | ||
@@ -219,7 +219,7 @@ static void cachefiles_update_object(struct fscache_object *_object) | |||
219 | return; | 219 | return; |
220 | } | 220 | } |
221 | 221 | ||
222 | auxdata = kmalloc(2 + 512 + 3, GFP_KERNEL); | 222 | auxdata = kmalloc(2 + 512 + 3, cachefiles_gfp); |
223 | if (!auxdata) { | 223 | if (!auxdata) { |
224 | _leave(" [nomem]"); | 224 | _leave(" [nomem]"); |
225 | return; | 225 | return; |
@@ -441,6 +441,54 @@ truncate_failed: | |||
441 | } | 441 | } |
442 | 442 | ||
443 | /* | 443 | /* |
444 | * Invalidate an object | ||
445 | */ | ||
446 | static void cachefiles_invalidate_object(struct fscache_operation *op) | ||
447 | { | ||
448 | struct cachefiles_object *object; | ||
449 | struct cachefiles_cache *cache; | ||
450 | const struct cred *saved_cred; | ||
451 | struct path path; | ||
452 | uint64_t ni_size; | ||
453 | int ret; | ||
454 | |||
455 | object = container_of(op->object, struct cachefiles_object, fscache); | ||
456 | cache = container_of(object->fscache.cache, | ||
457 | struct cachefiles_cache, cache); | ||
458 | |||
459 | op->object->cookie->def->get_attr(op->object->cookie->netfs_data, | ||
460 | &ni_size); | ||
461 | |||
462 | _enter("{OBJ%x},[%llu]", | ||
463 | op->object->debug_id, (unsigned long long)ni_size); | ||
464 | |||
465 | if (object->backer) { | ||
466 | ASSERT(S_ISREG(object->backer->d_inode->i_mode)); | ||
467 | |||
468 | fscache_set_store_limit(&object->fscache, ni_size); | ||
469 | |||
470 | path.dentry = object->backer; | ||
471 | path.mnt = cache->mnt; | ||
472 | |||
473 | cachefiles_begin_secure(cache, &saved_cred); | ||
474 | ret = vfs_truncate(&path, 0); | ||
475 | if (ret == 0) | ||
476 | ret = vfs_truncate(&path, ni_size); | ||
477 | cachefiles_end_secure(cache, saved_cred); | ||
478 | |||
479 | if (ret != 0) { | ||
480 | fscache_set_store_limit(&object->fscache, 0); | ||
481 | if (ret == -EIO) | ||
482 | cachefiles_io_error_obj(object, | ||
483 | "Invalidate failed"); | ||
484 | } | ||
485 | } | ||
486 | |||
487 | fscache_op_complete(op, true); | ||
488 | _leave(""); | ||
489 | } | ||
490 | |||
491 | /* | ||
444 | * dissociate a cache from all the pages it was backing | 492 | * dissociate a cache from all the pages it was backing |
445 | */ | 493 | */ |
446 | static void cachefiles_dissociate_pages(struct fscache_cache *cache) | 494 | static void cachefiles_dissociate_pages(struct fscache_cache *cache) |
@@ -455,6 +503,7 @@ const struct fscache_cache_ops cachefiles_cache_ops = { | |||
455 | .lookup_complete = cachefiles_lookup_complete, | 503 | .lookup_complete = cachefiles_lookup_complete, |
456 | .grab_object = cachefiles_grab_object, | 504 | .grab_object = cachefiles_grab_object, |
457 | .update_object = cachefiles_update_object, | 505 | .update_object = cachefiles_update_object, |
506 | .invalidate_object = cachefiles_invalidate_object, | ||
458 | .drop_object = cachefiles_drop_object, | 507 | .drop_object = cachefiles_drop_object, |
459 | .put_object = cachefiles_put_object, | 508 | .put_object = cachefiles_put_object, |
460 | .sync_cache = cachefiles_sync_cache, | 509 | .sync_cache = cachefiles_sync_cache, |
diff --git a/fs/cachefiles/internal.h b/fs/cachefiles/internal.h index bd6bc1bde2d7..49382519907a 100644 --- a/fs/cachefiles/internal.h +++ b/fs/cachefiles/internal.h | |||
@@ -23,6 +23,8 @@ extern unsigned cachefiles_debug; | |||
23 | #define CACHEFILES_DEBUG_KLEAVE 2 | 23 | #define CACHEFILES_DEBUG_KLEAVE 2 |
24 | #define CACHEFILES_DEBUG_KDEBUG 4 | 24 | #define CACHEFILES_DEBUG_KDEBUG 4 |
25 | 25 | ||
26 | #define cachefiles_gfp (__GFP_WAIT | __GFP_NORETRY | __GFP_NOMEMALLOC) | ||
27 | |||
26 | /* | 28 | /* |
27 | * node records | 29 | * node records |
28 | */ | 30 | */ |
diff --git a/fs/cachefiles/key.c b/fs/cachefiles/key.c index 81b8b2b3a674..33b58c60f2d1 100644 --- a/fs/cachefiles/key.c +++ b/fs/cachefiles/key.c | |||
@@ -78,7 +78,7 @@ char *cachefiles_cook_key(const u8 *raw, int keylen, uint8_t type) | |||
78 | 78 | ||
79 | _debug("max: %d", max); | 79 | _debug("max: %d", max); |
80 | 80 | ||
81 | key = kmalloc(max, GFP_KERNEL); | 81 | key = kmalloc(max, cachefiles_gfp); |
82 | if (!key) | 82 | if (!key) |
83 | return NULL; | 83 | return NULL; |
84 | 84 | ||
diff --git a/fs/cachefiles/namei.c b/fs/cachefiles/namei.c index b0b5f7cdfffa..8c01c5fcdf75 100644 --- a/fs/cachefiles/namei.c +++ b/fs/cachefiles/namei.c | |||
@@ -40,8 +40,7 @@ void __cachefiles_printk_object(struct cachefiles_object *object, | |||
40 | printk(KERN_ERR "%sobjstate=%s fl=%lx wbusy=%x ev=%lx[%lx]\n", | 40 | printk(KERN_ERR "%sobjstate=%s fl=%lx wbusy=%x ev=%lx[%lx]\n", |
41 | prefix, fscache_object_states[object->fscache.state], | 41 | prefix, fscache_object_states[object->fscache.state], |
42 | object->fscache.flags, work_busy(&object->fscache.work), | 42 | object->fscache.flags, work_busy(&object->fscache.work), |
43 | object->fscache.events, | 43 | object->fscache.events, object->fscache.event_mask); |
44 | object->fscache.event_mask & FSCACHE_OBJECT_EVENTS_MASK); | ||
45 | printk(KERN_ERR "%sops=%u inp=%u exc=%u\n", | 44 | printk(KERN_ERR "%sops=%u inp=%u exc=%u\n", |
46 | prefix, object->fscache.n_ops, object->fscache.n_in_progress, | 45 | prefix, object->fscache.n_ops, object->fscache.n_in_progress, |
47 | object->fscache.n_exclusive); | 46 | object->fscache.n_exclusive); |
diff --git a/fs/cachefiles/rdwr.c b/fs/cachefiles/rdwr.c index c994691d9445..480992259707 100644 --- a/fs/cachefiles/rdwr.c +++ b/fs/cachefiles/rdwr.c | |||
@@ -77,25 +77,25 @@ static int cachefiles_read_reissue(struct cachefiles_object *object, | |||
77 | struct page *backpage = monitor->back_page, *backpage2; | 77 | struct page *backpage = monitor->back_page, *backpage2; |
78 | int ret; | 78 | int ret; |
79 | 79 | ||
80 | kenter("{ino=%lx},{%lx,%lx}", | 80 | _enter("{ino=%lx},{%lx,%lx}", |
81 | object->backer->d_inode->i_ino, | 81 | object->backer->d_inode->i_ino, |
82 | backpage->index, backpage->flags); | 82 | backpage->index, backpage->flags); |
83 | 83 | ||
84 | /* skip if the page was truncated away completely */ | 84 | /* skip if the page was truncated away completely */ |
85 | if (backpage->mapping != bmapping) { | 85 | if (backpage->mapping != bmapping) { |
86 | kleave(" = -ENODATA [mapping]"); | 86 | _leave(" = -ENODATA [mapping]"); |
87 | return -ENODATA; | 87 | return -ENODATA; |
88 | } | 88 | } |
89 | 89 | ||
90 | backpage2 = find_get_page(bmapping, backpage->index); | 90 | backpage2 = find_get_page(bmapping, backpage->index); |
91 | if (!backpage2) { | 91 | if (!backpage2) { |
92 | kleave(" = -ENODATA [gone]"); | 92 | _leave(" = -ENODATA [gone]"); |
93 | return -ENODATA; | 93 | return -ENODATA; |
94 | } | 94 | } |
95 | 95 | ||
96 | if (backpage != backpage2) { | 96 | if (backpage != backpage2) { |
97 | put_page(backpage2); | 97 | put_page(backpage2); |
98 | kleave(" = -ENODATA [different]"); | 98 | _leave(" = -ENODATA [different]"); |
99 | return -ENODATA; | 99 | return -ENODATA; |
100 | } | 100 | } |
101 | 101 | ||
@@ -114,7 +114,7 @@ static int cachefiles_read_reissue(struct cachefiles_object *object, | |||
114 | if (PageUptodate(backpage)) | 114 | if (PageUptodate(backpage)) |
115 | goto unlock_discard; | 115 | goto unlock_discard; |
116 | 116 | ||
117 | kdebug("reissue read"); | 117 | _debug("reissue read"); |
118 | ret = bmapping->a_ops->readpage(NULL, backpage); | 118 | ret = bmapping->a_ops->readpage(NULL, backpage); |
119 | if (ret < 0) | 119 | if (ret < 0) |
120 | goto unlock_discard; | 120 | goto unlock_discard; |
@@ -129,7 +129,7 @@ static int cachefiles_read_reissue(struct cachefiles_object *object, | |||
129 | } | 129 | } |
130 | 130 | ||
131 | /* it'll reappear on the todo list */ | 131 | /* it'll reappear on the todo list */ |
132 | kleave(" = -EINPROGRESS"); | 132 | _leave(" = -EINPROGRESS"); |
133 | return -EINPROGRESS; | 133 | return -EINPROGRESS; |
134 | 134 | ||
135 | unlock_discard: | 135 | unlock_discard: |
@@ -137,7 +137,7 @@ unlock_discard: | |||
137 | spin_lock_irq(&object->work_lock); | 137 | spin_lock_irq(&object->work_lock); |
138 | list_del(&monitor->op_link); | 138 | list_del(&monitor->op_link); |
139 | spin_unlock_irq(&object->work_lock); | 139 | spin_unlock_irq(&object->work_lock); |
140 | kleave(" = %d", ret); | 140 | _leave(" = %d", ret); |
141 | return ret; | 141 | return ret; |
142 | } | 142 | } |
143 | 143 | ||
@@ -174,11 +174,13 @@ static void cachefiles_read_copier(struct fscache_operation *_op) | |||
174 | _debug("- copy {%lu}", monitor->back_page->index); | 174 | _debug("- copy {%lu}", monitor->back_page->index); |
175 | 175 | ||
176 | recheck: | 176 | recheck: |
177 | if (PageUptodate(monitor->back_page)) { | 177 | if (test_bit(FSCACHE_COOKIE_INVALIDATING, |
178 | &object->fscache.cookie->flags)) { | ||
179 | error = -ESTALE; | ||
180 | } else if (PageUptodate(monitor->back_page)) { | ||
178 | copy_highpage(monitor->netfs_page, monitor->back_page); | 181 | copy_highpage(monitor->netfs_page, monitor->back_page); |
179 | 182 | fscache_mark_page_cached(monitor->op, | |
180 | pagevec_add(&pagevec, monitor->netfs_page); | 183 | monitor->netfs_page); |
181 | fscache_mark_pages_cached(monitor->op, &pagevec); | ||
182 | error = 0; | 184 | error = 0; |
183 | } else if (!PageError(monitor->back_page)) { | 185 | } else if (!PageError(monitor->back_page)) { |
184 | /* the page has probably been truncated */ | 186 | /* the page has probably been truncated */ |
@@ -198,6 +200,7 @@ static void cachefiles_read_copier(struct fscache_operation *_op) | |||
198 | 200 | ||
199 | fscache_end_io(op, monitor->netfs_page, error); | 201 | fscache_end_io(op, monitor->netfs_page, error); |
200 | page_cache_release(monitor->netfs_page); | 202 | page_cache_release(monitor->netfs_page); |
203 | fscache_retrieval_complete(op, 1); | ||
201 | fscache_put_retrieval(op); | 204 | fscache_put_retrieval(op); |
202 | kfree(monitor); | 205 | kfree(monitor); |
203 | 206 | ||
@@ -239,7 +242,7 @@ static int cachefiles_read_backing_file_one(struct cachefiles_object *object, | |||
239 | _debug("read back %p{%lu,%d}", | 242 | _debug("read back %p{%lu,%d}", |
240 | netpage, netpage->index, page_count(netpage)); | 243 | netpage, netpage->index, page_count(netpage)); |
241 | 244 | ||
242 | monitor = kzalloc(sizeof(*monitor), GFP_KERNEL); | 245 | monitor = kzalloc(sizeof(*monitor), cachefiles_gfp); |
243 | if (!monitor) | 246 | if (!monitor) |
244 | goto nomem; | 247 | goto nomem; |
245 | 248 | ||
@@ -258,13 +261,14 @@ static int cachefiles_read_backing_file_one(struct cachefiles_object *object, | |||
258 | goto backing_page_already_present; | 261 | goto backing_page_already_present; |
259 | 262 | ||
260 | if (!newpage) { | 263 | if (!newpage) { |
261 | newpage = page_cache_alloc_cold(bmapping); | 264 | newpage = __page_cache_alloc(cachefiles_gfp | |
265 | __GFP_COLD); | ||
262 | if (!newpage) | 266 | if (!newpage) |
263 | goto nomem_monitor; | 267 | goto nomem_monitor; |
264 | } | 268 | } |
265 | 269 | ||
266 | ret = add_to_page_cache(newpage, bmapping, | 270 | ret = add_to_page_cache(newpage, bmapping, |
267 | netpage->index, GFP_KERNEL); | 271 | netpage->index, cachefiles_gfp); |
268 | if (ret == 0) | 272 | if (ret == 0) |
269 | goto installed_new_backing_page; | 273 | goto installed_new_backing_page; |
270 | if (ret != -EEXIST) | 274 | if (ret != -EEXIST) |
@@ -335,11 +339,11 @@ backing_page_already_present: | |||
335 | backing_page_already_uptodate: | 339 | backing_page_already_uptodate: |
336 | _debug("- uptodate"); | 340 | _debug("- uptodate"); |
337 | 341 | ||
338 | pagevec_add(pagevec, netpage); | 342 | fscache_mark_page_cached(op, netpage); |
339 | fscache_mark_pages_cached(op, pagevec); | ||
340 | 343 | ||
341 | copy_highpage(netpage, backpage); | 344 | copy_highpage(netpage, backpage); |
342 | fscache_end_io(op, netpage, 0); | 345 | fscache_end_io(op, netpage, 0); |
346 | fscache_retrieval_complete(op, 1); | ||
343 | 347 | ||
344 | success: | 348 | success: |
345 | _debug("success"); | 349 | _debug("success"); |
@@ -357,10 +361,13 @@ out: | |||
357 | 361 | ||
358 | read_error: | 362 | read_error: |
359 | _debug("read error %d", ret); | 363 | _debug("read error %d", ret); |
360 | if (ret == -ENOMEM) | 364 | if (ret == -ENOMEM) { |
365 | fscache_retrieval_complete(op, 1); | ||
361 | goto out; | 366 | goto out; |
367 | } | ||
362 | io_error: | 368 | io_error: |
363 | cachefiles_io_error_obj(object, "Page read error on backing file"); | 369 | cachefiles_io_error_obj(object, "Page read error on backing file"); |
370 | fscache_retrieval_complete(op, 1); | ||
364 | ret = -ENOBUFS; | 371 | ret = -ENOBUFS; |
365 | goto out; | 372 | goto out; |
366 | 373 | ||
@@ -370,6 +377,7 @@ nomem_monitor: | |||
370 | fscache_put_retrieval(monitor->op); | 377 | fscache_put_retrieval(monitor->op); |
371 | kfree(monitor); | 378 | kfree(monitor); |
372 | nomem: | 379 | nomem: |
380 | fscache_retrieval_complete(op, 1); | ||
373 | _leave(" = -ENOMEM"); | 381 | _leave(" = -ENOMEM"); |
374 | return -ENOMEM; | 382 | return -ENOMEM; |
375 | } | 383 | } |
@@ -408,7 +416,7 @@ int cachefiles_read_or_alloc_page(struct fscache_retrieval *op, | |||
408 | _enter("{%p},{%lx},,,", object, page->index); | 416 | _enter("{%p},{%lx},,,", object, page->index); |
409 | 417 | ||
410 | if (!object->backer) | 418 | if (!object->backer) |
411 | return -ENOBUFS; | 419 | goto enobufs; |
412 | 420 | ||
413 | inode = object->backer->d_inode; | 421 | inode = object->backer->d_inode; |
414 | ASSERT(S_ISREG(inode->i_mode)); | 422 | ASSERT(S_ISREG(inode->i_mode)); |
@@ -417,7 +425,7 @@ int cachefiles_read_or_alloc_page(struct fscache_retrieval *op, | |||
417 | 425 | ||
418 | /* calculate the shift required to use bmap */ | 426 | /* calculate the shift required to use bmap */ |
419 | if (inode->i_sb->s_blocksize > PAGE_SIZE) | 427 | if (inode->i_sb->s_blocksize > PAGE_SIZE) |
420 | return -ENOBUFS; | 428 | goto enobufs; |
421 | 429 | ||
422 | shift = PAGE_SHIFT - inode->i_sb->s_blocksize_bits; | 430 | shift = PAGE_SHIFT - inode->i_sb->s_blocksize_bits; |
423 | 431 | ||
@@ -448,15 +456,20 @@ int cachefiles_read_or_alloc_page(struct fscache_retrieval *op, | |||
448 | &pagevec); | 456 | &pagevec); |
449 | } else if (cachefiles_has_space(cache, 0, 1) == 0) { | 457 | } else if (cachefiles_has_space(cache, 0, 1) == 0) { |
450 | /* there's space in the cache we can use */ | 458 | /* there's space in the cache we can use */ |
451 | pagevec_add(&pagevec, page); | 459 | fscache_mark_page_cached(op, page); |
452 | fscache_mark_pages_cached(op, &pagevec); | 460 | fscache_retrieval_complete(op, 1); |
453 | ret = -ENODATA; | 461 | ret = -ENODATA; |
454 | } else { | 462 | } else { |
455 | ret = -ENOBUFS; | 463 | goto enobufs; |
456 | } | 464 | } |
457 | 465 | ||
458 | _leave(" = %d", ret); | 466 | _leave(" = %d", ret); |
459 | return ret; | 467 | return ret; |
468 | |||
469 | enobufs: | ||
470 | fscache_retrieval_complete(op, 1); | ||
471 | _leave(" = -ENOBUFS"); | ||
472 | return -ENOBUFS; | ||
460 | } | 473 | } |
461 | 474 | ||
462 | /* | 475 | /* |
@@ -465,8 +478,7 @@ int cachefiles_read_or_alloc_page(struct fscache_retrieval *op, | |||
465 | */ | 478 | */ |
466 | static int cachefiles_read_backing_file(struct cachefiles_object *object, | 479 | static int cachefiles_read_backing_file(struct cachefiles_object *object, |
467 | struct fscache_retrieval *op, | 480 | struct fscache_retrieval *op, |
468 | struct list_head *list, | 481 | struct list_head *list) |
469 | struct pagevec *mark_pvec) | ||
470 | { | 482 | { |
471 | struct cachefiles_one_read *monitor = NULL; | 483 | struct cachefiles_one_read *monitor = NULL; |
472 | struct address_space *bmapping = object->backer->d_inode->i_mapping; | 484 | struct address_space *bmapping = object->backer->d_inode->i_mapping; |
@@ -485,7 +497,7 @@ static int cachefiles_read_backing_file(struct cachefiles_object *object, | |||
485 | netpage, netpage->index, page_count(netpage)); | 497 | netpage, netpage->index, page_count(netpage)); |
486 | 498 | ||
487 | if (!monitor) { | 499 | if (!monitor) { |
488 | monitor = kzalloc(sizeof(*monitor), GFP_KERNEL); | 500 | monitor = kzalloc(sizeof(*monitor), cachefiles_gfp); |
489 | if (!monitor) | 501 | if (!monitor) |
490 | goto nomem; | 502 | goto nomem; |
491 | 503 | ||
@@ -500,13 +512,14 @@ static int cachefiles_read_backing_file(struct cachefiles_object *object, | |||
500 | goto backing_page_already_present; | 512 | goto backing_page_already_present; |
501 | 513 | ||
502 | if (!newpage) { | 514 | if (!newpage) { |
503 | newpage = page_cache_alloc_cold(bmapping); | 515 | newpage = __page_cache_alloc(cachefiles_gfp | |
516 | __GFP_COLD); | ||
504 | if (!newpage) | 517 | if (!newpage) |
505 | goto nomem; | 518 | goto nomem; |
506 | } | 519 | } |
507 | 520 | ||
508 | ret = add_to_page_cache(newpage, bmapping, | 521 | ret = add_to_page_cache(newpage, bmapping, |
509 | netpage->index, GFP_KERNEL); | 522 | netpage->index, cachefiles_gfp); |
510 | if (ret == 0) | 523 | if (ret == 0) |
511 | goto installed_new_backing_page; | 524 | goto installed_new_backing_page; |
512 | if (ret != -EEXIST) | 525 | if (ret != -EEXIST) |
@@ -536,10 +549,11 @@ static int cachefiles_read_backing_file(struct cachefiles_object *object, | |||
536 | _debug("- monitor add"); | 549 | _debug("- monitor add"); |
537 | 550 | ||
538 | ret = add_to_page_cache(netpage, op->mapping, netpage->index, | 551 | ret = add_to_page_cache(netpage, op->mapping, netpage->index, |
539 | GFP_KERNEL); | 552 | cachefiles_gfp); |
540 | if (ret < 0) { | 553 | if (ret < 0) { |
541 | if (ret == -EEXIST) { | 554 | if (ret == -EEXIST) { |
542 | page_cache_release(netpage); | 555 | page_cache_release(netpage); |
556 | fscache_retrieval_complete(op, 1); | ||
543 | continue; | 557 | continue; |
544 | } | 558 | } |
545 | goto nomem; | 559 | goto nomem; |
@@ -612,10 +626,11 @@ static int cachefiles_read_backing_file(struct cachefiles_object *object, | |||
612 | _debug("- uptodate"); | 626 | _debug("- uptodate"); |
613 | 627 | ||
614 | ret = add_to_page_cache(netpage, op->mapping, netpage->index, | 628 | ret = add_to_page_cache(netpage, op->mapping, netpage->index, |
615 | GFP_KERNEL); | 629 | cachefiles_gfp); |
616 | if (ret < 0) { | 630 | if (ret < 0) { |
617 | if (ret == -EEXIST) { | 631 | if (ret == -EEXIST) { |
618 | page_cache_release(netpage); | 632 | page_cache_release(netpage); |
633 | fscache_retrieval_complete(op, 1); | ||
619 | continue; | 634 | continue; |
620 | } | 635 | } |
621 | goto nomem; | 636 | goto nomem; |
@@ -626,16 +641,17 @@ static int cachefiles_read_backing_file(struct cachefiles_object *object, | |||
626 | page_cache_release(backpage); | 641 | page_cache_release(backpage); |
627 | backpage = NULL; | 642 | backpage = NULL; |
628 | 643 | ||
629 | if (!pagevec_add(mark_pvec, netpage)) | 644 | fscache_mark_page_cached(op, netpage); |
630 | fscache_mark_pages_cached(op, mark_pvec); | ||
631 | 645 | ||
632 | page_cache_get(netpage); | 646 | page_cache_get(netpage); |
633 | if (!pagevec_add(&lru_pvec, netpage)) | 647 | if (!pagevec_add(&lru_pvec, netpage)) |
634 | __pagevec_lru_add_file(&lru_pvec); | 648 | __pagevec_lru_add_file(&lru_pvec); |
635 | 649 | ||
650 | /* the netpage is unlocked and marked up to date here */ | ||
636 | fscache_end_io(op, netpage, 0); | 651 | fscache_end_io(op, netpage, 0); |
637 | page_cache_release(netpage); | 652 | page_cache_release(netpage); |
638 | netpage = NULL; | 653 | netpage = NULL; |
654 | fscache_retrieval_complete(op, 1); | ||
639 | continue; | 655 | continue; |
640 | } | 656 | } |
641 | 657 | ||
@@ -661,6 +677,7 @@ out: | |||
661 | list_for_each_entry_safe(netpage, _n, list, lru) { | 677 | list_for_each_entry_safe(netpage, _n, list, lru) { |
662 | list_del(&netpage->lru); | 678 | list_del(&netpage->lru); |
663 | page_cache_release(netpage); | 679 | page_cache_release(netpage); |
680 | fscache_retrieval_complete(op, 1); | ||
664 | } | 681 | } |
665 | 682 | ||
666 | _leave(" = %d", ret); | 683 | _leave(" = %d", ret); |
@@ -669,15 +686,17 @@ out: | |||
669 | nomem: | 686 | nomem: |
670 | _debug("nomem"); | 687 | _debug("nomem"); |
671 | ret = -ENOMEM; | 688 | ret = -ENOMEM; |
672 | goto out; | 689 | goto record_page_complete; |
673 | 690 | ||
674 | read_error: | 691 | read_error: |
675 | _debug("read error %d", ret); | 692 | _debug("read error %d", ret); |
676 | if (ret == -ENOMEM) | 693 | if (ret == -ENOMEM) |
677 | goto out; | 694 | goto record_page_complete; |
678 | io_error: | 695 | io_error: |
679 | cachefiles_io_error_obj(object, "Page read error on backing file"); | 696 | cachefiles_io_error_obj(object, "Page read error on backing file"); |
680 | ret = -ENOBUFS; | 697 | ret = -ENOBUFS; |
698 | record_page_complete: | ||
699 | fscache_retrieval_complete(op, 1); | ||
681 | goto out; | 700 | goto out; |
682 | } | 701 | } |
683 | 702 | ||
@@ -709,7 +728,7 @@ int cachefiles_read_or_alloc_pages(struct fscache_retrieval *op, | |||
709 | *nr_pages); | 728 | *nr_pages); |
710 | 729 | ||
711 | if (!object->backer) | 730 | if (!object->backer) |
712 | return -ENOBUFS; | 731 | goto all_enobufs; |
713 | 732 | ||
714 | space = 1; | 733 | space = 1; |
715 | if (cachefiles_has_space(cache, 0, *nr_pages) < 0) | 734 | if (cachefiles_has_space(cache, 0, *nr_pages) < 0) |
@@ -722,7 +741,7 @@ int cachefiles_read_or_alloc_pages(struct fscache_retrieval *op, | |||
722 | 741 | ||
723 | /* calculate the shift required to use bmap */ | 742 | /* calculate the shift required to use bmap */ |
724 | if (inode->i_sb->s_blocksize > PAGE_SIZE) | 743 | if (inode->i_sb->s_blocksize > PAGE_SIZE) |
725 | return -ENOBUFS; | 744 | goto all_enobufs; |
726 | 745 | ||
727 | shift = PAGE_SHIFT - inode->i_sb->s_blocksize_bits; | 746 | shift = PAGE_SHIFT - inode->i_sb->s_blocksize_bits; |
728 | 747 | ||
@@ -762,7 +781,10 @@ int cachefiles_read_or_alloc_pages(struct fscache_retrieval *op, | |||
762 | nrbackpages++; | 781 | nrbackpages++; |
763 | } else if (space && pagevec_add(&pagevec, page) == 0) { | 782 | } else if (space && pagevec_add(&pagevec, page) == 0) { |
764 | fscache_mark_pages_cached(op, &pagevec); | 783 | fscache_mark_pages_cached(op, &pagevec); |
784 | fscache_retrieval_complete(op, 1); | ||
765 | ret = -ENODATA; | 785 | ret = -ENODATA; |
786 | } else { | ||
787 | fscache_retrieval_complete(op, 1); | ||
766 | } | 788 | } |
767 | } | 789 | } |
768 | 790 | ||
@@ -775,18 +797,18 @@ int cachefiles_read_or_alloc_pages(struct fscache_retrieval *op, | |||
775 | /* submit the apparently valid pages to the backing fs to be read from | 797 | /* submit the apparently valid pages to the backing fs to be read from |
776 | * disk */ | 798 | * disk */ |
777 | if (nrbackpages > 0) { | 799 | if (nrbackpages > 0) { |
778 | ret2 = cachefiles_read_backing_file(object, op, &backpages, | 800 | ret2 = cachefiles_read_backing_file(object, op, &backpages); |
779 | &pagevec); | ||
780 | if (ret2 == -ENOMEM || ret2 == -EINTR) | 801 | if (ret2 == -ENOMEM || ret2 == -EINTR) |
781 | ret = ret2; | 802 | ret = ret2; |
782 | } | 803 | } |
783 | 804 | ||
784 | if (pagevec_count(&pagevec) > 0) | ||
785 | fscache_mark_pages_cached(op, &pagevec); | ||
786 | |||
787 | _leave(" = %d [nr=%u%s]", | 805 | _leave(" = %d [nr=%u%s]", |
788 | ret, *nr_pages, list_empty(pages) ? " empty" : ""); | 806 | ret, *nr_pages, list_empty(pages) ? " empty" : ""); |
789 | return ret; | 807 | return ret; |
808 | |||
809 | all_enobufs: | ||
810 | fscache_retrieval_complete(op, *nr_pages); | ||
811 | return -ENOBUFS; | ||
790 | } | 812 | } |
791 | 813 | ||
792 | /* | 814 | /* |
@@ -806,7 +828,6 @@ int cachefiles_allocate_page(struct fscache_retrieval *op, | |||
806 | { | 828 | { |
807 | struct cachefiles_object *object; | 829 | struct cachefiles_object *object; |
808 | struct cachefiles_cache *cache; | 830 | struct cachefiles_cache *cache; |
809 | struct pagevec pagevec; | ||
810 | int ret; | 831 | int ret; |
811 | 832 | ||
812 | object = container_of(op->op.object, | 833 | object = container_of(op->op.object, |
@@ -817,14 +838,12 @@ int cachefiles_allocate_page(struct fscache_retrieval *op, | |||
817 | _enter("%p,{%lx},", object, page->index); | 838 | _enter("%p,{%lx},", object, page->index); |
818 | 839 | ||
819 | ret = cachefiles_has_space(cache, 0, 1); | 840 | ret = cachefiles_has_space(cache, 0, 1); |
820 | if (ret == 0) { | 841 | if (ret == 0) |
821 | pagevec_init(&pagevec, 0); | 842 | fscache_mark_page_cached(op, page); |
822 | pagevec_add(&pagevec, page); | 843 | else |
823 | fscache_mark_pages_cached(op, &pagevec); | ||
824 | } else { | ||
825 | ret = -ENOBUFS; | 844 | ret = -ENOBUFS; |
826 | } | ||
827 | 845 | ||
846 | fscache_retrieval_complete(op, 1); | ||
828 | _leave(" = %d", ret); | 847 | _leave(" = %d", ret); |
829 | return ret; | 848 | return ret; |
830 | } | 849 | } |
@@ -874,6 +893,7 @@ int cachefiles_allocate_pages(struct fscache_retrieval *op, | |||
874 | ret = -ENOBUFS; | 893 | ret = -ENOBUFS; |
875 | } | 894 | } |
876 | 895 | ||
896 | fscache_retrieval_complete(op, *nr_pages); | ||
877 | _leave(" = %d", ret); | 897 | _leave(" = %d", ret); |
878 | return ret; | 898 | return ret; |
879 | } | 899 | } |
diff --git a/fs/cachefiles/xattr.c b/fs/cachefiles/xattr.c index e18b183b47e1..73b46288b54b 100644 --- a/fs/cachefiles/xattr.c +++ b/fs/cachefiles/xattr.c | |||
@@ -174,7 +174,7 @@ int cachefiles_check_object_xattr(struct cachefiles_object *object, | |||
174 | ASSERT(dentry); | 174 | ASSERT(dentry); |
175 | ASSERT(dentry->d_inode); | 175 | ASSERT(dentry->d_inode); |
176 | 176 | ||
177 | auxbuf = kmalloc(sizeof(struct cachefiles_xattr) + 512, GFP_KERNEL); | 177 | auxbuf = kmalloc(sizeof(struct cachefiles_xattr) + 512, cachefiles_gfp); |
178 | if (!auxbuf) { | 178 | if (!auxbuf) { |
179 | _leave(" = -ENOMEM"); | 179 | _leave(" = -ENOMEM"); |
180 | return -ENOMEM; | 180 | return -ENOMEM; |
diff --git a/fs/dcache.c b/fs/dcache.c index 3a463d0c4fe8..19153a0a810c 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
@@ -455,24 +455,6 @@ void d_drop(struct dentry *dentry) | |||
455 | EXPORT_SYMBOL(d_drop); | 455 | EXPORT_SYMBOL(d_drop); |
456 | 456 | ||
457 | /* | 457 | /* |
458 | * d_clear_need_lookup - drop a dentry from cache and clear the need lookup flag | ||
459 | * @dentry: dentry to drop | ||
460 | * | ||
461 | * This is called when we do a lookup on a placeholder dentry that needed to be | ||
462 | * looked up. The dentry should have been hashed in order for it to be found by | ||
463 | * the lookup code, but now needs to be unhashed while we do the actual lookup | ||
464 | * and clear the DCACHE_NEED_LOOKUP flag. | ||
465 | */ | ||
466 | void d_clear_need_lookup(struct dentry *dentry) | ||
467 | { | ||
468 | spin_lock(&dentry->d_lock); | ||
469 | __d_drop(dentry); | ||
470 | dentry->d_flags &= ~DCACHE_NEED_LOOKUP; | ||
471 | spin_unlock(&dentry->d_lock); | ||
472 | } | ||
473 | EXPORT_SYMBOL(d_clear_need_lookup); | ||
474 | |||
475 | /* | ||
476 | * Finish off a dentry we've decided to kill. | 458 | * Finish off a dentry we've decided to kill. |
477 | * dentry->d_lock must be held, returns with it unlocked. | 459 | * dentry->d_lock must be held, returns with it unlocked. |
478 | * If ref is non-zero, then decrement the refcount too. | 460 | * If ref is non-zero, then decrement the refcount too. |
@@ -565,13 +547,7 @@ repeat: | |||
565 | if (d_unhashed(dentry)) | 547 | if (d_unhashed(dentry)) |
566 | goto kill_it; | 548 | goto kill_it; |
567 | 549 | ||
568 | /* | 550 | dentry->d_flags |= DCACHE_REFERENCED; |
569 | * If this dentry needs lookup, don't set the referenced flag so that it | ||
570 | * is more likely to be cleaned up by the dcache shrinker in case of | ||
571 | * memory pressure. | ||
572 | */ | ||
573 | if (!d_need_lookup(dentry)) | ||
574 | dentry->d_flags |= DCACHE_REFERENCED; | ||
575 | dentry_lru_add(dentry); | 551 | dentry_lru_add(dentry); |
576 | 552 | ||
577 | dentry->d_count--; | 553 | dentry->d_count--; |
@@ -1583,7 +1559,7 @@ EXPORT_SYMBOL(d_find_any_alias); | |||
1583 | */ | 1559 | */ |
1584 | struct dentry *d_obtain_alias(struct inode *inode) | 1560 | struct dentry *d_obtain_alias(struct inode *inode) |
1585 | { | 1561 | { |
1586 | static const struct qstr anonstring = { .name = "" }; | 1562 | static const struct qstr anonstring = QSTR_INIT("/", 1); |
1587 | struct dentry *tmp; | 1563 | struct dentry *tmp; |
1588 | struct dentry *res; | 1564 | struct dentry *res; |
1589 | 1565 | ||
@@ -1737,13 +1713,6 @@ struct dentry *d_add_ci(struct dentry *dentry, struct inode *inode, | |||
1737 | } | 1713 | } |
1738 | 1714 | ||
1739 | /* | 1715 | /* |
1740 | * We are going to instantiate this dentry, unhash it and clear the | ||
1741 | * lookup flag so we can do that. | ||
1742 | */ | ||
1743 | if (unlikely(d_need_lookup(found))) | ||
1744 | d_clear_need_lookup(found); | ||
1745 | |||
1746 | /* | ||
1747 | * Negative dentry: instantiate it unless the inode is a directory and | 1716 | * Negative dentry: instantiate it unless the inode is a directory and |
1748 | * already has a dentry. | 1717 | * already has a dentry. |
1749 | */ | 1718 | */ |
diff --git a/fs/file_table.c b/fs/file_table.c index a72bf9ddd0d2..de9e9653d611 100644 --- a/fs/file_table.c +++ b/fs/file_table.c | |||
@@ -458,8 +458,8 @@ void mark_files_ro(struct super_block *sb) | |||
458 | spin_unlock(&f->f_lock); | 458 | spin_unlock(&f->f_lock); |
459 | if (file_check_writeable(f) != 0) | 459 | if (file_check_writeable(f) != 0) |
460 | continue; | 460 | continue; |
461 | __mnt_drop_write(f->f_path.mnt); | ||
461 | file_release_write(f); | 462 | file_release_write(f); |
462 | mnt_drop_write_file(f); | ||
463 | } while_file_list_for_each_entry; | 463 | } while_file_list_for_each_entry; |
464 | lg_global_unlock(&files_lglock); | 464 | lg_global_unlock(&files_lglock); |
465 | } | 465 | } |
diff --git a/fs/fscache/cache.c b/fs/fscache/cache.c index 6a3c48abd677..b52aed1dca97 100644 --- a/fs/fscache/cache.c +++ b/fs/fscache/cache.c | |||
@@ -314,10 +314,10 @@ EXPORT_SYMBOL(fscache_add_cache); | |||
314 | */ | 314 | */ |
315 | void fscache_io_error(struct fscache_cache *cache) | 315 | void fscache_io_error(struct fscache_cache *cache) |
316 | { | 316 | { |
317 | set_bit(FSCACHE_IOERROR, &cache->flags); | 317 | if (!test_and_set_bit(FSCACHE_IOERROR, &cache->flags)) |
318 | 318 | printk(KERN_ERR "FS-Cache:" | |
319 | printk(KERN_ERR "FS-Cache: Cache %s stopped due to I/O error\n", | 319 | " Cache '%s' stopped due to I/O error\n", |
320 | cache->ops->name); | 320 | cache->ops->name); |
321 | } | 321 | } |
322 | EXPORT_SYMBOL(fscache_io_error); | 322 | EXPORT_SYMBOL(fscache_io_error); |
323 | 323 | ||
diff --git a/fs/fscache/cookie.c b/fs/fscache/cookie.c index 990535071a8a..8dcb114758e3 100644 --- a/fs/fscache/cookie.c +++ b/fs/fscache/cookie.c | |||
@@ -370,6 +370,66 @@ cant_attach_object: | |||
370 | } | 370 | } |
371 | 371 | ||
372 | /* | 372 | /* |
373 | * Invalidate an object. Callable with spinlocks held. | ||
374 | */ | ||
375 | void __fscache_invalidate(struct fscache_cookie *cookie) | ||
376 | { | ||
377 | struct fscache_object *object; | ||
378 | |||
379 | _enter("{%s}", cookie->def->name); | ||
380 | |||
381 | fscache_stat(&fscache_n_invalidates); | ||
382 | |||
383 | /* Only permit invalidation of data files. Invalidating an index will | ||
384 | * require the caller to release all its attachments to the tree rooted | ||
385 | * there, and if it's doing that, it may as well just retire the | ||
386 | * cookie. | ||
387 | */ | ||
388 | ASSERTCMP(cookie->def->type, ==, FSCACHE_COOKIE_TYPE_DATAFILE); | ||
389 | |||
390 | /* We will be updating the cookie too. */ | ||
391 | BUG_ON(!cookie->def->get_aux); | ||
392 | |||
393 | /* If there's an object, we tell the object state machine to handle the | ||
394 | * invalidation on our behalf, otherwise there's nothing to do. | ||
395 | */ | ||
396 | if (!hlist_empty(&cookie->backing_objects)) { | ||
397 | spin_lock(&cookie->lock); | ||
398 | |||
399 | if (!hlist_empty(&cookie->backing_objects) && | ||
400 | !test_and_set_bit(FSCACHE_COOKIE_INVALIDATING, | ||
401 | &cookie->flags)) { | ||
402 | object = hlist_entry(cookie->backing_objects.first, | ||
403 | struct fscache_object, | ||
404 | cookie_link); | ||
405 | if (object->state < FSCACHE_OBJECT_DYING) | ||
406 | fscache_raise_event( | ||
407 | object, FSCACHE_OBJECT_EV_INVALIDATE); | ||
408 | } | ||
409 | |||
410 | spin_unlock(&cookie->lock); | ||
411 | } | ||
412 | |||
413 | _leave(""); | ||
414 | } | ||
415 | EXPORT_SYMBOL(__fscache_invalidate); | ||
416 | |||
417 | /* | ||
418 | * Wait for object invalidation to complete. | ||
419 | */ | ||
420 | void __fscache_wait_on_invalidate(struct fscache_cookie *cookie) | ||
421 | { | ||
422 | _enter("%p", cookie); | ||
423 | |||
424 | wait_on_bit(&cookie->flags, FSCACHE_COOKIE_INVALIDATING, | ||
425 | fscache_wait_bit_interruptible, | ||
426 | TASK_UNINTERRUPTIBLE); | ||
427 | |||
428 | _leave(""); | ||
429 | } | ||
430 | EXPORT_SYMBOL(__fscache_wait_on_invalidate); | ||
431 | |||
432 | /* | ||
373 | * update the index entries backing a cookie | 433 | * update the index entries backing a cookie |
374 | */ | 434 | */ |
375 | void __fscache_update_cookie(struct fscache_cookie *cookie) | 435 | void __fscache_update_cookie(struct fscache_cookie *cookie) |
@@ -442,16 +502,34 @@ void __fscache_relinquish_cookie(struct fscache_cookie *cookie, int retire) | |||
442 | 502 | ||
443 | event = retire ? FSCACHE_OBJECT_EV_RETIRE : FSCACHE_OBJECT_EV_RELEASE; | 503 | event = retire ? FSCACHE_OBJECT_EV_RETIRE : FSCACHE_OBJECT_EV_RELEASE; |
444 | 504 | ||
505 | try_again: | ||
445 | spin_lock(&cookie->lock); | 506 | spin_lock(&cookie->lock); |
446 | 507 | ||
447 | /* break links with all the active objects */ | 508 | /* break links with all the active objects */ |
448 | while (!hlist_empty(&cookie->backing_objects)) { | 509 | while (!hlist_empty(&cookie->backing_objects)) { |
510 | int n_reads; | ||
449 | object = hlist_entry(cookie->backing_objects.first, | 511 | object = hlist_entry(cookie->backing_objects.first, |
450 | struct fscache_object, | 512 | struct fscache_object, |
451 | cookie_link); | 513 | cookie_link); |
452 | 514 | ||
453 | _debug("RELEASE OBJ%x", object->debug_id); | 515 | _debug("RELEASE OBJ%x", object->debug_id); |
454 | 516 | ||
517 | set_bit(FSCACHE_COOKIE_WAITING_ON_READS, &cookie->flags); | ||
518 | n_reads = atomic_read(&object->n_reads); | ||
519 | if (n_reads) { | ||
520 | int n_ops = object->n_ops; | ||
521 | int n_in_progress = object->n_in_progress; | ||
522 | spin_unlock(&cookie->lock); | ||
523 | printk(KERN_ERR "FS-Cache:" | ||
524 | " Cookie '%s' still has %d outstanding reads (%d,%d)\n", | ||
525 | cookie->def->name, | ||
526 | n_reads, n_ops, n_in_progress); | ||
527 | wait_on_bit(&cookie->flags, FSCACHE_COOKIE_WAITING_ON_READS, | ||
528 | fscache_wait_bit, TASK_UNINTERRUPTIBLE); | ||
529 | printk("Wait finished\n"); | ||
530 | goto try_again; | ||
531 | } | ||
532 | |||
455 | /* detach each cache object from the object cookie */ | 533 | /* detach each cache object from the object cookie */ |
456 | spin_lock(&object->lock); | 534 | spin_lock(&object->lock); |
457 | hlist_del_init(&object->cookie_link); | 535 | hlist_del_init(&object->cookie_link); |
diff --git a/fs/fscache/internal.h b/fs/fscache/internal.h index f6aad48d38a8..ee38fef4be51 100644 --- a/fs/fscache/internal.h +++ b/fs/fscache/internal.h | |||
@@ -121,12 +121,19 @@ extern int fscache_submit_exclusive_op(struct fscache_object *, | |||
121 | struct fscache_operation *); | 121 | struct fscache_operation *); |
122 | extern int fscache_submit_op(struct fscache_object *, | 122 | extern int fscache_submit_op(struct fscache_object *, |
123 | struct fscache_operation *); | 123 | struct fscache_operation *); |
124 | extern int fscache_cancel_op(struct fscache_operation *); | 124 | extern int fscache_cancel_op(struct fscache_operation *, |
125 | void (*)(struct fscache_operation *)); | ||
126 | extern void fscache_cancel_all_ops(struct fscache_object *); | ||
125 | extern void fscache_abort_object(struct fscache_object *); | 127 | extern void fscache_abort_object(struct fscache_object *); |
126 | extern void fscache_start_operations(struct fscache_object *); | 128 | extern void fscache_start_operations(struct fscache_object *); |
127 | extern void fscache_operation_gc(struct work_struct *); | 129 | extern void fscache_operation_gc(struct work_struct *); |
128 | 130 | ||
129 | /* | 131 | /* |
132 | * page.c | ||
133 | */ | ||
134 | extern void fscache_invalidate_writes(struct fscache_cookie *); | ||
135 | |||
136 | /* | ||
130 | * proc.c | 137 | * proc.c |
131 | */ | 138 | */ |
132 | #ifdef CONFIG_PROC_FS | 139 | #ifdef CONFIG_PROC_FS |
@@ -194,6 +201,7 @@ extern atomic_t fscache_n_store_vmscan_not_storing; | |||
194 | extern atomic_t fscache_n_store_vmscan_gone; | 201 | extern atomic_t fscache_n_store_vmscan_gone; |
195 | extern atomic_t fscache_n_store_vmscan_busy; | 202 | extern atomic_t fscache_n_store_vmscan_busy; |
196 | extern atomic_t fscache_n_store_vmscan_cancelled; | 203 | extern atomic_t fscache_n_store_vmscan_cancelled; |
204 | extern atomic_t fscache_n_store_vmscan_wait; | ||
197 | 205 | ||
198 | extern atomic_t fscache_n_marks; | 206 | extern atomic_t fscache_n_marks; |
199 | extern atomic_t fscache_n_uncaches; | 207 | extern atomic_t fscache_n_uncaches; |
@@ -205,6 +213,9 @@ extern atomic_t fscache_n_acquires_ok; | |||
205 | extern atomic_t fscache_n_acquires_nobufs; | 213 | extern atomic_t fscache_n_acquires_nobufs; |
206 | extern atomic_t fscache_n_acquires_oom; | 214 | extern atomic_t fscache_n_acquires_oom; |
207 | 215 | ||
216 | extern atomic_t fscache_n_invalidates; | ||
217 | extern atomic_t fscache_n_invalidates_run; | ||
218 | |||
208 | extern atomic_t fscache_n_updates; | 219 | extern atomic_t fscache_n_updates; |
209 | extern atomic_t fscache_n_updates_null; | 220 | extern atomic_t fscache_n_updates_null; |
210 | extern atomic_t fscache_n_updates_run; | 221 | extern atomic_t fscache_n_updates_run; |
@@ -237,6 +248,7 @@ extern atomic_t fscache_n_cop_alloc_object; | |||
237 | extern atomic_t fscache_n_cop_lookup_object; | 248 | extern atomic_t fscache_n_cop_lookup_object; |
238 | extern atomic_t fscache_n_cop_lookup_complete; | 249 | extern atomic_t fscache_n_cop_lookup_complete; |
239 | extern atomic_t fscache_n_cop_grab_object; | 250 | extern atomic_t fscache_n_cop_grab_object; |
251 | extern atomic_t fscache_n_cop_invalidate_object; | ||
240 | extern atomic_t fscache_n_cop_update_object; | 252 | extern atomic_t fscache_n_cop_update_object; |
241 | extern atomic_t fscache_n_cop_drop_object; | 253 | extern atomic_t fscache_n_cop_drop_object; |
242 | extern atomic_t fscache_n_cop_put_object; | 254 | extern atomic_t fscache_n_cop_put_object; |
@@ -278,6 +290,7 @@ extern const struct file_operations fscache_stats_fops; | |||
278 | static inline void fscache_raise_event(struct fscache_object *object, | 290 | static inline void fscache_raise_event(struct fscache_object *object, |
279 | unsigned event) | 291 | unsigned event) |
280 | { | 292 | { |
293 | BUG_ON(event >= NR_FSCACHE_OBJECT_EVENTS); | ||
281 | if (!test_and_set_bit(event, &object->events) && | 294 | if (!test_and_set_bit(event, &object->events) && |
282 | test_bit(event, &object->event_mask)) | 295 | test_bit(event, &object->event_mask)) |
283 | fscache_enqueue_object(object); | 296 | fscache_enqueue_object(object); |
diff --git a/fs/fscache/object-list.c b/fs/fscache/object-list.c index ebe29c581380..f27c89d17885 100644 --- a/fs/fscache/object-list.c +++ b/fs/fscache/object-list.c | |||
@@ -245,7 +245,7 @@ static int fscache_objlist_show(struct seq_file *m, void *v) | |||
245 | obj->n_in_progress, | 245 | obj->n_in_progress, |
246 | obj->n_exclusive, | 246 | obj->n_exclusive, |
247 | atomic_read(&obj->n_reads), | 247 | atomic_read(&obj->n_reads), |
248 | obj->event_mask & FSCACHE_OBJECT_EVENTS_MASK, | 248 | obj->event_mask, |
249 | obj->events, | 249 | obj->events, |
250 | obj->flags, | 250 | obj->flags, |
251 | work_busy(&obj->work)); | 251 | work_busy(&obj->work)); |
diff --git a/fs/fscache/object.c b/fs/fscache/object.c index b6b897c550ac..50d41c180211 100644 --- a/fs/fscache/object.c +++ b/fs/fscache/object.c | |||
@@ -14,6 +14,7 @@ | |||
14 | 14 | ||
15 | #define FSCACHE_DEBUG_LEVEL COOKIE | 15 | #define FSCACHE_DEBUG_LEVEL COOKIE |
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/slab.h> | ||
17 | #include "internal.h" | 18 | #include "internal.h" |
18 | 19 | ||
19 | const char *fscache_object_states[FSCACHE_OBJECT__NSTATES] = { | 20 | const char *fscache_object_states[FSCACHE_OBJECT__NSTATES] = { |
@@ -22,6 +23,7 @@ const char *fscache_object_states[FSCACHE_OBJECT__NSTATES] = { | |||
22 | [FSCACHE_OBJECT_CREATING] = "OBJECT_CREATING", | 23 | [FSCACHE_OBJECT_CREATING] = "OBJECT_CREATING", |
23 | [FSCACHE_OBJECT_AVAILABLE] = "OBJECT_AVAILABLE", | 24 | [FSCACHE_OBJECT_AVAILABLE] = "OBJECT_AVAILABLE", |
24 | [FSCACHE_OBJECT_ACTIVE] = "OBJECT_ACTIVE", | 25 | [FSCACHE_OBJECT_ACTIVE] = "OBJECT_ACTIVE", |
26 | [FSCACHE_OBJECT_INVALIDATING] = "OBJECT_INVALIDATING", | ||
25 | [FSCACHE_OBJECT_UPDATING] = "OBJECT_UPDATING", | 27 | [FSCACHE_OBJECT_UPDATING] = "OBJECT_UPDATING", |
26 | [FSCACHE_OBJECT_DYING] = "OBJECT_DYING", | 28 | [FSCACHE_OBJECT_DYING] = "OBJECT_DYING", |
27 | [FSCACHE_OBJECT_LC_DYING] = "OBJECT_LC_DYING", | 29 | [FSCACHE_OBJECT_LC_DYING] = "OBJECT_LC_DYING", |
@@ -39,6 +41,7 @@ const char fscache_object_states_short[FSCACHE_OBJECT__NSTATES][5] = { | |||
39 | [FSCACHE_OBJECT_CREATING] = "CRTN", | 41 | [FSCACHE_OBJECT_CREATING] = "CRTN", |
40 | [FSCACHE_OBJECT_AVAILABLE] = "AVBL", | 42 | [FSCACHE_OBJECT_AVAILABLE] = "AVBL", |
41 | [FSCACHE_OBJECT_ACTIVE] = "ACTV", | 43 | [FSCACHE_OBJECT_ACTIVE] = "ACTV", |
44 | [FSCACHE_OBJECT_INVALIDATING] = "INVL", | ||
42 | [FSCACHE_OBJECT_UPDATING] = "UPDT", | 45 | [FSCACHE_OBJECT_UPDATING] = "UPDT", |
43 | [FSCACHE_OBJECT_DYING] = "DYNG", | 46 | [FSCACHE_OBJECT_DYING] = "DYNG", |
44 | [FSCACHE_OBJECT_LC_DYING] = "LCDY", | 47 | [FSCACHE_OBJECT_LC_DYING] = "LCDY", |
@@ -54,6 +57,7 @@ static void fscache_put_object(struct fscache_object *); | |||
54 | static void fscache_initialise_object(struct fscache_object *); | 57 | static void fscache_initialise_object(struct fscache_object *); |
55 | static void fscache_lookup_object(struct fscache_object *); | 58 | static void fscache_lookup_object(struct fscache_object *); |
56 | static void fscache_object_available(struct fscache_object *); | 59 | static void fscache_object_available(struct fscache_object *); |
60 | static void fscache_invalidate_object(struct fscache_object *); | ||
57 | static void fscache_release_object(struct fscache_object *); | 61 | static void fscache_release_object(struct fscache_object *); |
58 | static void fscache_withdraw_object(struct fscache_object *); | 62 | static void fscache_withdraw_object(struct fscache_object *); |
59 | static void fscache_enqueue_dependents(struct fscache_object *); | 63 | static void fscache_enqueue_dependents(struct fscache_object *); |
@@ -79,6 +83,15 @@ static inline void fscache_done_parent_op(struct fscache_object *object) | |||
79 | } | 83 | } |
80 | 84 | ||
81 | /* | 85 | /* |
86 | * Notify netfs of invalidation completion. | ||
87 | */ | ||
88 | static inline void fscache_invalidation_complete(struct fscache_cookie *cookie) | ||
89 | { | ||
90 | if (test_and_clear_bit(FSCACHE_COOKIE_INVALIDATING, &cookie->flags)) | ||
91 | wake_up_bit(&cookie->flags, FSCACHE_COOKIE_INVALIDATING); | ||
92 | } | ||
93 | |||
94 | /* | ||
82 | * process events that have been sent to an object's state machine | 95 | * process events that have been sent to an object's state machine |
83 | * - initiates parent lookup | 96 | * - initiates parent lookup |
84 | * - does object lookup | 97 | * - does object lookup |
@@ -90,6 +103,7 @@ static void fscache_object_state_machine(struct fscache_object *object) | |||
90 | { | 103 | { |
91 | enum fscache_object_state new_state; | 104 | enum fscache_object_state new_state; |
92 | struct fscache_cookie *cookie; | 105 | struct fscache_cookie *cookie; |
106 | int event; | ||
93 | 107 | ||
94 | ASSERT(object != NULL); | 108 | ASSERT(object != NULL); |
95 | 109 | ||
@@ -101,7 +115,8 @@ static void fscache_object_state_machine(struct fscache_object *object) | |||
101 | /* wait for the parent object to become ready */ | 115 | /* wait for the parent object to become ready */ |
102 | case FSCACHE_OBJECT_INIT: | 116 | case FSCACHE_OBJECT_INIT: |
103 | object->event_mask = | 117 | object->event_mask = |
104 | ULONG_MAX & ~(1 << FSCACHE_OBJECT_EV_CLEARED); | 118 | FSCACHE_OBJECT_EVENTS_MASK & |
119 | ~(1 << FSCACHE_OBJECT_EV_CLEARED); | ||
105 | fscache_initialise_object(object); | 120 | fscache_initialise_object(object); |
106 | goto done; | 121 | goto done; |
107 | 122 | ||
@@ -125,6 +140,16 @@ static void fscache_object_state_machine(struct fscache_object *object) | |||
125 | case FSCACHE_OBJECT_ACTIVE: | 140 | case FSCACHE_OBJECT_ACTIVE: |
126 | goto active_transit; | 141 | goto active_transit; |
127 | 142 | ||
143 | /* Invalidate an object on disk */ | ||
144 | case FSCACHE_OBJECT_INVALIDATING: | ||
145 | clear_bit(FSCACHE_OBJECT_EV_INVALIDATE, &object->events); | ||
146 | fscache_stat(&fscache_n_invalidates_run); | ||
147 | fscache_stat(&fscache_n_cop_invalidate_object); | ||
148 | fscache_invalidate_object(object); | ||
149 | fscache_stat_d(&fscache_n_cop_invalidate_object); | ||
150 | fscache_raise_event(object, FSCACHE_OBJECT_EV_UPDATE); | ||
151 | goto active_transit; | ||
152 | |||
128 | /* update the object metadata on disk */ | 153 | /* update the object metadata on disk */ |
129 | case FSCACHE_OBJECT_UPDATING: | 154 | case FSCACHE_OBJECT_UPDATING: |
130 | clear_bit(FSCACHE_OBJECT_EV_UPDATE, &object->events); | 155 | clear_bit(FSCACHE_OBJECT_EV_UPDATE, &object->events); |
@@ -251,13 +276,17 @@ static void fscache_object_state_machine(struct fscache_object *object) | |||
251 | 276 | ||
252 | /* determine the transition from a lookup state */ | 277 | /* determine the transition from a lookup state */ |
253 | lookup_transit: | 278 | lookup_transit: |
254 | switch (fls(object->events & object->event_mask) - 1) { | 279 | event = fls(object->events & object->event_mask) - 1; |
280 | switch (event) { | ||
255 | case FSCACHE_OBJECT_EV_WITHDRAW: | 281 | case FSCACHE_OBJECT_EV_WITHDRAW: |
256 | case FSCACHE_OBJECT_EV_RETIRE: | 282 | case FSCACHE_OBJECT_EV_RETIRE: |
257 | case FSCACHE_OBJECT_EV_RELEASE: | 283 | case FSCACHE_OBJECT_EV_RELEASE: |
258 | case FSCACHE_OBJECT_EV_ERROR: | 284 | case FSCACHE_OBJECT_EV_ERROR: |
259 | new_state = FSCACHE_OBJECT_LC_DYING; | 285 | new_state = FSCACHE_OBJECT_LC_DYING; |
260 | goto change_state; | 286 | goto change_state; |
287 | case FSCACHE_OBJECT_EV_INVALIDATE: | ||
288 | new_state = FSCACHE_OBJECT_INVALIDATING; | ||
289 | goto change_state; | ||
261 | case FSCACHE_OBJECT_EV_REQUEUE: | 290 | case FSCACHE_OBJECT_EV_REQUEUE: |
262 | goto done; | 291 | goto done; |
263 | case -1: | 292 | case -1: |
@@ -268,13 +297,17 @@ lookup_transit: | |||
268 | 297 | ||
269 | /* determine the transition from an active state */ | 298 | /* determine the transition from an active state */ |
270 | active_transit: | 299 | active_transit: |
271 | switch (fls(object->events & object->event_mask) - 1) { | 300 | event = fls(object->events & object->event_mask) - 1; |
301 | switch (event) { | ||
272 | case FSCACHE_OBJECT_EV_WITHDRAW: | 302 | case FSCACHE_OBJECT_EV_WITHDRAW: |
273 | case FSCACHE_OBJECT_EV_RETIRE: | 303 | case FSCACHE_OBJECT_EV_RETIRE: |
274 | case FSCACHE_OBJECT_EV_RELEASE: | 304 | case FSCACHE_OBJECT_EV_RELEASE: |
275 | case FSCACHE_OBJECT_EV_ERROR: | 305 | case FSCACHE_OBJECT_EV_ERROR: |
276 | new_state = FSCACHE_OBJECT_DYING; | 306 | new_state = FSCACHE_OBJECT_DYING; |
277 | goto change_state; | 307 | goto change_state; |
308 | case FSCACHE_OBJECT_EV_INVALIDATE: | ||
309 | new_state = FSCACHE_OBJECT_INVALIDATING; | ||
310 | goto change_state; | ||
278 | case FSCACHE_OBJECT_EV_UPDATE: | 311 | case FSCACHE_OBJECT_EV_UPDATE: |
279 | new_state = FSCACHE_OBJECT_UPDATING; | 312 | new_state = FSCACHE_OBJECT_UPDATING; |
280 | goto change_state; | 313 | goto change_state; |
@@ -287,7 +320,8 @@ active_transit: | |||
287 | 320 | ||
288 | /* determine the transition from a terminal state */ | 321 | /* determine the transition from a terminal state */ |
289 | terminal_transit: | 322 | terminal_transit: |
290 | switch (fls(object->events & object->event_mask) - 1) { | 323 | event = fls(object->events & object->event_mask) - 1; |
324 | switch (event) { | ||
291 | case FSCACHE_OBJECT_EV_WITHDRAW: | 325 | case FSCACHE_OBJECT_EV_WITHDRAW: |
292 | new_state = FSCACHE_OBJECT_WITHDRAWING; | 326 | new_state = FSCACHE_OBJECT_WITHDRAWING; |
293 | goto change_state; | 327 | goto change_state; |
@@ -320,8 +354,8 @@ done: | |||
320 | 354 | ||
321 | unsupported_event: | 355 | unsupported_event: |
322 | printk(KERN_ERR "FS-Cache:" | 356 | printk(KERN_ERR "FS-Cache:" |
323 | " Unsupported event %lx [mask %lx] in state %s\n", | 357 | " Unsupported event %d [%lx/%lx] in state %s\n", |
324 | object->events, object->event_mask, | 358 | event, object->events, object->event_mask, |
325 | fscache_object_states[object->state]); | 359 | fscache_object_states[object->state]); |
326 | BUG(); | 360 | BUG(); |
327 | } | 361 | } |
@@ -587,8 +621,6 @@ static void fscache_object_available(struct fscache_object *object) | |||
587 | if (object->n_in_progress == 0) { | 621 | if (object->n_in_progress == 0) { |
588 | if (object->n_ops > 0) { | 622 | if (object->n_ops > 0) { |
589 | ASSERTCMP(object->n_ops, >=, object->n_obj_ops); | 623 | ASSERTCMP(object->n_ops, >=, object->n_obj_ops); |
590 | ASSERTIF(object->n_ops > object->n_obj_ops, | ||
591 | !list_empty(&object->pending_ops)); | ||
592 | fscache_start_operations(object); | 624 | fscache_start_operations(object); |
593 | } else { | 625 | } else { |
594 | ASSERT(list_empty(&object->pending_ops)); | 626 | ASSERT(list_empty(&object->pending_ops)); |
@@ -681,6 +713,7 @@ static void fscache_withdraw_object(struct fscache_object *object) | |||
681 | if (object->cookie == cookie) { | 713 | if (object->cookie == cookie) { |
682 | hlist_del_init(&object->cookie_link); | 714 | hlist_del_init(&object->cookie_link); |
683 | object->cookie = NULL; | 715 | object->cookie = NULL; |
716 | fscache_invalidation_complete(cookie); | ||
684 | detached = true; | 717 | detached = true; |
685 | } | 718 | } |
686 | spin_unlock(&cookie->lock); | 719 | spin_unlock(&cookie->lock); |
@@ -890,3 +923,55 @@ enum fscache_checkaux fscache_check_aux(struct fscache_object *object, | |||
890 | return result; | 923 | return result; |
891 | } | 924 | } |
892 | EXPORT_SYMBOL(fscache_check_aux); | 925 | EXPORT_SYMBOL(fscache_check_aux); |
926 | |||
927 | /* | ||
928 | * Asynchronously invalidate an object. | ||
929 | */ | ||
930 | static void fscache_invalidate_object(struct fscache_object *object) | ||
931 | { | ||
932 | struct fscache_operation *op; | ||
933 | struct fscache_cookie *cookie = object->cookie; | ||
934 | |||
935 | _enter("{OBJ%x}", object->debug_id); | ||
936 | |||
937 | /* Reject any new read/write ops and abort any that are pending. */ | ||
938 | fscache_invalidate_writes(cookie); | ||
939 | clear_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags); | ||
940 | fscache_cancel_all_ops(object); | ||
941 | |||
942 | /* Now we have to wait for in-progress reads and writes */ | ||
943 | op = kzalloc(sizeof(*op), GFP_KERNEL); | ||
944 | if (!op) { | ||
945 | fscache_raise_event(object, FSCACHE_OBJECT_EV_ERROR); | ||
946 | _leave(" [ENOMEM]"); | ||
947 | return; | ||
948 | } | ||
949 | |||
950 | fscache_operation_init(op, object->cache->ops->invalidate_object, NULL); | ||
951 | op->flags = FSCACHE_OP_ASYNC | (1 << FSCACHE_OP_EXCLUSIVE); | ||
952 | |||
953 | spin_lock(&cookie->lock); | ||
954 | if (fscache_submit_exclusive_op(object, op) < 0) | ||
955 | goto submit_op_failed; | ||
956 | spin_unlock(&cookie->lock); | ||
957 | fscache_put_operation(op); | ||
958 | |||
959 | /* Once we've completed the invalidation, we know there will be no data | ||
960 | * stored in the cache and thus we can reinstate the data-check-skip | ||
961 | * optimisation. | ||
962 | */ | ||
963 | set_bit(FSCACHE_COOKIE_NO_DATA_YET, &cookie->flags); | ||
964 | |||
965 | /* We can allow read and write requests to come in once again. They'll | ||
966 | * queue up behind our exclusive invalidation operation. | ||
967 | */ | ||
968 | fscache_invalidation_complete(cookie); | ||
969 | _leave(""); | ||
970 | return; | ||
971 | |||
972 | submit_op_failed: | ||
973 | spin_unlock(&cookie->lock); | ||
974 | kfree(op); | ||
975 | fscache_raise_event(object, FSCACHE_OBJECT_EV_ERROR); | ||
976 | _leave(" [EIO]"); | ||
977 | } | ||
diff --git a/fs/fscache/operation.c b/fs/fscache/operation.c index 30afdfa7aec7..762a9ec4ffa4 100644 --- a/fs/fscache/operation.c +++ b/fs/fscache/operation.c | |||
@@ -37,6 +37,7 @@ void fscache_enqueue_operation(struct fscache_operation *op) | |||
37 | ASSERT(op->processor != NULL); | 37 | ASSERT(op->processor != NULL); |
38 | ASSERTCMP(op->object->state, >=, FSCACHE_OBJECT_AVAILABLE); | 38 | ASSERTCMP(op->object->state, >=, FSCACHE_OBJECT_AVAILABLE); |
39 | ASSERTCMP(atomic_read(&op->usage), >, 0); | 39 | ASSERTCMP(atomic_read(&op->usage), >, 0); |
40 | ASSERTCMP(op->state, ==, FSCACHE_OP_ST_IN_PROGRESS); | ||
40 | 41 | ||
41 | fscache_stat(&fscache_n_op_enqueue); | 42 | fscache_stat(&fscache_n_op_enqueue); |
42 | switch (op->flags & FSCACHE_OP_TYPE) { | 43 | switch (op->flags & FSCACHE_OP_TYPE) { |
@@ -64,6 +65,9 @@ EXPORT_SYMBOL(fscache_enqueue_operation); | |||
64 | static void fscache_run_op(struct fscache_object *object, | 65 | static void fscache_run_op(struct fscache_object *object, |
65 | struct fscache_operation *op) | 66 | struct fscache_operation *op) |
66 | { | 67 | { |
68 | ASSERTCMP(op->state, ==, FSCACHE_OP_ST_PENDING); | ||
69 | |||
70 | op->state = FSCACHE_OP_ST_IN_PROGRESS; | ||
67 | object->n_in_progress++; | 71 | object->n_in_progress++; |
68 | if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags)) | 72 | if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags)) |
69 | wake_up_bit(&op->flags, FSCACHE_OP_WAITING); | 73 | wake_up_bit(&op->flags, FSCACHE_OP_WAITING); |
@@ -84,18 +88,21 @@ int fscache_submit_exclusive_op(struct fscache_object *object, | |||
84 | 88 | ||
85 | _enter("{OBJ%x OP%x},", object->debug_id, op->debug_id); | 89 | _enter("{OBJ%x OP%x},", object->debug_id, op->debug_id); |
86 | 90 | ||
91 | ASSERTCMP(op->state, ==, FSCACHE_OP_ST_INITIALISED); | ||
92 | ASSERTCMP(atomic_read(&op->usage), >, 0); | ||
93 | |||
87 | spin_lock(&object->lock); | 94 | spin_lock(&object->lock); |
88 | ASSERTCMP(object->n_ops, >=, object->n_in_progress); | 95 | ASSERTCMP(object->n_ops, >=, object->n_in_progress); |
89 | ASSERTCMP(object->n_ops, >=, object->n_exclusive); | 96 | ASSERTCMP(object->n_ops, >=, object->n_exclusive); |
90 | ASSERT(list_empty(&op->pend_link)); | 97 | ASSERT(list_empty(&op->pend_link)); |
91 | 98 | ||
92 | ret = -ENOBUFS; | 99 | op->state = FSCACHE_OP_ST_PENDING; |
93 | if (fscache_object_is_active(object)) { | 100 | if (fscache_object_is_active(object)) { |
94 | op->object = object; | 101 | op->object = object; |
95 | object->n_ops++; | 102 | object->n_ops++; |
96 | object->n_exclusive++; /* reads and writes must wait */ | 103 | object->n_exclusive++; /* reads and writes must wait */ |
97 | 104 | ||
98 | if (object->n_ops > 1) { | 105 | if (object->n_in_progress > 0) { |
99 | atomic_inc(&op->usage); | 106 | atomic_inc(&op->usage); |
100 | list_add_tail(&op->pend_link, &object->pending_ops); | 107 | list_add_tail(&op->pend_link, &object->pending_ops); |
101 | fscache_stat(&fscache_n_op_pend); | 108 | fscache_stat(&fscache_n_op_pend); |
@@ -121,8 +128,11 @@ int fscache_submit_exclusive_op(struct fscache_object *object, | |||
121 | fscache_stat(&fscache_n_op_pend); | 128 | fscache_stat(&fscache_n_op_pend); |
122 | ret = 0; | 129 | ret = 0; |
123 | } else { | 130 | } else { |
124 | /* not allowed to submit ops in any other state */ | 131 | /* If we're in any other state, there must have been an I/O |
125 | BUG(); | 132 | * error of some nature. |
133 | */ | ||
134 | ASSERT(test_bit(FSCACHE_IOERROR, &object->cache->flags)); | ||
135 | ret = -EIO; | ||
126 | } | 136 | } |
127 | 137 | ||
128 | spin_unlock(&object->lock); | 138 | spin_unlock(&object->lock); |
@@ -186,6 +196,7 @@ int fscache_submit_op(struct fscache_object *object, | |||
186 | _enter("{OBJ%x OP%x},{%u}", | 196 | _enter("{OBJ%x OP%x},{%u}", |
187 | object->debug_id, op->debug_id, atomic_read(&op->usage)); | 197 | object->debug_id, op->debug_id, atomic_read(&op->usage)); |
188 | 198 | ||
199 | ASSERTCMP(op->state, ==, FSCACHE_OP_ST_INITIALISED); | ||
189 | ASSERTCMP(atomic_read(&op->usage), >, 0); | 200 | ASSERTCMP(atomic_read(&op->usage), >, 0); |
190 | 201 | ||
191 | spin_lock(&object->lock); | 202 | spin_lock(&object->lock); |
@@ -196,6 +207,7 @@ int fscache_submit_op(struct fscache_object *object, | |||
196 | ostate = object->state; | 207 | ostate = object->state; |
197 | smp_rmb(); | 208 | smp_rmb(); |
198 | 209 | ||
210 | op->state = FSCACHE_OP_ST_PENDING; | ||
199 | if (fscache_object_is_active(object)) { | 211 | if (fscache_object_is_active(object)) { |
200 | op->object = object; | 212 | op->object = object; |
201 | object->n_ops++; | 213 | object->n_ops++; |
@@ -225,12 +237,15 @@ int fscache_submit_op(struct fscache_object *object, | |||
225 | object->state == FSCACHE_OBJECT_LC_DYING || | 237 | object->state == FSCACHE_OBJECT_LC_DYING || |
226 | object->state == FSCACHE_OBJECT_WITHDRAWING) { | 238 | object->state == FSCACHE_OBJECT_WITHDRAWING) { |
227 | fscache_stat(&fscache_n_op_rejected); | 239 | fscache_stat(&fscache_n_op_rejected); |
240 | op->state = FSCACHE_OP_ST_CANCELLED; | ||
228 | ret = -ENOBUFS; | 241 | ret = -ENOBUFS; |
229 | } else if (!test_bit(FSCACHE_IOERROR, &object->cache->flags)) { | 242 | } else if (!test_bit(FSCACHE_IOERROR, &object->cache->flags)) { |
230 | fscache_report_unexpected_submission(object, op, ostate); | 243 | fscache_report_unexpected_submission(object, op, ostate); |
231 | ASSERT(!fscache_object_is_active(object)); | 244 | ASSERT(!fscache_object_is_active(object)); |
245 | op->state = FSCACHE_OP_ST_CANCELLED; | ||
232 | ret = -ENOBUFS; | 246 | ret = -ENOBUFS; |
233 | } else { | 247 | } else { |
248 | op->state = FSCACHE_OP_ST_CANCELLED; | ||
234 | ret = -ENOBUFS; | 249 | ret = -ENOBUFS; |
235 | } | 250 | } |
236 | 251 | ||
@@ -283,20 +298,28 @@ void fscache_start_operations(struct fscache_object *object) | |||
283 | /* | 298 | /* |
284 | * cancel an operation that's pending on an object | 299 | * cancel an operation that's pending on an object |
285 | */ | 300 | */ |
286 | int fscache_cancel_op(struct fscache_operation *op) | 301 | int fscache_cancel_op(struct fscache_operation *op, |
302 | void (*do_cancel)(struct fscache_operation *)) | ||
287 | { | 303 | { |
288 | struct fscache_object *object = op->object; | 304 | struct fscache_object *object = op->object; |
289 | int ret; | 305 | int ret; |
290 | 306 | ||
291 | _enter("OBJ%x OP%x}", op->object->debug_id, op->debug_id); | 307 | _enter("OBJ%x OP%x}", op->object->debug_id, op->debug_id); |
292 | 308 | ||
309 | ASSERTCMP(op->state, >=, FSCACHE_OP_ST_PENDING); | ||
310 | ASSERTCMP(op->state, !=, FSCACHE_OP_ST_CANCELLED); | ||
311 | ASSERTCMP(atomic_read(&op->usage), >, 0); | ||
312 | |||
293 | spin_lock(&object->lock); | 313 | spin_lock(&object->lock); |
294 | 314 | ||
295 | ret = -EBUSY; | 315 | ret = -EBUSY; |
296 | if (!list_empty(&op->pend_link)) { | 316 | if (op->state == FSCACHE_OP_ST_PENDING) { |
317 | ASSERT(!list_empty(&op->pend_link)); | ||
297 | fscache_stat(&fscache_n_op_cancelled); | 318 | fscache_stat(&fscache_n_op_cancelled); |
298 | list_del_init(&op->pend_link); | 319 | list_del_init(&op->pend_link); |
299 | object->n_ops--; | 320 | if (do_cancel) |
321 | do_cancel(op); | ||
322 | op->state = FSCACHE_OP_ST_CANCELLED; | ||
300 | if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags)) | 323 | if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags)) |
301 | object->n_exclusive--; | 324 | object->n_exclusive--; |
302 | if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags)) | 325 | if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags)) |
@@ -311,6 +334,70 @@ int fscache_cancel_op(struct fscache_operation *op) | |||
311 | } | 334 | } |
312 | 335 | ||
313 | /* | 336 | /* |
337 | * Cancel all pending operations on an object | ||
338 | */ | ||
339 | void fscache_cancel_all_ops(struct fscache_object *object) | ||
340 | { | ||
341 | struct fscache_operation *op; | ||
342 | |||
343 | _enter("OBJ%x", object->debug_id); | ||
344 | |||
345 | spin_lock(&object->lock); | ||
346 | |||
347 | while (!list_empty(&object->pending_ops)) { | ||
348 | op = list_entry(object->pending_ops.next, | ||
349 | struct fscache_operation, pend_link); | ||
350 | fscache_stat(&fscache_n_op_cancelled); | ||
351 | list_del_init(&op->pend_link); | ||
352 | |||
353 | ASSERTCMP(op->state, ==, FSCACHE_OP_ST_PENDING); | ||
354 | op->state = FSCACHE_OP_ST_CANCELLED; | ||
355 | |||
356 | if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags)) | ||
357 | object->n_exclusive--; | ||
358 | if (test_and_clear_bit(FSCACHE_OP_WAITING, &op->flags)) | ||
359 | wake_up_bit(&op->flags, FSCACHE_OP_WAITING); | ||
360 | fscache_put_operation(op); | ||
361 | cond_resched_lock(&object->lock); | ||
362 | } | ||
363 | |||
364 | spin_unlock(&object->lock); | ||
365 | _leave(""); | ||
366 | } | ||
367 | |||
368 | /* | ||
369 | * Record the completion or cancellation of an in-progress operation. | ||
370 | */ | ||
371 | void fscache_op_complete(struct fscache_operation *op, bool cancelled) | ||
372 | { | ||
373 | struct fscache_object *object = op->object; | ||
374 | |||
375 | _enter("OBJ%x", object->debug_id); | ||
376 | |||
377 | ASSERTCMP(op->state, ==, FSCACHE_OP_ST_IN_PROGRESS); | ||
378 | ASSERTCMP(object->n_in_progress, >, 0); | ||
379 | ASSERTIFCMP(test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags), | ||
380 | object->n_exclusive, >, 0); | ||
381 | ASSERTIFCMP(test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags), | ||
382 | object->n_in_progress, ==, 1); | ||
383 | |||
384 | spin_lock(&object->lock); | ||
385 | |||
386 | op->state = cancelled ? | ||
387 | FSCACHE_OP_ST_CANCELLED : FSCACHE_OP_ST_COMPLETE; | ||
388 | |||
389 | if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags)) | ||
390 | object->n_exclusive--; | ||
391 | object->n_in_progress--; | ||
392 | if (object->n_in_progress == 0) | ||
393 | fscache_start_operations(object); | ||
394 | |||
395 | spin_unlock(&object->lock); | ||
396 | _leave(""); | ||
397 | } | ||
398 | EXPORT_SYMBOL(fscache_op_complete); | ||
399 | |||
400 | /* | ||
314 | * release an operation | 401 | * release an operation |
315 | * - queues pending ops if this is the last in-progress op | 402 | * - queues pending ops if this is the last in-progress op |
316 | */ | 403 | */ |
@@ -328,8 +415,9 @@ void fscache_put_operation(struct fscache_operation *op) | |||
328 | return; | 415 | return; |
329 | 416 | ||
330 | _debug("PUT OP"); | 417 | _debug("PUT OP"); |
331 | if (test_and_set_bit(FSCACHE_OP_DEAD, &op->flags)) | 418 | ASSERTIFCMP(op->state != FSCACHE_OP_ST_COMPLETE, |
332 | BUG(); | 419 | op->state, ==, FSCACHE_OP_ST_CANCELLED); |
420 | op->state = FSCACHE_OP_ST_DEAD; | ||
333 | 421 | ||
334 | fscache_stat(&fscache_n_op_release); | 422 | fscache_stat(&fscache_n_op_release); |
335 | 423 | ||
@@ -340,8 +428,14 @@ void fscache_put_operation(struct fscache_operation *op) | |||
340 | 428 | ||
341 | object = op->object; | 429 | object = op->object; |
342 | 430 | ||
343 | if (test_bit(FSCACHE_OP_DEC_READ_CNT, &op->flags)) | 431 | if (test_bit(FSCACHE_OP_DEC_READ_CNT, &op->flags)) { |
344 | atomic_dec(&object->n_reads); | 432 | if (atomic_dec_and_test(&object->n_reads)) { |
433 | clear_bit(FSCACHE_COOKIE_WAITING_ON_READS, | ||
434 | &object->cookie->flags); | ||
435 | wake_up_bit(&object->cookie->flags, | ||
436 | FSCACHE_COOKIE_WAITING_ON_READS); | ||
437 | } | ||
438 | } | ||
345 | 439 | ||
346 | /* now... we may get called with the object spinlock held, so we | 440 | /* now... we may get called with the object spinlock held, so we |
347 | * complete the cleanup here only if we can immediately acquire the | 441 | * complete the cleanup here only if we can immediately acquire the |
@@ -359,16 +453,6 @@ void fscache_put_operation(struct fscache_operation *op) | |||
359 | return; | 453 | return; |
360 | } | 454 | } |
361 | 455 | ||
362 | if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags)) { | ||
363 | ASSERTCMP(object->n_exclusive, >, 0); | ||
364 | object->n_exclusive--; | ||
365 | } | ||
366 | |||
367 | ASSERTCMP(object->n_in_progress, >, 0); | ||
368 | object->n_in_progress--; | ||
369 | if (object->n_in_progress == 0) | ||
370 | fscache_start_operations(object); | ||
371 | |||
372 | ASSERTCMP(object->n_ops, >, 0); | 456 | ASSERTCMP(object->n_ops, >, 0); |
373 | object->n_ops--; | 457 | object->n_ops--; |
374 | if (object->n_ops == 0) | 458 | if (object->n_ops == 0) |
@@ -407,23 +491,14 @@ void fscache_operation_gc(struct work_struct *work) | |||
407 | spin_unlock(&cache->op_gc_list_lock); | 491 | spin_unlock(&cache->op_gc_list_lock); |
408 | 492 | ||
409 | object = op->object; | 493 | object = op->object; |
494 | spin_lock(&object->lock); | ||
410 | 495 | ||
411 | _debug("GC DEFERRED REL OBJ%x OP%x", | 496 | _debug("GC DEFERRED REL OBJ%x OP%x", |
412 | object->debug_id, op->debug_id); | 497 | object->debug_id, op->debug_id); |
413 | fscache_stat(&fscache_n_op_gc); | 498 | fscache_stat(&fscache_n_op_gc); |
414 | 499 | ||
415 | ASSERTCMP(atomic_read(&op->usage), ==, 0); | 500 | ASSERTCMP(atomic_read(&op->usage), ==, 0); |
416 | 501 | ASSERTCMP(op->state, ==, FSCACHE_OP_ST_DEAD); | |
417 | spin_lock(&object->lock); | ||
418 | if (test_bit(FSCACHE_OP_EXCLUSIVE, &op->flags)) { | ||
419 | ASSERTCMP(object->n_exclusive, >, 0); | ||
420 | object->n_exclusive--; | ||
421 | } | ||
422 | |||
423 | ASSERTCMP(object->n_in_progress, >, 0); | ||
424 | object->n_in_progress--; | ||
425 | if (object->n_in_progress == 0) | ||
426 | fscache_start_operations(object); | ||
427 | 502 | ||
428 | ASSERTCMP(object->n_ops, >, 0); | 503 | ASSERTCMP(object->n_ops, >, 0); |
429 | object->n_ops--; | 504 | object->n_ops--; |
@@ -431,6 +506,7 @@ void fscache_operation_gc(struct work_struct *work) | |||
431 | fscache_raise_event(object, FSCACHE_OBJECT_EV_CLEARED); | 506 | fscache_raise_event(object, FSCACHE_OBJECT_EV_CLEARED); |
432 | 507 | ||
433 | spin_unlock(&object->lock); | 508 | spin_unlock(&object->lock); |
509 | kfree(op); | ||
434 | 510 | ||
435 | } while (count++ < 20); | 511 | } while (count++ < 20); |
436 | 512 | ||
diff --git a/fs/fscache/page.c b/fs/fscache/page.c index 3f7a59bfa7ad..ff000e52072d 100644 --- a/fs/fscache/page.c +++ b/fs/fscache/page.c | |||
@@ -56,6 +56,7 @@ bool __fscache_maybe_release_page(struct fscache_cookie *cookie, | |||
56 | 56 | ||
57 | _enter("%p,%p,%x", cookie, page, gfp); | 57 | _enter("%p,%p,%x", cookie, page, gfp); |
58 | 58 | ||
59 | try_again: | ||
59 | rcu_read_lock(); | 60 | rcu_read_lock(); |
60 | val = radix_tree_lookup(&cookie->stores, page->index); | 61 | val = radix_tree_lookup(&cookie->stores, page->index); |
61 | if (!val) { | 62 | if (!val) { |
@@ -104,11 +105,19 @@ bool __fscache_maybe_release_page(struct fscache_cookie *cookie, | |||
104 | return true; | 105 | return true; |
105 | 106 | ||
106 | page_busy: | 107 | page_busy: |
107 | /* we might want to wait here, but that could deadlock the allocator as | 108 | /* We will wait here if we're allowed to, but that could deadlock the |
108 | * the work threads writing to the cache may all end up sleeping | 109 | * allocator as the work threads writing to the cache may all end up |
109 | * on memory allocation */ | 110 | * sleeping on memory allocation, so we may need to impose a timeout |
110 | fscache_stat(&fscache_n_store_vmscan_busy); | 111 | * too. */ |
111 | return false; | 112 | if (!(gfp & __GFP_WAIT)) { |
113 | fscache_stat(&fscache_n_store_vmscan_busy); | ||
114 | return false; | ||
115 | } | ||
116 | |||
117 | fscache_stat(&fscache_n_store_vmscan_wait); | ||
118 | __fscache_wait_on_page_write(cookie, page); | ||
119 | gfp &= ~__GFP_WAIT; | ||
120 | goto try_again; | ||
112 | } | 121 | } |
113 | EXPORT_SYMBOL(__fscache_maybe_release_page); | 122 | EXPORT_SYMBOL(__fscache_maybe_release_page); |
114 | 123 | ||
@@ -162,6 +171,7 @@ static void fscache_attr_changed_op(struct fscache_operation *op) | |||
162 | fscache_abort_object(object); | 171 | fscache_abort_object(object); |
163 | } | 172 | } |
164 | 173 | ||
174 | fscache_op_complete(op, true); | ||
165 | _leave(""); | 175 | _leave(""); |
166 | } | 176 | } |
167 | 177 | ||
@@ -223,6 +233,8 @@ static void fscache_release_retrieval_op(struct fscache_operation *_op) | |||
223 | 233 | ||
224 | _enter("{OP%x}", op->op.debug_id); | 234 | _enter("{OP%x}", op->op.debug_id); |
225 | 235 | ||
236 | ASSERTCMP(op->n_pages, ==, 0); | ||
237 | |||
226 | fscache_hist(fscache_retrieval_histogram, op->start_time); | 238 | fscache_hist(fscache_retrieval_histogram, op->start_time); |
227 | if (op->context) | 239 | if (op->context) |
228 | fscache_put_context(op->op.object->cookie, op->context); | 240 | fscache_put_context(op->op.object->cookie, op->context); |
@@ -291,6 +303,17 @@ static int fscache_wait_for_deferred_lookup(struct fscache_cookie *cookie) | |||
291 | } | 303 | } |
292 | 304 | ||
293 | /* | 305 | /* |
306 | * Handle cancellation of a pending retrieval op | ||
307 | */ | ||
308 | static void fscache_do_cancel_retrieval(struct fscache_operation *_op) | ||
309 | { | ||
310 | struct fscache_retrieval *op = | ||
311 | container_of(_op, struct fscache_retrieval, op); | ||
312 | |||
313 | op->n_pages = 0; | ||
314 | } | ||
315 | |||
316 | /* | ||
294 | * wait for an object to become active (or dead) | 317 | * wait for an object to become active (or dead) |
295 | */ | 318 | */ |
296 | static int fscache_wait_for_retrieval_activation(struct fscache_object *object, | 319 | static int fscache_wait_for_retrieval_activation(struct fscache_object *object, |
@@ -307,8 +330,8 @@ static int fscache_wait_for_retrieval_activation(struct fscache_object *object, | |||
307 | fscache_stat(stat_op_waits); | 330 | fscache_stat(stat_op_waits); |
308 | if (wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING, | 331 | if (wait_on_bit(&op->op.flags, FSCACHE_OP_WAITING, |
309 | fscache_wait_bit_interruptible, | 332 | fscache_wait_bit_interruptible, |
310 | TASK_INTERRUPTIBLE) < 0) { | 333 | TASK_INTERRUPTIBLE) != 0) { |
311 | ret = fscache_cancel_op(&op->op); | 334 | ret = fscache_cancel_op(&op->op, fscache_do_cancel_retrieval); |
312 | if (ret == 0) | 335 | if (ret == 0) |
313 | return -ERESTARTSYS; | 336 | return -ERESTARTSYS; |
314 | 337 | ||
@@ -320,7 +343,14 @@ static int fscache_wait_for_retrieval_activation(struct fscache_object *object, | |||
320 | _debug("<<< GO"); | 343 | _debug("<<< GO"); |
321 | 344 | ||
322 | check_if_dead: | 345 | check_if_dead: |
346 | if (op->op.state == FSCACHE_OP_ST_CANCELLED) { | ||
347 | fscache_stat(stat_object_dead); | ||
348 | _leave(" = -ENOBUFS [cancelled]"); | ||
349 | return -ENOBUFS; | ||
350 | } | ||
323 | if (unlikely(fscache_object_is_dead(object))) { | 351 | if (unlikely(fscache_object_is_dead(object))) { |
352 | pr_err("%s() = -ENOBUFS [obj dead %d]\n", __func__, op->op.state); | ||
353 | fscache_cancel_op(&op->op, fscache_do_cancel_retrieval); | ||
324 | fscache_stat(stat_object_dead); | 354 | fscache_stat(stat_object_dead); |
325 | return -ENOBUFS; | 355 | return -ENOBUFS; |
326 | } | 356 | } |
@@ -353,6 +383,11 @@ int __fscache_read_or_alloc_page(struct fscache_cookie *cookie, | |||
353 | if (hlist_empty(&cookie->backing_objects)) | 383 | if (hlist_empty(&cookie->backing_objects)) |
354 | goto nobufs; | 384 | goto nobufs; |
355 | 385 | ||
386 | if (test_bit(FSCACHE_COOKIE_INVALIDATING, &cookie->flags)) { | ||
387 | _leave(" = -ENOBUFS [invalidating]"); | ||
388 | return -ENOBUFS; | ||
389 | } | ||
390 | |||
356 | ASSERTCMP(cookie->def->type, !=, FSCACHE_COOKIE_TYPE_INDEX); | 391 | ASSERTCMP(cookie->def->type, !=, FSCACHE_COOKIE_TYPE_INDEX); |
357 | ASSERTCMP(page, !=, NULL); | 392 | ASSERTCMP(page, !=, NULL); |
358 | 393 | ||
@@ -364,6 +399,7 @@ int __fscache_read_or_alloc_page(struct fscache_cookie *cookie, | |||
364 | _leave(" = -ENOMEM"); | 399 | _leave(" = -ENOMEM"); |
365 | return -ENOMEM; | 400 | return -ENOMEM; |
366 | } | 401 | } |
402 | op->n_pages = 1; | ||
367 | 403 | ||
368 | spin_lock(&cookie->lock); | 404 | spin_lock(&cookie->lock); |
369 | 405 | ||
@@ -375,10 +411,10 @@ int __fscache_read_or_alloc_page(struct fscache_cookie *cookie, | |||
375 | ASSERTCMP(object->state, >, FSCACHE_OBJECT_LOOKING_UP); | 411 | ASSERTCMP(object->state, >, FSCACHE_OBJECT_LOOKING_UP); |
376 | 412 | ||
377 | atomic_inc(&object->n_reads); | 413 | atomic_inc(&object->n_reads); |
378 | set_bit(FSCACHE_OP_DEC_READ_CNT, &op->op.flags); | 414 | __set_bit(FSCACHE_OP_DEC_READ_CNT, &op->op.flags); |
379 | 415 | ||
380 | if (fscache_submit_op(object, &op->op) < 0) | 416 | if (fscache_submit_op(object, &op->op) < 0) |
381 | goto nobufs_unlock; | 417 | goto nobufs_unlock_dec; |
382 | spin_unlock(&cookie->lock); | 418 | spin_unlock(&cookie->lock); |
383 | 419 | ||
384 | fscache_stat(&fscache_n_retrieval_ops); | 420 | fscache_stat(&fscache_n_retrieval_ops); |
@@ -425,6 +461,8 @@ error: | |||
425 | _leave(" = %d", ret); | 461 | _leave(" = %d", ret); |
426 | return ret; | 462 | return ret; |
427 | 463 | ||
464 | nobufs_unlock_dec: | ||
465 | atomic_dec(&object->n_reads); | ||
428 | nobufs_unlock: | 466 | nobufs_unlock: |
429 | spin_unlock(&cookie->lock); | 467 | spin_unlock(&cookie->lock); |
430 | kfree(op); | 468 | kfree(op); |
@@ -472,6 +510,11 @@ int __fscache_read_or_alloc_pages(struct fscache_cookie *cookie, | |||
472 | if (hlist_empty(&cookie->backing_objects)) | 510 | if (hlist_empty(&cookie->backing_objects)) |
473 | goto nobufs; | 511 | goto nobufs; |
474 | 512 | ||
513 | if (test_bit(FSCACHE_COOKIE_INVALIDATING, &cookie->flags)) { | ||
514 | _leave(" = -ENOBUFS [invalidating]"); | ||
515 | return -ENOBUFS; | ||
516 | } | ||
517 | |||
475 | ASSERTCMP(cookie->def->type, !=, FSCACHE_COOKIE_TYPE_INDEX); | 518 | ASSERTCMP(cookie->def->type, !=, FSCACHE_COOKIE_TYPE_INDEX); |
476 | ASSERTCMP(*nr_pages, >, 0); | 519 | ASSERTCMP(*nr_pages, >, 0); |
477 | ASSERT(!list_empty(pages)); | 520 | ASSERT(!list_empty(pages)); |
@@ -482,6 +525,7 @@ int __fscache_read_or_alloc_pages(struct fscache_cookie *cookie, | |||
482 | op = fscache_alloc_retrieval(mapping, end_io_func, context); | 525 | op = fscache_alloc_retrieval(mapping, end_io_func, context); |
483 | if (!op) | 526 | if (!op) |
484 | return -ENOMEM; | 527 | return -ENOMEM; |
528 | op->n_pages = *nr_pages; | ||
485 | 529 | ||
486 | spin_lock(&cookie->lock); | 530 | spin_lock(&cookie->lock); |
487 | 531 | ||
@@ -491,10 +535,10 @@ int __fscache_read_or_alloc_pages(struct fscache_cookie *cookie, | |||
491 | struct fscache_object, cookie_link); | 535 | struct fscache_object, cookie_link); |
492 | 536 | ||
493 | atomic_inc(&object->n_reads); | 537 | atomic_inc(&object->n_reads); |
494 | set_bit(FSCACHE_OP_DEC_READ_CNT, &op->op.flags); | 538 | __set_bit(FSCACHE_OP_DEC_READ_CNT, &op->op.flags); |
495 | 539 | ||
496 | if (fscache_submit_op(object, &op->op) < 0) | 540 | if (fscache_submit_op(object, &op->op) < 0) |
497 | goto nobufs_unlock; | 541 | goto nobufs_unlock_dec; |
498 | spin_unlock(&cookie->lock); | 542 | spin_unlock(&cookie->lock); |
499 | 543 | ||
500 | fscache_stat(&fscache_n_retrieval_ops); | 544 | fscache_stat(&fscache_n_retrieval_ops); |
@@ -541,6 +585,8 @@ error: | |||
541 | _leave(" = %d", ret); | 585 | _leave(" = %d", ret); |
542 | return ret; | 586 | return ret; |
543 | 587 | ||
588 | nobufs_unlock_dec: | ||
589 | atomic_dec(&object->n_reads); | ||
544 | nobufs_unlock: | 590 | nobufs_unlock: |
545 | spin_unlock(&cookie->lock); | 591 | spin_unlock(&cookie->lock); |
546 | kfree(op); | 592 | kfree(op); |
@@ -577,12 +623,18 @@ int __fscache_alloc_page(struct fscache_cookie *cookie, | |||
577 | ASSERTCMP(cookie->def->type, !=, FSCACHE_COOKIE_TYPE_INDEX); | 623 | ASSERTCMP(cookie->def->type, !=, FSCACHE_COOKIE_TYPE_INDEX); |
578 | ASSERTCMP(page, !=, NULL); | 624 | ASSERTCMP(page, !=, NULL); |
579 | 625 | ||
626 | if (test_bit(FSCACHE_COOKIE_INVALIDATING, &cookie->flags)) { | ||
627 | _leave(" = -ENOBUFS [invalidating]"); | ||
628 | return -ENOBUFS; | ||
629 | } | ||
630 | |||
580 | if (fscache_wait_for_deferred_lookup(cookie) < 0) | 631 | if (fscache_wait_for_deferred_lookup(cookie) < 0) |
581 | return -ERESTARTSYS; | 632 | return -ERESTARTSYS; |
582 | 633 | ||
583 | op = fscache_alloc_retrieval(page->mapping, NULL, NULL); | 634 | op = fscache_alloc_retrieval(page->mapping, NULL, NULL); |
584 | if (!op) | 635 | if (!op) |
585 | return -ENOMEM; | 636 | return -ENOMEM; |
637 | op->n_pages = 1; | ||
586 | 638 | ||
587 | spin_lock(&cookie->lock); | 639 | spin_lock(&cookie->lock); |
588 | 640 | ||
@@ -658,9 +710,27 @@ static void fscache_write_op(struct fscache_operation *_op) | |||
658 | spin_lock(&object->lock); | 710 | spin_lock(&object->lock); |
659 | cookie = object->cookie; | 711 | cookie = object->cookie; |
660 | 712 | ||
661 | if (!fscache_object_is_active(object) || !cookie) { | 713 | if (!fscache_object_is_active(object)) { |
714 | /* If we get here, then the on-disk cache object likely longer | ||
715 | * exists, so we should just cancel this write operation. | ||
716 | */ | ||
717 | spin_unlock(&object->lock); | ||
718 | fscache_op_complete(&op->op, false); | ||
719 | _leave(" [inactive]"); | ||
720 | return; | ||
721 | } | ||
722 | |||
723 | if (!cookie) { | ||
724 | /* If we get here, then the cookie belonging to the object was | ||
725 | * detached, probably by the cookie being withdrawn due to | ||
726 | * memory pressure, which means that the pages we might write | ||
727 | * to the cache from no longer exist - therefore, we can just | ||
728 | * cancel this write operation. | ||
729 | */ | ||
662 | spin_unlock(&object->lock); | 730 | spin_unlock(&object->lock); |
663 | _leave(""); | 731 | fscache_op_complete(&op->op, false); |
732 | _leave(" [cancel] op{f=%lx s=%u} obj{s=%u f=%lx}", | ||
733 | _op->flags, _op->state, object->state, object->flags); | ||
664 | return; | 734 | return; |
665 | } | 735 | } |
666 | 736 | ||
@@ -696,6 +766,7 @@ static void fscache_write_op(struct fscache_operation *_op) | |||
696 | fscache_end_page_write(object, page); | 766 | fscache_end_page_write(object, page); |
697 | if (ret < 0) { | 767 | if (ret < 0) { |
698 | fscache_abort_object(object); | 768 | fscache_abort_object(object); |
769 | fscache_op_complete(&op->op, true); | ||
699 | } else { | 770 | } else { |
700 | fscache_enqueue_operation(&op->op); | 771 | fscache_enqueue_operation(&op->op); |
701 | } | 772 | } |
@@ -710,6 +781,38 @@ superseded: | |||
710 | spin_unlock(&cookie->stores_lock); | 781 | spin_unlock(&cookie->stores_lock); |
711 | clear_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags); | 782 | clear_bit(FSCACHE_OBJECT_PENDING_WRITE, &object->flags); |
712 | spin_unlock(&object->lock); | 783 | spin_unlock(&object->lock); |
784 | fscache_op_complete(&op->op, true); | ||
785 | _leave(""); | ||
786 | } | ||
787 | |||
788 | /* | ||
789 | * Clear the pages pending writing for invalidation | ||
790 | */ | ||
791 | void fscache_invalidate_writes(struct fscache_cookie *cookie) | ||
792 | { | ||
793 | struct page *page; | ||
794 | void *results[16]; | ||
795 | int n, i; | ||
796 | |||
797 | _enter(""); | ||
798 | |||
799 | while (spin_lock(&cookie->stores_lock), | ||
800 | n = radix_tree_gang_lookup_tag(&cookie->stores, results, 0, | ||
801 | ARRAY_SIZE(results), | ||
802 | FSCACHE_COOKIE_PENDING_TAG), | ||
803 | n > 0) { | ||
804 | for (i = n - 1; i >= 0; i--) { | ||
805 | page = results[i]; | ||
806 | radix_tree_delete(&cookie->stores, page->index); | ||
807 | } | ||
808 | |||
809 | spin_unlock(&cookie->stores_lock); | ||
810 | |||
811 | for (i = n - 1; i >= 0; i--) | ||
812 | page_cache_release(results[i]); | ||
813 | } | ||
814 | |||
815 | spin_unlock(&cookie->stores_lock); | ||
713 | _leave(""); | 816 | _leave(""); |
714 | } | 817 | } |
715 | 818 | ||
@@ -759,7 +862,12 @@ int __fscache_write_page(struct fscache_cookie *cookie, | |||
759 | 862 | ||
760 | fscache_stat(&fscache_n_stores); | 863 | fscache_stat(&fscache_n_stores); |
761 | 864 | ||
762 | op = kzalloc(sizeof(*op), GFP_NOIO); | 865 | if (test_bit(FSCACHE_COOKIE_INVALIDATING, &cookie->flags)) { |
866 | _leave(" = -ENOBUFS [invalidating]"); | ||
867 | return -ENOBUFS; | ||
868 | } | ||
869 | |||
870 | op = kzalloc(sizeof(*op), GFP_NOIO | __GFP_NOMEMALLOC | __GFP_NORETRY); | ||
763 | if (!op) | 871 | if (!op) |
764 | goto nomem; | 872 | goto nomem; |
765 | 873 | ||
@@ -915,6 +1023,40 @@ done: | |||
915 | EXPORT_SYMBOL(__fscache_uncache_page); | 1023 | EXPORT_SYMBOL(__fscache_uncache_page); |
916 | 1024 | ||
917 | /** | 1025 | /** |
1026 | * fscache_mark_page_cached - Mark a page as being cached | ||
1027 | * @op: The retrieval op pages are being marked for | ||
1028 | * @page: The page to be marked | ||
1029 | * | ||
1030 | * Mark a netfs page as being cached. After this is called, the netfs | ||
1031 | * must call fscache_uncache_page() to remove the mark. | ||
1032 | */ | ||
1033 | void fscache_mark_page_cached(struct fscache_retrieval *op, struct page *page) | ||
1034 | { | ||
1035 | struct fscache_cookie *cookie = op->op.object->cookie; | ||
1036 | |||
1037 | #ifdef CONFIG_FSCACHE_STATS | ||
1038 | atomic_inc(&fscache_n_marks); | ||
1039 | #endif | ||
1040 | |||
1041 | _debug("- mark %p{%lx}", page, page->index); | ||
1042 | if (TestSetPageFsCache(page)) { | ||
1043 | static bool once_only; | ||
1044 | if (!once_only) { | ||
1045 | once_only = true; | ||
1046 | printk(KERN_WARNING "FS-Cache:" | ||
1047 | " Cookie type %s marked page %lx" | ||
1048 | " multiple times\n", | ||
1049 | cookie->def->name, page->index); | ||
1050 | } | ||
1051 | } | ||
1052 | |||
1053 | if (cookie->def->mark_page_cached) | ||
1054 | cookie->def->mark_page_cached(cookie->netfs_data, | ||
1055 | op->mapping, page); | ||
1056 | } | ||
1057 | EXPORT_SYMBOL(fscache_mark_page_cached); | ||
1058 | |||
1059 | /** | ||
918 | * fscache_mark_pages_cached - Mark pages as being cached | 1060 | * fscache_mark_pages_cached - Mark pages as being cached |
919 | * @op: The retrieval op pages are being marked for | 1061 | * @op: The retrieval op pages are being marked for |
920 | * @pagevec: The pages to be marked | 1062 | * @pagevec: The pages to be marked |
@@ -925,32 +1067,11 @@ EXPORT_SYMBOL(__fscache_uncache_page); | |||
925 | void fscache_mark_pages_cached(struct fscache_retrieval *op, | 1067 | void fscache_mark_pages_cached(struct fscache_retrieval *op, |
926 | struct pagevec *pagevec) | 1068 | struct pagevec *pagevec) |
927 | { | 1069 | { |
928 | struct fscache_cookie *cookie = op->op.object->cookie; | ||
929 | unsigned long loop; | 1070 | unsigned long loop; |
930 | 1071 | ||
931 | #ifdef CONFIG_FSCACHE_STATS | 1072 | for (loop = 0; loop < pagevec->nr; loop++) |
932 | atomic_add(pagevec->nr, &fscache_n_marks); | 1073 | fscache_mark_page_cached(op, pagevec->pages[loop]); |
933 | #endif | ||
934 | |||
935 | for (loop = 0; loop < pagevec->nr; loop++) { | ||
936 | struct page *page = pagevec->pages[loop]; | ||
937 | |||
938 | _debug("- mark %p{%lx}", page, page->index); | ||
939 | if (TestSetPageFsCache(page)) { | ||
940 | static bool once_only; | ||
941 | if (!once_only) { | ||
942 | once_only = true; | ||
943 | printk(KERN_WARNING "FS-Cache:" | ||
944 | " Cookie type %s marked page %lx" | ||
945 | " multiple times\n", | ||
946 | cookie->def->name, page->index); | ||
947 | } | ||
948 | } | ||
949 | } | ||
950 | 1074 | ||
951 | if (cookie->def->mark_pages_cached) | ||
952 | cookie->def->mark_pages_cached(cookie->netfs_data, | ||
953 | op->mapping, pagevec); | ||
954 | pagevec_reinit(pagevec); | 1075 | pagevec_reinit(pagevec); |
955 | } | 1076 | } |
956 | EXPORT_SYMBOL(fscache_mark_pages_cached); | 1077 | EXPORT_SYMBOL(fscache_mark_pages_cached); |
diff --git a/fs/fscache/stats.c b/fs/fscache/stats.c index 4765190d537f..8179e8bc4a3d 100644 --- a/fs/fscache/stats.c +++ b/fs/fscache/stats.c | |||
@@ -69,6 +69,7 @@ atomic_t fscache_n_store_vmscan_not_storing; | |||
69 | atomic_t fscache_n_store_vmscan_gone; | 69 | atomic_t fscache_n_store_vmscan_gone; |
70 | atomic_t fscache_n_store_vmscan_busy; | 70 | atomic_t fscache_n_store_vmscan_busy; |
71 | atomic_t fscache_n_store_vmscan_cancelled; | 71 | atomic_t fscache_n_store_vmscan_cancelled; |
72 | atomic_t fscache_n_store_vmscan_wait; | ||
72 | 73 | ||
73 | atomic_t fscache_n_marks; | 74 | atomic_t fscache_n_marks; |
74 | atomic_t fscache_n_uncaches; | 75 | atomic_t fscache_n_uncaches; |
@@ -80,6 +81,9 @@ atomic_t fscache_n_acquires_ok; | |||
80 | atomic_t fscache_n_acquires_nobufs; | 81 | atomic_t fscache_n_acquires_nobufs; |
81 | atomic_t fscache_n_acquires_oom; | 82 | atomic_t fscache_n_acquires_oom; |
82 | 83 | ||
84 | atomic_t fscache_n_invalidates; | ||
85 | atomic_t fscache_n_invalidates_run; | ||
86 | |||
83 | atomic_t fscache_n_updates; | 87 | atomic_t fscache_n_updates; |
84 | atomic_t fscache_n_updates_null; | 88 | atomic_t fscache_n_updates_null; |
85 | atomic_t fscache_n_updates_run; | 89 | atomic_t fscache_n_updates_run; |
@@ -112,6 +116,7 @@ atomic_t fscache_n_cop_alloc_object; | |||
112 | atomic_t fscache_n_cop_lookup_object; | 116 | atomic_t fscache_n_cop_lookup_object; |
113 | atomic_t fscache_n_cop_lookup_complete; | 117 | atomic_t fscache_n_cop_lookup_complete; |
114 | atomic_t fscache_n_cop_grab_object; | 118 | atomic_t fscache_n_cop_grab_object; |
119 | atomic_t fscache_n_cop_invalidate_object; | ||
115 | atomic_t fscache_n_cop_update_object; | 120 | atomic_t fscache_n_cop_update_object; |
116 | atomic_t fscache_n_cop_drop_object; | 121 | atomic_t fscache_n_cop_drop_object; |
117 | atomic_t fscache_n_cop_put_object; | 122 | atomic_t fscache_n_cop_put_object; |
@@ -168,6 +173,10 @@ static int fscache_stats_show(struct seq_file *m, void *v) | |||
168 | atomic_read(&fscache_n_object_created), | 173 | atomic_read(&fscache_n_object_created), |
169 | atomic_read(&fscache_n_object_lookups_timed_out)); | 174 | atomic_read(&fscache_n_object_lookups_timed_out)); |
170 | 175 | ||
176 | seq_printf(m, "Invals : n=%u run=%u\n", | ||
177 | atomic_read(&fscache_n_invalidates), | ||
178 | atomic_read(&fscache_n_invalidates_run)); | ||
179 | |||
171 | seq_printf(m, "Updates: n=%u nul=%u run=%u\n", | 180 | seq_printf(m, "Updates: n=%u nul=%u run=%u\n", |
172 | atomic_read(&fscache_n_updates), | 181 | atomic_read(&fscache_n_updates), |
173 | atomic_read(&fscache_n_updates_null), | 182 | atomic_read(&fscache_n_updates_null), |
@@ -224,11 +233,12 @@ static int fscache_stats_show(struct seq_file *m, void *v) | |||
224 | atomic_read(&fscache_n_store_radix_deletes), | 233 | atomic_read(&fscache_n_store_radix_deletes), |
225 | atomic_read(&fscache_n_store_pages_over_limit)); | 234 | atomic_read(&fscache_n_store_pages_over_limit)); |
226 | 235 | ||
227 | seq_printf(m, "VmScan : nos=%u gon=%u bsy=%u can=%u\n", | 236 | seq_printf(m, "VmScan : nos=%u gon=%u bsy=%u can=%u wt=%u\n", |
228 | atomic_read(&fscache_n_store_vmscan_not_storing), | 237 | atomic_read(&fscache_n_store_vmscan_not_storing), |
229 | atomic_read(&fscache_n_store_vmscan_gone), | 238 | atomic_read(&fscache_n_store_vmscan_gone), |
230 | atomic_read(&fscache_n_store_vmscan_busy), | 239 | atomic_read(&fscache_n_store_vmscan_busy), |
231 | atomic_read(&fscache_n_store_vmscan_cancelled)); | 240 | atomic_read(&fscache_n_store_vmscan_cancelled), |
241 | atomic_read(&fscache_n_store_vmscan_wait)); | ||
232 | 242 | ||
233 | seq_printf(m, "Ops : pend=%u run=%u enq=%u can=%u rej=%u\n", | 243 | seq_printf(m, "Ops : pend=%u run=%u enq=%u can=%u rej=%u\n", |
234 | atomic_read(&fscache_n_op_pend), | 244 | atomic_read(&fscache_n_op_pend), |
@@ -246,7 +256,8 @@ static int fscache_stats_show(struct seq_file *m, void *v) | |||
246 | atomic_read(&fscache_n_cop_lookup_object), | 256 | atomic_read(&fscache_n_cop_lookup_object), |
247 | atomic_read(&fscache_n_cop_lookup_complete), | 257 | atomic_read(&fscache_n_cop_lookup_complete), |
248 | atomic_read(&fscache_n_cop_grab_object)); | 258 | atomic_read(&fscache_n_cop_grab_object)); |
249 | seq_printf(m, "CacheOp: upo=%d dro=%d pto=%d atc=%d syn=%d\n", | 259 | seq_printf(m, "CacheOp: inv=%d upo=%d dro=%d pto=%d atc=%d syn=%d\n", |
260 | atomic_read(&fscache_n_cop_invalidate_object), | ||
250 | atomic_read(&fscache_n_cop_update_object), | 261 | atomic_read(&fscache_n_cop_update_object), |
251 | atomic_read(&fscache_n_cop_drop_object), | 262 | atomic_read(&fscache_n_cop_drop_object), |
252 | atomic_read(&fscache_n_cop_put_object), | 263 | atomic_read(&fscache_n_cop_put_object), |
diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c index 0b35903219bc..d47f11658c17 100644 --- a/fs/hfs/inode.c +++ b/fs/hfs/inode.c | |||
@@ -35,6 +35,16 @@ static int hfs_readpage(struct file *file, struct page *page) | |||
35 | return block_read_full_page(page, hfs_get_block); | 35 | return block_read_full_page(page, hfs_get_block); |
36 | } | 36 | } |
37 | 37 | ||
38 | static void hfs_write_failed(struct address_space *mapping, loff_t to) | ||
39 | { | ||
40 | struct inode *inode = mapping->host; | ||
41 | |||
42 | if (to > inode->i_size) { | ||
43 | truncate_pagecache(inode, to, inode->i_size); | ||
44 | hfs_file_truncate(inode); | ||
45 | } | ||
46 | } | ||
47 | |||
38 | static int hfs_write_begin(struct file *file, struct address_space *mapping, | 48 | static int hfs_write_begin(struct file *file, struct address_space *mapping, |
39 | loff_t pos, unsigned len, unsigned flags, | 49 | loff_t pos, unsigned len, unsigned flags, |
40 | struct page **pagep, void **fsdata) | 50 | struct page **pagep, void **fsdata) |
@@ -45,11 +55,8 @@ static int hfs_write_begin(struct file *file, struct address_space *mapping, | |||
45 | ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, | 55 | ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, |
46 | hfs_get_block, | 56 | hfs_get_block, |
47 | &HFS_I(mapping->host)->phys_size); | 57 | &HFS_I(mapping->host)->phys_size); |
48 | if (unlikely(ret)) { | 58 | if (unlikely(ret)) |
49 | loff_t isize = mapping->host->i_size; | 59 | hfs_write_failed(mapping, pos + len); |
50 | if (pos + len > isize) | ||
51 | vmtruncate(mapping->host, isize); | ||
52 | } | ||
53 | 60 | ||
54 | return ret; | 61 | return ret; |
55 | } | 62 | } |
@@ -120,6 +127,7 @@ static ssize_t hfs_direct_IO(int rw, struct kiocb *iocb, | |||
120 | const struct iovec *iov, loff_t offset, unsigned long nr_segs) | 127 | const struct iovec *iov, loff_t offset, unsigned long nr_segs) |
121 | { | 128 | { |
122 | struct file *file = iocb->ki_filp; | 129 | struct file *file = iocb->ki_filp; |
130 | struct address_space *mapping = file->f_mapping; | ||
123 | struct inode *inode = file->f_path.dentry->d_inode->i_mapping->host; | 131 | struct inode *inode = file->f_path.dentry->d_inode->i_mapping->host; |
124 | ssize_t ret; | 132 | ssize_t ret; |
125 | 133 | ||
@@ -135,7 +143,7 @@ static ssize_t hfs_direct_IO(int rw, struct kiocb *iocb, | |||
135 | loff_t end = offset + iov_length(iov, nr_segs); | 143 | loff_t end = offset + iov_length(iov, nr_segs); |
136 | 144 | ||
137 | if (end > isize) | 145 | if (end > isize) |
138 | vmtruncate(inode, isize); | 146 | hfs_write_failed(mapping, end); |
139 | } | 147 | } |
140 | 148 | ||
141 | return ret; | 149 | return ret; |
@@ -617,9 +625,12 @@ int hfs_inode_setattr(struct dentry *dentry, struct iattr * attr) | |||
617 | attr->ia_size != i_size_read(inode)) { | 625 | attr->ia_size != i_size_read(inode)) { |
618 | inode_dio_wait(inode); | 626 | inode_dio_wait(inode); |
619 | 627 | ||
620 | error = vmtruncate(inode, attr->ia_size); | 628 | error = inode_newsize_ok(inode, attr->ia_size); |
621 | if (error) | 629 | if (error) |
622 | return error; | 630 | return error; |
631 | |||
632 | truncate_setsize(inode, attr->ia_size); | ||
633 | hfs_file_truncate(inode); | ||
623 | } | 634 | } |
624 | 635 | ||
625 | setattr_copy(inode, attr); | 636 | setattr_copy(inode, attr); |
@@ -668,7 +679,6 @@ static const struct file_operations hfs_file_operations = { | |||
668 | 679 | ||
669 | static const struct inode_operations hfs_file_inode_operations = { | 680 | static const struct inode_operations hfs_file_inode_operations = { |
670 | .lookup = hfs_file_lookup, | 681 | .lookup = hfs_file_lookup, |
671 | .truncate = hfs_file_truncate, | ||
672 | .setattr = hfs_inode_setattr, | 682 | .setattr = hfs_inode_setattr, |
673 | .setxattr = hfs_setxattr, | 683 | .setxattr = hfs_setxattr, |
674 | .getxattr = hfs_getxattr, | 684 | .getxattr = hfs_getxattr, |
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c index 2172aa5976f5..799b336b59f9 100644 --- a/fs/hfsplus/inode.c +++ b/fs/hfsplus/inode.c | |||
@@ -28,6 +28,16 @@ static int hfsplus_writepage(struct page *page, struct writeback_control *wbc) | |||
28 | return block_write_full_page(page, hfsplus_get_block, wbc); | 28 | return block_write_full_page(page, hfsplus_get_block, wbc); |
29 | } | 29 | } |
30 | 30 | ||
31 | static void hfsplus_write_failed(struct address_space *mapping, loff_t to) | ||
32 | { | ||
33 | struct inode *inode = mapping->host; | ||
34 | |||
35 | if (to > inode->i_size) { | ||
36 | truncate_pagecache(inode, to, inode->i_size); | ||
37 | hfsplus_file_truncate(inode); | ||
38 | } | ||
39 | } | ||
40 | |||
31 | static int hfsplus_write_begin(struct file *file, struct address_space *mapping, | 41 | static int hfsplus_write_begin(struct file *file, struct address_space *mapping, |
32 | loff_t pos, unsigned len, unsigned flags, | 42 | loff_t pos, unsigned len, unsigned flags, |
33 | struct page **pagep, void **fsdata) | 43 | struct page **pagep, void **fsdata) |
@@ -38,11 +48,8 @@ static int hfsplus_write_begin(struct file *file, struct address_space *mapping, | |||
38 | ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, | 48 | ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, |
39 | hfsplus_get_block, | 49 | hfsplus_get_block, |
40 | &HFSPLUS_I(mapping->host)->phys_size); | 50 | &HFSPLUS_I(mapping->host)->phys_size); |
41 | if (unlikely(ret)) { | 51 | if (unlikely(ret)) |
42 | loff_t isize = mapping->host->i_size; | 52 | hfsplus_write_failed(mapping, pos + len); |
43 | if (pos + len > isize) | ||
44 | vmtruncate(mapping->host, isize); | ||
45 | } | ||
46 | 53 | ||
47 | return ret; | 54 | return ret; |
48 | } | 55 | } |
@@ -116,6 +123,7 @@ static ssize_t hfsplus_direct_IO(int rw, struct kiocb *iocb, | |||
116 | const struct iovec *iov, loff_t offset, unsigned long nr_segs) | 123 | const struct iovec *iov, loff_t offset, unsigned long nr_segs) |
117 | { | 124 | { |
118 | struct file *file = iocb->ki_filp; | 125 | struct file *file = iocb->ki_filp; |
126 | struct address_space *mapping = file->f_mapping; | ||
119 | struct inode *inode = file->f_path.dentry->d_inode->i_mapping->host; | 127 | struct inode *inode = file->f_path.dentry->d_inode->i_mapping->host; |
120 | ssize_t ret; | 128 | ssize_t ret; |
121 | 129 | ||
@@ -131,7 +139,7 @@ static ssize_t hfsplus_direct_IO(int rw, struct kiocb *iocb, | |||
131 | loff_t end = offset + iov_length(iov, nr_segs); | 139 | loff_t end = offset + iov_length(iov, nr_segs); |
132 | 140 | ||
133 | if (end > isize) | 141 | if (end > isize) |
134 | vmtruncate(inode, isize); | 142 | hfsplus_write_failed(mapping, end); |
135 | } | 143 | } |
136 | 144 | ||
137 | return ret; | 145 | return ret; |
@@ -300,10 +308,8 @@ static int hfsplus_setattr(struct dentry *dentry, struct iattr *attr) | |||
300 | if ((attr->ia_valid & ATTR_SIZE) && | 308 | if ((attr->ia_valid & ATTR_SIZE) && |
301 | attr->ia_size != i_size_read(inode)) { | 309 | attr->ia_size != i_size_read(inode)) { |
302 | inode_dio_wait(inode); | 310 | inode_dio_wait(inode); |
303 | 311 | truncate_setsize(inode, attr->ia_size); | |
304 | error = vmtruncate(inode, attr->ia_size); | 312 | hfsplus_file_truncate(inode); |
305 | if (error) | ||
306 | return error; | ||
307 | } | 313 | } |
308 | 314 | ||
309 | setattr_copy(inode, attr); | 315 | setattr_copy(inode, attr); |
@@ -358,7 +364,6 @@ int hfsplus_file_fsync(struct file *file, loff_t start, loff_t end, | |||
358 | 364 | ||
359 | static const struct inode_operations hfsplus_file_inode_operations = { | 365 | static const struct inode_operations hfsplus_file_inode_operations = { |
360 | .lookup = hfsplus_file_lookup, | 366 | .lookup = hfsplus_file_lookup, |
361 | .truncate = hfsplus_file_truncate, | ||
362 | .setattr = hfsplus_setattr, | 367 | .setattr = hfsplus_setattr, |
363 | .setxattr = hfsplus_setxattr, | 368 | .setxattr = hfsplus_setxattr, |
364 | .getxattr = hfsplus_getxattr, | 369 | .getxattr = hfsplus_getxattr, |
diff --git a/fs/hpfs/file.c b/fs/hpfs/file.c index 89d2a5803ae3..fbfe2df5624b 100644 --- a/fs/hpfs/file.c +++ b/fs/hpfs/file.c | |||
@@ -50,7 +50,7 @@ static secno hpfs_bmap(struct inode *inode, unsigned file_secno) | |||
50 | return disk_secno; | 50 | return disk_secno; |
51 | } | 51 | } |
52 | 52 | ||
53 | static void hpfs_truncate(struct inode *i) | 53 | void hpfs_truncate(struct inode *i) |
54 | { | 54 | { |
55 | if (IS_IMMUTABLE(i)) return /*-EPERM*/; | 55 | if (IS_IMMUTABLE(i)) return /*-EPERM*/; |
56 | hpfs_lock_assert(i->i_sb); | 56 | hpfs_lock_assert(i->i_sb); |
@@ -105,6 +105,16 @@ static int hpfs_readpage(struct file *file, struct page *page) | |||
105 | return block_read_full_page(page,hpfs_get_block); | 105 | return block_read_full_page(page,hpfs_get_block); |
106 | } | 106 | } |
107 | 107 | ||
108 | static void hpfs_write_failed(struct address_space *mapping, loff_t to) | ||
109 | { | ||
110 | struct inode *inode = mapping->host; | ||
111 | |||
112 | if (to > inode->i_size) { | ||
113 | truncate_pagecache(inode, to, inode->i_size); | ||
114 | hpfs_truncate(inode); | ||
115 | } | ||
116 | } | ||
117 | |||
108 | static int hpfs_write_begin(struct file *file, struct address_space *mapping, | 118 | static int hpfs_write_begin(struct file *file, struct address_space *mapping, |
109 | loff_t pos, unsigned len, unsigned flags, | 119 | loff_t pos, unsigned len, unsigned flags, |
110 | struct page **pagep, void **fsdata) | 120 | struct page **pagep, void **fsdata) |
@@ -115,11 +125,8 @@ static int hpfs_write_begin(struct file *file, struct address_space *mapping, | |||
115 | ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, | 125 | ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, |
116 | hpfs_get_block, | 126 | hpfs_get_block, |
117 | &hpfs_i(mapping->host)->mmu_private); | 127 | &hpfs_i(mapping->host)->mmu_private); |
118 | if (unlikely(ret)) { | 128 | if (unlikely(ret)) |
119 | loff_t isize = mapping->host->i_size; | 129 | hpfs_write_failed(mapping, pos + len); |
120 | if (pos + len > isize) | ||
121 | vmtruncate(mapping->host, isize); | ||
122 | } | ||
123 | 130 | ||
124 | return ret; | 131 | return ret; |
125 | } | 132 | } |
@@ -166,6 +173,5 @@ const struct file_operations hpfs_file_ops = | |||
166 | 173 | ||
167 | const struct inode_operations hpfs_file_iops = | 174 | const struct inode_operations hpfs_file_iops = |
168 | { | 175 | { |
169 | .truncate = hpfs_truncate, | ||
170 | .setattr = hpfs_setattr, | 176 | .setattr = hpfs_setattr, |
171 | }; | 177 | }; |
diff --git a/fs/hpfs/hpfs_fn.h b/fs/hpfs/hpfs_fn.h index 7102aaecc244..b7ae286646b5 100644 --- a/fs/hpfs/hpfs_fn.h +++ b/fs/hpfs/hpfs_fn.h | |||
@@ -252,6 +252,7 @@ void hpfs_set_ea(struct inode *, struct fnode *, const char *, | |||
252 | /* file.c */ | 252 | /* file.c */ |
253 | 253 | ||
254 | int hpfs_file_fsync(struct file *, loff_t, loff_t, int); | 254 | int hpfs_file_fsync(struct file *, loff_t, loff_t, int); |
255 | void hpfs_truncate(struct inode *); | ||
255 | extern const struct file_operations hpfs_file_ops; | 256 | extern const struct file_operations hpfs_file_ops; |
256 | extern const struct inode_operations hpfs_file_iops; | 257 | extern const struct inode_operations hpfs_file_iops; |
257 | extern const struct address_space_operations hpfs_aops; | 258 | extern const struct address_space_operations hpfs_aops; |
diff --git a/fs/hpfs/inode.c b/fs/hpfs/inode.c index 804a9a842cbc..5dc06c837105 100644 --- a/fs/hpfs/inode.c +++ b/fs/hpfs/inode.c | |||
@@ -277,9 +277,12 @@ int hpfs_setattr(struct dentry *dentry, struct iattr *attr) | |||
277 | 277 | ||
278 | if ((attr->ia_valid & ATTR_SIZE) && | 278 | if ((attr->ia_valid & ATTR_SIZE) && |
279 | attr->ia_size != i_size_read(inode)) { | 279 | attr->ia_size != i_size_read(inode)) { |
280 | error = vmtruncate(inode, attr->ia_size); | 280 | error = inode_newsize_ok(inode, attr->ia_size); |
281 | if (error) | 281 | if (error) |
282 | goto out_unlock; | 282 | goto out_unlock; |
283 | |||
284 | truncate_setsize(inode, attr->ia_size); | ||
285 | hpfs_truncate(inode); | ||
283 | } | 286 | } |
284 | 287 | ||
285 | setattr_copy(inode, attr); | 288 | setattr_copy(inode, attr); |
diff --git a/fs/jfs/file.c b/fs/jfs/file.c index 9d3afd157f99..dd7442c58358 100644 --- a/fs/jfs/file.c +++ b/fs/jfs/file.c | |||
@@ -119,9 +119,12 @@ int jfs_setattr(struct dentry *dentry, struct iattr *iattr) | |||
119 | iattr->ia_size != i_size_read(inode)) { | 119 | iattr->ia_size != i_size_read(inode)) { |
120 | inode_dio_wait(inode); | 120 | inode_dio_wait(inode); |
121 | 121 | ||
122 | rc = vmtruncate(inode, iattr->ia_size); | 122 | rc = inode_newsize_ok(inode, iattr->ia_size); |
123 | if (rc) | 123 | if (rc) |
124 | return rc; | 124 | return rc; |
125 | |||
126 | truncate_setsize(inode, iattr->ia_size); | ||
127 | jfs_truncate(inode); | ||
125 | } | 128 | } |
126 | 129 | ||
127 | setattr_copy(inode, iattr); | 130 | setattr_copy(inode, iattr); |
@@ -133,7 +136,6 @@ int jfs_setattr(struct dentry *dentry, struct iattr *iattr) | |||
133 | } | 136 | } |
134 | 137 | ||
135 | const struct inode_operations jfs_file_inode_operations = { | 138 | const struct inode_operations jfs_file_inode_operations = { |
136 | .truncate = jfs_truncate, | ||
137 | .setxattr = jfs_setxattr, | 139 | .setxattr = jfs_setxattr, |
138 | .getxattr = jfs_getxattr, | 140 | .getxattr = jfs_getxattr, |
139 | .listxattr = jfs_listxattr, | 141 | .listxattr = jfs_listxattr, |
diff --git a/fs/jfs/inode.c b/fs/jfs/inode.c index 4692bf3ca8cb..b7dc47ba675e 100644 --- a/fs/jfs/inode.c +++ b/fs/jfs/inode.c | |||
@@ -300,6 +300,16 @@ static int jfs_readpages(struct file *file, struct address_space *mapping, | |||
300 | return mpage_readpages(mapping, pages, nr_pages, jfs_get_block); | 300 | return mpage_readpages(mapping, pages, nr_pages, jfs_get_block); |
301 | } | 301 | } |
302 | 302 | ||
303 | static void jfs_write_failed(struct address_space *mapping, loff_t to) | ||
304 | { | ||
305 | struct inode *inode = mapping->host; | ||
306 | |||
307 | if (to > inode->i_size) { | ||
308 | truncate_pagecache(inode, to, inode->i_size); | ||
309 | jfs_truncate(inode); | ||
310 | } | ||
311 | } | ||
312 | |||
303 | static int jfs_write_begin(struct file *file, struct address_space *mapping, | 313 | static int jfs_write_begin(struct file *file, struct address_space *mapping, |
304 | loff_t pos, unsigned len, unsigned flags, | 314 | loff_t pos, unsigned len, unsigned flags, |
305 | struct page **pagep, void **fsdata) | 315 | struct page **pagep, void **fsdata) |
@@ -308,11 +318,8 @@ static int jfs_write_begin(struct file *file, struct address_space *mapping, | |||
308 | 318 | ||
309 | ret = nobh_write_begin(mapping, pos, len, flags, pagep, fsdata, | 319 | ret = nobh_write_begin(mapping, pos, len, flags, pagep, fsdata, |
310 | jfs_get_block); | 320 | jfs_get_block); |
311 | if (unlikely(ret)) { | 321 | if (unlikely(ret)) |
312 | loff_t isize = mapping->host->i_size; | 322 | jfs_write_failed(mapping, pos + len); |
313 | if (pos + len > isize) | ||
314 | vmtruncate(mapping->host, isize); | ||
315 | } | ||
316 | 323 | ||
317 | return ret; | 324 | return ret; |
318 | } | 325 | } |
@@ -326,6 +333,7 @@ static ssize_t jfs_direct_IO(int rw, struct kiocb *iocb, | |||
326 | const struct iovec *iov, loff_t offset, unsigned long nr_segs) | 333 | const struct iovec *iov, loff_t offset, unsigned long nr_segs) |
327 | { | 334 | { |
328 | struct file *file = iocb->ki_filp; | 335 | struct file *file = iocb->ki_filp; |
336 | struct address_space *mapping = file->f_mapping; | ||
329 | struct inode *inode = file->f_mapping->host; | 337 | struct inode *inode = file->f_mapping->host; |
330 | ssize_t ret; | 338 | ssize_t ret; |
331 | 339 | ||
@@ -341,7 +349,7 @@ static ssize_t jfs_direct_IO(int rw, struct kiocb *iocb, | |||
341 | loff_t end = offset + iov_length(iov, nr_segs); | 349 | loff_t end = offset + iov_length(iov, nr_segs); |
342 | 350 | ||
343 | if (end > isize) | 351 | if (end > isize) |
344 | vmtruncate(inode, isize); | 352 | jfs_write_failed(mapping, end); |
345 | } | 353 | } |
346 | 354 | ||
347 | return ret; | 355 | return ret; |
diff --git a/fs/libfs.c b/fs/libfs.c index 35fc6e74cd88..916da8c4158b 100644 --- a/fs/libfs.c +++ b/fs/libfs.c | |||
@@ -369,8 +369,6 @@ int simple_setattr(struct dentry *dentry, struct iattr *iattr) | |||
369 | struct inode *inode = dentry->d_inode; | 369 | struct inode *inode = dentry->d_inode; |
370 | int error; | 370 | int error; |
371 | 371 | ||
372 | WARN_ON_ONCE(inode->i_op->truncate); | ||
373 | |||
374 | error = inode_change_ok(inode, iattr); | 372 | error = inode_change_ok(inode, iattr); |
375 | if (error) | 373 | if (error) |
376 | return error; | 374 | return error; |
diff --git a/fs/logfs/readwrite.c b/fs/logfs/readwrite.c index e1a3b6bf6324..9a59cbade2fb 100644 --- a/fs/logfs/readwrite.c +++ b/fs/logfs/readwrite.c | |||
@@ -1887,9 +1887,15 @@ int logfs_truncate(struct inode *inode, u64 target) | |||
1887 | logfs_put_wblocks(sb, NULL, 1); | 1887 | logfs_put_wblocks(sb, NULL, 1); |
1888 | } | 1888 | } |
1889 | 1889 | ||
1890 | if (!err) | 1890 | if (!err) { |
1891 | err = vmtruncate(inode, target); | 1891 | err = inode_newsize_ok(inode, target); |
1892 | if (err) | ||
1893 | goto out; | ||
1894 | |||
1895 | truncate_setsize(inode, target); | ||
1896 | } | ||
1892 | 1897 | ||
1898 | out: | ||
1893 | /* I don't trust error recovery yet. */ | 1899 | /* I don't trust error recovery yet. */ |
1894 | WARN_ON(err); | 1900 | WARN_ON(err); |
1895 | return err; | 1901 | return err; |
diff --git a/fs/minix/file.c b/fs/minix/file.c index 4493ce695ab8..adc6f5494231 100644 --- a/fs/minix/file.c +++ b/fs/minix/file.c | |||
@@ -34,9 +34,12 @@ static int minix_setattr(struct dentry *dentry, struct iattr *attr) | |||
34 | 34 | ||
35 | if ((attr->ia_valid & ATTR_SIZE) && | 35 | if ((attr->ia_valid & ATTR_SIZE) && |
36 | attr->ia_size != i_size_read(inode)) { | 36 | attr->ia_size != i_size_read(inode)) { |
37 | error = vmtruncate(inode, attr->ia_size); | 37 | error = inode_newsize_ok(inode, attr->ia_size); |
38 | if (error) | 38 | if (error) |
39 | return error; | 39 | return error; |
40 | |||
41 | truncate_setsize(inode, attr->ia_size); | ||
42 | minix_truncate(inode); | ||
40 | } | 43 | } |
41 | 44 | ||
42 | setattr_copy(inode, attr); | 45 | setattr_copy(inode, attr); |
@@ -45,7 +48,6 @@ static int minix_setattr(struct dentry *dentry, struct iattr *attr) | |||
45 | } | 48 | } |
46 | 49 | ||
47 | const struct inode_operations minix_file_inode_operations = { | 50 | const struct inode_operations minix_file_inode_operations = { |
48 | .truncate = minix_truncate, | ||
49 | .setattr = minix_setattr, | 51 | .setattr = minix_setattr, |
50 | .getattr = minix_getattr, | 52 | .getattr = minix_getattr, |
51 | }; | 53 | }; |
diff --git a/fs/minix/inode.c b/fs/minix/inode.c index 4fc5f8ab1c44..99541cceb584 100644 --- a/fs/minix/inode.c +++ b/fs/minix/inode.c | |||
@@ -395,6 +395,16 @@ int minix_prepare_chunk(struct page *page, loff_t pos, unsigned len) | |||
395 | return __block_write_begin(page, pos, len, minix_get_block); | 395 | return __block_write_begin(page, pos, len, minix_get_block); |
396 | } | 396 | } |
397 | 397 | ||
398 | static void minix_write_failed(struct address_space *mapping, loff_t to) | ||
399 | { | ||
400 | struct inode *inode = mapping->host; | ||
401 | |||
402 | if (to > inode->i_size) { | ||
403 | truncate_pagecache(inode, to, inode->i_size); | ||
404 | minix_truncate(inode); | ||
405 | } | ||
406 | } | ||
407 | |||
398 | static int minix_write_begin(struct file *file, struct address_space *mapping, | 408 | static int minix_write_begin(struct file *file, struct address_space *mapping, |
399 | loff_t pos, unsigned len, unsigned flags, | 409 | loff_t pos, unsigned len, unsigned flags, |
400 | struct page **pagep, void **fsdata) | 410 | struct page **pagep, void **fsdata) |
@@ -403,11 +413,8 @@ static int minix_write_begin(struct file *file, struct address_space *mapping, | |||
403 | 413 | ||
404 | ret = block_write_begin(mapping, pos, len, flags, pagep, | 414 | ret = block_write_begin(mapping, pos, len, flags, pagep, |
405 | minix_get_block); | 415 | minix_get_block); |
406 | if (unlikely(ret)) { | 416 | if (unlikely(ret)) |
407 | loff_t isize = mapping->host->i_size; | 417 | minix_write_failed(mapping, pos + len); |
408 | if (pos + len > isize) | ||
409 | vmtruncate(mapping->host, isize); | ||
410 | } | ||
411 | 418 | ||
412 | return ret; | 419 | return ret; |
413 | } | 420 | } |
diff --git a/fs/namei.c b/fs/namei.c index 5f4cdf3ad913..43a97ee1d4c8 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -1275,9 +1275,7 @@ static struct dentry *lookup_dcache(struct qstr *name, struct dentry *dir, | |||
1275 | *need_lookup = false; | 1275 | *need_lookup = false; |
1276 | dentry = d_lookup(dir, name); | 1276 | dentry = d_lookup(dir, name); |
1277 | if (dentry) { | 1277 | if (dentry) { |
1278 | if (d_need_lookup(dentry)) { | 1278 | if (dentry->d_flags & DCACHE_OP_REVALIDATE) { |
1279 | *need_lookup = true; | ||
1280 | } else if (dentry->d_flags & DCACHE_OP_REVALIDATE) { | ||
1281 | error = d_revalidate(dentry, flags); | 1279 | error = d_revalidate(dentry, flags); |
1282 | if (unlikely(error <= 0)) { | 1280 | if (unlikely(error <= 0)) { |
1283 | if (error < 0) { | 1281 | if (error < 0) { |
@@ -1383,8 +1381,6 @@ static int lookup_fast(struct nameidata *nd, struct qstr *name, | |||
1383 | return -ECHILD; | 1381 | return -ECHILD; |
1384 | nd->seq = seq; | 1382 | nd->seq = seq; |
1385 | 1383 | ||
1386 | if (unlikely(d_need_lookup(dentry))) | ||
1387 | goto unlazy; | ||
1388 | if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE)) { | 1384 | if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE)) { |
1389 | status = d_revalidate(dentry, nd->flags); | 1385 | status = d_revalidate(dentry, nd->flags); |
1390 | if (unlikely(status <= 0)) { | 1386 | if (unlikely(status <= 0)) { |
@@ -1410,11 +1406,6 @@ unlazy: | |||
1410 | if (unlikely(!dentry)) | 1406 | if (unlikely(!dentry)) |
1411 | goto need_lookup; | 1407 | goto need_lookup; |
1412 | 1408 | ||
1413 | if (unlikely(d_need_lookup(dentry))) { | ||
1414 | dput(dentry); | ||
1415 | goto need_lookup; | ||
1416 | } | ||
1417 | |||
1418 | if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE) && need_reval) | 1409 | if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE) && need_reval) |
1419 | status = d_revalidate(dentry, nd->flags); | 1410 | status = d_revalidate(dentry, nd->flags); |
1420 | if (unlikely(status <= 0)) { | 1411 | if (unlikely(status <= 0)) { |
@@ -1859,7 +1850,7 @@ static int path_init(int dfd, const char *name, unsigned int flags, | |||
1859 | if (flags & LOOKUP_ROOT) { | 1850 | if (flags & LOOKUP_ROOT) { |
1860 | struct inode *inode = nd->root.dentry->d_inode; | 1851 | struct inode *inode = nd->root.dentry->d_inode; |
1861 | if (*name) { | 1852 | if (*name) { |
1862 | if (!inode->i_op->lookup) | 1853 | if (!can_lookup(inode)) |
1863 | return -ENOTDIR; | 1854 | return -ENOTDIR; |
1864 | retval = inode_permission(inode, MAY_EXEC); | 1855 | retval = inode_permission(inode, MAY_EXEC); |
1865 | if (retval) | 1856 | if (retval) |
@@ -1903,6 +1894,7 @@ static int path_init(int dfd, const char *name, unsigned int flags, | |||
1903 | get_fs_pwd(current->fs, &nd->path); | 1894 | get_fs_pwd(current->fs, &nd->path); |
1904 | } | 1895 | } |
1905 | } else { | 1896 | } else { |
1897 | /* Caller must check execute permissions on the starting path component */ | ||
1906 | struct fd f = fdget_raw(dfd); | 1898 | struct fd f = fdget_raw(dfd); |
1907 | struct dentry *dentry; | 1899 | struct dentry *dentry; |
1908 | 1900 | ||
@@ -1912,16 +1904,10 @@ static int path_init(int dfd, const char *name, unsigned int flags, | |||
1912 | dentry = f.file->f_path.dentry; | 1904 | dentry = f.file->f_path.dentry; |
1913 | 1905 | ||
1914 | if (*name) { | 1906 | if (*name) { |
1915 | if (!S_ISDIR(dentry->d_inode->i_mode)) { | 1907 | if (!can_lookup(dentry->d_inode)) { |
1916 | fdput(f); | 1908 | fdput(f); |
1917 | return -ENOTDIR; | 1909 | return -ENOTDIR; |
1918 | } | 1910 | } |
1919 | |||
1920 | retval = inode_permission(dentry->d_inode, MAY_EXEC); | ||
1921 | if (retval) { | ||
1922 | fdput(f); | ||
1923 | return retval; | ||
1924 | } | ||
1925 | } | 1911 | } |
1926 | 1912 | ||
1927 | nd->path = f.file->f_path; | 1913 | nd->path = f.file->f_path; |
@@ -2189,15 +2175,19 @@ int user_path_at(int dfd, const char __user *name, unsigned flags, | |||
2189 | * path-walking is complete. | 2175 | * path-walking is complete. |
2190 | */ | 2176 | */ |
2191 | static struct filename * | 2177 | static struct filename * |
2192 | user_path_parent(int dfd, const char __user *path, struct nameidata *nd) | 2178 | user_path_parent(int dfd, const char __user *path, struct nameidata *nd, |
2179 | unsigned int flags) | ||
2193 | { | 2180 | { |
2194 | struct filename *s = getname(path); | 2181 | struct filename *s = getname(path); |
2195 | int error; | 2182 | int error; |
2196 | 2183 | ||
2184 | /* only LOOKUP_REVAL is allowed in extra flags */ | ||
2185 | flags &= LOOKUP_REVAL; | ||
2186 | |||
2197 | if (IS_ERR(s)) | 2187 | if (IS_ERR(s)) |
2198 | return s; | 2188 | return s; |
2199 | 2189 | ||
2200 | error = filename_lookup(dfd, s, LOOKUP_PARENT, nd); | 2190 | error = filename_lookup(dfd, s, flags | LOOKUP_PARENT, nd); |
2201 | if (error) { | 2191 | if (error) { |
2202 | putname(s); | 2192 | putname(s); |
2203 | return ERR_PTR(error); | 2193 | return ERR_PTR(error); |
@@ -3044,12 +3034,22 @@ struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt, | |||
3044 | return file; | 3034 | return file; |
3045 | } | 3035 | } |
3046 | 3036 | ||
3047 | struct dentry *kern_path_create(int dfd, const char *pathname, struct path *path, int is_dir) | 3037 | struct dentry *kern_path_create(int dfd, const char *pathname, |
3038 | struct path *path, unsigned int lookup_flags) | ||
3048 | { | 3039 | { |
3049 | struct dentry *dentry = ERR_PTR(-EEXIST); | 3040 | struct dentry *dentry = ERR_PTR(-EEXIST); |
3050 | struct nameidata nd; | 3041 | struct nameidata nd; |
3051 | int err2; | 3042 | int err2; |
3052 | int error = do_path_lookup(dfd, pathname, LOOKUP_PARENT, &nd); | 3043 | int error; |
3044 | bool is_dir = (lookup_flags & LOOKUP_DIRECTORY); | ||
3045 | |||
3046 | /* | ||
3047 | * Note that only LOOKUP_REVAL and LOOKUP_DIRECTORY matter here. Any | ||
3048 | * other flags passed in are ignored! | ||
3049 | */ | ||
3050 | lookup_flags &= LOOKUP_REVAL; | ||
3051 | |||
3052 | error = do_path_lookup(dfd, pathname, LOOKUP_PARENT|lookup_flags, &nd); | ||
3053 | if (error) | 3053 | if (error) |
3054 | return ERR_PTR(error); | 3054 | return ERR_PTR(error); |
3055 | 3055 | ||
@@ -3113,13 +3113,14 @@ void done_path_create(struct path *path, struct dentry *dentry) | |||
3113 | } | 3113 | } |
3114 | EXPORT_SYMBOL(done_path_create); | 3114 | EXPORT_SYMBOL(done_path_create); |
3115 | 3115 | ||
3116 | struct dentry *user_path_create(int dfd, const char __user *pathname, struct path *path, int is_dir) | 3116 | struct dentry *user_path_create(int dfd, const char __user *pathname, |
3117 | struct path *path, unsigned int lookup_flags) | ||
3117 | { | 3118 | { |
3118 | struct filename *tmp = getname(pathname); | 3119 | struct filename *tmp = getname(pathname); |
3119 | struct dentry *res; | 3120 | struct dentry *res; |
3120 | if (IS_ERR(tmp)) | 3121 | if (IS_ERR(tmp)) |
3121 | return ERR_CAST(tmp); | 3122 | return ERR_CAST(tmp); |
3122 | res = kern_path_create(dfd, tmp->name, path, is_dir); | 3123 | res = kern_path_create(dfd, tmp->name, path, lookup_flags); |
3123 | putname(tmp); | 3124 | putname(tmp); |
3124 | return res; | 3125 | return res; |
3125 | } | 3126 | } |
@@ -3175,12 +3176,13 @@ SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, umode_t, mode, | |||
3175 | struct dentry *dentry; | 3176 | struct dentry *dentry; |
3176 | struct path path; | 3177 | struct path path; |
3177 | int error; | 3178 | int error; |
3179 | unsigned int lookup_flags = 0; | ||
3178 | 3180 | ||
3179 | error = may_mknod(mode); | 3181 | error = may_mknod(mode); |
3180 | if (error) | 3182 | if (error) |
3181 | return error; | 3183 | return error; |
3182 | 3184 | retry: | |
3183 | dentry = user_path_create(dfd, filename, &path, 0); | 3185 | dentry = user_path_create(dfd, filename, &path, lookup_flags); |
3184 | if (IS_ERR(dentry)) | 3186 | if (IS_ERR(dentry)) |
3185 | return PTR_ERR(dentry); | 3187 | return PTR_ERR(dentry); |
3186 | 3188 | ||
@@ -3203,6 +3205,10 @@ SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, umode_t, mode, | |||
3203 | } | 3205 | } |
3204 | out: | 3206 | out: |
3205 | done_path_create(&path, dentry); | 3207 | done_path_create(&path, dentry); |
3208 | if (retry_estale(error, lookup_flags)) { | ||
3209 | lookup_flags |= LOOKUP_REVAL; | ||
3210 | goto retry; | ||
3211 | } | ||
3206 | return error; | 3212 | return error; |
3207 | } | 3213 | } |
3208 | 3214 | ||
@@ -3241,8 +3247,10 @@ SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, umode_t, mode) | |||
3241 | struct dentry *dentry; | 3247 | struct dentry *dentry; |
3242 | struct path path; | 3248 | struct path path; |
3243 | int error; | 3249 | int error; |
3250 | unsigned int lookup_flags = LOOKUP_DIRECTORY; | ||
3244 | 3251 | ||
3245 | dentry = user_path_create(dfd, pathname, &path, 1); | 3252 | retry: |
3253 | dentry = user_path_create(dfd, pathname, &path, lookup_flags); | ||
3246 | if (IS_ERR(dentry)) | 3254 | if (IS_ERR(dentry)) |
3247 | return PTR_ERR(dentry); | 3255 | return PTR_ERR(dentry); |
3248 | 3256 | ||
@@ -3252,6 +3260,10 @@ SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, umode_t, mode) | |||
3252 | if (!error) | 3260 | if (!error) |
3253 | error = vfs_mkdir(path.dentry->d_inode, dentry, mode); | 3261 | error = vfs_mkdir(path.dentry->d_inode, dentry, mode); |
3254 | done_path_create(&path, dentry); | 3262 | done_path_create(&path, dentry); |
3263 | if (retry_estale(error, lookup_flags)) { | ||
3264 | lookup_flags |= LOOKUP_REVAL; | ||
3265 | goto retry; | ||
3266 | } | ||
3255 | return error; | 3267 | return error; |
3256 | } | 3268 | } |
3257 | 3269 | ||
@@ -3327,8 +3339,9 @@ static long do_rmdir(int dfd, const char __user *pathname) | |||
3327 | struct filename *name; | 3339 | struct filename *name; |
3328 | struct dentry *dentry; | 3340 | struct dentry *dentry; |
3329 | struct nameidata nd; | 3341 | struct nameidata nd; |
3330 | 3342 | unsigned int lookup_flags = 0; | |
3331 | name = user_path_parent(dfd, pathname, &nd); | 3343 | retry: |
3344 | name = user_path_parent(dfd, pathname, &nd, lookup_flags); | ||
3332 | if (IS_ERR(name)) | 3345 | if (IS_ERR(name)) |
3333 | return PTR_ERR(name); | 3346 | return PTR_ERR(name); |
3334 | 3347 | ||
@@ -3370,6 +3383,10 @@ exit2: | |||
3370 | exit1: | 3383 | exit1: |
3371 | path_put(&nd.path); | 3384 | path_put(&nd.path); |
3372 | putname(name); | 3385 | putname(name); |
3386 | if (retry_estale(error, lookup_flags)) { | ||
3387 | lookup_flags |= LOOKUP_REVAL; | ||
3388 | goto retry; | ||
3389 | } | ||
3373 | return error; | 3390 | return error; |
3374 | } | 3391 | } |
3375 | 3392 | ||
@@ -3423,8 +3440,9 @@ static long do_unlinkat(int dfd, const char __user *pathname) | |||
3423 | struct dentry *dentry; | 3440 | struct dentry *dentry; |
3424 | struct nameidata nd; | 3441 | struct nameidata nd; |
3425 | struct inode *inode = NULL; | 3442 | struct inode *inode = NULL; |
3426 | 3443 | unsigned int lookup_flags = 0; | |
3427 | name = user_path_parent(dfd, pathname, &nd); | 3444 | retry: |
3445 | name = user_path_parent(dfd, pathname, &nd, lookup_flags); | ||
3428 | if (IS_ERR(name)) | 3446 | if (IS_ERR(name)) |
3429 | return PTR_ERR(name); | 3447 | return PTR_ERR(name); |
3430 | 3448 | ||
@@ -3462,6 +3480,11 @@ exit2: | |||
3462 | exit1: | 3480 | exit1: |
3463 | path_put(&nd.path); | 3481 | path_put(&nd.path); |
3464 | putname(name); | 3482 | putname(name); |
3483 | if (retry_estale(error, lookup_flags)) { | ||
3484 | lookup_flags |= LOOKUP_REVAL; | ||
3485 | inode = NULL; | ||
3486 | goto retry; | ||
3487 | } | ||
3465 | return error; | 3488 | return error; |
3466 | 3489 | ||
3467 | slashes: | 3490 | slashes: |
@@ -3513,12 +3536,13 @@ SYSCALL_DEFINE3(symlinkat, const char __user *, oldname, | |||
3513 | struct filename *from; | 3536 | struct filename *from; |
3514 | struct dentry *dentry; | 3537 | struct dentry *dentry; |
3515 | struct path path; | 3538 | struct path path; |
3539 | unsigned int lookup_flags = 0; | ||
3516 | 3540 | ||
3517 | from = getname(oldname); | 3541 | from = getname(oldname); |
3518 | if (IS_ERR(from)) | 3542 | if (IS_ERR(from)) |
3519 | return PTR_ERR(from); | 3543 | return PTR_ERR(from); |
3520 | 3544 | retry: | |
3521 | dentry = user_path_create(newdfd, newname, &path, 0); | 3545 | dentry = user_path_create(newdfd, newname, &path, lookup_flags); |
3522 | error = PTR_ERR(dentry); | 3546 | error = PTR_ERR(dentry); |
3523 | if (IS_ERR(dentry)) | 3547 | if (IS_ERR(dentry)) |
3524 | goto out_putname; | 3548 | goto out_putname; |
@@ -3527,6 +3551,10 @@ SYSCALL_DEFINE3(symlinkat, const char __user *, oldname, | |||
3527 | if (!error) | 3551 | if (!error) |
3528 | error = vfs_symlink(path.dentry->d_inode, dentry, from->name); | 3552 | error = vfs_symlink(path.dentry->d_inode, dentry, from->name); |
3529 | done_path_create(&path, dentry); | 3553 | done_path_create(&path, dentry); |
3554 | if (retry_estale(error, lookup_flags)) { | ||
3555 | lookup_flags |= LOOKUP_REVAL; | ||
3556 | goto retry; | ||
3557 | } | ||
3530 | out_putname: | 3558 | out_putname: |
3531 | putname(from); | 3559 | putname(from); |
3532 | return error; | 3560 | return error; |
@@ -3613,12 +3641,13 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname, | |||
3613 | 3641 | ||
3614 | if (flags & AT_SYMLINK_FOLLOW) | 3642 | if (flags & AT_SYMLINK_FOLLOW) |
3615 | how |= LOOKUP_FOLLOW; | 3643 | how |= LOOKUP_FOLLOW; |
3616 | 3644 | retry: | |
3617 | error = user_path_at(olddfd, oldname, how, &old_path); | 3645 | error = user_path_at(olddfd, oldname, how, &old_path); |
3618 | if (error) | 3646 | if (error) |
3619 | return error; | 3647 | return error; |
3620 | 3648 | ||
3621 | new_dentry = user_path_create(newdfd, newname, &new_path, 0); | 3649 | new_dentry = user_path_create(newdfd, newname, &new_path, |
3650 | (how & LOOKUP_REVAL)); | ||
3622 | error = PTR_ERR(new_dentry); | 3651 | error = PTR_ERR(new_dentry); |
3623 | if (IS_ERR(new_dentry)) | 3652 | if (IS_ERR(new_dentry)) |
3624 | goto out; | 3653 | goto out; |
@@ -3635,6 +3664,10 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname, | |||
3635 | error = vfs_link(old_path.dentry, new_path.dentry->d_inode, new_dentry); | 3664 | error = vfs_link(old_path.dentry, new_path.dentry->d_inode, new_dentry); |
3636 | out_dput: | 3665 | out_dput: |
3637 | done_path_create(&new_path, new_dentry); | 3666 | done_path_create(&new_path, new_dentry); |
3667 | if (retry_estale(error, how)) { | ||
3668 | how |= LOOKUP_REVAL; | ||
3669 | goto retry; | ||
3670 | } | ||
3638 | out: | 3671 | out: |
3639 | path_put(&old_path); | 3672 | path_put(&old_path); |
3640 | 3673 | ||
@@ -3807,15 +3840,17 @@ SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname, | |||
3807 | struct nameidata oldnd, newnd; | 3840 | struct nameidata oldnd, newnd; |
3808 | struct filename *from; | 3841 | struct filename *from; |
3809 | struct filename *to; | 3842 | struct filename *to; |
3843 | unsigned int lookup_flags = 0; | ||
3844 | bool should_retry = false; | ||
3810 | int error; | 3845 | int error; |
3811 | 3846 | retry: | |
3812 | from = user_path_parent(olddfd, oldname, &oldnd); | 3847 | from = user_path_parent(olddfd, oldname, &oldnd, lookup_flags); |
3813 | if (IS_ERR(from)) { | 3848 | if (IS_ERR(from)) { |
3814 | error = PTR_ERR(from); | 3849 | error = PTR_ERR(from); |
3815 | goto exit; | 3850 | goto exit; |
3816 | } | 3851 | } |
3817 | 3852 | ||
3818 | to = user_path_parent(newdfd, newname, &newnd); | 3853 | to = user_path_parent(newdfd, newname, &newnd, lookup_flags); |
3819 | if (IS_ERR(to)) { | 3854 | if (IS_ERR(to)) { |
3820 | error = PTR_ERR(to); | 3855 | error = PTR_ERR(to); |
3821 | goto exit1; | 3856 | goto exit1; |
@@ -3887,11 +3922,18 @@ exit3: | |||
3887 | unlock_rename(new_dir, old_dir); | 3922 | unlock_rename(new_dir, old_dir); |
3888 | mnt_drop_write(oldnd.path.mnt); | 3923 | mnt_drop_write(oldnd.path.mnt); |
3889 | exit2: | 3924 | exit2: |
3925 | if (retry_estale(error, lookup_flags)) | ||
3926 | should_retry = true; | ||
3890 | path_put(&newnd.path); | 3927 | path_put(&newnd.path); |
3891 | putname(to); | 3928 | putname(to); |
3892 | exit1: | 3929 | exit1: |
3893 | path_put(&oldnd.path); | 3930 | path_put(&oldnd.path); |
3894 | putname(from); | 3931 | putname(from); |
3932 | if (should_retry) { | ||
3933 | should_retry = false; | ||
3934 | lookup_flags |= LOOKUP_REVAL; | ||
3935 | goto retry; | ||
3936 | } | ||
3895 | exit: | 3937 | exit: |
3896 | return error; | 3938 | return error; |
3897 | } | 3939 | } |
diff --git a/fs/namespace.c b/fs/namespace.c index 398a50ff2438..55605c552787 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -313,7 +313,7 @@ int __mnt_want_write(struct vfsmount *m) | |||
313 | * incremented count after it has set MNT_WRITE_HOLD. | 313 | * incremented count after it has set MNT_WRITE_HOLD. |
314 | */ | 314 | */ |
315 | smp_mb(); | 315 | smp_mb(); |
316 | while (mnt->mnt.mnt_flags & MNT_WRITE_HOLD) | 316 | while (ACCESS_ONCE(mnt->mnt.mnt_flags) & MNT_WRITE_HOLD) |
317 | cpu_relax(); | 317 | cpu_relax(); |
318 | /* | 318 | /* |
319 | * After the slowpath clears MNT_WRITE_HOLD, mnt_is_readonly will | 319 | * After the slowpath clears MNT_WRITE_HOLD, mnt_is_readonly will |
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index d7e9fe77188a..1acdad7fcec7 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c | |||
@@ -976,9 +976,7 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr) | |||
976 | goto out; | 976 | goto out; |
977 | 977 | ||
978 | if (attr->ia_size != i_size_read(inode)) { | 978 | if (attr->ia_size != i_size_read(inode)) { |
979 | result = vmtruncate(inode, attr->ia_size); | 979 | truncate_setsize(inode, attr->ia_size); |
980 | if (result) | ||
981 | goto out; | ||
982 | mark_inode_dirty(inode); | 980 | mark_inode_dirty(inode); |
983 | } | 981 | } |
984 | } | 982 | } |
diff --git a/fs/nfs/fscache.c b/fs/nfs/fscache.c index c817787fbdb4..24d1d1c5fcaf 100644 --- a/fs/nfs/fscache.c +++ b/fs/nfs/fscache.c | |||
@@ -307,6 +307,7 @@ void nfs_fscache_set_inode_cookie(struct inode *inode, struct file *filp) | |||
307 | nfs_fscache_inode_unlock(inode); | 307 | nfs_fscache_inode_unlock(inode); |
308 | } | 308 | } |
309 | } | 309 | } |
310 | EXPORT_SYMBOL_GPL(nfs_fscache_set_inode_cookie); | ||
310 | 311 | ||
311 | /* | 312 | /* |
312 | * Replace a per-inode cookie due to revalidation detecting a file having | 313 | * Replace a per-inode cookie due to revalidation detecting a file having |
diff --git a/fs/nfs/fscache.h b/fs/nfs/fscache.h index c5b11b53ff33..277b02782897 100644 --- a/fs/nfs/fscache.h +++ b/fs/nfs/fscache.h | |||
@@ -153,6 +153,22 @@ static inline void nfs_readpage_to_fscache(struct inode *inode, | |||
153 | } | 153 | } |
154 | 154 | ||
155 | /* | 155 | /* |
156 | * Invalidate the contents of fscache for this inode. This will not sleep. | ||
157 | */ | ||
158 | static inline void nfs_fscache_invalidate(struct inode *inode) | ||
159 | { | ||
160 | fscache_invalidate(NFS_I(inode)->fscache); | ||
161 | } | ||
162 | |||
163 | /* | ||
164 | * Wait for an object to finish being invalidated. | ||
165 | */ | ||
166 | static inline void nfs_fscache_wait_on_invalidate(struct inode *inode) | ||
167 | { | ||
168 | fscache_wait_on_invalidate(NFS_I(inode)->fscache); | ||
169 | } | ||
170 | |||
171 | /* | ||
156 | * indicate the client caching state as readable text | 172 | * indicate the client caching state as readable text |
157 | */ | 173 | */ |
158 | static inline const char *nfs_server_fscache_state(struct nfs_server *server) | 174 | static inline const char *nfs_server_fscache_state(struct nfs_server *server) |
@@ -162,7 +178,6 @@ static inline const char *nfs_server_fscache_state(struct nfs_server *server) | |||
162 | return "no "; | 178 | return "no "; |
163 | } | 179 | } |
164 | 180 | ||
165 | |||
166 | #else /* CONFIG_NFS_FSCACHE */ | 181 | #else /* CONFIG_NFS_FSCACHE */ |
167 | static inline int nfs_fscache_register(void) { return 0; } | 182 | static inline int nfs_fscache_register(void) { return 0; } |
168 | static inline void nfs_fscache_unregister(void) {} | 183 | static inline void nfs_fscache_unregister(void) {} |
@@ -205,6 +220,9 @@ static inline int nfs_readpages_from_fscache(struct nfs_open_context *ctx, | |||
205 | static inline void nfs_readpage_to_fscache(struct inode *inode, | 220 | static inline void nfs_readpage_to_fscache(struct inode *inode, |
206 | struct page *page, int sync) {} | 221 | struct page *page, int sync) {} |
207 | 222 | ||
223 | |||
224 | static inline void nfs_fscache_invalidate(struct inode *inode) {} | ||
225 | |||
208 | static inline const char *nfs_server_fscache_state(struct nfs_server *server) | 226 | static inline const char *nfs_server_fscache_state(struct nfs_server *server) |
209 | { | 227 | { |
210 | return "no "; | 228 | return "no "; |
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 2faae14d89f4..ebeb94ce1b0b 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
@@ -161,10 +161,12 @@ static void nfs_zap_caches_locked(struct inode *inode) | |||
161 | nfsi->attrtimeo_timestamp = jiffies; | 161 | nfsi->attrtimeo_timestamp = jiffies; |
162 | 162 | ||
163 | memset(NFS_I(inode)->cookieverf, 0, sizeof(NFS_I(inode)->cookieverf)); | 163 | memset(NFS_I(inode)->cookieverf, 0, sizeof(NFS_I(inode)->cookieverf)); |
164 | if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) | 164 | if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) { |
165 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE; | 165 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE; |
166 | else | 166 | nfs_fscache_invalidate(inode); |
167 | } else { | ||
167 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE; | 168 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL|NFS_INO_REVAL_PAGECACHE; |
169 | } | ||
168 | } | 170 | } |
169 | 171 | ||
170 | void nfs_zap_caches(struct inode *inode) | 172 | void nfs_zap_caches(struct inode *inode) |
@@ -179,6 +181,7 @@ void nfs_zap_mapping(struct inode *inode, struct address_space *mapping) | |||
179 | if (mapping->nrpages != 0) { | 181 | if (mapping->nrpages != 0) { |
180 | spin_lock(&inode->i_lock); | 182 | spin_lock(&inode->i_lock); |
181 | NFS_I(inode)->cache_validity |= NFS_INO_INVALID_DATA; | 183 | NFS_I(inode)->cache_validity |= NFS_INO_INVALID_DATA; |
184 | nfs_fscache_invalidate(inode); | ||
182 | spin_unlock(&inode->i_lock); | 185 | spin_unlock(&inode->i_lock); |
183 | } | 186 | } |
184 | } | 187 | } |
@@ -881,7 +884,7 @@ static int nfs_invalidate_mapping(struct inode *inode, struct address_space *map | |||
881 | memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf)); | 884 | memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf)); |
882 | spin_unlock(&inode->i_lock); | 885 | spin_unlock(&inode->i_lock); |
883 | nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE); | 886 | nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE); |
884 | nfs_fscache_reset_inode_cookie(inode); | 887 | nfs_fscache_wait_on_invalidate(inode); |
885 | dfprintk(PAGECACHE, "NFS: (%s/%Ld) data cache invalidated\n", | 888 | dfprintk(PAGECACHE, "NFS: (%s/%Ld) data cache invalidated\n", |
886 | inode->i_sb->s_id, (long long)NFS_FILEID(inode)); | 889 | inode->i_sb->s_id, (long long)NFS_FILEID(inode)); |
887 | return 0; | 890 | return 0; |
@@ -957,6 +960,10 @@ static unsigned long nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr | |||
957 | i_size_write(inode, nfs_size_to_loff_t(fattr->size)); | 960 | i_size_write(inode, nfs_size_to_loff_t(fattr->size)); |
958 | ret |= NFS_INO_INVALID_ATTR; | 961 | ret |= NFS_INO_INVALID_ATTR; |
959 | } | 962 | } |
963 | |||
964 | if (nfsi->cache_validity & NFS_INO_INVALID_DATA) | ||
965 | nfs_fscache_invalidate(inode); | ||
966 | |||
960 | return ret; | 967 | return ret; |
961 | } | 968 | } |
962 | 969 | ||
@@ -1205,8 +1212,10 @@ static int nfs_post_op_update_inode_locked(struct inode *inode, struct nfs_fattr | |||
1205 | struct nfs_inode *nfsi = NFS_I(inode); | 1212 | struct nfs_inode *nfsi = NFS_I(inode); |
1206 | 1213 | ||
1207 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE; | 1214 | nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE; |
1208 | if (S_ISDIR(inode->i_mode)) | 1215 | if (S_ISDIR(inode->i_mode)) { |
1209 | nfsi->cache_validity |= NFS_INO_INVALID_DATA; | 1216 | nfsi->cache_validity |= NFS_INO_INVALID_DATA; |
1217 | nfs_fscache_invalidate(inode); | ||
1218 | } | ||
1210 | if ((fattr->valid & NFS_ATTR_FATTR) == 0) | 1219 | if ((fattr->valid & NFS_ATTR_FATTR) == 0) |
1211 | return 0; | 1220 | return 0; |
1212 | return nfs_refresh_inode_locked(inode, fattr); | 1221 | return nfs_refresh_inode_locked(inode, fattr); |
@@ -1494,6 +1503,9 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
1494 | (save_cache_validity & NFS_INO_REVAL_FORCED)) | 1503 | (save_cache_validity & NFS_INO_REVAL_FORCED)) |
1495 | nfsi->cache_validity |= invalid; | 1504 | nfsi->cache_validity |= invalid; |
1496 | 1505 | ||
1506 | if (invalid & NFS_INO_INVALID_DATA) | ||
1507 | nfs_fscache_invalidate(inode); | ||
1508 | |||
1497 | return 0; | 1509 | return 0; |
1498 | out_err: | 1510 | out_err: |
1499 | /* | 1511 | /* |
diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c index e7699308364a..08ddcccb8887 100644 --- a/fs/nfs/nfs4file.c +++ b/fs/nfs/nfs4file.c | |||
@@ -5,6 +5,7 @@ | |||
5 | */ | 5 | */ |
6 | #include <linux/nfs_fs.h> | 6 | #include <linux/nfs_fs.h> |
7 | #include "internal.h" | 7 | #include "internal.h" |
8 | #include "fscache.h" | ||
8 | #include "pnfs.h" | 9 | #include "pnfs.h" |
9 | 10 | ||
10 | #define NFSDBG_FACILITY NFSDBG_FILE | 11 | #define NFSDBG_FACILITY NFSDBG_FILE |
@@ -74,6 +75,7 @@ nfs4_file_open(struct inode *inode, struct file *filp) | |||
74 | 75 | ||
75 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); | 76 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); |
76 | nfs_file_set_open_context(filp, ctx); | 77 | nfs_file_set_open_context(filp, ctx); |
78 | nfs_fscache_set_inode_cookie(inode, filp); | ||
77 | err = 0; | 79 | err = 0; |
78 | 80 | ||
79 | out_put_ctx: | 81 | out_put_ctx: |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 493f0f41c554..5d864fb36578 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -64,7 +64,7 @@ | |||
64 | #include "pnfs.h" | 64 | #include "pnfs.h" |
65 | #include "netns.h" | 65 | #include "netns.h" |
66 | #include "nfs4session.h" | 66 | #include "nfs4session.h" |
67 | 67 | #include "fscache.h" | |
68 | 68 | ||
69 | #define NFSDBG_FACILITY NFSDBG_PROC | 69 | #define NFSDBG_FACILITY NFSDBG_PROC |
70 | 70 | ||
@@ -734,6 +734,7 @@ static void update_changeattr(struct inode *dir, struct nfs4_change_info *cinfo) | |||
734 | if (!cinfo->atomic || cinfo->before != dir->i_version) | 734 | if (!cinfo->atomic || cinfo->before != dir->i_version) |
735 | nfs_force_lookup_revalidate(dir); | 735 | nfs_force_lookup_revalidate(dir); |
736 | dir->i_version = cinfo->after; | 736 | dir->i_version = cinfo->after; |
737 | nfs_fscache_invalidate(dir); | ||
737 | spin_unlock(&dir->i_lock); | 738 | spin_unlock(&dir->i_lock); |
738 | } | 739 | } |
739 | 740 | ||
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 5209916e1222..b673be31590e 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
@@ -1794,7 +1794,8 @@ int nfs_migrate_page(struct address_space *mapping, struct page *newpage, | |||
1794 | if (PagePrivate(page)) | 1794 | if (PagePrivate(page)) |
1795 | return -EBUSY; | 1795 | return -EBUSY; |
1796 | 1796 | ||
1797 | nfs_fscache_release_page(page, GFP_KERNEL); | 1797 | if (!nfs_fscache_release_page(page, GFP_KERNEL)) |
1798 | return -EBUSY; | ||
1798 | 1799 | ||
1799 | return migrate_page(mapping, newpage, page, mode); | 1800 | return migrate_page(mapping, newpage, page, mode); |
1800 | } | 1801 | } |
diff --git a/fs/nilfs2/file.c b/fs/nilfs2/file.c index 16f35f7423c5..61946883025c 100644 --- a/fs/nilfs2/file.c +++ b/fs/nilfs2/file.c | |||
@@ -167,7 +167,6 @@ const struct file_operations nilfs_file_operations = { | |||
167 | }; | 167 | }; |
168 | 168 | ||
169 | const struct inode_operations nilfs_file_inode_operations = { | 169 | const struct inode_operations nilfs_file_inode_operations = { |
170 | .truncate = nilfs_truncate, | ||
171 | .setattr = nilfs_setattr, | 170 | .setattr = nilfs_setattr, |
172 | .permission = nilfs_permission, | 171 | .permission = nilfs_permission, |
173 | .fiemap = nilfs_fiemap, | 172 | .fiemap = nilfs_fiemap, |
diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c index 4d31d2cca7fd..6b49f14eac8c 100644 --- a/fs/nilfs2/inode.c +++ b/fs/nilfs2/inode.c | |||
@@ -213,6 +213,16 @@ static int nilfs_set_page_dirty(struct page *page) | |||
213 | return ret; | 213 | return ret; |
214 | } | 214 | } |
215 | 215 | ||
216 | void nilfs_write_failed(struct address_space *mapping, loff_t to) | ||
217 | { | ||
218 | struct inode *inode = mapping->host; | ||
219 | |||
220 | if (to > inode->i_size) { | ||
221 | truncate_pagecache(inode, to, inode->i_size); | ||
222 | nilfs_truncate(inode); | ||
223 | } | ||
224 | } | ||
225 | |||
216 | static int nilfs_write_begin(struct file *file, struct address_space *mapping, | 226 | static int nilfs_write_begin(struct file *file, struct address_space *mapping, |
217 | loff_t pos, unsigned len, unsigned flags, | 227 | loff_t pos, unsigned len, unsigned flags, |
218 | struct page **pagep, void **fsdata) | 228 | struct page **pagep, void **fsdata) |
@@ -227,10 +237,7 @@ static int nilfs_write_begin(struct file *file, struct address_space *mapping, | |||
227 | err = block_write_begin(mapping, pos, len, flags, pagep, | 237 | err = block_write_begin(mapping, pos, len, flags, pagep, |
228 | nilfs_get_block); | 238 | nilfs_get_block); |
229 | if (unlikely(err)) { | 239 | if (unlikely(err)) { |
230 | loff_t isize = mapping->host->i_size; | 240 | nilfs_write_failed(mapping, pos + len); |
231 | if (pos + len > isize) | ||
232 | vmtruncate(mapping->host, isize); | ||
233 | |||
234 | nilfs_transaction_abort(inode->i_sb); | 241 | nilfs_transaction_abort(inode->i_sb); |
235 | } | 242 | } |
236 | return err; | 243 | return err; |
@@ -259,6 +266,7 @@ nilfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, | |||
259 | loff_t offset, unsigned long nr_segs) | 266 | loff_t offset, unsigned long nr_segs) |
260 | { | 267 | { |
261 | struct file *file = iocb->ki_filp; | 268 | struct file *file = iocb->ki_filp; |
269 | struct address_space *mapping = file->f_mapping; | ||
262 | struct inode *inode = file->f_mapping->host; | 270 | struct inode *inode = file->f_mapping->host; |
263 | ssize_t size; | 271 | ssize_t size; |
264 | 272 | ||
@@ -278,7 +286,7 @@ nilfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, | |||
278 | loff_t end = offset + iov_length(iov, nr_segs); | 286 | loff_t end = offset + iov_length(iov, nr_segs); |
279 | 287 | ||
280 | if (end > isize) | 288 | if (end > isize) |
281 | vmtruncate(inode, isize); | 289 | nilfs_write_failed(mapping, end); |
282 | } | 290 | } |
283 | 291 | ||
284 | return size; | 292 | return size; |
@@ -786,10 +794,8 @@ int nilfs_setattr(struct dentry *dentry, struct iattr *iattr) | |||
786 | if ((iattr->ia_valid & ATTR_SIZE) && | 794 | if ((iattr->ia_valid & ATTR_SIZE) && |
787 | iattr->ia_size != i_size_read(inode)) { | 795 | iattr->ia_size != i_size_read(inode)) { |
788 | inode_dio_wait(inode); | 796 | inode_dio_wait(inode); |
789 | 797 | truncate_setsize(inode, iattr->ia_size); | |
790 | err = vmtruncate(inode, iattr->ia_size); | 798 | nilfs_truncate(inode); |
791 | if (unlikely(err)) | ||
792 | goto out_err; | ||
793 | } | 799 | } |
794 | 800 | ||
795 | setattr_copy(inode, iattr); | 801 | setattr_copy(inode, iattr); |
diff --git a/fs/nilfs2/nilfs.h b/fs/nilfs2/nilfs.h index 74cece80e9a3..9bc72dec3fa6 100644 --- a/fs/nilfs2/nilfs.h +++ b/fs/nilfs2/nilfs.h | |||
@@ -277,6 +277,7 @@ extern void nilfs_update_inode(struct inode *, struct buffer_head *); | |||
277 | extern void nilfs_truncate(struct inode *); | 277 | extern void nilfs_truncate(struct inode *); |
278 | extern void nilfs_evict_inode(struct inode *); | 278 | extern void nilfs_evict_inode(struct inode *); |
279 | extern int nilfs_setattr(struct dentry *, struct iattr *); | 279 | extern int nilfs_setattr(struct dentry *, struct iattr *); |
280 | extern void nilfs_write_failed(struct address_space *mapping, loff_t to); | ||
280 | int nilfs_permission(struct inode *inode, int mask); | 281 | int nilfs_permission(struct inode *inode, int mask); |
281 | int nilfs_load_inode_block(struct inode *inode, struct buffer_head **pbh); | 282 | int nilfs_load_inode_block(struct inode *inode, struct buffer_head **pbh); |
282 | extern int nilfs_inode_dirty(struct inode *); | 283 | extern int nilfs_inode_dirty(struct inode *); |
diff --git a/fs/nilfs2/recovery.c b/fs/nilfs2/recovery.c index f1626f5011c5..ff00a0b7acb9 100644 --- a/fs/nilfs2/recovery.c +++ b/fs/nilfs2/recovery.c | |||
@@ -527,7 +527,8 @@ static int nilfs_recover_dsync_blocks(struct the_nilfs *nilfs, | |||
527 | if (unlikely(err)) { | 527 | if (unlikely(err)) { |
528 | loff_t isize = inode->i_size; | 528 | loff_t isize = inode->i_size; |
529 | if (pos + blocksize > isize) | 529 | if (pos + blocksize > isize) |
530 | vmtruncate(inode, isize); | 530 | nilfs_write_failed(inode->i_mapping, |
531 | pos + blocksize); | ||
531 | goto failed_inode; | 532 | goto failed_inode; |
532 | } | 533 | } |
533 | 534 | ||
diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c index 1ecf46448f85..5b2d4f0853ac 100644 --- a/fs/ntfs/file.c +++ b/fs/ntfs/file.c | |||
@@ -1762,6 +1762,16 @@ err_out: | |||
1762 | return err; | 1762 | return err; |
1763 | } | 1763 | } |
1764 | 1764 | ||
1765 | static void ntfs_write_failed(struct address_space *mapping, loff_t to) | ||
1766 | { | ||
1767 | struct inode *inode = mapping->host; | ||
1768 | |||
1769 | if (to > inode->i_size) { | ||
1770 | truncate_pagecache(inode, to, inode->i_size); | ||
1771 | ntfs_truncate_vfs(inode); | ||
1772 | } | ||
1773 | } | ||
1774 | |||
1765 | /** | 1775 | /** |
1766 | * ntfs_file_buffered_write - | 1776 | * ntfs_file_buffered_write - |
1767 | * | 1777 | * |
@@ -2022,8 +2032,9 @@ static ssize_t ntfs_file_buffered_write(struct kiocb *iocb, | |||
2022 | * allocated space, which is not a disaster. | 2032 | * allocated space, which is not a disaster. |
2023 | */ | 2033 | */ |
2024 | i_size = i_size_read(vi); | 2034 | i_size = i_size_read(vi); |
2025 | if (pos + bytes > i_size) | 2035 | if (pos + bytes > i_size) { |
2026 | vmtruncate(vi, i_size); | 2036 | ntfs_write_failed(mapping, pos + bytes); |
2037 | } | ||
2027 | break; | 2038 | break; |
2028 | } | 2039 | } |
2029 | } | 2040 | } |
@@ -2227,7 +2238,6 @@ const struct file_operations ntfs_file_ops = { | |||
2227 | 2238 | ||
2228 | const struct inode_operations ntfs_file_inode_ops = { | 2239 | const struct inode_operations ntfs_file_inode_ops = { |
2229 | #ifdef NTFS_RW | 2240 | #ifdef NTFS_RW |
2230 | .truncate = ntfs_truncate_vfs, | ||
2231 | .setattr = ntfs_setattr, | 2241 | .setattr = ntfs_setattr, |
2232 | #endif /* NTFS_RW */ | 2242 | #endif /* NTFS_RW */ |
2233 | }; | 2243 | }; |
diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c index 1d27331e6fc9..d3e118cc6ffa 100644 --- a/fs/ntfs/inode.c +++ b/fs/ntfs/inode.c | |||
@@ -2866,9 +2866,11 @@ conv_err_out: | |||
2866 | * | 2866 | * |
2867 | * See ntfs_truncate() description above for details. | 2867 | * See ntfs_truncate() description above for details. |
2868 | */ | 2868 | */ |
2869 | #ifdef NTFS_RW | ||
2869 | void ntfs_truncate_vfs(struct inode *vi) { | 2870 | void ntfs_truncate_vfs(struct inode *vi) { |
2870 | ntfs_truncate(vi); | 2871 | ntfs_truncate(vi); |
2871 | } | 2872 | } |
2873 | #endif | ||
2872 | 2874 | ||
2873 | /** | 2875 | /** |
2874 | * ntfs_setattr - called from notify_change() when an attribute is being changed | 2876 | * ntfs_setattr - called from notify_change() when an attribute is being changed |
@@ -2914,8 +2916,10 @@ int ntfs_setattr(struct dentry *dentry, struct iattr *attr) | |||
2914 | NInoCompressed(ni) ? | 2916 | NInoCompressed(ni) ? |
2915 | "compressed" : "encrypted"); | 2917 | "compressed" : "encrypted"); |
2916 | err = -EOPNOTSUPP; | 2918 | err = -EOPNOTSUPP; |
2917 | } else | 2919 | } else { |
2918 | err = vmtruncate(vi, attr->ia_size); | 2920 | truncate_setsize(vi, attr->ia_size); |
2921 | ntfs_truncate_vfs(vi); | ||
2922 | } | ||
2919 | if (err || ia_valid == ATTR_SIZE) | 2923 | if (err || ia_valid == ATTR_SIZE) |
2920 | goto out; | 2924 | goto out; |
2921 | } else { | 2925 | } else { |
diff --git a/fs/ntfs/inode.h b/fs/ntfs/inode.h index db29695f845c..76b6cfb579d7 100644 --- a/fs/ntfs/inode.h +++ b/fs/ntfs/inode.h | |||
@@ -316,6 +316,10 @@ static inline void ntfs_commit_inode(struct inode *vi) | |||
316 | return; | 316 | return; |
317 | } | 317 | } |
318 | 318 | ||
319 | #else | ||
320 | |||
321 | static inline void ntfs_truncate_vfs(struct inode *vi) {} | ||
322 | |||
319 | #endif /* NTFS_RW */ | 323 | #endif /* NTFS_RW */ |
320 | 324 | ||
321 | #endif /* _LINUX_NTFS_INODE_H */ | 325 | #endif /* _LINUX_NTFS_INODE_H */ |
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index fe492e1a3cfc..37d313ede159 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c | |||
@@ -1218,24 +1218,6 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr) | |||
1218 | } | 1218 | } |
1219 | } | 1219 | } |
1220 | 1220 | ||
1221 | /* | ||
1222 | * This will intentionally not wind up calling truncate_setsize(), | ||
1223 | * since all the work for a size change has been done above. | ||
1224 | * Otherwise, we could get into problems with truncate as | ||
1225 | * ip_alloc_sem is used there to protect against i_size | ||
1226 | * changes. | ||
1227 | * | ||
1228 | * XXX: this means the conditional below can probably be removed. | ||
1229 | */ | ||
1230 | if ((attr->ia_valid & ATTR_SIZE) && | ||
1231 | attr->ia_size != i_size_read(inode)) { | ||
1232 | status = vmtruncate(inode, attr->ia_size); | ||
1233 | if (status) { | ||
1234 | mlog_errno(status); | ||
1235 | goto bail_commit; | ||
1236 | } | ||
1237 | } | ||
1238 | |||
1239 | setattr_copy(inode, attr); | 1221 | setattr_copy(inode, attr); |
1240 | mark_inode_dirty(inode); | 1222 | mark_inode_dirty(inode); |
1241 | 1223 | ||
diff --git a/fs/omfs/file.c b/fs/omfs/file.c index 77e3cb2962b4..e0d9b3e722bd 100644 --- a/fs/omfs/file.c +++ b/fs/omfs/file.c | |||
@@ -306,6 +306,16 @@ omfs_writepages(struct address_space *mapping, struct writeback_control *wbc) | |||
306 | return mpage_writepages(mapping, wbc, omfs_get_block); | 306 | return mpage_writepages(mapping, wbc, omfs_get_block); |
307 | } | 307 | } |
308 | 308 | ||
309 | static void omfs_write_failed(struct address_space *mapping, loff_t to) | ||
310 | { | ||
311 | struct inode *inode = mapping->host; | ||
312 | |||
313 | if (to > inode->i_size) { | ||
314 | truncate_pagecache(inode, to, inode->i_size); | ||
315 | omfs_truncate(inode); | ||
316 | } | ||
317 | } | ||
318 | |||
309 | static int omfs_write_begin(struct file *file, struct address_space *mapping, | 319 | static int omfs_write_begin(struct file *file, struct address_space *mapping, |
310 | loff_t pos, unsigned len, unsigned flags, | 320 | loff_t pos, unsigned len, unsigned flags, |
311 | struct page **pagep, void **fsdata) | 321 | struct page **pagep, void **fsdata) |
@@ -314,11 +324,8 @@ static int omfs_write_begin(struct file *file, struct address_space *mapping, | |||
314 | 324 | ||
315 | ret = block_write_begin(mapping, pos, len, flags, pagep, | 325 | ret = block_write_begin(mapping, pos, len, flags, pagep, |
316 | omfs_get_block); | 326 | omfs_get_block); |
317 | if (unlikely(ret)) { | 327 | if (unlikely(ret)) |
318 | loff_t isize = mapping->host->i_size; | 328 | omfs_write_failed(mapping, pos + len); |
319 | if (pos + len > isize) | ||
320 | vmtruncate(mapping->host, isize); | ||
321 | } | ||
322 | 329 | ||
323 | return ret; | 330 | return ret; |
324 | } | 331 | } |
@@ -350,9 +357,11 @@ static int omfs_setattr(struct dentry *dentry, struct iattr *attr) | |||
350 | 357 | ||
351 | if ((attr->ia_valid & ATTR_SIZE) && | 358 | if ((attr->ia_valid & ATTR_SIZE) && |
352 | attr->ia_size != i_size_read(inode)) { | 359 | attr->ia_size != i_size_read(inode)) { |
353 | error = vmtruncate(inode, attr->ia_size); | 360 | error = inode_newsize_ok(inode, attr->ia_size); |
354 | if (error) | 361 | if (error) |
355 | return error; | 362 | return error; |
363 | truncate_setsize(inode, attr->ia_size); | ||
364 | omfs_truncate(inode); | ||
356 | } | 365 | } |
357 | 366 | ||
358 | setattr_copy(inode, attr); | 367 | setattr_copy(inode, attr); |
@@ -362,7 +371,6 @@ static int omfs_setattr(struct dentry *dentry, struct iattr *attr) | |||
362 | 371 | ||
363 | const struct inode_operations omfs_file_inops = { | 372 | const struct inode_operations omfs_file_inops = { |
364 | .setattr = omfs_setattr, | 373 | .setattr = omfs_setattr, |
365 | .truncate = omfs_truncate | ||
366 | }; | 374 | }; |
367 | 375 | ||
368 | const struct address_space_operations omfs_aops = { | 376 | const struct address_space_operations omfs_aops = { |
@@ -61,33 +61,22 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, | |||
61 | return ret; | 61 | return ret; |
62 | } | 62 | } |
63 | 63 | ||
64 | static long do_sys_truncate(const char __user *pathname, loff_t length) | 64 | long vfs_truncate(struct path *path, loff_t length) |
65 | { | 65 | { |
66 | struct path path; | ||
67 | struct inode *inode; | 66 | struct inode *inode; |
68 | int error; | 67 | long error; |
69 | |||
70 | error = -EINVAL; | ||
71 | if (length < 0) /* sorry, but loff_t says... */ | ||
72 | goto out; | ||
73 | 68 | ||
74 | error = user_path(pathname, &path); | 69 | inode = path->dentry->d_inode; |
75 | if (error) | ||
76 | goto out; | ||
77 | inode = path.dentry->d_inode; | ||
78 | 70 | ||
79 | /* For directories it's -EISDIR, for other non-regulars - -EINVAL */ | 71 | /* For directories it's -EISDIR, for other non-regulars - -EINVAL */ |
80 | error = -EISDIR; | ||
81 | if (S_ISDIR(inode->i_mode)) | 72 | if (S_ISDIR(inode->i_mode)) |
82 | goto dput_and_out; | 73 | return -EISDIR; |
83 | |||
84 | error = -EINVAL; | ||
85 | if (!S_ISREG(inode->i_mode)) | 74 | if (!S_ISREG(inode->i_mode)) |
86 | goto dput_and_out; | 75 | return -EINVAL; |
87 | 76 | ||
88 | error = mnt_want_write(path.mnt); | 77 | error = mnt_want_write(path->mnt); |
89 | if (error) | 78 | if (error) |
90 | goto dput_and_out; | 79 | goto out; |
91 | 80 | ||
92 | error = inode_permission(inode, MAY_WRITE); | 81 | error = inode_permission(inode, MAY_WRITE); |
93 | if (error) | 82 | if (error) |
@@ -111,19 +100,40 @@ static long do_sys_truncate(const char __user *pathname, loff_t length) | |||
111 | 100 | ||
112 | error = locks_verify_truncate(inode, NULL, length); | 101 | error = locks_verify_truncate(inode, NULL, length); |
113 | if (!error) | 102 | if (!error) |
114 | error = security_path_truncate(&path); | 103 | error = security_path_truncate(path); |
115 | if (!error) | 104 | if (!error) |
116 | error = do_truncate(path.dentry, length, 0, NULL); | 105 | error = do_truncate(path->dentry, length, 0, NULL); |
117 | 106 | ||
118 | put_write_and_out: | 107 | put_write_and_out: |
119 | put_write_access(inode); | 108 | put_write_access(inode); |
120 | mnt_drop_write_and_out: | 109 | mnt_drop_write_and_out: |
121 | mnt_drop_write(path.mnt); | 110 | mnt_drop_write(path->mnt); |
122 | dput_and_out: | ||
123 | path_put(&path); | ||
124 | out: | 111 | out: |
125 | return error; | 112 | return error; |
126 | } | 113 | } |
114 | EXPORT_SYMBOL_GPL(vfs_truncate); | ||
115 | |||
116 | static long do_sys_truncate(const char __user *pathname, loff_t length) | ||
117 | { | ||
118 | unsigned int lookup_flags = LOOKUP_FOLLOW; | ||
119 | struct path path; | ||
120 | int error; | ||
121 | |||
122 | if (length < 0) /* sorry, but loff_t says... */ | ||
123 | return -EINVAL; | ||
124 | |||
125 | retry: | ||
126 | error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path); | ||
127 | if (!error) { | ||
128 | error = vfs_truncate(&path, length); | ||
129 | path_put(&path); | ||
130 | } | ||
131 | if (retry_estale(error, lookup_flags)) { | ||
132 | lookup_flags |= LOOKUP_REVAL; | ||
133 | goto retry; | ||
134 | } | ||
135 | return error; | ||
136 | } | ||
127 | 137 | ||
128 | SYSCALL_DEFINE2(truncate, const char __user *, path, long, length) | 138 | SYSCALL_DEFINE2(truncate, const char __user *, path, long, length) |
129 | { | 139 | { |
@@ -306,6 +316,7 @@ SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode) | |||
306 | struct path path; | 316 | struct path path; |
307 | struct inode *inode; | 317 | struct inode *inode; |
308 | int res; | 318 | int res; |
319 | unsigned int lookup_flags = LOOKUP_FOLLOW; | ||
309 | 320 | ||
310 | if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */ | 321 | if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */ |
311 | return -EINVAL; | 322 | return -EINVAL; |
@@ -328,8 +339,8 @@ SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode) | |||
328 | } | 339 | } |
329 | 340 | ||
330 | old_cred = override_creds(override_cred); | 341 | old_cred = override_creds(override_cred); |
331 | 342 | retry: | |
332 | res = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path); | 343 | res = user_path_at(dfd, filename, lookup_flags, &path); |
333 | if (res) | 344 | if (res) |
334 | goto out; | 345 | goto out; |
335 | 346 | ||
@@ -364,6 +375,10 @@ SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode) | |||
364 | 375 | ||
365 | out_path_release: | 376 | out_path_release: |
366 | path_put(&path); | 377 | path_put(&path); |
378 | if (retry_estale(res, lookup_flags)) { | ||
379 | lookup_flags |= LOOKUP_REVAL; | ||
380 | goto retry; | ||
381 | } | ||
367 | out: | 382 | out: |
368 | revert_creds(old_cred); | 383 | revert_creds(old_cred); |
369 | put_cred(override_cred); | 384 | put_cred(override_cred); |
@@ -379,8 +394,9 @@ SYSCALL_DEFINE1(chdir, const char __user *, filename) | |||
379 | { | 394 | { |
380 | struct path path; | 395 | struct path path; |
381 | int error; | 396 | int error; |
382 | 397 | unsigned int lookup_flags = LOOKUP_FOLLOW | LOOKUP_DIRECTORY; | |
383 | error = user_path_dir(filename, &path); | 398 | retry: |
399 | error = user_path_at(AT_FDCWD, filename, lookup_flags, &path); | ||
384 | if (error) | 400 | if (error) |
385 | goto out; | 401 | goto out; |
386 | 402 | ||
@@ -392,6 +408,10 @@ SYSCALL_DEFINE1(chdir, const char __user *, filename) | |||
392 | 408 | ||
393 | dput_and_out: | 409 | dput_and_out: |
394 | path_put(&path); | 410 | path_put(&path); |
411 | if (retry_estale(error, lookup_flags)) { | ||
412 | lookup_flags |= LOOKUP_REVAL; | ||
413 | goto retry; | ||
414 | } | ||
395 | out: | 415 | out: |
396 | return error; | 416 | return error; |
397 | } | 417 | } |
@@ -425,8 +445,9 @@ SYSCALL_DEFINE1(chroot, const char __user *, filename) | |||
425 | { | 445 | { |
426 | struct path path; | 446 | struct path path; |
427 | int error; | 447 | int error; |
428 | 448 | unsigned int lookup_flags = LOOKUP_FOLLOW | LOOKUP_DIRECTORY; | |
429 | error = user_path_dir(filename, &path); | 449 | retry: |
450 | error = user_path_at(AT_FDCWD, filename, lookup_flags, &path); | ||
430 | if (error) | 451 | if (error) |
431 | goto out; | 452 | goto out; |
432 | 453 | ||
@@ -445,6 +466,10 @@ SYSCALL_DEFINE1(chroot, const char __user *, filename) | |||
445 | error = 0; | 466 | error = 0; |
446 | dput_and_out: | 467 | dput_and_out: |
447 | path_put(&path); | 468 | path_put(&path); |
469 | if (retry_estale(error, lookup_flags)) { | ||
470 | lookup_flags |= LOOKUP_REVAL; | ||
471 | goto retry; | ||
472 | } | ||
448 | out: | 473 | out: |
449 | return error; | 474 | return error; |
450 | } | 475 | } |
@@ -489,11 +514,16 @@ SYSCALL_DEFINE3(fchmodat, int, dfd, const char __user *, filename, umode_t, mode | |||
489 | { | 514 | { |
490 | struct path path; | 515 | struct path path; |
491 | int error; | 516 | int error; |
492 | 517 | unsigned int lookup_flags = LOOKUP_FOLLOW; | |
493 | error = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path); | 518 | retry: |
519 | error = user_path_at(dfd, filename, lookup_flags, &path); | ||
494 | if (!error) { | 520 | if (!error) { |
495 | error = chmod_common(&path, mode); | 521 | error = chmod_common(&path, mode); |
496 | path_put(&path); | 522 | path_put(&path); |
523 | if (retry_estale(error, lookup_flags)) { | ||
524 | lookup_flags |= LOOKUP_REVAL; | ||
525 | goto retry; | ||
526 | } | ||
497 | } | 527 | } |
498 | return error; | 528 | return error; |
499 | } | 529 | } |
@@ -552,6 +582,7 @@ SYSCALL_DEFINE5(fchownat, int, dfd, const char __user *, filename, uid_t, user, | |||
552 | lookup_flags = (flag & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW; | 582 | lookup_flags = (flag & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW; |
553 | if (flag & AT_EMPTY_PATH) | 583 | if (flag & AT_EMPTY_PATH) |
554 | lookup_flags |= LOOKUP_EMPTY; | 584 | lookup_flags |= LOOKUP_EMPTY; |
585 | retry: | ||
555 | error = user_path_at(dfd, filename, lookup_flags, &path); | 586 | error = user_path_at(dfd, filename, lookup_flags, &path); |
556 | if (error) | 587 | if (error) |
557 | goto out; | 588 | goto out; |
@@ -562,6 +593,10 @@ SYSCALL_DEFINE5(fchownat, int, dfd, const char __user *, filename, uid_t, user, | |||
562 | mnt_drop_write(path.mnt); | 593 | mnt_drop_write(path.mnt); |
563 | out_release: | 594 | out_release: |
564 | path_put(&path); | 595 | path_put(&path); |
596 | if (retry_estale(error, lookup_flags)) { | ||
597 | lookup_flags |= LOOKUP_REVAL; | ||
598 | goto retry; | ||
599 | } | ||
565 | out: | 600 | out: |
566 | return error; | 601 | return error; |
567 | } | 602 | } |
diff --git a/fs/proc/base.c b/fs/proc/base.c index 5a5a0be40e40..9b43ff77a51e 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -542,13 +542,6 @@ int proc_setattr(struct dentry *dentry, struct iattr *attr) | |||
542 | if (error) | 542 | if (error) |
543 | return error; | 543 | return error; |
544 | 544 | ||
545 | if ((attr->ia_valid & ATTR_SIZE) && | ||
546 | attr->ia_size != i_size_read(inode)) { | ||
547 | error = vmtruncate(inode, attr->ia_size); | ||
548 | if (error) | ||
549 | return error; | ||
550 | } | ||
551 | |||
552 | setattr_copy(inode, attr); | 545 | setattr_copy(inode, attr); |
553 | mark_inode_dirty(inode); | 546 | mark_inode_dirty(inode); |
554 | return 0; | 547 | return 0; |
diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 7b3ae3cc0ef9..2e4ed13b9eed 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c | |||
@@ -261,16 +261,9 @@ static int proc_notify_change(struct dentry *dentry, struct iattr *iattr) | |||
261 | if (error) | 261 | if (error) |
262 | return error; | 262 | return error; |
263 | 263 | ||
264 | if ((iattr->ia_valid & ATTR_SIZE) && | ||
265 | iattr->ia_size != i_size_read(inode)) { | ||
266 | error = vmtruncate(inode, iattr->ia_size); | ||
267 | if (error) | ||
268 | return error; | ||
269 | } | ||
270 | |||
271 | setattr_copy(inode, iattr); | 264 | setattr_copy(inode, iattr); |
272 | mark_inode_dirty(inode); | 265 | mark_inode_dirty(inode); |
273 | 266 | ||
274 | de->uid = inode->i_uid; | 267 | de->uid = inode->i_uid; |
275 | de->gid = inode->i_gid; | 268 | de->gid = inode->i_gid; |
276 | de->mode = inode->i_mode; | 269 | de->mode = inode->i_mode; |
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index 701580ddfcc3..1827d88ad58b 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c | |||
@@ -736,13 +736,6 @@ static int proc_sys_setattr(struct dentry *dentry, struct iattr *attr) | |||
736 | if (error) | 736 | if (error) |
737 | return error; | 737 | return error; |
738 | 738 | ||
739 | if ((attr->ia_valid & ATTR_SIZE) && | ||
740 | attr->ia_size != i_size_read(inode)) { | ||
741 | error = vmtruncate(inode, attr->ia_size); | ||
742 | if (error) | ||
743 | return error; | ||
744 | } | ||
745 | |||
746 | setattr_copy(inode, attr); | 739 | setattr_copy(inode, attr); |
747 | mark_inode_dirty(inode); | 740 | mark_inode_dirty(inode); |
748 | return 0; | 741 | return 0; |
diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c index 8375c922c0d5..50302d6f8895 100644 --- a/fs/reiserfs/file.c +++ b/fs/reiserfs/file.c | |||
@@ -126,7 +126,7 @@ static int reiserfs_file_open(struct inode *inode, struct file *file) | |||
126 | return err; | 126 | return err; |
127 | } | 127 | } |
128 | 128 | ||
129 | static void reiserfs_vfs_truncate_file(struct inode *inode) | 129 | void reiserfs_vfs_truncate_file(struct inode *inode) |
130 | { | 130 | { |
131 | mutex_lock(&(REISERFS_I(inode)->tailpack)); | 131 | mutex_lock(&(REISERFS_I(inode)->tailpack)); |
132 | reiserfs_truncate_file(inode, 1); | 132 | reiserfs_truncate_file(inode, 1); |
@@ -312,7 +312,6 @@ const struct file_operations reiserfs_file_operations = { | |||
312 | }; | 312 | }; |
313 | 313 | ||
314 | const struct inode_operations reiserfs_file_inode_operations = { | 314 | const struct inode_operations reiserfs_file_inode_operations = { |
315 | .truncate = reiserfs_vfs_truncate_file, | ||
316 | .setattr = reiserfs_setattr, | 315 | .setattr = reiserfs_setattr, |
317 | .setxattr = reiserfs_setxattr, | 316 | .setxattr = reiserfs_setxattr, |
318 | .getxattr = reiserfs_getxattr, | 317 | .getxattr = reiserfs_getxattr, |
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index d83736fbc26c..95d7680ead47 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c | |||
@@ -3085,8 +3085,10 @@ static ssize_t reiserfs_direct_IO(int rw, struct kiocb *iocb, | |||
3085 | loff_t isize = i_size_read(inode); | 3085 | loff_t isize = i_size_read(inode); |
3086 | loff_t end = offset + iov_length(iov, nr_segs); | 3086 | loff_t end = offset + iov_length(iov, nr_segs); |
3087 | 3087 | ||
3088 | if (end > isize) | 3088 | if ((end > isize) && inode_newsize_ok(inode, isize) == 0) { |
3089 | vmtruncate(inode, isize); | 3089 | truncate_setsize(inode, isize); |
3090 | reiserfs_vfs_truncate_file(inode); | ||
3091 | } | ||
3090 | } | 3092 | } |
3091 | 3093 | ||
3092 | return ret; | 3094 | return ret; |
@@ -3200,8 +3202,13 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) | |||
3200 | */ | 3202 | */ |
3201 | reiserfs_write_unlock_once(inode->i_sb, depth); | 3203 | reiserfs_write_unlock_once(inode->i_sb, depth); |
3202 | if ((attr->ia_valid & ATTR_SIZE) && | 3204 | if ((attr->ia_valid & ATTR_SIZE) && |
3203 | attr->ia_size != i_size_read(inode)) | 3205 | attr->ia_size != i_size_read(inode)) { |
3204 | error = vmtruncate(inode, attr->ia_size); | 3206 | error = inode_newsize_ok(inode, attr->ia_size); |
3207 | if (!error) { | ||
3208 | truncate_setsize(inode, attr->ia_size); | ||
3209 | reiserfs_vfs_truncate_file(inode); | ||
3210 | } | ||
3211 | } | ||
3205 | 3212 | ||
3206 | if (!error) { | 3213 | if (!error) { |
3207 | setattr_copy(inode, attr); | 3214 | setattr_copy(inode, attr); |
diff --git a/fs/reiserfs/reiserfs.h b/fs/reiserfs/reiserfs.h index 33215f57ea06..157e474ab303 100644 --- a/fs/reiserfs/reiserfs.h +++ b/fs/reiserfs/reiserfs.h | |||
@@ -2455,6 +2455,7 @@ struct reiserfs_transaction_handle *reiserfs_persistent_transaction(struct | |||
2455 | *, | 2455 | *, |
2456 | int count); | 2456 | int count); |
2457 | int reiserfs_end_persistent_transaction(struct reiserfs_transaction_handle *); | 2457 | int reiserfs_end_persistent_transaction(struct reiserfs_transaction_handle *); |
2458 | void reiserfs_vfs_truncate_file(struct inode *inode); | ||
2458 | int reiserfs_commit_page(struct inode *inode, struct page *page, | 2459 | int reiserfs_commit_page(struct inode *inode, struct page *page, |
2459 | unsigned from, unsigned to); | 2460 | unsigned from, unsigned to); |
2460 | void reiserfs_flush_old_commits(struct super_block *); | 2461 | void reiserfs_flush_old_commits(struct super_block *); |
@@ -74,7 +74,7 @@ int vfs_fstatat(int dfd, const char __user *filename, struct kstat *stat, | |||
74 | { | 74 | { |
75 | struct path path; | 75 | struct path path; |
76 | int error = -EINVAL; | 76 | int error = -EINVAL; |
77 | int lookup_flags = 0; | 77 | unsigned int lookup_flags = 0; |
78 | 78 | ||
79 | if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT | | 79 | if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT | |
80 | AT_EMPTY_PATH)) != 0) | 80 | AT_EMPTY_PATH)) != 0) |
@@ -84,13 +84,17 @@ int vfs_fstatat(int dfd, const char __user *filename, struct kstat *stat, | |||
84 | lookup_flags |= LOOKUP_FOLLOW; | 84 | lookup_flags |= LOOKUP_FOLLOW; |
85 | if (flag & AT_EMPTY_PATH) | 85 | if (flag & AT_EMPTY_PATH) |
86 | lookup_flags |= LOOKUP_EMPTY; | 86 | lookup_flags |= LOOKUP_EMPTY; |
87 | 87 | retry: | |
88 | error = user_path_at(dfd, filename, lookup_flags, &path); | 88 | error = user_path_at(dfd, filename, lookup_flags, &path); |
89 | if (error) | 89 | if (error) |
90 | goto out; | 90 | goto out; |
91 | 91 | ||
92 | error = vfs_getattr(path.mnt, path.dentry, stat); | 92 | error = vfs_getattr(path.mnt, path.dentry, stat); |
93 | path_put(&path); | 93 | path_put(&path); |
94 | if (retry_estale(error, lookup_flags)) { | ||
95 | lookup_flags |= LOOKUP_REVAL; | ||
96 | goto retry; | ||
97 | } | ||
94 | out: | 98 | out: |
95 | return error; | 99 | return error; |
96 | } | 100 | } |
@@ -296,11 +300,13 @@ SYSCALL_DEFINE4(readlinkat, int, dfd, const char __user *, pathname, | |||
296 | struct path path; | 300 | struct path path; |
297 | int error; | 301 | int error; |
298 | int empty = 0; | 302 | int empty = 0; |
303 | unsigned int lookup_flags = LOOKUP_EMPTY; | ||
299 | 304 | ||
300 | if (bufsiz <= 0) | 305 | if (bufsiz <= 0) |
301 | return -EINVAL; | 306 | return -EINVAL; |
302 | 307 | ||
303 | error = user_path_at_empty(dfd, pathname, LOOKUP_EMPTY, &path, &empty); | 308 | retry: |
309 | error = user_path_at_empty(dfd, pathname, lookup_flags, &path, &empty); | ||
304 | if (!error) { | 310 | if (!error) { |
305 | struct inode *inode = path.dentry->d_inode; | 311 | struct inode *inode = path.dentry->d_inode; |
306 | 312 | ||
@@ -314,6 +320,10 @@ SYSCALL_DEFINE4(readlinkat, int, dfd, const char __user *, pathname, | |||
314 | } | 320 | } |
315 | } | 321 | } |
316 | path_put(&path); | 322 | path_put(&path); |
323 | if (retry_estale(error, lookup_flags)) { | ||
324 | lookup_flags |= LOOKUP_REVAL; | ||
325 | goto retry; | ||
326 | } | ||
317 | } | 327 | } |
318 | return error; | 328 | return error; |
319 | } | 329 | } |
diff --git a/fs/statfs.c b/fs/statfs.c index f8e832e6f0a2..c219e733f553 100644 --- a/fs/statfs.c +++ b/fs/statfs.c | |||
@@ -77,10 +77,17 @@ EXPORT_SYMBOL(vfs_statfs); | |||
77 | int user_statfs(const char __user *pathname, struct kstatfs *st) | 77 | int user_statfs(const char __user *pathname, struct kstatfs *st) |
78 | { | 78 | { |
79 | struct path path; | 79 | struct path path; |
80 | int error = user_path_at(AT_FDCWD, pathname, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &path); | 80 | int error; |
81 | unsigned int lookup_flags = LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT; | ||
82 | retry: | ||
83 | error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path); | ||
81 | if (!error) { | 84 | if (!error) { |
82 | error = vfs_statfs(&path, st); | 85 | error = vfs_statfs(&path, st); |
83 | path_put(&path); | 86 | path_put(&path); |
87 | if (retry_estale(error, lookup_flags)) { | ||
88 | lookup_flags |= LOOKUP_REVAL; | ||
89 | goto retry; | ||
90 | } | ||
84 | } | 91 | } |
85 | return error; | 92 | return error; |
86 | } | 93 | } |
diff --git a/fs/sysv/file.c b/fs/sysv/file.c index 0a65939508e9..9d4dc6831792 100644 --- a/fs/sysv/file.c +++ b/fs/sysv/file.c | |||
@@ -41,9 +41,11 @@ static int sysv_setattr(struct dentry *dentry, struct iattr *attr) | |||
41 | 41 | ||
42 | if ((attr->ia_valid & ATTR_SIZE) && | 42 | if ((attr->ia_valid & ATTR_SIZE) && |
43 | attr->ia_size != i_size_read(inode)) { | 43 | attr->ia_size != i_size_read(inode)) { |
44 | error = vmtruncate(inode, attr->ia_size); | 44 | error = inode_newsize_ok(inode, attr->ia_size); |
45 | if (error) | 45 | if (error) |
46 | return error; | 46 | return error; |
47 | truncate_setsize(inode, attr->ia_size); | ||
48 | sysv_truncate(inode); | ||
47 | } | 49 | } |
48 | 50 | ||
49 | setattr_copy(inode, attr); | 51 | setattr_copy(inode, attr); |
@@ -52,7 +54,6 @@ static int sysv_setattr(struct dentry *dentry, struct iattr *attr) | |||
52 | } | 54 | } |
53 | 55 | ||
54 | const struct inode_operations sysv_file_inode_operations = { | 56 | const struct inode_operations sysv_file_inode_operations = { |
55 | .truncate = sysv_truncate, | ||
56 | .setattr = sysv_setattr, | 57 | .setattr = sysv_setattr, |
57 | .getattr = sysv_getattr, | 58 | .getattr = sysv_getattr, |
58 | }; | 59 | }; |
diff --git a/fs/sysv/itree.c b/fs/sysv/itree.c index 90b54b438789..c1a591a4725b 100644 --- a/fs/sysv/itree.c +++ b/fs/sysv/itree.c | |||
@@ -464,6 +464,16 @@ int sysv_prepare_chunk(struct page *page, loff_t pos, unsigned len) | |||
464 | return __block_write_begin(page, pos, len, get_block); | 464 | return __block_write_begin(page, pos, len, get_block); |
465 | } | 465 | } |
466 | 466 | ||
467 | static void sysv_write_failed(struct address_space *mapping, loff_t to) | ||
468 | { | ||
469 | struct inode *inode = mapping->host; | ||
470 | |||
471 | if (to > inode->i_size) { | ||
472 | truncate_pagecache(inode, to, inode->i_size); | ||
473 | sysv_truncate(inode); | ||
474 | } | ||
475 | } | ||
476 | |||
467 | static int sysv_write_begin(struct file *file, struct address_space *mapping, | 477 | static int sysv_write_begin(struct file *file, struct address_space *mapping, |
468 | loff_t pos, unsigned len, unsigned flags, | 478 | loff_t pos, unsigned len, unsigned flags, |
469 | struct page **pagep, void **fsdata) | 479 | struct page **pagep, void **fsdata) |
@@ -471,11 +481,8 @@ static int sysv_write_begin(struct file *file, struct address_space *mapping, | |||
471 | int ret; | 481 | int ret; |
472 | 482 | ||
473 | ret = block_write_begin(mapping, pos, len, flags, pagep, get_block); | 483 | ret = block_write_begin(mapping, pos, len, flags, pagep, get_block); |
474 | if (unlikely(ret)) { | 484 | if (unlikely(ret)) |
475 | loff_t isize = mapping->host->i_size; | 485 | sysv_write_failed(mapping, pos + len); |
476 | if (pos + len > isize) | ||
477 | vmtruncate(mapping->host, isize); | ||
478 | } | ||
479 | 486 | ||
480 | return ret; | 487 | return ret; |
481 | } | 488 | } |
diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index eb6d0b7dc879..ff24e4449ece 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c | |||
@@ -526,6 +526,14 @@ int ufs_prepare_chunk(struct page *page, loff_t pos, unsigned len) | |||
526 | return __block_write_begin(page, pos, len, ufs_getfrag_block); | 526 | return __block_write_begin(page, pos, len, ufs_getfrag_block); |
527 | } | 527 | } |
528 | 528 | ||
529 | static void ufs_write_failed(struct address_space *mapping, loff_t to) | ||
530 | { | ||
531 | struct inode *inode = mapping->host; | ||
532 | |||
533 | if (to > inode->i_size) | ||
534 | truncate_pagecache(inode, to, inode->i_size); | ||
535 | } | ||
536 | |||
529 | static int ufs_write_begin(struct file *file, struct address_space *mapping, | 537 | static int ufs_write_begin(struct file *file, struct address_space *mapping, |
530 | loff_t pos, unsigned len, unsigned flags, | 538 | loff_t pos, unsigned len, unsigned flags, |
531 | struct page **pagep, void **fsdata) | 539 | struct page **pagep, void **fsdata) |
@@ -534,11 +542,8 @@ static int ufs_write_begin(struct file *file, struct address_space *mapping, | |||
534 | 542 | ||
535 | ret = block_write_begin(mapping, pos, len, flags, pagep, | 543 | ret = block_write_begin(mapping, pos, len, flags, pagep, |
536 | ufs_getfrag_block); | 544 | ufs_getfrag_block); |
537 | if (unlikely(ret)) { | 545 | if (unlikely(ret)) |
538 | loff_t isize = mapping->host->i_size; | 546 | ufs_write_failed(mapping, pos + len); |
539 | if (pos + len > isize) | ||
540 | vmtruncate(mapping->host, isize); | ||
541 | } | ||
542 | 547 | ||
543 | return ret; | 548 | return ret; |
544 | } | 549 | } |
diff --git a/fs/utimes.c b/fs/utimes.c index bb0696a41735..f4fb7eca10e8 100644 --- a/fs/utimes.c +++ b/fs/utimes.c | |||
@@ -158,13 +158,17 @@ long do_utimes(int dfd, const char __user *filename, struct timespec *times, | |||
158 | 158 | ||
159 | if (!(flags & AT_SYMLINK_NOFOLLOW)) | 159 | if (!(flags & AT_SYMLINK_NOFOLLOW)) |
160 | lookup_flags |= LOOKUP_FOLLOW; | 160 | lookup_flags |= LOOKUP_FOLLOW; |
161 | 161 | retry: | |
162 | error = user_path_at(dfd, filename, lookup_flags, &path); | 162 | error = user_path_at(dfd, filename, lookup_flags, &path); |
163 | if (error) | 163 | if (error) |
164 | goto out; | 164 | goto out; |
165 | 165 | ||
166 | error = utimes_common(&path, times); | 166 | error = utimes_common(&path, times); |
167 | path_put(&path); | 167 | path_put(&path); |
168 | if (retry_estale(error, lookup_flags)) { | ||
169 | lookup_flags |= LOOKUP_REVAL; | ||
170 | goto retry; | ||
171 | } | ||
168 | } | 172 | } |
169 | 173 | ||
170 | out: | 174 | out: |
diff --git a/fs/xattr.c b/fs/xattr.c index e21c119f4f99..3377dff18404 100644 --- a/fs/xattr.c +++ b/fs/xattr.c | |||
@@ -370,8 +370,9 @@ SYSCALL_DEFINE5(setxattr, const char __user *, pathname, | |||
370 | { | 370 | { |
371 | struct path path; | 371 | struct path path; |
372 | int error; | 372 | int error; |
373 | 373 | unsigned int lookup_flags = LOOKUP_FOLLOW; | |
374 | error = user_path(pathname, &path); | 374 | retry: |
375 | error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path); | ||
375 | if (error) | 376 | if (error) |
376 | return error; | 377 | return error; |
377 | error = mnt_want_write(path.mnt); | 378 | error = mnt_want_write(path.mnt); |
@@ -380,6 +381,10 @@ SYSCALL_DEFINE5(setxattr, const char __user *, pathname, | |||
380 | mnt_drop_write(path.mnt); | 381 | mnt_drop_write(path.mnt); |
381 | } | 382 | } |
382 | path_put(&path); | 383 | path_put(&path); |
384 | if (retry_estale(error, lookup_flags)) { | ||
385 | lookup_flags |= LOOKUP_REVAL; | ||
386 | goto retry; | ||
387 | } | ||
383 | return error; | 388 | return error; |
384 | } | 389 | } |
385 | 390 | ||
@@ -389,8 +394,9 @@ SYSCALL_DEFINE5(lsetxattr, const char __user *, pathname, | |||
389 | { | 394 | { |
390 | struct path path; | 395 | struct path path; |
391 | int error; | 396 | int error; |
392 | 397 | unsigned int lookup_flags = 0; | |
393 | error = user_lpath(pathname, &path); | 398 | retry: |
399 | error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path); | ||
394 | if (error) | 400 | if (error) |
395 | return error; | 401 | return error; |
396 | error = mnt_want_write(path.mnt); | 402 | error = mnt_want_write(path.mnt); |
@@ -399,6 +405,10 @@ SYSCALL_DEFINE5(lsetxattr, const char __user *, pathname, | |||
399 | mnt_drop_write(path.mnt); | 405 | mnt_drop_write(path.mnt); |
400 | } | 406 | } |
401 | path_put(&path); | 407 | path_put(&path); |
408 | if (retry_estale(error, lookup_flags)) { | ||
409 | lookup_flags |= LOOKUP_REVAL; | ||
410 | goto retry; | ||
411 | } | ||
402 | return error; | 412 | return error; |
403 | } | 413 | } |
404 | 414 | ||
@@ -476,12 +486,17 @@ SYSCALL_DEFINE4(getxattr, const char __user *, pathname, | |||
476 | { | 486 | { |
477 | struct path path; | 487 | struct path path; |
478 | ssize_t error; | 488 | ssize_t error; |
479 | 489 | unsigned int lookup_flags = LOOKUP_FOLLOW; | |
480 | error = user_path(pathname, &path); | 490 | retry: |
491 | error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path); | ||
481 | if (error) | 492 | if (error) |
482 | return error; | 493 | return error; |
483 | error = getxattr(path.dentry, name, value, size); | 494 | error = getxattr(path.dentry, name, value, size); |
484 | path_put(&path); | 495 | path_put(&path); |
496 | if (retry_estale(error, lookup_flags)) { | ||
497 | lookup_flags |= LOOKUP_REVAL; | ||
498 | goto retry; | ||
499 | } | ||
485 | return error; | 500 | return error; |
486 | } | 501 | } |
487 | 502 | ||
@@ -490,12 +505,17 @@ SYSCALL_DEFINE4(lgetxattr, const char __user *, pathname, | |||
490 | { | 505 | { |
491 | struct path path; | 506 | struct path path; |
492 | ssize_t error; | 507 | ssize_t error; |
493 | 508 | unsigned int lookup_flags = 0; | |
494 | error = user_lpath(pathname, &path); | 509 | retry: |
510 | error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path); | ||
495 | if (error) | 511 | if (error) |
496 | return error; | 512 | return error; |
497 | error = getxattr(path.dentry, name, value, size); | 513 | error = getxattr(path.dentry, name, value, size); |
498 | path_put(&path); | 514 | path_put(&path); |
515 | if (retry_estale(error, lookup_flags)) { | ||
516 | lookup_flags |= LOOKUP_REVAL; | ||
517 | goto retry; | ||
518 | } | ||
499 | return error; | 519 | return error; |
500 | } | 520 | } |
501 | 521 | ||
@@ -556,12 +576,17 @@ SYSCALL_DEFINE3(listxattr, const char __user *, pathname, char __user *, list, | |||
556 | { | 576 | { |
557 | struct path path; | 577 | struct path path; |
558 | ssize_t error; | 578 | ssize_t error; |
559 | 579 | unsigned int lookup_flags = LOOKUP_FOLLOW; | |
560 | error = user_path(pathname, &path); | 580 | retry: |
581 | error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path); | ||
561 | if (error) | 582 | if (error) |
562 | return error; | 583 | return error; |
563 | error = listxattr(path.dentry, list, size); | 584 | error = listxattr(path.dentry, list, size); |
564 | path_put(&path); | 585 | path_put(&path); |
586 | if (retry_estale(error, lookup_flags)) { | ||
587 | lookup_flags |= LOOKUP_REVAL; | ||
588 | goto retry; | ||
589 | } | ||
565 | return error; | 590 | return error; |
566 | } | 591 | } |
567 | 592 | ||
@@ -570,12 +595,17 @@ SYSCALL_DEFINE3(llistxattr, const char __user *, pathname, char __user *, list, | |||
570 | { | 595 | { |
571 | struct path path; | 596 | struct path path; |
572 | ssize_t error; | 597 | ssize_t error; |
573 | 598 | unsigned int lookup_flags = 0; | |
574 | error = user_lpath(pathname, &path); | 599 | retry: |
600 | error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path); | ||
575 | if (error) | 601 | if (error) |
576 | return error; | 602 | return error; |
577 | error = listxattr(path.dentry, list, size); | 603 | error = listxattr(path.dentry, list, size); |
578 | path_put(&path); | 604 | path_put(&path); |
605 | if (retry_estale(error, lookup_flags)) { | ||
606 | lookup_flags |= LOOKUP_REVAL; | ||
607 | goto retry; | ||
608 | } | ||
579 | return error; | 609 | return error; |
580 | } | 610 | } |
581 | 611 | ||
@@ -615,8 +645,9 @@ SYSCALL_DEFINE2(removexattr, const char __user *, pathname, | |||
615 | { | 645 | { |
616 | struct path path; | 646 | struct path path; |
617 | int error; | 647 | int error; |
618 | 648 | unsigned int lookup_flags = LOOKUP_FOLLOW; | |
619 | error = user_path(pathname, &path); | 649 | retry: |
650 | error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path); | ||
620 | if (error) | 651 | if (error) |
621 | return error; | 652 | return error; |
622 | error = mnt_want_write(path.mnt); | 653 | error = mnt_want_write(path.mnt); |
@@ -625,6 +656,10 @@ SYSCALL_DEFINE2(removexattr, const char __user *, pathname, | |||
625 | mnt_drop_write(path.mnt); | 656 | mnt_drop_write(path.mnt); |
626 | } | 657 | } |
627 | path_put(&path); | 658 | path_put(&path); |
659 | if (retry_estale(error, lookup_flags)) { | ||
660 | lookup_flags |= LOOKUP_REVAL; | ||
661 | goto retry; | ||
662 | } | ||
628 | return error; | 663 | return error; |
629 | } | 664 | } |
630 | 665 | ||
@@ -633,8 +668,9 @@ SYSCALL_DEFINE2(lremovexattr, const char __user *, pathname, | |||
633 | { | 668 | { |
634 | struct path path; | 669 | struct path path; |
635 | int error; | 670 | int error; |
636 | 671 | unsigned int lookup_flags = 0; | |
637 | error = user_lpath(pathname, &path); | 672 | retry: |
673 | error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path); | ||
638 | if (error) | 674 | if (error) |
639 | return error; | 675 | return error; |
640 | error = mnt_want_write(path.mnt); | 676 | error = mnt_want_write(path.mnt); |
@@ -643,6 +679,10 @@ SYSCALL_DEFINE2(lremovexattr, const char __user *, pathname, | |||
643 | mnt_drop_write(path.mnt); | 679 | mnt_drop_write(path.mnt); |
644 | } | 680 | } |
645 | path_put(&path); | 681 | path_put(&path); |
682 | if (retry_estale(error, lookup_flags)) { | ||
683 | lookup_flags |= LOOKUP_REVAL; | ||
684 | goto retry; | ||
685 | } | ||
646 | return error; | 686 | return error; |
647 | } | 687 | } |
648 | 688 | ||