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:
commit
50d0f78f5c
37
fs/afs/dir.c
37
fs/afs/dir.c
|
@ -895,20 +895,38 @@ static int afs_rmdir(struct inode *dir, struct dentry *dentry)
|
|||
* 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:
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue