You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull VFS update from Al Viro: "fscache fixes, ESTALE patchset, vmtruncate removal series, assorted misc stuff." * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (79 commits) vfs: make lremovexattr retry once on ESTALE error vfs: make removexattr retry once on ESTALE vfs: make llistxattr retry once on ESTALE error vfs: make listxattr retry once on ESTALE error vfs: make lgetxattr retry once on ESTALE vfs: make getxattr retry once on an ESTALE error vfs: allow lsetxattr() to retry once on ESTALE errors vfs: allow setxattr to retry once on ESTALE errors vfs: allow utimensat() calls to retry once on an ESTALE error vfs: fix user_statfs to retry once on ESTALE errors vfs: make fchownat retry once on ESTALE errors vfs: make fchmodat retry once on ESTALE errors vfs: have chroot retry once on ESTALE error vfs: have chdir retry lookup and call once on ESTALE error vfs: have faccessat retry once on an ESTALE error vfs: have do_sys_truncate retry once on an ESTALE error vfs: fix renameat to retry on ESTALE errors vfs: make do_unlinkat retry once on ESTALE errors vfs: make do_rmdir retry once on ESTALE errors vfs: add a flags argument to user_path_parent ...
This commit is contained in:
@@ -80,7 +80,6 @@ rename: yes (all) (see below)
|
||||
readlink: no
|
||||
follow_link: no
|
||||
put_link: no
|
||||
truncate: yes (see below)
|
||||
setattr: yes
|
||||
permission: no (may not block if called in rcu-walk mode)
|
||||
get_acl: no
|
||||
@@ -96,11 +95,6 @@ atomic_open: yes
|
||||
Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_mutex on
|
||||
victim.
|
||||
cross-directory ->rename() has (per-superblock) ->s_vfs_rename_sem.
|
||||
->truncate() is never called directly - it's a callback, not a
|
||||
method. It's called by vmtruncate() - deprecated library function used by
|
||||
->setattr(). Locking information above applies to that call (i.e. is
|
||||
inherited from ->setattr() - vmtruncate() is used when ATTR_SIZE had been
|
||||
passed).
|
||||
|
||||
See Documentation/filesystems/directory-locking for more detailed discussion
|
||||
of the locking scheme for directory operations.
|
||||
|
||||
@@ -308,6 +308,18 @@ performed on the denizens of the cache. These are held in a structure of type:
|
||||
obtained by calling object->cookie->def->get_aux()/get_attr().
|
||||
|
||||
|
||||
(*) Invalidate data object [mandatory]:
|
||||
|
||||
int (*invalidate_object)(struct fscache_operation *op)
|
||||
|
||||
This is called to invalidate a data object (as pointed to by op->object).
|
||||
All the data stored for this object should be discarded and an
|
||||
attr_changed operation should be performed. The caller will follow up
|
||||
with an object update operation.
|
||||
|
||||
fscache_op_complete() must be called on op before returning.
|
||||
|
||||
|
||||
(*) Discard object [mandatory]:
|
||||
|
||||
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:
|
||||
|
||||
If an I/O error occurs, fscache_io_error() should be called and -ENOBUFS
|
||||
returned if possible or fscache_end_io() called with a suitable error
|
||||
code..
|
||||
code.
|
||||
|
||||
fscache_put_retrieval() should be called after a page or pages are dealt
|
||||
with. This will complete the operation when all pages are dealt with.
|
||||
|
||||
|
||||
(*) Request pages be read from cache [mandatory]:
|
||||
@@ -526,6 +541,27 @@ FS-Cache provides some utilities that a cache backend may make use of:
|
||||
error value should be 0 if successful and an error otherwise.
|
||||
|
||||
|
||||
(*) Record that one or more pages being retrieved or allocated have been dealt
|
||||
with:
|
||||
|
||||
void fscache_retrieval_complete(struct fscache_retrieval *op,
|
||||
int n_pages);
|
||||
|
||||
This is called to record the fact that one or more pages have been dealt
|
||||
with and are no longer the concern of this operation. When the number of
|
||||
pages remaining in the operation reaches 0, the operation will be
|
||||
completed.
|
||||
|
||||
|
||||
(*) Record operation completion:
|
||||
|
||||
void fscache_op_complete(struct fscache_operation *op);
|
||||
|
||||
This is called to record the completion of an operation. This deducts
|
||||
this operation from the parent object's run state, potentially permitting
|
||||
one or more pending operations to start running.
|
||||
|
||||
|
||||
(*) Set highest store limit:
|
||||
|
||||
void fscache_set_store_limit(struct fscache_object *object,
|
||||
|
||||
@@ -35,8 +35,9 @@ This document contains the following sections:
|
||||
(12) Index and data file update
|
||||
(13) Miscellaneous cookie operations
|
||||
(14) Cookie unregistration
|
||||
(15) Index and data file invalidation
|
||||
(16) FS-Cache specific page flags.
|
||||
(15) Index invalidation
|
||||
(16) Data file invalidation
|
||||
(17) FS-Cache specific page flags.
|
||||
|
||||
|
||||
=============================
|
||||
@@ -767,13 +768,42 @@ the cookies for "child" indices, objects and pages have been relinquished
|
||||
first.
|
||||
|
||||
|
||||
================================
|
||||
INDEX AND DATA FILE INVALIDATION
|
||||
================================
|
||||
==================
|
||||
INDEX INVALIDATION
|
||||
==================
|
||||
|
||||
There is no direct way to invalidate an index subtree or a data file. To do
|
||||
this, the caller should relinquish and retire the cookie they have, and then
|
||||
acquire a new one.
|
||||
There is no direct way to invalidate an index subtree. To do this, the caller
|
||||
should relinquish and retire the cookie they have, and then acquire a new one.
|
||||
|
||||
|
||||
======================
|
||||
DATA FILE INVALIDATION
|
||||
======================
|
||||
|
||||
Sometimes it will be necessary to invalidate an object that contains data.
|
||||
Typically this will be necessary when the server tells the netfs of a foreign
|
||||
change - at which point the netfs has to throw away all the state it had for an
|
||||
inode and reload from the server.
|
||||
|
||||
To indicate that a cache object should be invalidated, the following function
|
||||
can be called:
|
||||
|
||||
void fscache_invalidate(struct fscache_cookie *cookie);
|
||||
|
||||
This can be called with spinlocks held as it defers the work to a thread pool.
|
||||
All extant storage, retrieval and attribute change ops at this point are
|
||||
cancelled and discarded. Some future operations will be rejected until the
|
||||
cache has had a chance to insert a barrier in the operations queue. After
|
||||
that, operations will be queued again behind the invalidation operation.
|
||||
|
||||
The invalidation operation will perform an attribute change operation and an
|
||||
auxiliary data update operation as it is very likely these will have changed.
|
||||
|
||||
Using the following function, the netfs can wait for the invalidation operation
|
||||
to have reached a point at which it can start submitting ordinary operations
|
||||
once again:
|
||||
|
||||
void fscache_wait_on_invalidate(struct fscache_cookie *cookie);
|
||||
|
||||
|
||||
===========================
|
||||
|
||||
@@ -216,7 +216,14 @@ servicing netfs requests:
|
||||
The normal running state. In this state, requests the netfs makes will be
|
||||
passed on to the cache.
|
||||
|
||||
(6) State FSCACHE_OBJECT_UPDATING.
|
||||
(6) State FSCACHE_OBJECT_INVALIDATING.
|
||||
|
||||
The object is undergoing invalidation. When the state comes here, it
|
||||
discards all pending read, write and attribute change operations as it is
|
||||
going to clear out the cache entirely and reinitialise it. It will then
|
||||
continue to the FSCACHE_OBJECT_UPDATING state.
|
||||
|
||||
(7) State FSCACHE_OBJECT_UPDATING.
|
||||
|
||||
The state machine comes here to update the object in the cache from the
|
||||
netfs's records. This involves updating the auxiliary data that is used
|
||||
@@ -225,13 +232,13 @@ servicing netfs requests:
|
||||
And there are terminal states in which an object cleans itself up, deallocates
|
||||
memory and potentially deletes stuff from disk:
|
||||
|
||||
(7) State FSCACHE_OBJECT_LC_DYING.
|
||||
(8) State FSCACHE_OBJECT_LC_DYING.
|
||||
|
||||
The object comes here if it is dying because of a lookup or creation
|
||||
error. This would be due to a disk error or system error of some sort.
|
||||
Temporary data is cleaned up, and the parent is released.
|
||||
|
||||
(8) State FSCACHE_OBJECT_DYING.
|
||||
(9) State FSCACHE_OBJECT_DYING.
|
||||
|
||||
The object comes here if it is dying due to an error, because its parent
|
||||
cookie has been relinquished by the netfs or because the cache is being
|
||||
@@ -241,27 +248,27 @@ memory and potentially deletes stuff from disk:
|
||||
can destroy themselves. This object waits for all its children to go away
|
||||
before advancing to the next state.
|
||||
|
||||
(9) State FSCACHE_OBJECT_ABORT_INIT.
|
||||
(10) State FSCACHE_OBJECT_ABORT_INIT.
|
||||
|
||||
The object comes to this state if it was waiting on its parent in
|
||||
FSCACHE_OBJECT_INIT, but its parent died. The object will destroy itself
|
||||
so that the parent may proceed from the FSCACHE_OBJECT_DYING state.
|
||||
|
||||
(10) State FSCACHE_OBJECT_RELEASING.
|
||||
(11) State FSCACHE_OBJECT_RECYCLING.
|
||||
(11) State FSCACHE_OBJECT_RELEASING.
|
||||
(12) State FSCACHE_OBJECT_RECYCLING.
|
||||
|
||||
The object comes to one of these two states when dying once it is rid of
|
||||
all its children, if it is dying because the netfs relinquished its
|
||||
cookie. In the first state, the cached data is expected to persist, and
|
||||
in the second it will be deleted.
|
||||
|
||||
(12) State FSCACHE_OBJECT_WITHDRAWING.
|
||||
(13) State FSCACHE_OBJECT_WITHDRAWING.
|
||||
|
||||
The object transits to this state if the cache decides it wants to
|
||||
withdraw the object from service, perhaps to make space, but also due to
|
||||
error or just because the whole cache is being withdrawn.
|
||||
|
||||
(13) State FSCACHE_OBJECT_DEAD.
|
||||
(14) State FSCACHE_OBJECT_DEAD.
|
||||
|
||||
The object transits to this state when the in-memory object record is
|
||||
ready to be deleted. The object processor shouldn't ever see an object in
|
||||
|
||||
@@ -174,7 +174,7 @@ Operations are used through the following procedure:
|
||||
necessary (the object might have died whilst the thread was waiting).
|
||||
|
||||
When it has finished doing its processing, it should call
|
||||
fscache_put_operation() on it.
|
||||
fscache_op_complete() and fscache_put_operation() on it.
|
||||
|
||||
(4) The operation holds an effective lock upon the object, preventing other
|
||||
exclusive ops conflicting until it is released. The operation can be
|
||||
|
||||
@@ -281,7 +281,7 @@ ext2_write_failed and callers for an example.
|
||||
|
||||
[mandatory]
|
||||
|
||||
->truncate is going away. The whole truncate sequence needs to be
|
||||
->truncate is gone. The whole truncate sequence needs to be
|
||||
implemented in ->setattr, which is now mandatory for filesystems
|
||||
implementing on-disk size changes. Start with a copy of the old inode_setattr
|
||||
and vmtruncate, and the reorder the vmtruncate + foofs_vmtruncate sequence to
|
||||
|
||||
@@ -350,7 +350,6 @@ struct inode_operations {
|
||||
int (*readlink) (struct dentry *, char __user *,int);
|
||||
void * (*follow_link) (struct dentry *, struct nameidata *);
|
||||
void (*put_link) (struct dentry *, struct nameidata *, void *);
|
||||
void (*truncate) (struct inode *);
|
||||
int (*permission) (struct inode *, int);
|
||||
int (*get_acl)(struct inode *, int);
|
||||
int (*setattr) (struct dentry *, struct iattr *);
|
||||
@@ -431,16 +430,6 @@ otherwise noted.
|
||||
started might not be in the page cache at the end of the
|
||||
walk).
|
||||
|
||||
truncate: Deprecated. This will not be called if ->setsize is defined.
|
||||
Called by the VFS to change the size of a file. The
|
||||
i_size field of the inode is set to the desired size by the
|
||||
VFS before this method is called. This method is called by
|
||||
the truncate(2) system call and related functionality.
|
||||
|
||||
Note: ->truncate and vmtruncate are deprecated. Do not add new
|
||||
instances/calls of these. Filesystems should be converted to do their
|
||||
truncate sequence via ->setattr().
|
||||
|
||||
permission: called by the VFS to check for access rights on a POSIX-like
|
||||
filesystem.
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ static long do_spu_create(const char __user *pathname, unsigned int flags,
|
||||
struct dentry *dentry;
|
||||
int ret;
|
||||
|
||||
dentry = user_path_create(AT_FDCWD, pathname, &path, 1);
|
||||
dentry = user_path_create(AT_FDCWD, pathname, &path, LOOKUP_DIRECTORY);
|
||||
ret = PTR_ERR(dentry);
|
||||
if (!IS_ERR(dentry)) {
|
||||
ret = spufs_create(&path, dentry, flags, mode, neighbor);
|
||||
|
||||
@@ -148,7 +148,7 @@ static int dev_mkdir(const char *name, umode_t mode)
|
||||
struct path path;
|
||||
int err;
|
||||
|
||||
dentry = kern_path_create(AT_FDCWD, name, &path, 1);
|
||||
dentry = kern_path_create(AT_FDCWD, name, &path, LOOKUP_DIRECTORY);
|
||||
if (IS_ERR(dentry))
|
||||
return PTR_ERR(dentry);
|
||||
|
||||
|
||||
+10
-5
@@ -45,6 +45,14 @@ static int adfs_readpage(struct file *file, struct page *page)
|
||||
return block_read_full_page(page, adfs_get_block);
|
||||
}
|
||||
|
||||
static void adfs_write_failed(struct address_space *mapping, loff_t to)
|
||||
{
|
||||
struct inode *inode = mapping->host;
|
||||
|
||||
if (to > inode->i_size)
|
||||
truncate_pagecache(inode, to, inode->i_size);
|
||||
}
|
||||
|
||||
static int adfs_write_begin(struct file *file, struct address_space *mapping,
|
||||
loff_t pos, unsigned len, unsigned flags,
|
||||
struct page **pagep, void **fsdata)
|
||||
@@ -55,11 +63,8 @@ static int adfs_write_begin(struct file *file, struct address_space *mapping,
|
||||
ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
|
||||
adfs_get_block,
|
||||
&ADFS_I(mapping->host)->mmu_private);
|
||||
if (unlikely(ret)) {
|
||||
loff_t isize = mapping->host->i_size;
|
||||
if (pos + len > isize)
|
||||
vmtruncate(mapping->host, isize);
|
||||
}
|
||||
if (unlikely(ret))
|
||||
adfs_write_failed(mapping, pos + len);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
+12
-6
@@ -39,7 +39,6 @@ const struct file_operations affs_file_operations = {
|
||||
};
|
||||
|
||||
const struct inode_operations affs_file_inode_operations = {
|
||||
.truncate = affs_truncate,
|
||||
.setattr = affs_notify_change,
|
||||
};
|
||||
|
||||
@@ -402,6 +401,16 @@ static int affs_readpage(struct file *file, struct page *page)
|
||||
return block_read_full_page(page, affs_get_block);
|
||||
}
|
||||
|
||||
static void affs_write_failed(struct address_space *mapping, loff_t to)
|
||||
{
|
||||
struct inode *inode = mapping->host;
|
||||
|
||||
if (to > inode->i_size) {
|
||||
truncate_pagecache(inode, to, inode->i_size);
|
||||
affs_truncate(inode);
|
||||
}
|
||||
}
|
||||
|
||||
static int affs_write_begin(struct file *file, struct address_space *mapping,
|
||||
loff_t pos, unsigned len, unsigned flags,
|
||||
struct page **pagep, void **fsdata)
|
||||
@@ -412,11 +421,8 @@ static int affs_write_begin(struct file *file, struct address_space *mapping,
|
||||
ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
|
||||
affs_get_block,
|
||||
&AFFS_I(mapping->host)->mmu_private);
|
||||
if (unlikely(ret)) {
|
||||
loff_t isize = mapping->host->i_size;
|
||||
if (pos + len > isize)
|
||||
vmtruncate(mapping->host, isize);
|
||||
}
|
||||
if (unlikely(ret))
|
||||
affs_write_failed(mapping, pos + len);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
+4
-1
@@ -237,9 +237,12 @@ affs_notify_change(struct dentry *dentry, struct iattr *attr)
|
||||
|
||||
if ((attr->ia_valid & ATTR_SIZE) &&
|
||||
attr->ia_size != i_size_read(inode)) {
|
||||
error = vmtruncate(inode, attr->ia_size);
|
||||
error = inode_newsize_ok(inode, attr->ia_size);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
truncate_setsize(inode, attr->ia_size);
|
||||
affs_truncate(inode);
|
||||
}
|
||||
|
||||
setattr_copy(inode, attr);
|
||||
|
||||
+10
-5
@@ -161,6 +161,14 @@ static int bfs_readpage(struct file *file, struct page *page)
|
||||
return block_read_full_page(page, bfs_get_block);
|
||||
}
|
||||
|
||||
static void bfs_write_failed(struct address_space *mapping, loff_t to)
|
||||
{
|
||||
struct inode *inode = mapping->host;
|
||||
|
||||
if (to > inode->i_size)
|
||||
truncate_pagecache(inode, to, inode->i_size);
|
||||
}
|
||||
|
||||
static int bfs_write_begin(struct file *file, struct address_space *mapping,
|
||||
loff_t pos, unsigned len, unsigned flags,
|
||||
struct page **pagep, void **fsdata)
|
||||
@@ -169,11 +177,8 @@ static int bfs_write_begin(struct file *file, struct address_space *mapping,
|
||||
|
||||
ret = block_write_begin(mapping, pos, len, flags, pagep,
|
||||
bfs_get_block);
|
||||
if (unlikely(ret)) {
|
||||
loff_t isize = mapping->host->i_size;
|
||||
if (pos + len > isize)
|
||||
vmtruncate(mapping->host, isize);
|
||||
}
|
||||
if (unlikely(ret))
|
||||
bfs_write_failed(mapping, pos + len);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
+1
-15
@@ -4262,16 +4262,7 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry)
|
||||
if (dentry->d_name.len > BTRFS_NAME_LEN)
|
||||
return ERR_PTR(-ENAMETOOLONG);
|
||||
|
||||
if (unlikely(d_need_lookup(dentry))) {
|
||||
memcpy(&location, dentry->d_fsdata, sizeof(struct btrfs_key));
|
||||
kfree(dentry->d_fsdata);
|
||||
dentry->d_fsdata = NULL;
|
||||
/* This thing is hashed, drop it for now */
|
||||
d_drop(dentry);
|
||||
} else {
|
||||
ret = btrfs_inode_by_name(dir, dentry, &location);
|
||||
}
|
||||
|
||||
ret = btrfs_inode_by_name(dir, dentry, &location);
|
||||
if (ret < 0)
|
||||
return ERR_PTR(ret);
|
||||
|
||||
@@ -4341,11 +4332,6 @@ static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry,
|
||||
struct dentry *ret;
|
||||
|
||||
ret = d_splice_alias(btrfs_lookup_dentry(dir, dentry), dentry);
|
||||
if (unlikely(d_need_lookup(dentry))) {
|
||||
spin_lock(&dentry->d_lock);
|
||||
dentry->d_flags &= ~DCACHE_NEED_LOOKUP;
|
||||
spin_unlock(&dentry->d_lock);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -41,12 +41,12 @@ static struct fscache_object *cachefiles_alloc_object(
|
||||
|
||||
_enter("{%s},%p,", cache->cache.identifier, cookie);
|
||||
|
||||
lookup_data = kmalloc(sizeof(*lookup_data), GFP_KERNEL);
|
||||
lookup_data = kmalloc(sizeof(*lookup_data), cachefiles_gfp);
|
||||
if (!lookup_data)
|
||||
goto nomem_lookup_data;
|
||||
|
||||
/* create a new object record and a temporary leaf image */
|
||||
object = kmem_cache_alloc(cachefiles_object_jar, GFP_KERNEL);
|
||||
object = kmem_cache_alloc(cachefiles_object_jar, cachefiles_gfp);
|
||||
if (!object)
|
||||
goto nomem_object;
|
||||
|
||||
@@ -63,7 +63,7 @@ static struct fscache_object *cachefiles_alloc_object(
|
||||
* - stick the length on the front and leave space on the back for the
|
||||
* encoder
|
||||
*/
|
||||
buffer = kmalloc((2 + 512) + 3, GFP_KERNEL);
|
||||
buffer = kmalloc((2 + 512) + 3, cachefiles_gfp);
|
||||
if (!buffer)
|
||||
goto nomem_buffer;
|
||||
|
||||
@@ -219,7 +219,7 @@ static void cachefiles_update_object(struct fscache_object *_object)
|
||||
return;
|
||||
}
|
||||
|
||||
auxdata = kmalloc(2 + 512 + 3, GFP_KERNEL);
|
||||
auxdata = kmalloc(2 + 512 + 3, cachefiles_gfp);
|
||||
if (!auxdata) {
|
||||
_leave(" [nomem]");
|
||||
return;
|
||||
@@ -440,6 +440,54 @@ truncate_failed:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Invalidate an object
|
||||
*/
|
||||
static void cachefiles_invalidate_object(struct fscache_operation *op)
|
||||
{
|
||||
struct cachefiles_object *object;
|
||||
struct cachefiles_cache *cache;
|
||||
const struct cred *saved_cred;
|
||||
struct path path;
|
||||
uint64_t ni_size;
|
||||
int ret;
|
||||
|
||||
object = container_of(op->object, struct cachefiles_object, fscache);
|
||||
cache = container_of(object->fscache.cache,
|
||||
struct cachefiles_cache, cache);
|
||||
|
||||
op->object->cookie->def->get_attr(op->object->cookie->netfs_data,
|
||||
&ni_size);
|
||||
|
||||
_enter("{OBJ%x},[%llu]",
|
||||
op->object->debug_id, (unsigned long long)ni_size);
|
||||
|
||||
if (object->backer) {
|
||||
ASSERT(S_ISREG(object->backer->d_inode->i_mode));
|
||||
|
||||
fscache_set_store_limit(&object->fscache, ni_size);
|
||||
|
||||
path.dentry = object->backer;
|
||||
path.mnt = cache->mnt;
|
||||
|
||||
cachefiles_begin_secure(cache, &saved_cred);
|
||||
ret = vfs_truncate(&path, 0);
|
||||
if (ret == 0)
|
||||
ret = vfs_truncate(&path, ni_size);
|
||||
cachefiles_end_secure(cache, saved_cred);
|
||||
|
||||
if (ret != 0) {
|
||||
fscache_set_store_limit(&object->fscache, 0);
|
||||
if (ret == -EIO)
|
||||
cachefiles_io_error_obj(object,
|
||||
"Invalidate failed");
|
||||
}
|
||||
}
|
||||
|
||||
fscache_op_complete(op, true);
|
||||
_leave("");
|
||||
}
|
||||
|
||||
/*
|
||||
* dissociate a cache from all the pages it was backing
|
||||
*/
|
||||
@@ -455,6 +503,7 @@ const struct fscache_cache_ops cachefiles_cache_ops = {
|
||||
.lookup_complete = cachefiles_lookup_complete,
|
||||
.grab_object = cachefiles_grab_object,
|
||||
.update_object = cachefiles_update_object,
|
||||
.invalidate_object = cachefiles_invalidate_object,
|
||||
.drop_object = cachefiles_drop_object,
|
||||
.put_object = cachefiles_put_object,
|
||||
.sync_cache = cachefiles_sync_cache,
|
||||
|
||||
@@ -23,6 +23,8 @@ extern unsigned cachefiles_debug;
|
||||
#define CACHEFILES_DEBUG_KLEAVE 2
|
||||
#define CACHEFILES_DEBUG_KDEBUG 4
|
||||
|
||||
#define cachefiles_gfp (__GFP_WAIT | __GFP_NORETRY | __GFP_NOMEMALLOC)
|
||||
|
||||
/*
|
||||
* node records
|
||||
*/
|
||||
|
||||
+1
-1
@@ -78,7 +78,7 @@ char *cachefiles_cook_key(const u8 *raw, int keylen, uint8_t type)
|
||||
|
||||
_debug("max: %d", max);
|
||||
|
||||
key = kmalloc(max, GFP_KERNEL);
|
||||
key = kmalloc(max, cachefiles_gfp);
|
||||
if (!key)
|
||||
return NULL;
|
||||
|
||||
|
||||
@@ -40,8 +40,7 @@ void __cachefiles_printk_object(struct cachefiles_object *object,
|
||||
printk(KERN_ERR "%sobjstate=%s fl=%lx wbusy=%x ev=%lx[%lx]\n",
|
||||
prefix, fscache_object_states[object->fscache.state],
|
||||
object->fscache.flags, work_busy(&object->fscache.work),
|
||||
object->fscache.events,
|
||||
object->fscache.event_mask & FSCACHE_OBJECT_EVENTS_MASK);
|
||||
object->fscache.events, object->fscache.event_mask);
|
||||
printk(KERN_ERR "%sops=%u inp=%u exc=%u\n",
|
||||
prefix, object->fscache.n_ops, object->fscache.n_in_progress,
|
||||
object->fscache.n_exclusive);
|
||||
|
||||
+67
-47
@@ -77,25 +77,25 @@ static int cachefiles_read_reissue(struct cachefiles_object *object,
|
||||
struct page *backpage = monitor->back_page, *backpage2;
|
||||
int ret;
|
||||
|
||||
kenter("{ino=%lx},{%lx,%lx}",
|
||||
_enter("{ino=%lx},{%lx,%lx}",
|
||||
object->backer->d_inode->i_ino,
|
||||
backpage->index, backpage->flags);
|
||||
|
||||
/* skip if the page was truncated away completely */
|
||||
if (backpage->mapping != bmapping) {
|
||||
kleave(" = -ENODATA [mapping]");
|
||||
_leave(" = -ENODATA [mapping]");
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
backpage2 = find_get_page(bmapping, backpage->index);
|
||||
if (!backpage2) {
|
||||
kleave(" = -ENODATA [gone]");
|
||||
_leave(" = -ENODATA [gone]");
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
if (backpage != backpage2) {
|
||||
put_page(backpage2);
|
||||
kleave(" = -ENODATA [different]");
|
||||
_leave(" = -ENODATA [different]");
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ static int cachefiles_read_reissue(struct cachefiles_object *object,
|
||||
if (PageUptodate(backpage))
|
||||
goto unlock_discard;
|
||||
|
||||
kdebug("reissue read");
|
||||
_debug("reissue read");
|
||||
ret = bmapping->a_ops->readpage(NULL, backpage);
|
||||
if (ret < 0)
|
||||
goto unlock_discard;
|
||||
@@ -129,7 +129,7 @@ static int cachefiles_read_reissue(struct cachefiles_object *object,
|
||||
}
|
||||
|
||||
/* it'll reappear on the todo list */
|
||||
kleave(" = -EINPROGRESS");
|
||||
_leave(" = -EINPROGRESS");
|
||||
return -EINPROGRESS;
|
||||
|
||||
unlock_discard:
|
||||
@@ -137,7 +137,7 @@ unlock_discard:
|
||||
spin_lock_irq(&object->work_lock);
|
||||
list_del(&monitor->op_link);
|
||||
spin_unlock_irq(&object->work_lock);
|
||||
kleave(" = %d", ret);
|
||||
_leave(" = %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -174,11 +174,13 @@ static void cachefiles_read_copier(struct fscache_operation *_op)
|
||||
_debug("- copy {%lu}", monitor->back_page->index);
|
||||
|
||||
recheck:
|
||||
if (PageUptodate(monitor->back_page)) {
|
||||
if (test_bit(FSCACHE_COOKIE_INVALIDATING,
|
||||
&object->fscache.cookie->flags)) {
|
||||
error = -ESTALE;
|
||||
} else if (PageUptodate(monitor->back_page)) {
|
||||
copy_highpage(monitor->netfs_page, monitor->back_page);
|
||||
|
||||
pagevec_add(&pagevec, monitor->netfs_page);
|
||||
fscache_mark_pages_cached(monitor->op, &pagevec);
|
||||
fscache_mark_page_cached(monitor->op,
|
||||
monitor->netfs_page);
|
||||
error = 0;
|
||||
} else if (!PageError(monitor->back_page)) {
|
||||
/* the page has probably been truncated */
|
||||
@@ -198,6 +200,7 @@ static void cachefiles_read_copier(struct fscache_operation *_op)
|
||||
|
||||
fscache_end_io(op, monitor->netfs_page, error);
|
||||
page_cache_release(monitor->netfs_page);
|
||||
fscache_retrieval_complete(op, 1);
|
||||
fscache_put_retrieval(op);
|
||||
kfree(monitor);
|
||||
|
||||
@@ -239,7 +242,7 @@ static int cachefiles_read_backing_file_one(struct cachefiles_object *object,
|
||||
_debug("read back %p{%lu,%d}",
|
||||
netpage, netpage->index, page_count(netpage));
|
||||
|
||||
monitor = kzalloc(sizeof(*monitor), GFP_KERNEL);
|
||||
monitor = kzalloc(sizeof(*monitor), cachefiles_gfp);
|
||||
if (!monitor)
|
||||
goto nomem;
|
||||
|
||||
@@ -258,13 +261,14 @@ static int cachefiles_read_backing_file_one(struct cachefiles_object *object,
|
||||
goto backing_page_already_present;
|
||||
|
||||
if (!newpage) {
|
||||
newpage = page_cache_alloc_cold(bmapping);
|
||||
newpage = __page_cache_alloc(cachefiles_gfp |
|
||||
__GFP_COLD);
|
||||
if (!newpage)
|
||||
goto nomem_monitor;
|
||||
}
|
||||
|
||||
ret = add_to_page_cache(newpage, bmapping,
|
||||
netpage->index, GFP_KERNEL);
|
||||
netpage->index, cachefiles_gfp);
|
||||
if (ret == 0)
|
||||
goto installed_new_backing_page;
|
||||
if (ret != -EEXIST)
|
||||
@@ -335,11 +339,11 @@ backing_page_already_present:
|
||||
backing_page_already_uptodate:
|
||||
_debug("- uptodate");
|
||||
|
||||
pagevec_add(pagevec, netpage);
|
||||
fscache_mark_pages_cached(op, pagevec);
|
||||
fscache_mark_page_cached(op, netpage);
|
||||
|
||||
copy_highpage(netpage, backpage);
|
||||
fscache_end_io(op, netpage, 0);
|
||||
fscache_retrieval_complete(op, 1);
|
||||
|
||||
success:
|
||||
_debug("success");
|
||||
@@ -357,10 +361,13 @@ out:
|
||||
|
||||
read_error:
|
||||
_debug("read error %d", ret);
|
||||
if (ret == -ENOMEM)
|
||||
if (ret == -ENOMEM) {
|
||||
fscache_retrieval_complete(op, 1);
|
||||
goto out;
|
||||
}
|
||||
io_error:
|
||||
cachefiles_io_error_obj(object, "Page read error on backing file");
|
||||
fscache_retrieval_complete(op, 1);
|
||||
ret = -ENOBUFS;
|
||||
goto out;
|
||||
|
||||
@@ -370,6 +377,7 @@ nomem_monitor:
|
||||
fscache_put_retrieval(monitor->op);
|
||||
kfree(monitor);
|
||||
nomem:
|
||||
fscache_retrieval_complete(op, 1);
|
||||
_leave(" = -ENOMEM");
|
||||
return -ENOMEM;
|
||||
}
|
||||
@@ -408,7 +416,7 @@ int cachefiles_read_or_alloc_page(struct fscache_retrieval *op,
|
||||
_enter("{%p},{%lx},,,", object, page->index);
|
||||
|
||||
if (!object->backer)
|
||||
return -ENOBUFS;
|
||||
goto enobufs;
|
||||
|
||||
inode = object->backer->d_inode;
|
||||
ASSERT(S_ISREG(inode->i_mode));
|
||||
@@ -417,7 +425,7 @@ int cachefiles_read_or_alloc_page(struct fscache_retrieval *op,
|
||||
|
||||
/* calculate the shift required to use bmap */
|
||||
if (inode->i_sb->s_blocksize > PAGE_SIZE)
|
||||
return -ENOBUFS;
|
||||
goto enobufs;
|
||||
|
||||
shift = PAGE_SHIFT - inode->i_sb->s_blocksize_bits;
|
||||
|
||||
@@ -448,15 +456,20 @@ int cachefiles_read_or_alloc_page(struct fscache_retrieval *op,
|
||||
&pagevec);
|
||||
} else if (cachefiles_has_space(cache, 0, 1) == 0) {
|
||||
/* there's space in the cache we can use */
|
||||
pagevec_add(&pagevec, page);
|
||||
fscache_mark_pages_cached(op, &pagevec);
|
||||
fscache_mark_page_cached(op, page);
|
||||
fscache_retrieval_complete(op, 1);
|
||||
ret = -ENODATA;
|
||||
} else {
|
||||
ret = -ENOBUFS;
|
||||
goto enobufs;
|
||||
}
|
||||
|
||||
_leave(" = %d", ret);
|
||||
return ret;
|
||||
|
||||
enobufs:
|
||||
fscache_retrieval_complete(op, 1);
|
||||
_leave(" = -ENOBUFS");
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -465,8 +478,7 @@ int cachefiles_read_or_alloc_page(struct fscache_retrieval *op,
|
||||
*/
|
||||
static int cachefiles_read_backing_file(struct cachefiles_object *object,
|
||||
struct fscache_retrieval *op,
|
||||
struct list_head *list,
|
||||
struct pagevec *mark_pvec)
|
||||
struct list_head *list)
|
||||
{
|
||||
struct cachefiles_one_read *monitor = NULL;
|
||||
struct address_space *bmapping = object->backer->d_inode->i_mapping;
|
||||
@@ -485,7 +497,7 @@ static int cachefiles_read_backing_file(struct cachefiles_object *object,
|
||||
netpage, netpage->index, page_count(netpage));
|
||||
|
||||
if (!monitor) {
|
||||
monitor = kzalloc(sizeof(*monitor), GFP_KERNEL);
|
||||
monitor = kzalloc(sizeof(*monitor), cachefiles_gfp);
|
||||
if (!monitor)
|
||||
goto nomem;
|
||||
|
||||
@@ -500,13 +512,14 @@ static int cachefiles_read_backing_file(struct cachefiles_object *object,
|
||||
goto backing_page_already_present;
|
||||
|
||||
if (!newpage) {
|
||||
newpage = page_cache_alloc_cold(bmapping);
|
||||
newpage = __page_cache_alloc(cachefiles_gfp |
|
||||
__GFP_COLD);
|
||||
if (!newpage)
|
||||
goto nomem;
|
||||
}
|
||||
|
||||
ret = add_to_page_cache(newpage, bmapping,
|
||||
netpage->index, GFP_KERNEL);
|
||||
netpage->index, cachefiles_gfp);
|
||||
if (ret == 0)
|
||||
goto installed_new_backing_page;
|
||||
if (ret != -EEXIST)
|
||||
@@ -536,10 +549,11 @@ static int cachefiles_read_backing_file(struct cachefiles_object *object,
|
||||
_debug("- monitor add");
|
||||
|
||||
ret = add_to_page_cache(netpage, op->mapping, netpage->index,
|
||||
GFP_KERNEL);
|
||||
cachefiles_gfp);
|
||||
if (ret < 0) {
|
||||
if (ret == -EEXIST) {
|
||||
page_cache_release(netpage);
|
||||
fscache_retrieval_complete(op, 1);
|
||||
continue;
|
||||
}
|
||||
goto nomem;
|
||||
@@ -612,10 +626,11 @@ static int cachefiles_read_backing_file(struct cachefiles_object *object,
|
||||
_debug("- uptodate");
|
||||
|
||||
ret = add_to_page_cache(netpage, op->mapping, netpage->index,
|
||||
GFP_KERNEL);
|
||||
cachefiles_gfp);
|
||||
if (ret < 0) {
|
||||
if (ret == -EEXIST) {
|
||||
page_cache_release(netpage);
|
||||
fscache_retrieval_complete(op, 1);
|
||||
continue;
|
||||
}
|
||||
goto nomem;
|
||||
@@ -626,16 +641,17 @@ static int cachefiles_read_backing_file(struct cachefiles_object *object,
|
||||
page_cache_release(backpage);
|
||||
backpage = NULL;
|
||||
|
||||
if (!pagevec_add(mark_pvec, netpage))
|
||||
fscache_mark_pages_cached(op, mark_pvec);
|
||||
fscache_mark_page_cached(op, netpage);
|
||||
|
||||
page_cache_get(netpage);
|
||||
if (!pagevec_add(&lru_pvec, netpage))
|
||||
__pagevec_lru_add_file(&lru_pvec);
|
||||
|
||||
/* the netpage is unlocked and marked up to date here */
|
||||
fscache_end_io(op, netpage, 0);
|
||||
page_cache_release(netpage);
|
||||
netpage = NULL;
|
||||
fscache_retrieval_complete(op, 1);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -661,6 +677,7 @@ out:
|
||||
list_for_each_entry_safe(netpage, _n, list, lru) {
|
||||
list_del(&netpage->lru);
|
||||
page_cache_release(netpage);
|
||||
fscache_retrieval_complete(op, 1);
|
||||
}
|
||||
|
||||
_leave(" = %d", ret);
|
||||
@@ -669,15 +686,17 @@ out:
|
||||
nomem:
|
||||
_debug("nomem");
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
goto record_page_complete;
|
||||
|
||||
read_error:
|
||||
_debug("read error %d", ret);
|
||||
if (ret == -ENOMEM)
|
||||
goto out;
|
||||
goto record_page_complete;
|
||||
io_error:
|
||||
cachefiles_io_error_obj(object, "Page read error on backing file");
|
||||
ret = -ENOBUFS;
|
||||
record_page_complete:
|
||||
fscache_retrieval_complete(op, 1);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -709,7 +728,7 @@ int cachefiles_read_or_alloc_pages(struct fscache_retrieval *op,
|
||||
*nr_pages);
|
||||
|
||||
if (!object->backer)
|
||||
return -ENOBUFS;
|
||||
goto all_enobufs;
|
||||
|
||||
space = 1;
|
||||
if (cachefiles_has_space(cache, 0, *nr_pages) < 0)
|
||||
@@ -722,7 +741,7 @@ int cachefiles_read_or_alloc_pages(struct fscache_retrieval *op,
|
||||
|
||||
/* calculate the shift required to use bmap */
|
||||
if (inode->i_sb->s_blocksize > PAGE_SIZE)
|
||||
return -ENOBUFS;
|
||||
goto all_enobufs;
|
||||
|
||||
shift = PAGE_SHIFT - inode->i_sb->s_blocksize_bits;
|
||||
|
||||
@@ -762,7 +781,10 @@ int cachefiles_read_or_alloc_pages(struct fscache_retrieval *op,
|
||||
nrbackpages++;
|
||||
} else if (space && pagevec_add(&pagevec, page) == 0) {
|
||||
fscache_mark_pages_cached(op, &pagevec);
|
||||
fscache_retrieval_complete(op, 1);
|
||||
ret = -ENODATA;
|
||||
} else {
|
||||
fscache_retrieval_complete(op, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -775,18 +797,18 @@ int cachefiles_read_or_alloc_pages(struct fscache_retrieval *op,
|
||||
/* submit the apparently valid pages to the backing fs to be read from
|
||||
* disk */
|
||||
if (nrbackpages > 0) {
|
||||
ret2 = cachefiles_read_backing_file(object, op, &backpages,
|
||||
&pagevec);
|
||||
ret2 = cachefiles_read_backing_file(object, op, &backpages);
|
||||
if (ret2 == -ENOMEM || ret2 == -EINTR)
|
||||
ret = ret2;
|
||||
}
|
||||
|
||||
if (pagevec_count(&pagevec) > 0)
|
||||
fscache_mark_pages_cached(op, &pagevec);
|
||||
|
||||
_leave(" = %d [nr=%u%s]",
|
||||
ret, *nr_pages, list_empty(pages) ? " empty" : "");
|
||||
return ret;
|
||||
|
||||
all_enobufs:
|
||||
fscache_retrieval_complete(op, *nr_pages);
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -806,7 +828,6 @@ int cachefiles_allocate_page(struct fscache_retrieval *op,
|
||||
{
|
||||
struct cachefiles_object *object;
|
||||
struct cachefiles_cache *cache;
|
||||
struct pagevec pagevec;
|
||||
int ret;
|
||||
|
||||
object = container_of(op->op.object,
|
||||
@@ -817,14 +838,12 @@ int cachefiles_allocate_page(struct fscache_retrieval *op,
|
||||
_enter("%p,{%lx},", object, page->index);
|
||||
|
||||
ret = cachefiles_has_space(cache, 0, 1);
|
||||
if (ret == 0) {
|
||||
pagevec_init(&pagevec, 0);
|
||||
pagevec_add(&pagevec, page);
|
||||
fscache_mark_pages_cached(op, &pagevec);
|
||||
} else {
|
||||
if (ret == 0)
|
||||
fscache_mark_page_cached(op, page);
|
||||
else
|
||||
ret = -ENOBUFS;
|
||||
}
|
||||
|
||||
fscache_retrieval_complete(op, 1);
|
||||
_leave(" = %d", ret);
|
||||
return ret;
|
||||
}
|
||||
@@ -874,6 +893,7 @@ int cachefiles_allocate_pages(struct fscache_retrieval *op,
|
||||
ret = -ENOBUFS;
|
||||
}
|
||||
|
||||
fscache_retrieval_complete(op, *nr_pages);
|
||||
_leave(" = %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -174,7 +174,7 @@ int cachefiles_check_object_xattr(struct cachefiles_object *object,
|
||||
ASSERT(dentry);
|
||||
ASSERT(dentry->d_inode);
|
||||
|
||||
auxbuf = kmalloc(sizeof(struct cachefiles_xattr) + 512, GFP_KERNEL);
|
||||
auxbuf = kmalloc(sizeof(struct cachefiles_xattr) + 512, cachefiles_gfp);
|
||||
if (!auxbuf) {
|
||||
_leave(" = -ENOMEM");
|
||||
return -ENOMEM;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user