@@ -28,6 +28,8 @@ module_param(allow_sys_admin_access, bool, 0644);
2828MODULE_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+
3133static 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
0 commit comments