@@ -92,7 +92,7 @@ static void fuse_dentry_settime(struct dentry *dentry, u64 time)
92
92
/*
93
93
* Calculate the time in jiffies until a dentry/attributes are valid
94
94
*/
95
- static u64 time_to_jiffies (u64 sec , u32 nsec )
95
+ u64 fuse_time_to_jiffies (u64 sec , u32 nsec )
96
96
{
97
97
if (sec || nsec ) {
98
98
struct timespec64 ts = {
@@ -112,17 +112,7 @@ static u64 time_to_jiffies(u64 sec, u32 nsec)
112
112
void fuse_change_entry_timeout (struct dentry * entry , struct fuse_entry_out * o )
113
113
{
114
114
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 ));
126
116
}
127
117
128
118
void fuse_invalidate_attr_mask (struct inode * inode , u32 mask )
@@ -265,8 +255,8 @@ static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
265
255
goto invalid ;
266
256
267
257
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 ),
270
260
attr_version );
271
261
fuse_change_entry_timeout (entry , & outarg );
272
262
} else if (inode ) {
@@ -360,10 +350,14 @@ int fuse_valid_type(int m)
360
350
S_ISBLK (m ) || S_ISFIFO (m ) || S_ISSOCK (m );
361
351
}
362
352
353
+ static bool fuse_valid_size (u64 size )
354
+ {
355
+ return size <= LLONG_MAX ;
356
+ }
357
+
363
358
bool fuse_invalid_attr (struct fuse_attr * attr )
364
359
{
365
- return !fuse_valid_type (attr -> mode ) ||
366
- attr -> size > LLONG_MAX ;
360
+ return !fuse_valid_type (attr -> mode ) || !fuse_valid_size (attr -> size );
367
361
}
368
362
369
363
int 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
399
393
goto out_put_forget ;
400
394
401
395
* inode = fuse_iget (sb , outarg -> nodeid , outarg -> generation ,
402
- & outarg -> attr , entry_attr_timeout (outarg ),
396
+ & outarg -> attr , ATTR_TIMEOUT (outarg ),
403
397
attr_version );
404
398
err = - ENOMEM ;
405
399
if (!* inode ) {
@@ -686,7 +680,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry,
686
680
ff -> nodeid = outentry .nodeid ;
687
681
ff -> open_flags = outopen .open_flags ;
688
682
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 );
690
684
if (!inode ) {
691
685
flags &= ~(O_CREAT | O_EXCL | O_TRUNC );
692
686
fuse_sync_release (NULL , ff , flags );
@@ -755,7 +749,8 @@ static int fuse_atomic_open(struct inode *dir, struct dentry *entry,
755
749
if (err == - ENOSYS ) {
756
750
fc -> no_create = 1 ;
757
751
goto mknod ;
758
- }
752
+ } else if (err == - EEXIST )
753
+ fuse_invalidate_entry (entry );
759
754
out_dput :
760
755
dput (res );
761
756
return err ;
@@ -813,7 +808,7 @@ static int create_new_entry(struct fuse_mount *fm, struct fuse_args *args,
813
808
goto out_put_forget_req ;
814
809
815
810
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 );
817
812
if (!inode ) {
818
813
fuse_queue_forget (fm -> fc , forget , outarg .nodeid , 1 );
819
814
return - ENOMEM ;
@@ -835,6 +830,8 @@ static int create_new_entry(struct fuse_mount *fm, struct fuse_args *args,
835
830
return 0 ;
836
831
837
832
out_put_forget_req :
833
+ if (err == - EEXIST )
834
+ fuse_invalidate_entry (entry );
838
835
kfree (forget );
839
836
return err ;
840
837
}
@@ -986,7 +983,7 @@ static int fuse_unlink(struct inode *dir, struct dentry *entry)
986
983
if (!err ) {
987
984
fuse_dir_changed (dir );
988
985
fuse_entry_unlinked (entry );
989
- } else if (err == - EINTR )
986
+ } else if (err == - EINTR || err == - ENOENT )
990
987
fuse_invalidate_entry (entry );
991
988
return err ;
992
989
}
@@ -1009,7 +1006,7 @@ static int fuse_rmdir(struct inode *dir, struct dentry *entry)
1009
1006
if (!err ) {
1010
1007
fuse_dir_changed (dir );
1011
1008
fuse_entry_unlinked (entry );
1012
- } else if (err == - EINTR )
1009
+ } else if (err == - EINTR || err == - ENOENT )
1013
1010
fuse_invalidate_entry (entry );
1014
1011
return err ;
1015
1012
}
@@ -1050,7 +1047,7 @@ static int fuse_rename_common(struct inode *olddir, struct dentry *oldent,
1050
1047
/* newent will end up negative */
1051
1048
if (!(flags & RENAME_EXCHANGE ) && d_really_is_positive (newent ))
1052
1049
fuse_entry_unlinked (newent );
1053
- } else if (err == - EINTR ) {
1050
+ } else if (err == - EINTR || err == - ENOENT ) {
1054
1051
/* If request was interrupted, DEITY only knows if the
1055
1052
rename actually took place. If the invalidation
1056
1053
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,
1153
1150
stat -> blksize = 1 << blkbits ;
1154
1151
}
1155
1152
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
+
1156
1234
static int fuse_do_getattr (struct inode * inode , struct kstat * stat ,
1157
1235
struct file * file )
1158
1236
{
@@ -1189,8 +1267,8 @@ static int fuse_do_getattr(struct inode *inode, struct kstat *stat,
1189
1267
fuse_make_bad (inode );
1190
1268
err = - EIO ;
1191
1269
} else {
1192
- fuse_change_attributes (inode , & outarg .attr ,
1193
- attr_timeout (& outarg ),
1270
+ fuse_change_attributes (inode , & outarg .attr , NULL ,
1271
+ ATTR_TIMEOUT (& outarg ),
1194
1272
attr_version );
1195
1273
if (stat )
1196
1274
fuse_fillattr (inode , & outarg .attr , stat );
@@ -1204,12 +1282,22 @@ static int fuse_update_get_attr(struct inode *inode, struct file *file,
1204
1282
unsigned int flags )
1205
1283
{
1206
1284
struct fuse_inode * fi = get_fuse_inode (inode );
1285
+ struct fuse_conn * fc = get_fuse_conn (inode );
1207
1286
int err = 0 ;
1208
1287
bool sync ;
1209
1288
u32 inval_mask = READ_ONCE (fi -> inval_mask );
1210
1289
u32 cache_mask = fuse_get_cache_mask (inode );
1211
1290
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 )
1213
1301
sync = true;
1214
1302
else if (flags & AT_STATX_DONT_SYNC )
1215
1303
sync = false;
@@ -1220,11 +1308,24 @@ static int fuse_update_get_attr(struct inode *inode, struct file *file,
1220
1308
1221
1309
if (sync ) {
1222
1310
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
+ }
1224
1321
} else if (stat ) {
1225
1322
generic_fillattr (& nop_mnt_idmap , request_mask , inode , stat );
1226
1323
stat -> mode = fi -> orig_i_mode ;
1227
1324
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
+ }
1228
1329
}
1229
1330
1230
1331
return err ;
@@ -1861,8 +1962,8 @@ int fuse_do_setattr(struct dentry *dentry, struct iattr *attr,
1861
1962
/* FIXME: clear I_DIRTY_SYNC? */
1862
1963
}
1863
1964
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 ),
1866
1967
fuse_get_cache_mask (inode ));
1867
1968
oldsize = inode -> i_size ;
1868
1969
/* see the comment in fuse_change_attributes() */
0 commit comments