Merge branch 'afs-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs

Pull afs/fscache fixes from David Howells:

 - Fix the default return of fscache_maybe_release_page() when a cache
   isn't in use - it prevents a filesystem from releasing pages. This
   can cause a system to OOM.

 - Fix a potential uninitialised variable in AFS.

 - Fix AFS unlink's handling of the nlink count. It needs to use the
   nlink manipulation functions so that inode structs of deleted inodes
   actually get scheduled for destruction.

 - Fix error handling in afs_write_end() so that the page gets unlocked
   and put if we can't fill the unwritten portion.

* 'afs-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs:
  afs: Fix missing error handling in afs_write_end()
  afs: Fix unlink
  afs: Potential uninitialized variable in afs_extract_data()
  fscache: Fix the default for fscache_maybe_release_page()
This commit is contained in:
Linus Torvalds 2018-01-03 10:58:56 -08:00
commit 50d0f78f5c
5 changed files with 40 additions and 13 deletions

View File

@ -895,20 +895,38 @@ error:
* However, if we didn't have a callback promise outstanding, or it was
* outstanding on a different server, then it won't break it either...
*/
static int afs_dir_remove_link(struct dentry *dentry, struct key *key)
static int afs_dir_remove_link(struct dentry *dentry, struct key *key,
unsigned long d_version_before,
unsigned long d_version_after)
{
bool dir_valid;
int ret = 0;
/* There were no intervening changes on the server if the version
* number we got back was incremented by exactly 1.
*/
dir_valid = (d_version_after == d_version_before + 1);
if (d_really_is_positive(dentry)) {
struct afs_vnode *vnode = AFS_FS_I(d_inode(dentry));
if (test_bit(AFS_VNODE_DELETED, &vnode->flags))
kdebug("AFS_VNODE_DELETED");
clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags);
ret = afs_validate(vnode, key);
if (ret == -ESTALE)
if (dir_valid) {
drop_nlink(&vnode->vfs_inode);
if (vnode->vfs_inode.i_nlink == 0) {
set_bit(AFS_VNODE_DELETED, &vnode->flags);
clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags);
}
ret = 0;
} else {
clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags);
if (test_bit(AFS_VNODE_DELETED, &vnode->flags))
kdebug("AFS_VNODE_DELETED");
ret = afs_validate(vnode, key);
if (ret == -ESTALE)
ret = 0;
}
_debug("nlink %d [val %d]", vnode->vfs_inode.i_nlink, ret);
}
@ -923,6 +941,7 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry)
struct afs_fs_cursor fc;
struct afs_vnode *dvnode = AFS_FS_I(dir), *vnode;
struct key *key;
unsigned long d_version = (unsigned long)dentry->d_fsdata;
int ret;
_enter("{%x:%u},{%pd}",
@ -955,7 +974,9 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry)
afs_vnode_commit_status(&fc, dvnode, fc.cb_break);
ret = afs_end_vnode_operation(&fc);
if (ret == 0)
ret = afs_dir_remove_link(dentry, key);
ret = afs_dir_remove_link(
dentry, key, d_version,
(unsigned long)dvnode->status.data_version);
}
error_key:

View File

@ -377,6 +377,10 @@ int afs_validate(struct afs_vnode *vnode, struct key *key)
}
read_sequnlock_excl(&vnode->cb_lock);
if (test_bit(AFS_VNODE_DELETED, &vnode->flags))
clear_nlink(&vnode->vfs_inode);
if (valid)
goto valid;

View File

@ -885,7 +885,7 @@ int afs_extract_data(struct afs_call *call, void *buf, size_t count,
{
struct afs_net *net = call->net;
enum afs_call_state state;
u32 remote_abort;
u32 remote_abort = 0;
int ret;
_enter("{%s,%zu},,%zu,%d",

View File

@ -198,7 +198,7 @@ int afs_write_end(struct file *file, struct address_space *mapping,
ret = afs_fill_page(vnode, key, pos + copied,
len - copied, page);
if (ret < 0)
return ret;
goto out;
}
SetPageUptodate(page);
}
@ -206,10 +206,12 @@ int afs_write_end(struct file *file, struct address_space *mapping,
set_page_dirty(page);
if (PageDirty(page))
_debug("dirtied");
ret = copied;
out:
unlock_page(page);
put_page(page);
return copied;
return ret;
}
/*

View File

@ -755,7 +755,7 @@ bool fscache_maybe_release_page(struct fscache_cookie *cookie,
{
if (fscache_cookie_valid(cookie) && PageFsCache(page))
return __fscache_maybe_release_page(cookie, page, gfp);
return false;
return true;
}
/**