Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 50d0f78f authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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()
parents b4df268d afae457d
Loading
Loading
Loading
Loading
+29 −8
Original line number Diff line number Diff line
@@ -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 (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");
		clear_bit(AFS_VNODE_CB_PROMISED, &vnode->flags);

			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:
+4 −0
Original line number Diff line number Diff line
@@ -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;

+1 −1
Original line number Diff line number Diff line
@@ -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",
+5 −3
Original line number Diff line number Diff line
@@ -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;
}

/*
+1 −1
Original line number Diff line number Diff line
@@ -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;
}

/**