Commit 4f8d3702 authored by Miklos Szeredi's avatar Miklos Szeredi
Browse files

fuse: add "expire only" mode to FUSE_NOTIFY_INVAL_ENTRY



Add a flag to entry expiration that lets the filesystem expire a dentry
without kicking it out from the cache immediately.

This makes a difference for overmounted dentries, where plain invalidation
would detach all submounts before dropping the dentry from the cache.  If
only expiry is set on the dentry, then any overmounts are left alone and
until ->d_revalidate() is called.

Note: ->d_revalidate() is not called for the case of following a submount,
so invalidation will only be triggered for the non-overmounted case.  The
dentry could also be mounted in a different mount instance, in which case
any submounts will still be detached.

Suggested-by: default avatarJakob Blomer <jblomer@cern.ch>
Signed-off-by: default avatarMiklos Szeredi <mszeredi@redhat.com>
parent a1db2f7e
Loading
Loading
Loading
Loading
+2 −2
Original line number Original line Diff line number Diff line
@@ -1498,7 +1498,7 @@ static int fuse_notify_inval_entry(struct fuse_conn *fc, unsigned int size,
	buf[outarg.namelen] = 0;
	buf[outarg.namelen] = 0;


	down_read(&fc->killsb);
	down_read(&fc->killsb);
	err = fuse_reverse_inval_entry(fc, outarg.parent, 0, &name);
	err = fuse_reverse_inval_entry(fc, outarg.parent, 0, &name, outarg.flags);
	up_read(&fc->killsb);
	up_read(&fc->killsb);
	kfree(buf);
	kfree(buf);
	return err;
	return err;
@@ -1546,7 +1546,7 @@ static int fuse_notify_delete(struct fuse_conn *fc, unsigned int size,
	buf[outarg.namelen] = 0;
	buf[outarg.namelen] = 0;


	down_read(&fc->killsb);
	down_read(&fc->killsb);
	err = fuse_reverse_inval_entry(fc, outarg.parent, outarg.child, &name);
	err = fuse_reverse_inval_entry(fc, outarg.parent, outarg.child, &name, 0);
	up_read(&fc->killsb);
	up_read(&fc->killsb);
	kfree(buf);
	kfree(buf);
	return err;
	return err;
+4 −2
Original line number Original line Diff line number Diff line
@@ -1170,7 +1170,7 @@ int fuse_update_attributes(struct inode *inode, struct file *file, u32 mask)
}
}


int fuse_reverse_inval_entry(struct fuse_conn *fc, u64 parent_nodeid,
int fuse_reverse_inval_entry(struct fuse_conn *fc, u64 parent_nodeid,
			     u64 child_nodeid, struct qstr *name)
			     u64 child_nodeid, struct qstr *name, u32 flags)
{
{
	int err = -ENOTDIR;
	int err = -ENOTDIR;
	struct inode *parent;
	struct inode *parent;
@@ -1197,7 +1197,9 @@ int fuse_reverse_inval_entry(struct fuse_conn *fc, u64 parent_nodeid,
		goto unlock;
		goto unlock;


	fuse_dir_changed(parent);
	fuse_dir_changed(parent);
	fuse_invalidate_entry(entry);
	if (!(flags & FUSE_EXPIRE_ONLY))
		d_invalidate(entry);
	fuse_invalidate_entry_cache(entry);


	if (child_nodeid != 0 && d_really_is_positive(entry)) {
	if (child_nodeid != 0 && d_really_is_positive(entry)) {
		inode_lock(d_inode(entry));
		inode_lock(d_inode(entry));
+1 −1
Original line number Original line Diff line number Diff line
@@ -1220,7 +1220,7 @@ int fuse_reverse_inval_inode(struct fuse_conn *fc, u64 nodeid,
 * then the dentry is unhashed (d_delete()).
 * then the dentry is unhashed (d_delete()).
 */
 */
int fuse_reverse_inval_entry(struct fuse_conn *fc, u64 parent_nodeid,
int fuse_reverse_inval_entry(struct fuse_conn *fc, u64 parent_nodeid,
			     u64 child_nodeid, struct qstr *name);
			     u64 child_nodeid, struct qstr *name, u32 flags);


int fuse_do_open(struct fuse_mount *fm, u64 nodeid, struct file *file,
int fuse_do_open(struct fuse_mount *fm, u64 nodeid, struct file *file,
		 bool isdir);
		 bool isdir);
+11 −2
Original line number Original line Diff line number Diff line
@@ -197,6 +197,9 @@
 *
 *
 *  7.37
 *  7.37
 *  - add FUSE_TMPFILE
 *  - add FUSE_TMPFILE
 *
 *  7.38
 *  - add FUSE_EXPIRE_ONLY flag to fuse_notify_inval_entry
 */
 */


#ifndef _LINUX_FUSE_H
#ifndef _LINUX_FUSE_H
@@ -232,7 +235,7 @@
#define FUSE_KERNEL_VERSION 7
#define FUSE_KERNEL_VERSION 7


/** Minor version number of this interface */
/** Minor version number of this interface */
#define FUSE_KERNEL_MINOR_VERSION 37
#define FUSE_KERNEL_MINOR_VERSION 38


/** The node ID of the root inode */
/** The node ID of the root inode */
#define FUSE_ROOT_ID 1
#define FUSE_ROOT_ID 1
@@ -491,6 +494,12 @@ struct fuse_file_lock {
 */
 */
#define FUSE_SETXATTR_ACL_KILL_SGID	(1 << 0)
#define FUSE_SETXATTR_ACL_KILL_SGID	(1 << 0)


/**
 * notify_inval_entry flags
 * FUSE_EXPIRE_ONLY
 */
#define FUSE_EXPIRE_ONLY		(1 << 0)

enum fuse_opcode {
enum fuse_opcode {
	FUSE_LOOKUP		= 1,
	FUSE_LOOKUP		= 1,
	FUSE_FORGET		= 2,  /* no reply */
	FUSE_FORGET		= 2,  /* no reply */
@@ -919,7 +928,7 @@ struct fuse_notify_inval_inode_out {
struct fuse_notify_inval_entry_out {
struct fuse_notify_inval_entry_out {
	uint64_t	parent;
	uint64_t	parent;
	uint32_t	namelen;
	uint32_t	namelen;
	uint32_t	padding;
	uint32_t	flags;
};
};


struct fuse_notify_delete_out {
struct fuse_notify_delete_out {