diff options
80 files changed, 1311 insertions, 531 deletions
diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking index e540a24e5d06..f48e0c6b4c42 100644 --- a/Documentation/filesystems/Locking +++ b/Documentation/filesystems/Locking | |||
| @@ -80,7 +80,6 @@ rename: yes (all) (see below) | |||
| 80 | readlink: no | 80 | readlink: no |
| 81 | follow_link: no | 81 | follow_link: no |
| 82 | put_link: no | 82 | put_link: no |
| 83 | truncate: yes (see below) | ||
| 84 | setattr: yes | 83 | setattr: yes |
| 85 | permission: no (may not block if called in rcu-walk mode) | 84 | permission: no (may not block if called in rcu-walk mode) |
| 86 | get_acl: no | 85 | get_acl: no |
| @@ -96,11 +95,6 @@ atomic_open: yes | |||
| 96 | Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_mutex on | 95 | Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_mutex on |
| 97 | victim. | 96 | victim. |
| 98 | cross-directory ->rename() has (per-superblock) ->s_vfs_rename_sem. | 97 | cross-directory ->rename() has (per-superblock) ->s_vfs_rename_sem. |
| 99 | ->truncate() is never called directly - it's a callback, not a | ||
| 100 | method. It's called by vmtruncate() - deprecated library function used by | ||
| 101 | ->setattr(). Locking information above applies to that call (i.e. is | ||
| 102 | inherited from ->setattr() - vmtruncate() is used when ATTR_SIZE had been | ||
| 103 | passed). | ||
| 104 | 98 | ||
| 105 | See Documentation/filesystems/directory-locking for more detailed discussion | 99 | See Documentation/filesystems/directory-locking for more detailed discussion |
| 106 | of the locking scheme for directory operations. | 100 | of the locking scheme for directory operations. |
diff --git a/Documentation/filesystems/caching/backend-api.txt b/Documentation/filesystems/caching/backend-api.txt index 382d52cdaf2d..d78bab9622c6 100644 --- a/Documentation/filesystems/caching/backend-api.txt +++ b/Documentation/filesystems/caching/backend-api.txt | |||
| @@ -308,6 +308,18 @@ performed on the denizens of the cache. These are held in a structure of type: | |||
| 308 | obtained by calling object->cookie->def->get_aux()/get_attr(). | 308 | obtained by calling object->cookie->def->get_aux()/get_attr(). |
| 309 | 309 | ||
| 310 | 310 | ||
| 311 | (*) Invalidate data object [mandatory]: | ||
| 312 | |||
| 313 | int (*invalidate_object)(struct fscache_operation *op) | ||
| 314 | |||
| 315 | This is called to invalidate a data object (as pointed to by op->object). | ||
| 316 | All the data stored for this object should be discarded and an | ||
| 317 | attr_changed operation should be performed. The caller will follow up | ||
| 318 | with an object update operation. | ||
| 319 | |||
| 320 | fscache_op_complete() must be called on op before returning. | ||
| 321 | |||
| 322 | |||
| 311 | (*) Discard object [mandatory]: | 323 | (*) Discard object [mandatory]: |
| 312 | 324 | ||
| 313 | void (*drop_object)(struct fscache_object *object) | 325 | void (*drop_object)(struct fscache_object *object) |
| @@ -419,7 +431,10 @@ performed on the denizens of the cache. These are held in a structure of type: | |||
| 419 | 431 | ||
| 420 | If an I/O error occurs, fscache_io_error() should be called and -ENOBUFS | 432 | If an I/O error occurs, fscache_io_error() should be called and -ENOBUFS |
| 421 | returned if possible or fscache_end_io() called with a suitable error | 433 | returned if possible or fscache_end_io() called with a suitable error |
| 422 | code.. | 434 | code. |
| 435 | |||
| 436 | fscache_put_retrieval() should be called after a page or pages are dealt | ||
| 437 | with. This will complete the operation when all pages are dealt with. | ||
| 423 | 438 | ||
| 424 | 439 | ||
| 425 | (*) Request pages be read from cache [mandatory]: | 440 | (*) Request pages be read from cache [mandatory]: |
| @@ -526,6 +541,27 @@ FS-Cache provides some utilities that a cache backend may make use of: | |||
| 526 | error value should be 0 if successful and an error otherwise. | 541 | error value should be 0 if successful and an error otherwise. |
| 527 | 542 | ||
| 528 | 543 | ||
| 544 | (*) Record that one or more pages being retrieved or allocated have been dealt | ||
| 545 | with: | ||
| 546 | |||
| 547 | void fscache_retrieval_complete(struct fscache_retrieval *op, | ||
| 548 | int n_pages); | ||
| 549 | |||
| 550 | This is called to record the fact that one or more pages have been dealt | ||
| 551 | with and are no longer the concern of this operation. When the number of | ||
| 552 | pages remaining in the operation reaches 0, the operation will be | ||
| 553 | completed. | ||
| 554 | |||
| 555 | |||
| 556 | (*) Record operation completion: | ||
| 557 | |||
| 558 | void fscache_op_complete(struct fscache_operation *op); | ||
| 559 | |||
| 560 | This is called to record the completion of an operation. This deducts | ||
| 561 | this operation from the parent object's run state, potentially permitting | ||
| 562 | one or more pending operations to start running. | ||
| 563 | |||
| 564 | |||
| 529 | (*) Set highest store limit: | 565 | (*) Set highest store limit: |
| 530 | 566 | ||
| 531 | void fscache_set_store_limit(struct fscache_object *object, | 567 | void fscache_set_store_limit(struct fscache_object *object, |
diff --git a/Documentation/filesystems/caching/netfs-api.txt b/Documentation/filesystems/caching/netfs-api.txt index 7cc6bf2871eb..97e6c0ecc5ef 100644 --- a/Documentation/filesystems/caching/netfs-api.txt +++ b/Documentation/filesystems/caching/netfs-api.txt | |||
| @@ -35,8 +35,9 @@ This document contains the following sections: | |||
| 35 | (12) Index and data file update | 35 | (12) Index and data file update |
| 36 | (13) Miscellaneous cookie operations | 36 | (13) Miscellaneous cookie operations |
| 37 | (14) Cookie unregistration | 37 | (14) Cookie unregistration |
| 38 | (15) Index and data file invalidation | 38 | (15) Index invalidation |
| 39 | (16) FS-Cache specific page flags. | 39 | (16) Data file invalidation |
| 40 | (17) FS-Cache specific page flags. | ||
| 40 | 41 | ||
| 41 | 42 | ||
| 42 | ============================= | 43 | ============================= |
| @@ -767,13 +768,42 @@ the cookies for "child" indices, objects and pages have been relinquished | |||
| 767 | first. | 768 | first. |
| 768 | 769 | ||
| 769 | 770 | ||
| 770 | ================================ | 771 | ================== |
| 771 | INDEX AND DATA FILE INVALIDATION | 772 | INDEX INVALIDATION |
| 772 | ================================ | 773 | ================== |
| 774 | |||
| 775 | There is no direct way to invalidate an index subtree. To do this, the caller | ||
| 776 | should relinquish and retire the cookie they have, and then acquire a new one. | ||
| 777 | |||
| 778 | |||
| 779 | ====================== | ||
| 780 | DATA FILE INVALIDATION | ||
| 781 | ====================== | ||
| 782 | |||
| 783 | Sometimes it will be necessary to invalidate an object that contains data. | ||
| 784 | Typically this will be necessary when the server tells the netfs of a foreign | ||
| 785 | change - at which point the netfs has to throw away all the state it had for an | ||
| 786 | inode and reload from the server. | ||
| 787 | |||
| 788 | To indicate that a cache object should be invalidated, the following function | ||
| 789 | can be called: | ||
| 790 | |||
| 791 | void fscache_invalidate(struct fscache_cookie *cookie); | ||
| 792 | |||
| 793 | This can be called with spinlocks held as it defers the work to a thread pool. | ||
| 794 | All extant storage, retrieval and attribute change ops at this point are | ||
| 795 | cancelled and discarded. Some future operations will be rejected until the | ||
| 796 | cache has had a chance to insert a barrier in the operations queue. After | ||
| 797 | that, operations will be queued again behind the invalidation operation. | ||
| 798 | |||
| 799 | The invalidation operation will perform an attribute change operation and an | ||
| 800 | auxiliary data update operation as it is very likely these will have changed. | ||
| 801 | |||
| 802 | Using the following function, the netfs can wait for the invalidation operation | ||
| 803 | to have reached a point at which it can start submitting ordinary operations | ||
| 804 | once again: | ||
| 773 | 805 | ||
| 774 | There is no direct way to invalidate an index subtree or a data file. To do | 806 | void fscache_wait_on_invalidate(struct fscache_cookie *cookie); |
| 775 | this, the caller should relinquish and retire the cookie they have, and then | ||
| 776 | acquire a new one. | ||
| 777 | 807 | ||
| 778 | 808 | ||
| 779 | =========================== | 809 | =========================== |
diff --git a/Documentation/filesystems/caching/object.txt b/Documentation/filesystems/caching/object.txt index 58313348da87..100ff41127e4 100644 --- a/Documentation/filesystems/caching/object.txt +++ b/Documentation/filesystems/caching/object.txt | |||
| @@ -216,7 +216,14 @@ servicing netfs requests: | |||
| 216 | The normal running state. In this state, requests the netfs makes will be | 216 | The normal running state. In this state, requests the netfs makes will be |
| 217 | passed on to the cache. | 217 | passed on to the cache. |
| 218 | 218 | ||
| 219 | (6) State FSCACHE_OBJECT_UPDATING. | 219 | (6) State FSCACHE_OBJECT_INVALIDATING. |
| 220 | |||
| 221 | The object is undergoing invalidation. When the state comes here, it | ||
| 222 | discards all pending read, write and attribute change operations as it is | ||
| 223 | going to clear out the cache entirely and reinitialise it. It will then | ||
| 224 | continue to the FSCACHE_OBJECT_UPDATING state. | ||
| 225 | |||
| 226 | (7) State FSCACHE_OBJECT_UPDATING. | ||
| 220 | 227 | ||
| 221 | The state machine comes here to update the object in the cache from the | 228 | The state machine comes here to update the object in the cache from the |
| 222 | netfs's records. This involves updating the auxiliary data that is used | 229 | netfs's records. This involves updating the auxiliary data that is used |
| @@ -225,13 +232,13 @@ servicing netfs requests: | |||
| 225 | And there are terminal states in which an object cleans itself up, deallocates | 232 | And there are terminal states in which an object cleans itself up, deallocates |
| 226 | memory and potentially deletes stuff from disk: | 233 | memory and potentially deletes stuff from disk: |
| 227 | 234 | ||
| 228 | (7) State FSCACHE_OBJECT_LC_DYING. | 235 | (8) State FSCACHE_OBJECT_LC_DYING. |
| 229 | 236 | ||
| 230 | The object comes here if it is dying because of a lookup or creation | 237 | The object comes here if it is dying because of a lookup or creation |
| 231 | error. This would be due to a disk error or system error of some sort. | 238 | error. This would be due to a disk error or system error of some sort. |
| 232 | Temporary data is cleaned up, and the parent is released. | 239 | Temporary data is cleaned up, and the parent is released. |
| 233 | 240 | ||
| 234 | (8) State FSCACHE_OBJECT_DYING. | 241 | (9) State FSCACHE_OBJECT_DYING. |
| 235 | 242 | ||
| 236 | The object comes here if it is dying due to an error, because its parent | 243 | The object comes here if it is dying due to an error, because its parent |
| 237 | cookie has been relinquished by the netfs or because the cache is being | 244 | cookie has been relinquished by the netfs or because the cache is being |
| @@ -241,27 +248,27 @@ memory and potentially deletes stuff from disk: | |||
| 241 | can destroy themselves. This object waits for all its children to go away | 248 | can destroy themselves. This object waits for all its children to go away |
| 242 | before advancing to the next state. | 249 | before advancing to the next state. |
| 243 | 250 | ||
| 244 | (9) State FSCACHE_OBJECT_ABORT_INIT. | 251 | (10) State FSCACHE_OBJECT_ABORT_INIT. |
| 245 | 252 | ||
| 246 | The object comes to this state if it was waiting on its parent in | 253 | The object comes to this state if it was waiting on its parent in |
| 247 | FSCACHE_OBJECT_INIT, but its parent died. The object will destroy itself | 254 | FSCACHE_OBJECT_INIT, but its parent died. The object will destroy itself |
| 248 | so that the parent may proceed from the FSCACHE_OBJECT_DYING state. | 255 | so that the parent may proceed from the FSCACHE_OBJECT_DYING state. |
| 249 | 256 | ||
| 250 | (10) State FSCACHE_OBJECT_RELEASING. | 257 | (11) State FSCACHE_OBJECT_RELEASING. |
| 251 | (11) State FSCACHE_OBJECT_RECYCLING. | 258 | (12) State FSCACHE_OBJECT_RECYCLING. |
| 252 | 259 | ||
| 253 | The object comes to one of these two states when dying once it is rid of | 260 | The object comes to one of these two states when dying once it is rid of |
| 254 | all its children, if it is dying because the netfs relinquished its | 261 | all its children, if it is dying because the netfs relinquished its |
| 255 | cookie. In the first state, the cached data is expected to persist, and | 262 | cookie. In the first state, the cached data is expected to persist, and |
| 256 | in the second it will be deleted. | 263 | in the second it will be deleted. |
| 257 | 264 | ||
| 258 | (12) State FSCACHE_OBJECT_WITHDRAWING. | 265 | (13) State FSCACHE_OBJECT_WITHDRAWING. |
| 259 | 266 | ||
| 260 | The object transits to this state if the cache decides it wants to | 267 | The object transits to this state if the cache decides it wants to |
| 261 | withdraw the object from service, perhaps to make space, but also due to | 268 | withdraw the object from service, perhaps to make space, but also due to |
| 262 | error or just because the whole cache is being withdrawn. | 269 | error or just because the whole cache is being withdrawn. |
| 263 | 270 | ||
| 264 | (13) State FSCACHE_OBJECT_DEAD. | 271 | (14) State FSCACHE_OBJECT_DEAD. |
| 265 | 272 | ||
| 266 | The object transits to this state when the in-memory object record is | 273 | The object transits to this state when the in-memory object record is |
| 267 | ready to be deleted. The object processor shouldn't ever see an object in | 274 | ready to be deleted. The object processor shouldn't ever see an object in |
diff --git a/Documentation/filesystems/caching/operations.txt b/Documentation/filesystems/caching/operations.txt index b6b070c57cbf..bee2a5f93d60 100644 --- a/Documentation/filesystems/caching/operations.txt +++ b/Documentation/filesystems/caching/operations.txt | |||
| @@ -174,7 +174,7 @@ Operations are used through the following procedure: | |||
| 174 | necessary (the object might have died whilst the thread was waiting). | 174 | necessary (the object might have died whilst the thread was waiting). |
| 175 | 175 | ||
| 176 | When it has finished doing its processing, it should call | 176 | When it has finished doing its processing, it should call |
| 177 | fscache_put_operation() on it. | 177 | fscache_op_complete() and fscache_put_operation() on it. |
| 178 | 178 | ||
| 179 | (4) The operation holds an effective lock upon the object, preventing other | 179 | (4) The operation holds an effective lock upon the object, preventing other |
| 180 | exclusive ops conflicting until it is released. The operation can be | 180 | exclusive ops conflicting until it is released. The operation can be |
diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting index 0742feebc6e2..0472c31c163b 100644 --- a/Documentation/filesystems/porting +++ b/Documentation/filesystems/porting | |||
| @@ -281,7 +281,7 @@ ext2_write_failed and callers for an example. | |||
| 281 | 281 | ||
| 282 | [mandatory] | 282 | [mandatory] |
| 283 | 283 | ||
| 284 | ->truncate is going away. The whole truncate sequence needs to be | 284 | ->truncate is gone. The whole truncate sequence needs to be |
| 285 | implemented in ->setattr, which is now mandatory for filesystems | 285 | implemented in ->setattr, which is now mandatory for filesystems |
| 286 | implementing on-disk size changes. Start with a copy of the old inode_setattr | 286 | implementing on-disk size changes. Start with a copy of the old inode_setattr |
| 287 | and vmtruncate, and the reorder the vmtruncate + foofs_vmtruncate sequence to | 287 | and vmtruncate, and the reorder the vmtruncate + foofs_vmtruncate sequence to |
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt index 2ee133e030c3..e3869098163e 100644 --- a/Documentation/filesystems/vfs.txt +++ b/Documentation/filesystems/vfs.txt | |||
| @@ -350,7 +350,6 @@ struct inode_operations { | |||
| 350 | int (*readlink) (struct dentry *, char __user *,int); | 350 | int (*readlink) (struct dentry *, char __user *,int); |
| 351 | void * (*follow_link) (struct dentry *, struct nameidata *); | 351 | void * (*follow_link) (struct dentry *, struct nameidata *); |
| 352 | void (*put_link) (struct dentry *, struct nameidata *, void *); | 352 | void (*put_link) (struct dentry *, struct nameidata *, void *); |
| 353 | void (*truncate) (struct inode *); | ||
| 354 | int (*permission) (struct inode *, int); | 353 | int (*permission) (struct inode *, int); |
| 355 | int (*get_acl)(struct inode *, int); | 354 | int (*get_acl)(struct inode *, int); |
| 356 | int (*setattr) (struct dentry *, struct iattr *); | 355 | int (*setattr) (struct dentry *, struct iattr *); |
| @@ -431,16 +430,6 @@ otherwise noted. | |||
| 431 | started might not be in the page cache at the end of the | 430 | started might not be in the page cache at the end of the |
| 432 | walk). | 431 | walk). |
| 433 | 432 | ||
| 434 | truncate: Deprecated. This will not be called if ->setsize is defined. | ||
| 435 | Called by the VFS to change the size of a file. The | ||
| 436 | i_size field of the inode is set to the desired size by the | ||
| 437 | VFS before this method is called. This method is called by | ||
| 438 | the truncate(2) system call and related functionality. | ||
| 439 | |||
| 440 | Note: ->truncate and vmtruncate are deprecated. Do not add new | ||
| 441 | instances/calls of these. Filesystems should be converted to do their | ||
| 442 | truncate sequence via ->setattr(). | ||
| 443 | |||
| 444 | permission: called by the VFS to check for access rights on a POSIX-like | 433 | permission: called by the VFS to check for access rights on a POSIX-like |
| 445 | filesystem. | 434 | filesystem. |
| 446 | 435 | ||
diff --git a/arch/powerpc/platforms/cell/spufs/syscalls.c b/arch/powerpc/platforms/cell/spufs/syscalls.c index 5b7d8ffbf890..baee994fe810 100644 --- a/arch/powerpc/platforms/cell/spufs/syscalls.c +++ b/arch/powerpc/platforms/cell/spufs/syscalls.c | |||
| @@ -66,7 +66,7 @@ static long do_spu_create(const char __user *pathname, unsigned int flags, | |||
| 66 | struct dentry *dentry; | 66 | struct dentry *dentry; |
| 67 | int ret; | 67 | int ret; |
| 68 | 68 | ||
| 69 | dentry = user_path_create(AT_FDCWD, pathname, &path, 1); | 69 | dentry = user_path_create(AT_FDCWD, pathname, &path, LOOKUP_DIRECTORY); |
| 70 | ret = PTR_ERR(dentry); | 70 | ret = PTR_ERR(dentry); |
| 71 | if (!IS_ERR(dentry)) { | 71 | if (!IS_ERR(dentry)) { |
| 72 | ret = spufs_create(&path, dentry, flags, mode, neighbor); | 72 | ret = spufs_create(&path, dentry, flags, mode, neighbor); |
diff --git a/drivers/base/devtmpfs.c b/drivers/base/devtmpfs.c index 147d1a4dd269..17cf7cad601e 100644 --- a/drivers/base/devtmpfs.c +++ b/drivers/base/devtmpfs.c | |||
| @@ -148,7 +148,7 @@ static int dev_mkdir(const char *name, umode_t mode) | |||
| 148 | struct path path; | 148 | struct path path; |
| 149 | int err; | 149 | int err; |
| 150 | 150 | ||
| 151 | dentry = kern_path_create(AT_FDCWD, name, &path, 1); | 151 | dentry = kern_path_create(AT_FDCWD, name, &path, LOOKUP_DIRECTORY); |
| 152 | if (IS_ERR(dentry)) | 152 | if (IS_ERR(dentry)) |
| 153 | return PTR_ERR(dentry); | 153 | return PTR_ERR(dentry); |
| 154 | 154 | ||
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 | ||
diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 59200795482e..c1754b59ddd3 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h | |||
| @@ -202,7 +202,6 @@ struct dentry_operations { | |||
| 202 | #define DCACHE_MOUNTED 0x10000 /* is a mountpoint */ | 202 | #define DCACHE_MOUNTED 0x10000 /* is a mountpoint */ |
| 203 | #define DCACHE_NEED_AUTOMOUNT 0x20000 /* handle automount on this dir */ | 203 | #define DCACHE_NEED_AUTOMOUNT 0x20000 /* handle automount on this dir */ |
| 204 | #define DCACHE_MANAGE_TRANSIT 0x40000 /* manage transit from this dirent */ | 204 | #define DCACHE_MANAGE_TRANSIT 0x40000 /* manage transit from this dirent */ |
| 205 | #define DCACHE_NEED_LOOKUP 0x80000 /* dentry requires i_op->lookup */ | ||
| 206 | #define DCACHE_MANAGED_DENTRY \ | 205 | #define DCACHE_MANAGED_DENTRY \ |
| 207 | (DCACHE_MOUNTED|DCACHE_NEED_AUTOMOUNT|DCACHE_MANAGE_TRANSIT) | 206 | (DCACHE_MOUNTED|DCACHE_NEED_AUTOMOUNT|DCACHE_MANAGE_TRANSIT) |
| 208 | 207 | ||
| @@ -408,13 +407,6 @@ static inline bool d_mountpoint(struct dentry *dentry) | |||
| 408 | return dentry->d_flags & DCACHE_MOUNTED; | 407 | return dentry->d_flags & DCACHE_MOUNTED; |
| 409 | } | 408 | } |
| 410 | 409 | ||
| 411 | static inline bool d_need_lookup(struct dentry *dentry) | ||
| 412 | { | ||
| 413 | return dentry->d_flags & DCACHE_NEED_LOOKUP; | ||
| 414 | } | ||
| 415 | |||
| 416 | extern void d_clear_need_lookup(struct dentry *dentry); | ||
| 417 | |||
| 418 | extern int sysctl_vfs_cache_pressure; | 410 | extern int sysctl_vfs_cache_pressure; |
| 419 | 411 | ||
| 420 | #endif /* __LINUX_DCACHE_H */ | 412 | #endif /* __LINUX_DCACHE_H */ |
diff --git a/include/linux/fs.h b/include/linux/fs.h index a823d4be38e7..7617ee04f066 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
| @@ -1445,10 +1445,6 @@ static inline void sb_start_intwrite(struct super_block *sb) | |||
| 1445 | 1445 | ||
| 1446 | extern bool inode_owner_or_capable(const struct inode *inode); | 1446 | extern bool inode_owner_or_capable(const struct inode *inode); |
| 1447 | 1447 | ||
| 1448 | /* not quite ready to be deprecated, but... */ | ||
| 1449 | extern void lock_super(struct super_block *); | ||
| 1450 | extern void unlock_super(struct super_block *); | ||
| 1451 | |||
| 1452 | /* | 1448 | /* |
| 1453 | * VFS helper functions.. | 1449 | * VFS helper functions.. |
| 1454 | */ | 1450 | */ |
| @@ -1565,7 +1561,6 @@ struct inode_operations { | |||
| 1565 | int (*mknod) (struct inode *,struct dentry *,umode_t,dev_t); | 1561 | int (*mknod) (struct inode *,struct dentry *,umode_t,dev_t); |
| 1566 | int (*rename) (struct inode *, struct dentry *, | 1562 | int (*rename) (struct inode *, struct dentry *, |
| 1567 | struct inode *, struct dentry *); | 1563 | struct inode *, struct dentry *); |
| 1568 | void (*truncate) (struct inode *); | ||
| 1569 | int (*setattr) (struct dentry *, struct iattr *); | 1564 | int (*setattr) (struct dentry *, struct iattr *); |
| 1570 | int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *); | 1565 | int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *); |
| 1571 | int (*setxattr) (struct dentry *, const char *,const void *,size_t,int); | 1566 | int (*setxattr) (struct dentry *, const char *,const void *,size_t,int); |
| @@ -1999,6 +1994,7 @@ struct filename { | |||
| 1999 | bool separate; /* should "name" be freed? */ | 1994 | bool separate; /* should "name" be freed? */ |
| 2000 | }; | 1995 | }; |
| 2001 | 1996 | ||
| 1997 | extern long vfs_truncate(struct path *, loff_t); | ||
| 2002 | extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs, | 1998 | extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs, |
| 2003 | struct file *filp); | 1999 | struct file *filp); |
| 2004 | extern int do_fallocate(struct file *file, int mode, loff_t offset, | 2000 | extern int do_fallocate(struct file *file, int mode, loff_t offset, |
diff --git a/include/linux/fscache-cache.h b/include/linux/fscache-cache.h index ce31408b1e47..5dfa0aa216b6 100644 --- a/include/linux/fscache-cache.h +++ b/include/linux/fscache-cache.h | |||
| @@ -75,6 +75,16 @@ extern wait_queue_head_t fscache_cache_cleared_wq; | |||
| 75 | typedef void (*fscache_operation_release_t)(struct fscache_operation *op); | 75 | typedef void (*fscache_operation_release_t)(struct fscache_operation *op); |
| 76 | typedef void (*fscache_operation_processor_t)(struct fscache_operation *op); | 76 | typedef void (*fscache_operation_processor_t)(struct fscache_operation *op); |
| 77 | 77 | ||
| 78 | enum fscache_operation_state { | ||
| 79 | FSCACHE_OP_ST_BLANK, /* Op is not yet submitted */ | ||
| 80 | FSCACHE_OP_ST_INITIALISED, /* Op is initialised */ | ||
| 81 | FSCACHE_OP_ST_PENDING, /* Op is blocked from running */ | ||
| 82 | FSCACHE_OP_ST_IN_PROGRESS, /* Op is in progress */ | ||
| 83 | FSCACHE_OP_ST_COMPLETE, /* Op is complete */ | ||
| 84 | FSCACHE_OP_ST_CANCELLED, /* Op has been cancelled */ | ||
| 85 | FSCACHE_OP_ST_DEAD /* Op is now dead */ | ||
| 86 | }; | ||
| 87 | |||
| 78 | struct fscache_operation { | 88 | struct fscache_operation { |
| 79 | struct work_struct work; /* record for async ops */ | 89 | struct work_struct work; /* record for async ops */ |
| 80 | struct list_head pend_link; /* link in object->pending_ops */ | 90 | struct list_head pend_link; /* link in object->pending_ops */ |
| @@ -86,10 +96,10 @@ struct fscache_operation { | |||
| 86 | #define FSCACHE_OP_MYTHREAD 0x0002 /* - processing is done be issuing thread, not pool */ | 96 | #define FSCACHE_OP_MYTHREAD 0x0002 /* - processing is done be issuing thread, not pool */ |
| 87 | #define FSCACHE_OP_WAITING 4 /* cleared when op is woken */ | 97 | #define FSCACHE_OP_WAITING 4 /* cleared when op is woken */ |
| 88 | #define FSCACHE_OP_EXCLUSIVE 5 /* exclusive op, other ops must wait */ | 98 | #define FSCACHE_OP_EXCLUSIVE 5 /* exclusive op, other ops must wait */ |
| 89 | #define FSCACHE_OP_DEAD 6 /* op is now dead */ | 99 | #define FSCACHE_OP_DEC_READ_CNT 6 /* decrement object->n_reads on destruction */ |
| 90 | #define FSCACHE_OP_DEC_READ_CNT 7 /* decrement object->n_reads on destruction */ | 100 | #define FSCACHE_OP_KEEP_FLAGS 0x0070 /* flags to keep when repurposing an op */ |
| 91 | #define FSCACHE_OP_KEEP_FLAGS 0xc0 /* flags to keep when repurposing an op */ | ||
| 92 | 101 | ||
| 102 | enum fscache_operation_state state; | ||
| 93 | atomic_t usage; | 103 | atomic_t usage; |
| 94 | unsigned debug_id; /* debugging ID */ | 104 | unsigned debug_id; /* debugging ID */ |
| 95 | 105 | ||
| @@ -106,6 +116,7 @@ extern atomic_t fscache_op_debug_id; | |||
| 106 | extern void fscache_op_work_func(struct work_struct *work); | 116 | extern void fscache_op_work_func(struct work_struct *work); |
| 107 | 117 | ||
| 108 | extern void fscache_enqueue_operation(struct fscache_operation *); | 118 | extern void fscache_enqueue_operation(struct fscache_operation *); |
| 119 | extern void fscache_op_complete(struct fscache_operation *, bool); | ||
| 109 | extern void fscache_put_operation(struct fscache_operation *); | 120 | extern void fscache_put_operation(struct fscache_operation *); |
| 110 | 121 | ||
| 111 | /** | 122 | /** |
| @@ -122,6 +133,7 @@ static inline void fscache_operation_init(struct fscache_operation *op, | |||
| 122 | { | 133 | { |
| 123 | INIT_WORK(&op->work, fscache_op_work_func); | 134 | INIT_WORK(&op->work, fscache_op_work_func); |
| 124 | atomic_set(&op->usage, 1); | 135 | atomic_set(&op->usage, 1); |
| 136 | op->state = FSCACHE_OP_ST_INITIALISED; | ||
| 125 | op->debug_id = atomic_inc_return(&fscache_op_debug_id); | 137 | op->debug_id = atomic_inc_return(&fscache_op_debug_id); |
| 126 | op->processor = processor; | 138 | op->processor = processor; |
| 127 | op->release = release; | 139 | op->release = release; |
| @@ -138,6 +150,7 @@ struct fscache_retrieval { | |||
| 138 | void *context; /* netfs read context (pinned) */ | 150 | void *context; /* netfs read context (pinned) */ |
| 139 | struct list_head to_do; /* list of things to be done by the backend */ | 151 | struct list_head to_do; /* list of things to be done by the backend */ |
| 140 | unsigned long start_time; /* time at which retrieval started */ | 152 | unsigned long start_time; /* time at which retrieval started */ |
| 153 | unsigned n_pages; /* number of pages to be retrieved */ | ||
| 141 | }; | 154 | }; |
| 142 | 155 | ||
| 143 | typedef int (*fscache_page_retrieval_func_t)(struct fscache_retrieval *op, | 156 | typedef int (*fscache_page_retrieval_func_t)(struct fscache_retrieval *op, |
| @@ -174,8 +187,22 @@ static inline void fscache_enqueue_retrieval(struct fscache_retrieval *op) | |||
| 174 | } | 187 | } |
| 175 | 188 | ||
| 176 | /** | 189 | /** |
| 190 | * fscache_retrieval_complete - Record (partial) completion of a retrieval | ||
| 191 | * @op: The retrieval operation affected | ||
| 192 | * @n_pages: The number of pages to account for | ||
| 193 | */ | ||
| 194 | static inline void fscache_retrieval_complete(struct fscache_retrieval *op, | ||
| 195 | int n_pages) | ||
| 196 | { | ||
| 197 | op->n_pages -= n_pages; | ||
| 198 | if (op->n_pages <= 0) | ||
| 199 | fscache_op_complete(&op->op, true); | ||
| 200 | } | ||
| 201 | |||
| 202 | /** | ||
| 177 | * fscache_put_retrieval - Drop a reference to a retrieval operation | 203 | * fscache_put_retrieval - Drop a reference to a retrieval operation |
| 178 | * @op: The retrieval operation affected | 204 | * @op: The retrieval operation affected |
| 205 | * @n_pages: The number of pages to account for | ||
| 179 | * | 206 | * |
| 180 | * Drop a reference to a retrieval operation. | 207 | * Drop a reference to a retrieval operation. |
| 181 | */ | 208 | */ |
| @@ -227,6 +254,9 @@ struct fscache_cache_ops { | |||
| 227 | /* store the updated auxiliary data on an object */ | 254 | /* store the updated auxiliary data on an object */ |
| 228 | void (*update_object)(struct fscache_object *object); | 255 | void (*update_object)(struct fscache_object *object); |
| 229 | 256 | ||
| 257 | /* Invalidate an object */ | ||
| 258 | void (*invalidate_object)(struct fscache_operation *op); | ||
| 259 | |||
| 230 | /* discard the resources pinned by an object and effect retirement if | 260 | /* discard the resources pinned by an object and effect retirement if |
| 231 | * necessary */ | 261 | * necessary */ |
| 232 | void (*drop_object)(struct fscache_object *object); | 262 | void (*drop_object)(struct fscache_object *object); |
| @@ -301,11 +331,30 @@ struct fscache_cookie { | |||
| 301 | #define FSCACHE_COOKIE_PENDING_FILL 3 /* T if pending initial fill on object */ | 331 | #define FSCACHE_COOKIE_PENDING_FILL 3 /* T if pending initial fill on object */ |
| 302 | #define FSCACHE_COOKIE_FILLING 4 /* T if filling object incrementally */ | 332 | #define FSCACHE_COOKIE_FILLING 4 /* T if filling object incrementally */ |
| 303 | #define FSCACHE_COOKIE_UNAVAILABLE 5 /* T if cookie is unavailable (error, etc) */ | 333 | #define FSCACHE_COOKIE_UNAVAILABLE 5 /* T if cookie is unavailable (error, etc) */ |
| 334 | #define FSCACHE_COOKIE_WAITING_ON_READS 6 /* T if cookie is waiting on reads */ | ||
| 335 | #define FSCACHE_COOKIE_INVALIDATING 7 /* T if cookie is being invalidated */ | ||
| 304 | }; | 336 | }; |
| 305 | 337 | ||
| 306 | extern struct fscache_cookie fscache_fsdef_index; | 338 | extern struct fscache_cookie fscache_fsdef_index; |
| 307 | 339 | ||
| 308 | /* | 340 | /* |
| 341 | * Event list for fscache_object::{event_mask,events} | ||
| 342 | */ | ||
| 343 | enum { | ||
| 344 | FSCACHE_OBJECT_EV_REQUEUE, /* T if object should be requeued */ | ||
| 345 | FSCACHE_OBJECT_EV_UPDATE, /* T if object should be updated */ | ||
| 346 | FSCACHE_OBJECT_EV_INVALIDATE, /* T if cache requested object invalidation */ | ||
| 347 | FSCACHE_OBJECT_EV_CLEARED, /* T if accessors all gone */ | ||
| 348 | FSCACHE_OBJECT_EV_ERROR, /* T if fatal error occurred during processing */ | ||
| 349 | FSCACHE_OBJECT_EV_RELEASE, /* T if netfs requested object release */ | ||
| 350 | FSCACHE_OBJECT_EV_RETIRE, /* T if netfs requested object retirement */ | ||
| 351 | FSCACHE_OBJECT_EV_WITHDRAW, /* T if cache requested object withdrawal */ | ||
| 352 | NR_FSCACHE_OBJECT_EVENTS | ||
| 353 | }; | ||
| 354 | |||
| 355 | #define FSCACHE_OBJECT_EVENTS_MASK ((1UL << NR_FSCACHE_OBJECT_EVENTS) - 1) | ||
| 356 | |||
| 357 | /* | ||
| 309 | * on-disk cache file or index handle | 358 | * on-disk cache file or index handle |
| 310 | */ | 359 | */ |
| 311 | struct fscache_object { | 360 | struct fscache_object { |
| @@ -317,6 +366,7 @@ struct fscache_object { | |||
| 317 | /* active states */ | 366 | /* active states */ |
| 318 | FSCACHE_OBJECT_AVAILABLE, /* cleaning up object after creation */ | 367 | FSCACHE_OBJECT_AVAILABLE, /* cleaning up object after creation */ |
| 319 | FSCACHE_OBJECT_ACTIVE, /* object is usable */ | 368 | FSCACHE_OBJECT_ACTIVE, /* object is usable */ |
| 369 | FSCACHE_OBJECT_INVALIDATING, /* object is invalidating */ | ||
| 320 | FSCACHE_OBJECT_UPDATING, /* object is updating */ | 370 | FSCACHE_OBJECT_UPDATING, /* object is updating */ |
| 321 | 371 | ||
| 322 | /* terminal states */ | 372 | /* terminal states */ |
| @@ -332,10 +382,10 @@ struct fscache_object { | |||
| 332 | 382 | ||
| 333 | int debug_id; /* debugging ID */ | 383 | int debug_id; /* debugging ID */ |
| 334 | int n_children; /* number of child objects */ | 384 | int n_children; /* number of child objects */ |
| 335 | int n_ops; /* number of ops outstanding on object */ | 385 | int n_ops; /* number of extant ops on object */ |
| 336 | int n_obj_ops; /* number of object ops outstanding on object */ | 386 | int n_obj_ops; /* number of object ops outstanding on object */ |
| 337 | int n_in_progress; /* number of ops in progress */ | 387 | int n_in_progress; /* number of ops in progress */ |
| 338 | int n_exclusive; /* number of exclusive ops queued */ | 388 | int n_exclusive; /* number of exclusive ops queued or in progress */ |
| 339 | atomic_t n_reads; /* number of read ops in progress */ | 389 | atomic_t n_reads; /* number of read ops in progress */ |
| 340 | spinlock_t lock; /* state and operations lock */ | 390 | spinlock_t lock; /* state and operations lock */ |
| 341 | 391 | ||
| @@ -343,14 +393,6 @@ struct fscache_object { | |||
| 343 | unsigned long event_mask; /* events this object is interested in */ | 393 | unsigned long event_mask; /* events this object is interested in */ |
| 344 | unsigned long events; /* events to be processed by this object | 394 | unsigned long events; /* events to be processed by this object |
| 345 | * (order is important - using fls) */ | 395 | * (order is important - using fls) */ |
| 346 | #define FSCACHE_OBJECT_EV_REQUEUE 0 /* T if object should be requeued */ | ||
| 347 | #define FSCACHE_OBJECT_EV_UPDATE 1 /* T if object should be updated */ | ||
| 348 | #define FSCACHE_OBJECT_EV_CLEARED 2 /* T if accessors all gone */ | ||
| 349 | #define FSCACHE_OBJECT_EV_ERROR 3 /* T if fatal error occurred during processing */ | ||
| 350 | #define FSCACHE_OBJECT_EV_RELEASE 4 /* T if netfs requested object release */ | ||
| 351 | #define FSCACHE_OBJECT_EV_RETIRE 5 /* T if netfs requested object retirement */ | ||
| 352 | #define FSCACHE_OBJECT_EV_WITHDRAW 6 /* T if cache requested object withdrawal */ | ||
| 353 | #define FSCACHE_OBJECT_EVENTS_MASK 0x7f /* mask of all events*/ | ||
| 354 | 396 | ||
| 355 | unsigned long flags; | 397 | unsigned long flags; |
| 356 | #define FSCACHE_OBJECT_LOCK 0 /* T if object is busy being processed */ | 398 | #define FSCACHE_OBJECT_LOCK 0 /* T if object is busy being processed */ |
| @@ -504,6 +546,9 @@ extern void fscache_withdraw_cache(struct fscache_cache *cache); | |||
| 504 | 546 | ||
| 505 | extern void fscache_io_error(struct fscache_cache *cache); | 547 | extern void fscache_io_error(struct fscache_cache *cache); |
| 506 | 548 | ||
| 549 | extern void fscache_mark_page_cached(struct fscache_retrieval *op, | ||
| 550 | struct page *page); | ||
| 551 | |||
| 507 | extern void fscache_mark_pages_cached(struct fscache_retrieval *op, | 552 | extern void fscache_mark_pages_cached(struct fscache_retrieval *op, |
| 508 | struct pagevec *pagevec); | 553 | struct pagevec *pagevec); |
| 509 | 554 | ||
diff --git a/include/linux/fscache.h b/include/linux/fscache.h index 9ec20dec3353..7a086235da4b 100644 --- a/include/linux/fscache.h +++ b/include/linux/fscache.h | |||
| @@ -135,14 +135,14 @@ struct fscache_cookie_def { | |||
| 135 | */ | 135 | */ |
| 136 | void (*put_context)(void *cookie_netfs_data, void *context); | 136 | void (*put_context)(void *cookie_netfs_data, void *context); |
| 137 | 137 | ||
| 138 | /* indicate pages that now have cache metadata retained | 138 | /* indicate page that now have cache metadata retained |
| 139 | * - this function should mark the specified pages as now being cached | 139 | * - this function should mark the specified page as now being cached |
| 140 | * - the pages will have been marked with PG_fscache before this is | 140 | * - the page will have been marked with PG_fscache before this is |
| 141 | * called, so this is optional | 141 | * called, so this is optional |
| 142 | */ | 142 | */ |
| 143 | void (*mark_pages_cached)(void *cookie_netfs_data, | 143 | void (*mark_page_cached)(void *cookie_netfs_data, |
| 144 | struct address_space *mapping, | 144 | struct address_space *mapping, |
| 145 | struct pagevec *cached_pvec); | 145 | struct page *page); |
| 146 | 146 | ||
| 147 | /* indicate the cookie is no longer cached | 147 | /* indicate the cookie is no longer cached |
| 148 | * - this function is called when the backing store currently caching | 148 | * - this function is called when the backing store currently caching |
| @@ -185,6 +185,8 @@ extern struct fscache_cookie *__fscache_acquire_cookie( | |||
| 185 | extern void __fscache_relinquish_cookie(struct fscache_cookie *, int); | 185 | extern void __fscache_relinquish_cookie(struct fscache_cookie *, int); |
| 186 | extern void __fscache_update_cookie(struct fscache_cookie *); | 186 | extern void __fscache_update_cookie(struct fscache_cookie *); |
| 187 | extern int __fscache_attr_changed(struct fscache_cookie *); | 187 | extern int __fscache_attr_changed(struct fscache_cookie *); |
| 188 | extern void __fscache_invalidate(struct fscache_cookie *); | ||
| 189 | extern void __fscache_wait_on_invalidate(struct fscache_cookie *); | ||
| 188 | extern int __fscache_read_or_alloc_page(struct fscache_cookie *, | 190 | extern int __fscache_read_or_alloc_page(struct fscache_cookie *, |
| 189 | struct page *, | 191 | struct page *, |
| 190 | fscache_rw_complete_t, | 192 | fscache_rw_complete_t, |
| @@ -390,6 +392,42 @@ int fscache_attr_changed(struct fscache_cookie *cookie) | |||
| 390 | } | 392 | } |
| 391 | 393 | ||
| 392 | /** | 394 | /** |
| 395 | * fscache_invalidate - Notify cache that an object needs invalidation | ||
| 396 | * @cookie: The cookie representing the cache object | ||
| 397 | * | ||
| 398 | * Notify the cache that an object is needs to be invalidated and that it | ||
| 399 | * should abort any retrievals or stores it is doing on the cache. The object | ||
| 400 | * is then marked non-caching until such time as the invalidation is complete. | ||
| 401 | * | ||
| 402 | * This can be called with spinlocks held. | ||
| 403 | * | ||
| 404 | * See Documentation/filesystems/caching/netfs-api.txt for a complete | ||
| 405 | * description. | ||
| 406 | */ | ||
| 407 | static inline | ||
| 408 | void fscache_invalidate(struct fscache_cookie *cookie) | ||
| 409 | { | ||
| 410 | if (fscache_cookie_valid(cookie)) | ||
| 411 | __fscache_invalidate(cookie); | ||
| 412 | } | ||
| 413 | |||
| 414 | /** | ||
| 415 | * fscache_wait_on_invalidate - Wait for invalidation to complete | ||
| 416 | * @cookie: The cookie representing the cache object | ||
| 417 | * | ||
| 418 | * Wait for the invalidation of an object to complete. | ||
| 419 | * | ||
| 420 | * See Documentation/filesystems/caching/netfs-api.txt for a complete | ||
| 421 | * description. | ||
| 422 | */ | ||
| 423 | static inline | ||
| 424 | void fscache_wait_on_invalidate(struct fscache_cookie *cookie) | ||
| 425 | { | ||
| 426 | if (fscache_cookie_valid(cookie)) | ||
| 427 | __fscache_wait_on_invalidate(cookie); | ||
| 428 | } | ||
| 429 | |||
| 430 | /** | ||
| 393 | * fscache_reserve_space - Reserve data space for a cached object | 431 | * fscache_reserve_space - Reserve data space for a cached object |
| 394 | * @cookie: The cookie representing the cache object | 432 | * @cookie: The cookie representing the cache object |
| 395 | * @i_size: The amount of space to be reserved | 433 | * @i_size: The amount of space to be reserved |
diff --git a/include/linux/mm.h b/include/linux/mm.h index 7f4f906190bd..63204078f72b 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h | |||
| @@ -1007,7 +1007,6 @@ static inline void unmap_shared_mapping_range(struct address_space *mapping, | |||
| 1007 | 1007 | ||
| 1008 | extern void truncate_pagecache(struct inode *inode, loff_t old, loff_t new); | 1008 | extern void truncate_pagecache(struct inode *inode, loff_t old, loff_t new); |
| 1009 | extern void truncate_setsize(struct inode *inode, loff_t newsize); | 1009 | extern void truncate_setsize(struct inode *inode, loff_t newsize); |
| 1010 | extern int vmtruncate(struct inode *inode, loff_t offset); | ||
| 1011 | void truncate_pagecache_range(struct inode *inode, loff_t offset, loff_t end); | 1010 | void truncate_pagecache_range(struct inode *inode, loff_t offset, loff_t end); |
| 1012 | int truncate_inode_page(struct address_space *mapping, struct page *page); | 1011 | int truncate_inode_page(struct address_space *mapping, struct page *page); |
| 1013 | int generic_error_remove_page(struct address_space *mapping, struct page *page); | 1012 | int generic_error_remove_page(struct address_space *mapping, struct page *page); |
diff --git a/include/linux/namei.h b/include/linux/namei.h index 4bf19d8174ed..e998c030061d 100644 --- a/include/linux/namei.h +++ b/include/linux/namei.h | |||
| @@ -65,8 +65,8 @@ extern int user_path_at_empty(int, const char __user *, unsigned, struct path *, | |||
| 65 | 65 | ||
| 66 | extern int kern_path(const char *, unsigned, struct path *); | 66 | extern int kern_path(const char *, unsigned, struct path *); |
| 67 | 67 | ||
| 68 | extern struct dentry *kern_path_create(int, const char *, struct path *, int); | 68 | extern struct dentry *kern_path_create(int, const char *, struct path *, unsigned int); |
| 69 | extern struct dentry *user_path_create(int, const char __user *, struct path *, int); | 69 | extern struct dentry *user_path_create(int, const char __user *, struct path *, unsigned int); |
| 70 | extern void done_path_create(struct path *, struct dentry *); | 70 | extern void done_path_create(struct path *, struct dentry *); |
| 71 | extern struct dentry *kern_path_locked(const char *, struct path *); | 71 | extern struct dentry *kern_path_locked(const char *, struct path *); |
| 72 | extern int vfs_path_lookup(struct dentry *, struct vfsmount *, | 72 | extern int vfs_path_lookup(struct dentry *, struct vfsmount *, |
| @@ -98,4 +98,20 @@ static inline void nd_terminate_link(void *name, size_t len, size_t maxlen) | |||
| 98 | ((char *) name)[min(len, maxlen)] = '\0'; | 98 | ((char *) name)[min(len, maxlen)] = '\0'; |
| 99 | } | 99 | } |
| 100 | 100 | ||
| 101 | /** | ||
| 102 | * retry_estale - determine whether the caller should retry an operation | ||
| 103 | * @error: the error that would currently be returned | ||
| 104 | * @flags: flags being used for next lookup attempt | ||
| 105 | * | ||
| 106 | * Check to see if the error code was -ESTALE, and then determine whether | ||
| 107 | * to retry the call based on whether "flags" already has LOOKUP_REVAL set. | ||
| 108 | * | ||
| 109 | * Returns true if the caller should try the operation again. | ||
| 110 | */ | ||
| 111 | static inline bool | ||
| 112 | retry_estale(const long error, const unsigned int flags) | ||
| 113 | { | ||
| 114 | return error == -ESTALE && !(flags & LOOKUP_REVAL); | ||
| 115 | } | ||
| 116 | |||
| 101 | #endif /* _LINUX_NAMEI_H */ | 117 | #endif /* _LINUX_NAMEI_H */ |
diff --git a/mm/truncate.c b/mm/truncate.c index d51ce92d6e83..c75b736e54b7 100644 --- a/mm/truncate.c +++ b/mm/truncate.c | |||
| @@ -577,29 +577,6 @@ void truncate_setsize(struct inode *inode, loff_t newsize) | |||
| 577 | EXPORT_SYMBOL(truncate_setsize); | 577 | EXPORT_SYMBOL(truncate_setsize); |
| 578 | 578 | ||
| 579 | /** | 579 | /** |
| 580 | * vmtruncate - unmap mappings "freed" by truncate() syscall | ||
| 581 | * @inode: inode of the file used | ||
| 582 | * @newsize: file offset to start truncating | ||
| 583 | * | ||
| 584 | * This function is deprecated and truncate_setsize or truncate_pagecache | ||
| 585 | * should be used instead, together with filesystem specific block truncation. | ||
| 586 | */ | ||
| 587 | int vmtruncate(struct inode *inode, loff_t newsize) | ||
| 588 | { | ||
| 589 | int error; | ||
| 590 | |||
| 591 | error = inode_newsize_ok(inode, newsize); | ||
| 592 | if (error) | ||
| 593 | return error; | ||
| 594 | |||
| 595 | truncate_setsize(inode, newsize); | ||
| 596 | if (inode->i_op->truncate) | ||
| 597 | inode->i_op->truncate(inode); | ||
| 598 | return 0; | ||
| 599 | } | ||
| 600 | EXPORT_SYMBOL(vmtruncate); | ||
| 601 | |||
| 602 | /** | ||
| 603 | * truncate_pagecache_range - unmap and remove pagecache that is hole-punched | 580 | * truncate_pagecache_range - unmap and remove pagecache that is hole-punched |
| 604 | * @inode: inode | 581 | * @inode: inode |
| 605 | * @lstart: offset of beginning of hole | 582 | * @lstart: offset of beginning of hole |
