Skip to content

Commit e10fd80

Browse files
committed
fuse: add lookupx support
This is an extended version of lookup that supports additional flags and returns attributes with valid masks via fuse_reply_lookupx.
1 parent 09ed47b commit e10fd80

4 files changed

Lines changed: 128 additions & 14 deletions

File tree

fs/fuse/dir.c

Lines changed: 106 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ module_param(allow_sys_admin_access, bool, 0644);
2828
MODULE_PARM_DESC(allow_sys_admin_access,
2929
"Allow users with CAP_SYS_ADMIN in initial userns to bypass allow_other access check");
3030

31+
static void fuse_attr_to_statx(struct fuse_attr *attr, struct fuse_statx *sx, uint32_t mask);
32+
3133
static void fuse_advise_use_readdirplus(struct inode *dir)
3234
{
3335
struct fuse_inode *fi = get_fuse_inode(dir);
@@ -185,6 +187,72 @@ static void fuse_lookup_init(struct fuse_conn *fc, struct fuse_args *args,
185187
args->out_args[0].value = outarg;
186188
}
187189

190+
/**
191+
* fuse_do_lookupx - Perform a FUSE_LOOKUPX operation
192+
*
193+
* @ext_out: extended output argument structure
194+
* @lookup_flags: lookup flags (e.g., FUSE_LOOKUPX_REVALIDATE)
195+
*/
196+
static int fuse_do_lookupx(struct fuse_mount *fm, u64 nodeid,
197+
const struct qstr *name,
198+
struct fuse_lookupx_out *ext_out,
199+
uint32_t lookup_flags)
200+
{
201+
struct fuse_conn *fc = fm->fc;
202+
FUSE_ARGS(args);
203+
struct fuse_lookupx_in inarg;
204+
int err;
205+
206+
memset(ext_out, 0, sizeof(*ext_out));
207+
args.nodeid = nodeid;
208+
209+
if (!fc->lookupx)
210+
goto fallback;
211+
212+
args.opcode = FUSE_LOOKUPX;
213+
memset(&inarg, 0, sizeof(inarg));
214+
inarg.lookup_flags = lookup_flags;
215+
216+
args.in_numargs = 3;
217+
args.in_args[0].size = sizeof(inarg);
218+
args.in_args[0].value = &inarg;
219+
args.in_args[1].size = 0;
220+
args.in_args[1].value = NULL;
221+
args.in_args[2].size = name->len + 1;
222+
args.in_args[2].value = name->name;
223+
args.out_numargs = 1;
224+
args.out_args[0].size = sizeof(struct fuse_lookupx_out);
225+
args.out_args[0].value = ext_out;
226+
227+
err = fuse_simple_request(fm, &args);
228+
if (err) {
229+
if (err == -ENOSYS) {
230+
fc->lookupx = 0;
231+
goto fallback;
232+
}
233+
return err;
234+
}
235+
236+
return 0;
237+
238+
fallback:
239+
args.opcode = FUSE_LOOKUP;
240+
args.in_numargs = 2;
241+
fuse_set_zero_arg0(&args);
242+
args.in_args[1].size = name->len + 1;
243+
args.in_args[1].value = name->name;
244+
args.out_numargs = 1;
245+
args.out_args[0].size = sizeof(struct fuse_entry_out);
246+
args.out_args[0].value = &ext_out->entry;
247+
248+
err = fuse_simple_request(fm, &args);
249+
if (err)
250+
return err;
251+
252+
ext_out->mask = STATX_BASIC_STATS;
253+
return 0;
254+
}
255+
188256
/*
189257
* Check whether the dentry is still valid
190258
*
@@ -207,8 +275,8 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
207275
goto invalid;
208276
else if (time_before64(fuse_dentry_time(entry), get_jiffies_64()) ||
209277
(flags & (LOOKUP_EXCL | LOOKUP_REVAL | LOOKUP_RENAME_TARGET))) {
210-
struct fuse_entry_out outarg;
211-
FUSE_ARGS(args);
278+
struct fuse_lookupx_out ext_out;
279+
struct fuse_statx sx;
212280
struct fuse_forget_link *forget;
213281
u64 attr_version;
214282

@@ -230,19 +298,19 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
230298
attr_version = fuse_get_attr_version(fm->fc);
231299

232300
parent = dget_parent(entry);
233-
fuse_lookup_init(fm->fc, &args, get_node_id(d_inode(parent)),
234-
&entry->d_name, &outarg);
235-
ret = fuse_simple_request(fm, &args);
301+
ret = fuse_do_lookupx(fm, get_node_id(d_inode(parent)),
302+
&entry->d_name, &ext_out,
303+
FUSE_LOOKUPX_REVALIDATE);
236304
dput(parent);
237305
/* Zero nodeid is same as -ENOENT */
238-
if (!ret && !outarg.nodeid)
306+
if (!ret && !ext_out.entry.nodeid)
239307
ret = -ENOENT;
240308
if (!ret) {
241309
fi = get_fuse_inode(inode);
242-
if (outarg.nodeid != get_node_id(inode) ||
243-
(bool) IS_AUTOMOUNT(inode) != (bool) (outarg.attr.flags & FUSE_ATTR_SUBMOUNT)) {
310+
if (ext_out.entry.nodeid != get_node_id(inode) ||
311+
(bool) IS_AUTOMOUNT(inode) != (bool) (ext_out.entry.attr.flags & FUSE_ATTR_SUBMOUNT)) {
244312
fuse_queue_forget(fm->fc, forget,
245-
outarg.nodeid, 1);
313+
ext_out.entry.nodeid, 1);
246314
goto invalid;
247315
}
248316
spin_lock(&fi->lock);
@@ -252,15 +320,17 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
252320
kfree(forget);
253321
if (ret == -ENOMEM || ret == -EINTR)
254322
goto out;
255-
if (ret || fuse_invalid_attr(&outarg.attr) ||
256-
fuse_stale_inode(inode, outarg.generation, &outarg.attr))
323+
if (ret || fuse_invalid_attr(&ext_out.entry.attr) ||
324+
fuse_stale_inode(inode, ext_out.entry.generation, &ext_out.entry.attr))
257325
goto invalid;
258326

259327
forget_all_cached_acls(inode);
260-
fuse_change_attributes(inode, &outarg.attr, NULL,
261-
ATTR_TIMEOUT(&outarg),
328+
fuse_attr_to_statx(&ext_out.entry.attr, &sx, ext_out.mask);
329+
fuse_change_attributes(inode, &ext_out.entry.attr, &sx,
330+
ATTR_TIMEOUT(&ext_out.entry),
262331
attr_version);
263-
fuse_change_entry_timeout(entry, &outarg);
332+
if ((ext_out.mask & STATX_BASIC_STATS) == STATX_BASIC_STATS)
333+
fuse_change_entry_timeout(entry, &ext_out.entry);
264334
} else if (inode) {
265335
fi = get_fuse_inode(inode);
266336
if (flags & LOOKUP_RCU) {
@@ -1183,6 +1253,28 @@ static void fuse_statx_to_attr(struct fuse_statx *sx, struct fuse_attr *attr)
11831253
attr->blksize = sx->blksize;
11841254
}
11851255

1256+
static void fuse_attr_to_statx(struct fuse_attr *attr, struct fuse_statx *sx, uint32_t mask)
1257+
{
1258+
memset(sx, 0, sizeof(*sx));
1259+
sx->mask = mask;
1260+
sx->ino = attr->ino;
1261+
sx->size = attr->size;
1262+
sx->blocks = attr->blocks;
1263+
sx->atime.tv_sec = attr->atime;
1264+
sx->mtime.tv_sec = attr->mtime;
1265+
sx->ctime.tv_sec = attr->ctime;
1266+
sx->atime.tv_nsec = attr->atimensec;
1267+
sx->mtime.tv_nsec = attr->mtimensec;
1268+
sx->ctime.tv_nsec = attr->ctimensec;
1269+
sx->mode = attr->mode;
1270+
sx->nlink = attr->nlink;
1271+
sx->uid = attr->uid;
1272+
sx->gid = attr->gid;
1273+
sx->rdev_major = MAJOR(attr->rdev);
1274+
sx->rdev_minor = MINOR(attr->rdev);
1275+
sx->blksize = attr->blksize;
1276+
}
1277+
11861278
/*
11871279
* @param sx_mask request mask send to to fuse-server
11881280
* @param mandatory_sx_mask subset of (or complete) sx_mask that the server

fs/fuse/fuse_i.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -864,6 +864,9 @@ struct fuse_conn {
864864
/* do we have support for dlm in the fs? */
865865
unsigned int dlm:1;
866866

867+
/* Is extended lookup implemented by fs? */
868+
unsigned int lookupx:1;
869+
867870
/* Is synchronous FUSE_INIT allowed? */
868871
unsigned int sync_init:1;
869872

fs/fuse/inode.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1184,6 +1184,7 @@ void fuse_conn_init(struct fuse_conn *fc, struct fuse_mount *fm,
11841184
fc->initialized = 0;
11851185
fc->connected = 1;
11861186
fc->dlm = 1;
1187+
fc->lookupx = 1;
11871188

11881189
/* module option for now */
11891190
fc->compound_open_getattr = enable_compound;

include/uapi/linux/fuse.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,12 @@ struct fuse_file_lock {
575575
*/
576576
#define FUSE_OPEN_KILL_SUIDGID (1 << 0)
577577

578+
/**
579+
* Lookup flags
580+
* FUSE_LOOKUPX_REVALIDATE: lookup called from revalidate
581+
*/
582+
#define FUSE_LOOKUPX_REVALIDATE (1 << 0)
583+
578584
/**
579585
* setxattr flags
580586
* FUSE_SETXATTR_ACL_KILL_SGID: Clear SGID when system.posix_acl_access is set
@@ -660,6 +666,9 @@ enum fuse_opcode {
660666
*/
661667
FUSE_COMPOUND = 101,
662668

669+
/* Extented lookup operation */
670+
FUSE_LOOKUPX = 102,
671+
663672
/* CUSE specific operations */
664673
CUSE_INIT = 4096,
665674

@@ -694,6 +703,15 @@ struct fuse_entry_out {
694703
struct fuse_attr attr;
695704
};
696705

706+
struct fuse_lookupx_in {
707+
uint32_t lookup_flags;
708+
};
709+
710+
struct fuse_lookupx_out {
711+
struct fuse_entry_out entry;
712+
uint32_t mask; /* Mask of valid attributes in statx format */
713+
};
714+
697715
struct fuse_forget_in {
698716
uint64_t nlookup;
699717
};

0 commit comments

Comments
 (0)