@@ -92,7 +92,7 @@ static void fuse_dentry_settime(struct dentry *dentry, u64 time)
9292/*
9393 * Calculate the time in jiffies until a dentry/attributes are valid
9494 */
95- static u64 time_to_jiffies (u64 sec , u32 nsec )
95+ u64 fuse_time_to_jiffies (u64 sec , u32 nsec )
9696{
9797 if (sec || nsec ) {
9898 struct timespec64 ts = {
@@ -112,17 +112,7 @@ static u64 time_to_jiffies(u64 sec, u32 nsec)
112112void fuse_change_entry_timeout (struct dentry * entry , struct fuse_entry_out * o )
113113{
114114 fuse_dentry_settime (entry ,
115- time_to_jiffies (o -> entry_valid , o -> entry_valid_nsec ));
116- }
117-
118- static u64 attr_timeout (struct fuse_attr_out * o )
119- {
120- return time_to_jiffies (o -> attr_valid , o -> attr_valid_nsec );
121- }
122-
123- u64 entry_attr_timeout (struct fuse_entry_out * o )
124- {
125- return time_to_jiffies (o -> attr_valid , o -> attr_valid_nsec );
115+ fuse_time_to_jiffies (o -> entry_valid , o -> entry_valid_nsec ));
126116}
127117
128118void fuse_invalidate_attr_mask (struct inode * inode , u32 mask )
@@ -265,8 +255,8 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
265255 goto invalid ;
266256
267257 forget_all_cached_acls (inode );
268- fuse_change_attributes (inode , & outarg .attr ,
269- entry_attr_timeout (& outarg ),
258+ fuse_change_attributes (inode , & outarg .attr , NULL ,
259+ ATTR_TIMEOUT (& outarg ),
270260 attr_version );
271261 fuse_change_entry_timeout (entry , & outarg );
272262 } else if (inode ) {
@@ -360,10 +350,14 @@ int fuse_valid_type(int m)
360350 S_ISBLK (m ) || S_ISFIFO (m ) || S_ISSOCK (m );
361351}
362352
353+ static bool fuse_valid_size (u64 size )
354+ {
355+ return size <= LLONG_MAX ;
356+ }
357+
363358bool fuse_invalid_attr (struct fuse_attr * attr )
364359{
365- return !fuse_valid_type (attr -> mode ) ||
366- attr -> size > LLONG_MAX ;
360+ return !fuse_valid_type (attr -> mode ) || !fuse_valid_size (attr -> size );
367361}
368362
369363int fuse_lookup_name (struct super_block * sb , u64 nodeid , const struct qstr * name ,
@@ -399,7 +393,7 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, const struct qstr *name
399393 goto out_put_forget ;
400394
401395 * inode = fuse_iget (sb , outarg -> nodeid , outarg -> generation ,
402- & outarg -> attr , entry_attr_timeout (outarg ),
396+ & outarg -> attr , ATTR_TIMEOUT (outarg ),
403397 attr_version );
404398 err = - ENOMEM ;
405399 if (!* inode ) {
@@ -686,7 +680,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry,
686680 ff -> nodeid = outentry .nodeid ;
687681 ff -> open_flags = outopen .open_flags ;
688682 inode = fuse_iget (dir -> i_sb , outentry .nodeid , outentry .generation ,
689- & outentry .attr , entry_attr_timeout (& outentry ), 0 );
683+ & outentry .attr , ATTR_TIMEOUT (& outentry ), 0 );
690684 if (!inode ) {
691685 flags &= ~(O_CREAT | O_EXCL | O_TRUNC );
692686 fuse_sync_release (NULL , ff , flags );
@@ -755,7 +749,8 @@ static int fuse_atomic_open(struct inode *dir, struct dentry *entry,
755749 if (err == - ENOSYS ) {
756750 fc -> no_create = 1 ;
757751 goto mknod ;
758- }
752+ } else if (err == - EEXIST )
753+ fuse_invalidate_entry (entry );
759754out_dput :
760755 dput (res );
761756 return err ;
@@ -813,7 +808,7 @@ static int create_new_entry(struct fuse_mount *fm, struct fuse_args *args,
813808 goto out_put_forget_req ;
814809
815810 inode = fuse_iget (dir -> i_sb , outarg .nodeid , outarg .generation ,
816- & outarg .attr , entry_attr_timeout (& outarg ), 0 );
811+ & outarg .attr , ATTR_TIMEOUT (& outarg ), 0 );
817812 if (!inode ) {
818813 fuse_queue_forget (fm -> fc , forget , outarg .nodeid , 1 );
819814 return - ENOMEM ;
@@ -835,6 +830,8 @@ static int create_new_entry(struct fuse_mount *fm, struct fuse_args *args,
835830 return 0 ;
836831
837832 out_put_forget_req :
833+ if (err == - EEXIST )
834+ fuse_invalidate_entry (entry );
838835 kfree (forget );
839836 return err ;
840837}
@@ -986,7 +983,7 @@ static int fuse_unlink(struct inode *dir, struct dentry *entry)
986983 if (!err ) {
987984 fuse_dir_changed (dir );
988985 fuse_entry_unlinked (entry );
989- } else if (err == - EINTR )
986+ } else if (err == - EINTR || err == - ENOENT )
990987 fuse_invalidate_entry (entry );
991988 return err ;
992989}
@@ -1009,7 +1006,7 @@ static int fuse_rmdir(struct inode *dir, struct dentry *entry)
10091006 if (!err ) {
10101007 fuse_dir_changed (dir );
10111008 fuse_entry_unlinked (entry );
1012- } else if (err == - EINTR )
1009+ } else if (err == - EINTR || err == - ENOENT )
10131010 fuse_invalidate_entry (entry );
10141011 return err ;
10151012}
@@ -1050,7 +1047,7 @@ static int fuse_rename_common(struct inode *olddir, struct dentry *oldent,
10501047 /* newent will end up negative */
10511048 if (!(flags & RENAME_EXCHANGE ) && d_really_is_positive (newent ))
10521049 fuse_entry_unlinked (newent );
1053- } else if (err == - EINTR ) {
1050+ } else if (err == - EINTR || err == - ENOENT ) {
10541051 /* If request was interrupted, DEITY only knows if the
10551052 rename actually took place. If the invalidation
10561053 fails (e.g. some process has CWD under the renamed
@@ -1153,6 +1150,87 @@ static void fuse_fillattr(struct inode *inode, struct fuse_attr *attr,
11531150 stat -> blksize = 1 << blkbits ;
11541151}
11551152
1153+ static void fuse_statx_to_attr (struct fuse_statx * sx , struct fuse_attr * attr )
1154+ {
1155+ memset (attr , 0 , sizeof (* attr ));
1156+ attr -> ino = sx -> ino ;
1157+ attr -> size = sx -> size ;
1158+ attr -> blocks = sx -> blocks ;
1159+ attr -> atime = sx -> atime .tv_sec ;
1160+ attr -> mtime = sx -> mtime .tv_sec ;
1161+ attr -> ctime = sx -> ctime .tv_sec ;
1162+ attr -> atimensec = sx -> atime .tv_nsec ;
1163+ attr -> mtimensec = sx -> mtime .tv_nsec ;
1164+ attr -> ctimensec = sx -> ctime .tv_nsec ;
1165+ attr -> mode = sx -> mode ;
1166+ attr -> nlink = sx -> nlink ;
1167+ attr -> uid = sx -> uid ;
1168+ attr -> gid = sx -> gid ;
1169+ attr -> rdev = new_encode_dev (MKDEV (sx -> rdev_major , sx -> rdev_minor ));
1170+ attr -> blksize = sx -> blksize ;
1171+ }
1172+
1173+ static int fuse_do_statx (struct inode * inode , struct file * file ,
1174+ struct kstat * stat )
1175+ {
1176+ int err ;
1177+ struct fuse_attr attr ;
1178+ struct fuse_statx * sx ;
1179+ struct fuse_statx_in inarg ;
1180+ struct fuse_statx_out outarg ;
1181+ struct fuse_mount * fm = get_fuse_mount (inode );
1182+ u64 attr_version = fuse_get_attr_version (fm -> fc );
1183+ FUSE_ARGS (args );
1184+
1185+ memset (& inarg , 0 , sizeof (inarg ));
1186+ memset (& outarg , 0 , sizeof (outarg ));
1187+ /* Directories have separate file-handle space */
1188+ if (file && S_ISREG (inode -> i_mode )) {
1189+ struct fuse_file * ff = file -> private_data ;
1190+
1191+ inarg .getattr_flags |= FUSE_GETATTR_FH ;
1192+ inarg .fh = ff -> fh ;
1193+ }
1194+ /* For now leave sync hints as the default, request all stats. */
1195+ inarg .sx_flags = 0 ;
1196+ inarg .sx_mask = STATX_BASIC_STATS | STATX_BTIME ;
1197+ args .opcode = FUSE_STATX ;
1198+ args .nodeid = get_node_id (inode );
1199+ args .in_numargs = 1 ;
1200+ args .in_args [0 ].size = sizeof (inarg );
1201+ args .in_args [0 ].value = & inarg ;
1202+ args .out_numargs = 1 ;
1203+ args .out_args [0 ].size = sizeof (outarg );
1204+ args .out_args [0 ].value = & outarg ;
1205+ err = fuse_simple_request (fm , & args );
1206+ if (err )
1207+ return err ;
1208+
1209+ sx = & outarg .stat ;
1210+ if (((sx -> mask & STATX_SIZE ) && !fuse_valid_size (sx -> size )) ||
1211+ ((sx -> mask & STATX_TYPE ) && (!fuse_valid_type (sx -> mode ) ||
1212+ inode_wrong_type (inode , sx -> mode )))) {
1213+ make_bad_inode (inode );
1214+ return - EIO ;
1215+ }
1216+
1217+ fuse_statx_to_attr (& outarg .stat , & attr );
1218+ if ((sx -> mask & STATX_BASIC_STATS ) == STATX_BASIC_STATS ) {
1219+ fuse_change_attributes (inode , & attr , & outarg .stat ,
1220+ ATTR_TIMEOUT (& outarg ), attr_version );
1221+ }
1222+
1223+ if (stat ) {
1224+ stat -> result_mask = sx -> mask & (STATX_BASIC_STATS | STATX_BTIME );
1225+ stat -> btime .tv_sec = sx -> btime .tv_sec ;
1226+ stat -> btime .tv_nsec = min_t (u32 , sx -> btime .tv_nsec , NSEC_PER_SEC - 1 );
1227+ fuse_fillattr (inode , & attr , stat );
1228+ stat -> result_mask |= STATX_TYPE ;
1229+ }
1230+
1231+ return 0 ;
1232+ }
1233+
11561234static int fuse_do_getattr (struct inode * inode , struct kstat * stat ,
11571235 struct file * file )
11581236{
@@ -1189,8 +1267,8 @@ static int fuse_do_getattr(struct inode *inode, struct kstat *stat,
11891267 fuse_make_bad (inode );
11901268 err = - EIO ;
11911269 } else {
1192- fuse_change_attributes (inode , & outarg .attr ,
1193- attr_timeout (& outarg ),
1270+ fuse_change_attributes (inode , & outarg .attr , NULL ,
1271+ ATTR_TIMEOUT (& outarg ),
11941272 attr_version );
11951273 if (stat )
11961274 fuse_fillattr (inode , & outarg .attr , stat );
@@ -1204,12 +1282,22 @@ static int fuse_update_get_attr(struct inode *inode, struct file *file,
12041282 unsigned int flags )
12051283{
12061284 struct fuse_inode * fi = get_fuse_inode (inode );
1285+ struct fuse_conn * fc = get_fuse_conn (inode );
12071286 int err = 0 ;
12081287 bool sync ;
12091288 u32 inval_mask = READ_ONCE (fi -> inval_mask );
12101289 u32 cache_mask = fuse_get_cache_mask (inode );
12111290
1212- if (flags & AT_STATX_FORCE_SYNC )
1291+
1292+ /* FUSE only supports basic stats and possibly btime */
1293+ request_mask &= STATX_BASIC_STATS | STATX_BTIME ;
1294+ retry :
1295+ if (fc -> no_statx )
1296+ request_mask &= STATX_BASIC_STATS ;
1297+
1298+ if (!request_mask )
1299+ sync = false;
1300+ else if (flags & AT_STATX_FORCE_SYNC )
12131301 sync = true;
12141302 else if (flags & AT_STATX_DONT_SYNC )
12151303 sync = false;
@@ -1220,11 +1308,24 @@ static int fuse_update_get_attr(struct inode *inode, struct file *file,
12201308
12211309 if (sync ) {
12221310 forget_all_cached_acls (inode );
1223- err = fuse_do_getattr (inode , stat , file );
1311+ /* Try statx if BTIME is requested */
1312+ if (!fc -> no_statx && (request_mask & ~STATX_BASIC_STATS )) {
1313+ err = fuse_do_statx (inode , file , stat );
1314+ if (err == - ENOSYS ) {
1315+ fc -> no_statx = 1 ;
1316+ goto retry ;
1317+ }
1318+ } else {
1319+ err = fuse_do_getattr (inode , stat , file );
1320+ }
12241321 } else if (stat ) {
12251322 generic_fillattr (& nop_mnt_idmap , request_mask , inode , stat );
12261323 stat -> mode = fi -> orig_i_mode ;
12271324 stat -> ino = fi -> orig_ino ;
1325+ if (test_bit (FUSE_I_BTIME , & fi -> state )) {
1326+ stat -> btime = fi -> i_btime ;
1327+ stat -> result_mask |= STATX_BTIME ;
1328+ }
12281329 }
12291330
12301331 return err ;
@@ -1861,8 +1962,8 @@ int fuse_do_setattr(struct dentry *dentry, struct iattr *attr,
18611962 /* FIXME: clear I_DIRTY_SYNC? */
18621963 }
18631964
1864- fuse_change_attributes_common (inode , & outarg .attr ,
1865- attr_timeout (& outarg ),
1965+ fuse_change_attributes_common (inode , & outarg .attr , NULL ,
1966+ ATTR_TIMEOUT (& outarg ),
18661967 fuse_get_cache_mask (inode ));
18671968 oldsize = inode -> i_size ;
18681969 /* see the comment in fuse_change_attributes() */
0 commit comments