mirror of
https://github.com/torvalds/linux.git
synced 2026-05-29 17:43:52 +02:00
fuse: add prune notification
Some fuse servers need to prune their caches, which can only be done if the
kernel's own dentry/inode caches are pruned first to avoid dangling
references.
Add FUSE_NOTIFY_PRUNE, which takes an array of node ID's to try and get rid
of. Inodes with active references are skipped.
A similar functionality is already provided by FUSE_NOTIFY_INVAL_ENTRY with
the FUSE_EXPIRE_ONLY flag. Differences in the interface are
FUSE_NOTIFY_INVAL_ENTRY:
- can only prune one dentry
- dentry is determined by parent ID and name
- if inode has multiple aliases (cached hard links), then they would have
to be invalidated individually to be able to get rid of the inode
FUSE_NOTIFY_PRUNE:
- can prune multiple inodes
- inodes determined by their node ID
- aliases are taken care of automatically
Reviewed-by: Joanne Koong <joannelkoong@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
This commit is contained in:
parent
60e1579a0d
commit
3f29d59e92
|
|
@ -2034,6 +2034,42 @@ static int fuse_notify_inc_epoch(struct fuse_conn *fc)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int fuse_notify_prune(struct fuse_conn *fc, unsigned int size,
|
||||
struct fuse_copy_state *cs)
|
||||
{
|
||||
struct fuse_notify_prune_out outarg;
|
||||
const unsigned int batch = 512;
|
||||
u64 *nodeids __free(kfree) = kmalloc(sizeof(u64) * batch, GFP_KERNEL);
|
||||
unsigned int num, i;
|
||||
int err;
|
||||
|
||||
if (!nodeids)
|
||||
return -ENOMEM;
|
||||
|
||||
if (size < sizeof(outarg))
|
||||
return -EINVAL;
|
||||
|
||||
err = fuse_copy_one(cs, &outarg, sizeof(outarg));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (size - sizeof(outarg) != outarg.count * sizeof(u64))
|
||||
return -EINVAL;
|
||||
|
||||
for (; outarg.count; outarg.count -= num) {
|
||||
num = min(batch, outarg.count);
|
||||
err = fuse_copy_one(cs, nodeids, num * sizeof(u64));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
scoped_guard(rwsem_read, &fc->killsb) {
|
||||
for (i = 0; i < num; i++)
|
||||
fuse_try_prune_one_inode(fc, nodeids[i]);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code,
|
||||
unsigned int size, struct fuse_copy_state *cs)
|
||||
{
|
||||
|
|
@ -2065,6 +2101,9 @@ static int fuse_notify(struct fuse_conn *fc, enum fuse_notify_code code,
|
|||
case FUSE_NOTIFY_INC_EPOCH:
|
||||
return fuse_notify_inc_epoch(fc);
|
||||
|
||||
case FUSE_NOTIFY_PRUNE:
|
||||
return fuse_notify_prune(fc, size, cs);
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1413,6 +1413,12 @@ int fuse_reverse_inval_inode(struct fuse_conn *fc, u64 nodeid,
|
|||
int fuse_reverse_inval_entry(struct fuse_conn *fc, u64 parent_nodeid,
|
||||
u64 child_nodeid, struct qstr *name, u32 flags);
|
||||
|
||||
/*
|
||||
* Try to prune this inode. If neither the inode itself nor dentries associated
|
||||
* with this inode have any external reference, then the inode can be freed.
|
||||
*/
|
||||
void fuse_try_prune_one_inode(struct fuse_conn *fc, u64 nodeid);
|
||||
|
||||
int fuse_do_open(struct fuse_mount *fm, u64 nodeid, struct file *file,
|
||||
bool isdir);
|
||||
|
||||
|
|
|
|||
|
|
@ -585,6 +585,17 @@ int fuse_reverse_inval_inode(struct fuse_conn *fc, u64 nodeid,
|
|||
return 0;
|
||||
}
|
||||
|
||||
void fuse_try_prune_one_inode(struct fuse_conn *fc, u64 nodeid)
|
||||
{
|
||||
struct inode *inode;
|
||||
|
||||
inode = fuse_ilookup(fc, nodeid, NULL);
|
||||
if (!inode)
|
||||
return;
|
||||
d_prune_aliases(inode);
|
||||
iput(inode);
|
||||
}
|
||||
|
||||
bool fuse_lock_inode(struct inode *inode)
|
||||
{
|
||||
bool locked = false;
|
||||
|
|
|
|||
|
|
@ -239,6 +239,7 @@
|
|||
* 7.45
|
||||
* - add FUSE_COPY_FILE_RANGE_64
|
||||
* - add struct fuse_copy_file_range_out
|
||||
* - add FUSE_NOTIFY_PRUNE
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_FUSE_H
|
||||
|
|
@ -680,6 +681,7 @@ enum fuse_notify_code {
|
|||
FUSE_NOTIFY_DELETE = 6,
|
||||
FUSE_NOTIFY_RESEND = 7,
|
||||
FUSE_NOTIFY_INC_EPOCH = 8,
|
||||
FUSE_NOTIFY_PRUNE = 9,
|
||||
};
|
||||
|
||||
/* The read buffer is required to be at least 8k, but may be much larger */
|
||||
|
|
@ -1118,6 +1120,12 @@ struct fuse_notify_retrieve_in {
|
|||
uint64_t dummy4;
|
||||
};
|
||||
|
||||
struct fuse_notify_prune_out {
|
||||
uint32_t count;
|
||||
uint32_t padding;
|
||||
uint64_t spare;
|
||||
};
|
||||
|
||||
struct fuse_backing_map {
|
||||
int32_t fd;
|
||||
uint32_t flags;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user