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

Commit 27ac0ffe authored by J. Bruce Fields's avatar J. Bruce Fields Committed by Al Viro
Browse files

locks: break delegations on any attribute modification



NFSv4 uses leases to guarantee that clients can cache metadata as well
as data.

Cc: Mikulas Patocka <mikulas@artax.karlin.mff.cuni.cz>
Cc: David Howells <dhowells@redhat.com>
Cc: Tyler Hicks <tyhicks@canonical.com>
Cc: Dustin Kirkland <dustin.kirkland@gazzang.com>
Acked-by: default avatarJeff Layton <jlayton@redhat.com>
Signed-off-by: default avatarJ. Bruce Fields <bfields@redhat.com>
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 146a8595
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -216,7 +216,7 @@ static int handle_create(const char *nodename, umode_t mode, kuid_t uid,
		newattrs.ia_gid = gid;
		newattrs.ia_valid = ATTR_MODE|ATTR_UID|ATTR_GID;
		mutex_lock(&dentry->d_inode->i_mutex);
		notify_change(dentry, &newattrs);
		notify_change(dentry, &newattrs, NULL);
		mutex_unlock(&dentry->d_inode->i_mutex);

		/* mark as kernel-created inode */
@@ -322,7 +322,7 @@ static int handle_remove(const char *nodename, struct device *dev)
			newattrs.ia_valid =
				ATTR_UID|ATTR_GID|ATTR_MODE;
			mutex_lock(&dentry->d_inode->i_mutex);
			notify_change(dentry, &newattrs);
			notify_change(dentry, &newattrs, NULL);
			mutex_unlock(&dentry->d_inode->i_mutex);
			err = vfs_unlink(parent.dentry->d_inode, dentry, NULL);
			if (!err || err == -ENOENT)
+24 −1
Original line number Diff line number Diff line
@@ -167,7 +167,27 @@ void setattr_copy(struct inode *inode, const struct iattr *attr)
}
EXPORT_SYMBOL(setattr_copy);

int notify_change(struct dentry * dentry, struct iattr * attr)
/**
 * notify_change - modify attributes of a filesytem object
 * @dentry:	object affected
 * @iattr:	new attributes
 * @delegated_inode: returns inode, if the inode is delegated
 *
 * The caller must hold the i_mutex on the affected object.
 *
 * If notify_change discovers a delegation in need of breaking,
 * it will return -EWOULDBLOCK and return a reference to the inode in
 * delegated_inode.  The caller should then break the delegation and
 * retry.  Because breaking a delegation may take a long time, the
 * caller should drop the i_mutex before doing so.
 *
 * Alternatively, a caller may pass NULL for delegated_inode.  This may
 * be appropriate for callers that expect the underlying filesystem not
 * to be NFS exported.  Also, passing NULL is fine for callers holding
 * the file open for write, as there can be no conflicting delegation in
 * that case.
 */
int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **delegated_inode)
{
	struct inode *inode = dentry->d_inode;
	umode_t mode = inode->i_mode;
@@ -241,6 +261,9 @@ int notify_change(struct dentry * dentry, struct iattr * attr)
		return 0;

	error = security_inode_setattr(dentry, attr);
	if (error)
		return error;
	error = try_break_deleg(inode, delegated_inode);
	if (error)
		return error;

+2 −2
Original line number Diff line number Diff line
@@ -449,14 +449,14 @@ static int cachefiles_attr_changed(struct fscache_object *_object)
		_debug("discard tail %llx", oi_size);
		newattrs.ia_valid = ATTR_SIZE;
		newattrs.ia_size = oi_size & PAGE_MASK;
		ret = notify_change(object->backer, &newattrs);
		ret = notify_change(object->backer, &newattrs, NULL);
		if (ret < 0)
			goto truncate_failed;
	}

	newattrs.ia_valid = ATTR_SIZE;
	newattrs.ia_size = ni_size;
	ret = notify_change(object->backer, &newattrs);
	ret = notify_change(object->backer, &newattrs, NULL);

truncate_failed:
	mutex_unlock(&object->backer->d_inode->i_mutex);
+2 −2
Original line number Diff line number Diff line
@@ -882,7 +882,7 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length)
		struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);

		mutex_lock(&lower_dentry->d_inode->i_mutex);
		rc = notify_change(lower_dentry, &lower_ia);
		rc = notify_change(lower_dentry, &lower_ia, NULL);
		mutex_unlock(&lower_dentry->d_inode->i_mutex);
	}
	return rc;
@@ -983,7 +983,7 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia)
		lower_ia.ia_valid &= ~ATTR_MODE;

	mutex_lock(&lower_dentry->d_inode->i_mutex);
	rc = notify_change(lower_dentry, &lower_ia);
	rc = notify_change(lower_dentry, &lower_ia, NULL);
	mutex_unlock(&lower_dentry->d_inode->i_mutex);
out:
	fsstack_copy_attr_all(inode, lower_inode);
+1 −1
Original line number Diff line number Diff line
@@ -407,7 +407,7 @@ static int hpfs_unlink(struct inode *dir, struct dentry *dentry)
			/*printk("HPFS: truncating file before delete.\n");*/
			newattrs.ia_size = 0;
			newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
			err = notify_change(dentry, &newattrs);
			err = notify_change(dentry, &newattrs, NULL);
			put_write_access(inode);
			if (!err)
				goto again;
Loading