Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'fuse-update-6.6' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse

Pull fuse updates from Miklos Szeredi:

- Revert non-waiting FLUSH due to a regression

- Fix a lookup counter leak in readdirplus

- Add an option to allow shared mmaps in no-cache mode

- Add btime support and statx intrastructure to the protocol

- Invalidate positive/negative dentry on failed create/delete

* tag 'fuse-update-6.6' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse:
fuse: conditionally fill kstat in fuse_do_statx()
fuse: invalidate dentry on EEXIST creates or ENOENT deletes
fuse: cache btime
fuse: implement statx
fuse: add ATTR_TIMEOUT macro
fuse: add STATX request
fuse: handle empty request_mask in statx
fuse: write back dirty pages before direct write in direct_io_relax mode
fuse: add a new fuse init flag to relax restrictions in no cache mode
fuse: invalidate page cache pages before direct write
fuse: nlookup missing decrement in fuse_direntplus_link
Revert "fuse: in fuse_flush only wait if someone wants the return code"

+296 -106
+130 -29
fs/fuse/dir.c
··· 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 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) ··· 255 265 goto invalid; 256 266 257 267 forget_all_cached_acls(inode); 258 - fuse_change_attributes(inode, &outarg.attr, 259 - entry_attr_timeout(&outarg), 268 + fuse_change_attributes(inode, &outarg.attr, NULL, 269 + ATTR_TIMEOUT(&outarg), 260 270 attr_version); 261 271 fuse_change_entry_timeout(entry, &outarg); 262 272 } else if (inode) { ··· 350 360 S_ISBLK(m) || S_ISFIFO(m) || S_ISSOCK(m); 351 361 } 352 362 363 + static bool fuse_valid_size(u64 size) 364 + { 365 + return size <= LLONG_MAX; 366 + } 367 + 353 368 bool fuse_invalid_attr(struct fuse_attr *attr) 354 369 { 355 - return !fuse_valid_type(attr->mode) || 356 - attr->size > LLONG_MAX; 370 + return !fuse_valid_type(attr->mode) || !fuse_valid_size(attr->size); 357 371 } 358 372 359 373 int fuse_lookup_name(struct super_block *sb, u64 nodeid, const struct qstr *name, ··· 393 399 goto out_put_forget; 394 400 395 401 *inode = fuse_iget(sb, outarg->nodeid, outarg->generation, 396 - &outarg->attr, entry_attr_timeout(outarg), 402 + &outarg->attr, ATTR_TIMEOUT(outarg), 397 403 attr_version); 398 404 err = -ENOMEM; 399 405 if (!*inode) { ··· 680 686 ff->nodeid = outentry.nodeid; 681 687 ff->open_flags = outopen.open_flags; 682 688 inode = fuse_iget(dir->i_sb, outentry.nodeid, outentry.generation, 683 - &outentry.attr, entry_attr_timeout(&outentry), 0); 689 + &outentry.attr, ATTR_TIMEOUT(&outentry), 0); 684 690 if (!inode) { 685 691 flags &= ~(O_CREAT | O_EXCL | O_TRUNC); 686 692 fuse_sync_release(NULL, ff, flags); ··· 749 755 if (err == -ENOSYS) { 750 756 fc->no_create = 1; 751 757 goto mknod; 752 - } 758 + } else if (err == -EEXIST) 759 + fuse_invalidate_entry(entry); 753 760 out_dput: 754 761 dput(res); 755 762 return err; ··· 808 813 goto out_put_forget_req; 809 814 810 815 inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, 811 - &outarg.attr, entry_attr_timeout(&outarg), 0); 816 + &outarg.attr, ATTR_TIMEOUT(&outarg), 0); 812 817 if (!inode) { 813 818 fuse_queue_forget(fm->fc, forget, outarg.nodeid, 1); 814 819 return -ENOMEM; ··· 830 835 return 0; 831 836 832 837 out_put_forget_req: 838 + if (err == -EEXIST) 839 + fuse_invalidate_entry(entry); 833 840 kfree(forget); 834 841 return err; 835 842 } ··· 983 986 if (!err) { 984 987 fuse_dir_changed(dir); 985 988 fuse_entry_unlinked(entry); 986 - } else if (err == -EINTR) 989 + } else if (err == -EINTR || err == -ENOENT) 987 990 fuse_invalidate_entry(entry); 988 991 return err; 989 992 } ··· 1006 1009 if (!err) { 1007 1010 fuse_dir_changed(dir); 1008 1011 fuse_entry_unlinked(entry); 1009 - } else if (err == -EINTR) 1012 + } else if (err == -EINTR || err == -ENOENT) 1010 1013 fuse_invalidate_entry(entry); 1011 1014 return err; 1012 1015 } ··· 1047 1050 /* newent will end up negative */ 1048 1051 if (!(flags & RENAME_EXCHANGE) && d_really_is_positive(newent)) 1049 1052 fuse_entry_unlinked(newent); 1050 - } else if (err == -EINTR) { 1053 + } else if (err == -EINTR || err == -ENOENT) { 1051 1054 /* If request was interrupted, DEITY only knows if the 1052 1055 rename actually took place. If the invalidation 1053 1056 fails (e.g. some process has CWD under the renamed ··· 1150 1153 stat->blksize = 1 << blkbits; 1151 1154 } 1152 1155 1156 + static void fuse_statx_to_attr(struct fuse_statx *sx, struct fuse_attr *attr) 1157 + { 1158 + memset(attr, 0, sizeof(*attr)); 1159 + attr->ino = sx->ino; 1160 + attr->size = sx->size; 1161 + attr->blocks = sx->blocks; 1162 + attr->atime = sx->atime.tv_sec; 1163 + attr->mtime = sx->mtime.tv_sec; 1164 + attr->ctime = sx->ctime.tv_sec; 1165 + attr->atimensec = sx->atime.tv_nsec; 1166 + attr->mtimensec = sx->mtime.tv_nsec; 1167 + attr->ctimensec = sx->ctime.tv_nsec; 1168 + attr->mode = sx->mode; 1169 + attr->nlink = sx->nlink; 1170 + attr->uid = sx->uid; 1171 + attr->gid = sx->gid; 1172 + attr->rdev = new_encode_dev(MKDEV(sx->rdev_major, sx->rdev_minor)); 1173 + attr->blksize = sx->blksize; 1174 + } 1175 + 1176 + static int fuse_do_statx(struct inode *inode, struct file *file, 1177 + struct kstat *stat) 1178 + { 1179 + int err; 1180 + struct fuse_attr attr; 1181 + struct fuse_statx *sx; 1182 + struct fuse_statx_in inarg; 1183 + struct fuse_statx_out outarg; 1184 + struct fuse_mount *fm = get_fuse_mount(inode); 1185 + u64 attr_version = fuse_get_attr_version(fm->fc); 1186 + FUSE_ARGS(args); 1187 + 1188 + memset(&inarg, 0, sizeof(inarg)); 1189 + memset(&outarg, 0, sizeof(outarg)); 1190 + /* Directories have separate file-handle space */ 1191 + if (file && S_ISREG(inode->i_mode)) { 1192 + struct fuse_file *ff = file->private_data; 1193 + 1194 + inarg.getattr_flags |= FUSE_GETATTR_FH; 1195 + inarg.fh = ff->fh; 1196 + } 1197 + /* For now leave sync hints as the default, request all stats. */ 1198 + inarg.sx_flags = 0; 1199 + inarg.sx_mask = STATX_BASIC_STATS | STATX_BTIME; 1200 + args.opcode = FUSE_STATX; 1201 + args.nodeid = get_node_id(inode); 1202 + args.in_numargs = 1; 1203 + args.in_args[0].size = sizeof(inarg); 1204 + args.in_args[0].value = &inarg; 1205 + args.out_numargs = 1; 1206 + args.out_args[0].size = sizeof(outarg); 1207 + args.out_args[0].value = &outarg; 1208 + err = fuse_simple_request(fm, &args); 1209 + if (err) 1210 + return err; 1211 + 1212 + sx = &outarg.stat; 1213 + if (((sx->mask & STATX_SIZE) && !fuse_valid_size(sx->size)) || 1214 + ((sx->mask & STATX_TYPE) && (!fuse_valid_type(sx->mode) || 1215 + inode_wrong_type(inode, sx->mode)))) { 1216 + make_bad_inode(inode); 1217 + return -EIO; 1218 + } 1219 + 1220 + fuse_statx_to_attr(&outarg.stat, &attr); 1221 + if ((sx->mask & STATX_BASIC_STATS) == STATX_BASIC_STATS) { 1222 + fuse_change_attributes(inode, &attr, &outarg.stat, 1223 + ATTR_TIMEOUT(&outarg), attr_version); 1224 + } 1225 + 1226 + if (stat) { 1227 + stat->result_mask = sx->mask & (STATX_BASIC_STATS | STATX_BTIME); 1228 + stat->btime.tv_sec = sx->btime.tv_sec; 1229 + stat->btime.tv_nsec = min_t(u32, sx->btime.tv_nsec, NSEC_PER_SEC - 1); 1230 + fuse_fillattr(inode, &attr, stat); 1231 + stat->result_mask |= STATX_TYPE; 1232 + } 1233 + 1234 + return 0; 1235 + } 1236 + 1153 1237 static int fuse_do_getattr(struct inode *inode, struct kstat *stat, 1154 1238 struct file *file) 1155 1239 { ··· 1267 1189 fuse_make_bad(inode); 1268 1190 err = -EIO; 1269 1191 } else { 1270 - fuse_change_attributes(inode, &outarg.attr, 1271 - attr_timeout(&outarg), 1192 + fuse_change_attributes(inode, &outarg.attr, NULL, 1193 + ATTR_TIMEOUT(&outarg), 1272 1194 attr_version); 1273 1195 if (stat) 1274 1196 fuse_fillattr(inode, &outarg.attr, stat); ··· 1282 1204 unsigned int flags) 1283 1205 { 1284 1206 struct fuse_inode *fi = get_fuse_inode(inode); 1207 + struct fuse_conn *fc = get_fuse_conn(inode); 1285 1208 int err = 0; 1286 1209 bool sync; 1287 1210 u32 inval_mask = READ_ONCE(fi->inval_mask); 1288 1211 u32 cache_mask = fuse_get_cache_mask(inode); 1289 1212 1290 - if (flags & AT_STATX_FORCE_SYNC) 1213 + 1214 + /* FUSE only supports basic stats and possibly btime */ 1215 + request_mask &= STATX_BASIC_STATS | STATX_BTIME; 1216 + retry: 1217 + if (fc->no_statx) 1218 + request_mask &= STATX_BASIC_STATS; 1219 + 1220 + if (!request_mask) 1221 + sync = false; 1222 + else if (flags & AT_STATX_FORCE_SYNC) 1291 1223 sync = true; 1292 1224 else if (flags & AT_STATX_DONT_SYNC) 1293 1225 sync = false; ··· 1308 1220 1309 1221 if (sync) { 1310 1222 forget_all_cached_acls(inode); 1311 - err = fuse_do_getattr(inode, stat, file); 1223 + /* Try statx if BTIME is requested */ 1224 + if (!fc->no_statx && (request_mask & ~STATX_BASIC_STATS)) { 1225 + err = fuse_do_statx(inode, file, stat); 1226 + if (err == -ENOSYS) { 1227 + fc->no_statx = 1; 1228 + goto retry; 1229 + } 1230 + } else { 1231 + err = fuse_do_getattr(inode, stat, file); 1232 + } 1312 1233 } else if (stat) { 1313 1234 generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat); 1314 1235 stat->mode = fi->orig_i_mode; 1315 1236 stat->ino = fi->orig_ino; 1237 + if (test_bit(FUSE_I_BTIME, &fi->state)) { 1238 + stat->btime = fi->i_btime; 1239 + stat->result_mask |= STATX_BTIME; 1240 + } 1316 1241 } 1317 1242 1318 1243 return err; ··· 1962 1861 /* FIXME: clear I_DIRTY_SYNC? */ 1963 1862 } 1964 1863 1965 - fuse_change_attributes_common(inode, &outarg.attr, 1966 - attr_timeout(&outarg), 1864 + fuse_change_attributes_common(inode, &outarg.attr, NULL, 1865 + ATTR_TIMEOUT(&outarg), 1967 1866 fuse_get_cache_mask(inode)); 1968 1867 oldsize = inode->i_size; 1969 1868 /* see the comment in fuse_change_attributes() */
+49 -66
fs/fuse/file.c
··· 19 19 #include <linux/uio.h> 20 20 #include <linux/fs.h> 21 21 #include <linux/filelock.h> 22 - #include <linux/file.h> 23 22 24 23 static int fuse_send_open(struct fuse_mount *fm, u64 nodeid, 25 24 unsigned int open_flags, int opcode, ··· 478 479 fuse_release_nowrite(inode); 479 480 } 480 481 481 - struct fuse_flush_args { 482 - struct fuse_args args; 483 - struct fuse_flush_in inarg; 484 - struct work_struct work; 485 - struct file *file; 486 - }; 487 - 488 - static int fuse_do_flush(struct fuse_flush_args *fa) 482 + static int fuse_flush(struct file *file, fl_owner_t id) 489 483 { 490 - int err; 491 - struct inode *inode = file_inode(fa->file); 484 + struct inode *inode = file_inode(file); 492 485 struct fuse_mount *fm = get_fuse_mount(inode); 486 + struct fuse_file *ff = file->private_data; 487 + struct fuse_flush_in inarg; 488 + FUSE_ARGS(args); 489 + int err; 490 + 491 + if (fuse_is_bad(inode)) 492 + return -EIO; 493 + 494 + if (ff->open_flags & FOPEN_NOFLUSH && !fm->fc->writeback_cache) 495 + return 0; 493 496 494 497 err = write_inode_now(inode, 1); 495 498 if (err) 496 - goto out; 499 + return err; 497 500 498 501 inode_lock(inode); 499 502 fuse_sync_writes(inode); 500 503 inode_unlock(inode); 501 504 502 - err = filemap_check_errors(fa->file->f_mapping); 505 + err = filemap_check_errors(file->f_mapping); 503 506 if (err) 504 - goto out; 507 + return err; 505 508 506 509 err = 0; 507 510 if (fm->fc->no_flush) 508 511 goto inval_attr_out; 509 512 510 - err = fuse_simple_request(fm, &fa->args); 513 + memset(&inarg, 0, sizeof(inarg)); 514 + inarg.fh = ff->fh; 515 + inarg.lock_owner = fuse_lock_owner_id(fm->fc, id); 516 + args.opcode = FUSE_FLUSH; 517 + args.nodeid = get_node_id(inode); 518 + args.in_numargs = 1; 519 + args.in_args[0].size = sizeof(inarg); 520 + args.in_args[0].value = &inarg; 521 + args.force = true; 522 + 523 + err = fuse_simple_request(fm, &args); 511 524 if (err == -ENOSYS) { 512 525 fm->fc->no_flush = 1; 513 526 err = 0; ··· 532 521 */ 533 522 if (!err && fm->fc->writeback_cache) 534 523 fuse_invalidate_attr_mask(inode, STATX_BLOCKS); 535 - 536 - out: 537 - fput(fa->file); 538 - kfree(fa); 539 524 return err; 540 - } 541 - 542 - static void fuse_flush_async(struct work_struct *work) 543 - { 544 - struct fuse_flush_args *fa = container_of(work, typeof(*fa), work); 545 - 546 - fuse_do_flush(fa); 547 - } 548 - 549 - static int fuse_flush(struct file *file, fl_owner_t id) 550 - { 551 - struct fuse_flush_args *fa; 552 - struct inode *inode = file_inode(file); 553 - struct fuse_mount *fm = get_fuse_mount(inode); 554 - struct fuse_file *ff = file->private_data; 555 - 556 - if (fuse_is_bad(inode)) 557 - return -EIO; 558 - 559 - if (ff->open_flags & FOPEN_NOFLUSH && !fm->fc->writeback_cache) 560 - return 0; 561 - 562 - fa = kzalloc(sizeof(*fa), GFP_KERNEL); 563 - if (!fa) 564 - return -ENOMEM; 565 - 566 - fa->inarg.fh = ff->fh; 567 - fa->inarg.lock_owner = fuse_lock_owner_id(fm->fc, id); 568 - fa->args.opcode = FUSE_FLUSH; 569 - fa->args.nodeid = get_node_id(inode); 570 - fa->args.in_numargs = 1; 571 - fa->args.in_args[0].size = sizeof(fa->inarg); 572 - fa->args.in_args[0].value = &fa->inarg; 573 - fa->args.force = true; 574 - fa->file = get_file(file); 575 - 576 - /* Don't wait if the task is exiting */ 577 - if (current->flags & PF_EXITING) { 578 - INIT_WORK(&fa->work, fuse_flush_async); 579 - schedule_work(&fa->work); 580 - return 0; 581 - } 582 - 583 - return fuse_do_flush(fa); 584 525 } 585 526 586 527 int fuse_fsync_common(struct file *file, loff_t start, loff_t end, ··· 1428 1465 int write = flags & FUSE_DIO_WRITE; 1429 1466 int cuse = flags & FUSE_DIO_CUSE; 1430 1467 struct file *file = io->iocb->ki_filp; 1431 - struct inode *inode = file->f_mapping->host; 1468 + struct address_space *mapping = file->f_mapping; 1469 + struct inode *inode = mapping->host; 1432 1470 struct fuse_file *ff = file->private_data; 1433 1471 struct fuse_conn *fc = ff->fm->fc; 1434 1472 size_t nmax = write ? fc->max_write : fc->max_read; ··· 1441 1477 int err = 0; 1442 1478 struct fuse_io_args *ia; 1443 1479 unsigned int max_pages; 1480 + bool fopen_direct_io = ff->open_flags & FOPEN_DIRECT_IO; 1444 1481 1445 1482 max_pages = iov_iter_npages(iter, fc->max_pages); 1446 1483 ia = fuse_io_alloc(io, max_pages); 1447 1484 if (!ia) 1448 1485 return -ENOMEM; 1449 1486 1487 + if (fopen_direct_io && fc->direct_io_relax) { 1488 + res = filemap_write_and_wait_range(mapping, pos, pos + count - 1); 1489 + if (res) { 1490 + fuse_io_free(ia); 1491 + return res; 1492 + } 1493 + } 1450 1494 if (!cuse && fuse_range_is_writeback(inode, idx_from, idx_to)) { 1451 1495 if (!write) 1452 1496 inode_lock(inode); 1453 1497 fuse_sync_writes(inode); 1454 1498 if (!write) 1455 1499 inode_unlock(inode); 1500 + } 1501 + 1502 + if (fopen_direct_io && write) { 1503 + res = invalidate_inode_pages2_range(mapping, idx_from, idx_to); 1504 + if (res) { 1505 + fuse_io_free(ia); 1506 + return res; 1507 + } 1456 1508 } 1457 1509 1458 1510 io->should_dirty = !write && user_backed_iter(iter); ··· 2458 2478 static int fuse_file_mmap(struct file *file, struct vm_area_struct *vma) 2459 2479 { 2460 2480 struct fuse_file *ff = file->private_data; 2481 + struct fuse_conn *fc = ff->fm->fc; 2461 2482 2462 2483 /* DAX mmap is superior to direct_io mmap */ 2463 2484 if (FUSE_IS_DAX(file_inode(file))) 2464 2485 return fuse_dax_mmap(file, vma); 2465 2486 2466 2487 if (ff->open_flags & FOPEN_DIRECT_IO) { 2467 - /* Can't provide the coherency needed for MAP_SHARED */ 2468 - if (vma->vm_flags & VM_MAYSHARE) 2488 + /* Can't provide the coherency needed for MAP_SHARED 2489 + * if FUSE_DIRECT_IO_RELAX isn't set. 2490 + */ 2491 + if ((vma->vm_flags & VM_MAYSHARE) && !fc->direct_io_relax) 2469 2492 return -ENODEV; 2470 2493 2471 2494 invalidate_inode_pages2(file->f_mapping);
+17 -1
fs/fuse/fuse_i.h
··· 88 88 preserve the original mode */ 89 89 umode_t orig_i_mode; 90 90 91 + /* Cache birthtime */ 92 + struct timespec64 i_btime; 93 + 91 94 /** 64 bit inode number */ 92 95 u64 orig_ino; 93 96 ··· 170 167 FUSE_I_SIZE_UNSTABLE, 171 168 /* Bad inode */ 172 169 FUSE_I_BAD, 170 + /* Has btime */ 171 + FUSE_I_BTIME, 173 172 }; 174 173 175 174 struct fuse_conn; ··· 797 792 /* Is tmpfile not implemented by fs? */ 798 793 unsigned int no_tmpfile:1; 799 794 795 + /* relax restrictions in FOPEN_DIRECT_IO mode */ 796 + unsigned int direct_io_relax:1; 797 + 798 + /* Is statx not implemented by fs? */ 799 + unsigned int no_statx:1; 800 + 800 801 /** The number of requests waiting for completion */ 801 802 atomic_t num_waiting; 802 803 ··· 1069 1058 * Change attributes of an inode 1070 1059 */ 1071 1060 void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr, 1061 + struct fuse_statx *sx, 1072 1062 u64 attr_valid, u64 attr_version); 1073 1063 1074 1064 void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr, 1065 + struct fuse_statx *sx, 1075 1066 u64 attr_valid, u32 cache_mask); 1076 1067 1077 1068 u32 fuse_get_cache_mask(struct inode *inode); ··· 1124 1111 1125 1112 void fuse_invalidate_atime(struct inode *inode); 1126 1113 1127 - u64 entry_attr_timeout(struct fuse_entry_out *o); 1114 + u64 fuse_time_to_jiffies(u64 sec, u32 nsec); 1115 + #define ATTR_TIMEOUT(o) \ 1116 + fuse_time_to_jiffies((o)->attr_valid, (o)->attr_valid_nsec) 1117 + 1128 1118 void fuse_change_entry_timeout(struct dentry *entry, struct fuse_entry_out *o); 1129 1119 1130 1120 /**
+29 -5
fs/fuse/inode.c
··· 77 77 return NULL; 78 78 79 79 fi->i_time = 0; 80 - fi->inval_mask = 0; 80 + fi->inval_mask = ~0; 81 81 fi->nodeid = 0; 82 82 fi->nlookup = 0; 83 83 fi->attr_version = 0; ··· 163 163 } 164 164 165 165 void fuse_change_attributes_common(struct inode *inode, struct fuse_attr *attr, 166 + struct fuse_statx *sx, 166 167 u64 attr_valid, u32 cache_mask) 167 168 { 168 169 struct fuse_conn *fc = get_fuse_conn(inode); ··· 173 172 174 173 fi->attr_version = atomic64_inc_return(&fc->attr_version); 175 174 fi->i_time = attr_valid; 176 - WRITE_ONCE(fi->inval_mask, 0); 175 + /* Clear basic stats from invalid mask */ 176 + set_mask_bits(&fi->inval_mask, STATX_BASIC_STATS, 0); 177 177 178 178 inode->i_ino = fuse_squash_ino(attr->ino); 179 179 inode->i_mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777); ··· 197 195 } 198 196 if (!(cache_mask & STATX_CTIME)) { 199 197 inode_set_ctime(inode, attr->ctime, attr->ctimensec); 198 + } 199 + if (sx) { 200 + /* Sanitize nsecs */ 201 + sx->btime.tv_nsec = 202 + min_t(u32, sx->btime.tv_nsec, NSEC_PER_SEC - 1); 203 + 204 + /* 205 + * Btime has been queried, cache is valid (whether or not btime 206 + * is available or not) so clear STATX_BTIME from inval_mask. 207 + * 208 + * Availability of the btime attribute is indicated in 209 + * FUSE_I_BTIME 210 + */ 211 + set_mask_bits(&fi->inval_mask, STATX_BTIME, 0); 212 + if (sx->mask & STATX_BTIME) { 213 + set_bit(FUSE_I_BTIME, &fi->state); 214 + fi->i_btime.tv_sec = sx->btime.tv_sec; 215 + fi->i_btime.tv_nsec = sx->btime.tv_nsec; 216 + } 200 217 } 201 218 202 219 if (attr->blksize != 0) ··· 256 235 } 257 236 258 237 void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr, 238 + struct fuse_statx *sx, 259 239 u64 attr_valid, u64 attr_version) 260 240 { 261 241 struct fuse_conn *fc = get_fuse_conn(inode); ··· 291 269 } 292 270 293 271 old_mtime = inode->i_mtime; 294 - fuse_change_attributes_common(inode, attr, attr_valid, cache_mask); 272 + fuse_change_attributes_common(inode, attr, sx, attr_valid, cache_mask); 295 273 296 274 oldsize = inode->i_size; 297 275 /* ··· 428 406 spin_lock(&fi->lock); 429 407 fi->nlookup++; 430 408 spin_unlock(&fi->lock); 431 - fuse_change_attributes(inode, attr, attr_valid, attr_version); 409 + fuse_change_attributes(inode, attr, NULL, attr_valid, attr_version); 432 410 433 411 return inode; 434 412 } ··· 1232 1210 fc->init_security = 1; 1233 1211 if (flags & FUSE_CREATE_SUPP_GROUP) 1234 1212 fc->create_supp_group = 1; 1213 + if (flags & FUSE_DIRECT_IO_RELAX) 1214 + fc->direct_io_relax = 1; 1235 1215 } else { 1236 1216 ra_pages = fc->max_read / PAGE_SIZE; 1237 1217 fc->no_lock = 1; ··· 1280 1256 FUSE_NO_OPENDIR_SUPPORT | FUSE_EXPLICIT_INVAL_DATA | 1281 1257 FUSE_HANDLE_KILLPRIV_V2 | FUSE_SETXATTR_EXT | FUSE_INIT_EXT | 1282 1258 FUSE_SECURITY_CTX | FUSE_CREATE_SUPP_GROUP | 1283 - FUSE_HAS_EXPIRE_ONLY; 1259 + FUSE_HAS_EXPIRE_ONLY | FUSE_DIRECT_IO_RELAX; 1284 1260 #ifdef CONFIG_FUSE_DAX 1285 1261 if (fm->fc->dax) 1286 1262 flags |= FUSE_MAP_ALIGNMENT;
+12 -4
fs/fuse/readdir.c
··· 223 223 spin_unlock(&fi->lock); 224 224 225 225 forget_all_cached_acls(inode); 226 - fuse_change_attributes(inode, &o->attr, 227 - entry_attr_timeout(o), 226 + fuse_change_attributes(inode, &o->attr, NULL, 227 + ATTR_TIMEOUT(o), 228 228 attr_version); 229 229 /* 230 230 * The other branch comes via fuse_iget() ··· 232 232 */ 233 233 } else { 234 234 inode = fuse_iget(dir->i_sb, o->nodeid, o->generation, 235 - &o->attr, entry_attr_timeout(o), 235 + &o->attr, ATTR_TIMEOUT(o), 236 236 attr_version); 237 237 if (!inode) 238 238 inode = ERR_PTR(-ENOMEM); ··· 243 243 dput(dentry); 244 244 dentry = alias; 245 245 } 246 - if (IS_ERR(dentry)) 246 + if (IS_ERR(dentry)) { 247 + if (!IS_ERR(inode)) { 248 + struct fuse_inode *fi = get_fuse_inode(inode); 249 + 250 + spin_lock(&fi->lock); 251 + fi->nlookup--; 252 + spin_unlock(&fi->lock); 253 + } 247 254 return PTR_ERR(dentry); 255 + } 248 256 } 249 257 if (fc->readdirplus_auto) 250 258 set_bit(FUSE_I_INIT_RDPLUS, &get_fuse_inode(inode)->state);
+59 -1
include/uapi/linux/fuse.h
··· 207 207 * - add FUSE_EXT_GROUPS 208 208 * - add FUSE_CREATE_SUPP_GROUP 209 209 * - add FUSE_HAS_EXPIRE_ONLY 210 + * 211 + * 7.39 212 + * - add FUSE_DIRECT_IO_RELAX 213 + * - add FUSE_STATX and related structures 210 214 */ 211 215 212 216 #ifndef _LINUX_FUSE_H ··· 246 242 #define FUSE_KERNEL_VERSION 7 247 243 248 244 /** Minor version number of this interface */ 249 - #define FUSE_KERNEL_MINOR_VERSION 38 245 + #define FUSE_KERNEL_MINOR_VERSION 39 250 246 251 247 /** The node ID of the root inode */ 252 248 #define FUSE_ROOT_ID 1 ··· 271 267 uint32_t rdev; 272 268 uint32_t blksize; 273 269 uint32_t flags; 270 + }; 271 + 272 + /* 273 + * The following structures are bit-for-bit compatible with the statx(2) ABI in 274 + * Linux. 275 + */ 276 + struct fuse_sx_time { 277 + int64_t tv_sec; 278 + uint32_t tv_nsec; 279 + int32_t __reserved; 280 + }; 281 + 282 + struct fuse_statx { 283 + uint32_t mask; 284 + uint32_t blksize; 285 + uint64_t attributes; 286 + uint32_t nlink; 287 + uint32_t uid; 288 + uint32_t gid; 289 + uint16_t mode; 290 + uint16_t __spare0[1]; 291 + uint64_t ino; 292 + uint64_t size; 293 + uint64_t blocks; 294 + uint64_t attributes_mask; 295 + struct fuse_sx_time atime; 296 + struct fuse_sx_time btime; 297 + struct fuse_sx_time ctime; 298 + struct fuse_sx_time mtime; 299 + uint32_t rdev_major; 300 + uint32_t rdev_minor; 301 + uint32_t dev_major; 302 + uint32_t dev_minor; 303 + uint64_t __spare2[14]; 274 304 }; 275 305 276 306 struct fuse_kstatfs { ··· 409 371 * FUSE_CREATE_SUPP_GROUP: add supplementary group info to create, mkdir, 410 372 * symlink and mknod (single group that matches parent) 411 373 * FUSE_HAS_EXPIRE_ONLY: kernel supports expiry-only entry invalidation 374 + * FUSE_DIRECT_IO_RELAX: relax restrictions in FOPEN_DIRECT_IO mode, for now 375 + * allow shared mmap 412 376 */ 413 377 #define FUSE_ASYNC_READ (1 << 0) 414 378 #define FUSE_POSIX_LOCKS (1 << 1) ··· 449 409 #define FUSE_HAS_INODE_DAX (1ULL << 33) 450 410 #define FUSE_CREATE_SUPP_GROUP (1ULL << 34) 451 411 #define FUSE_HAS_EXPIRE_ONLY (1ULL << 35) 412 + #define FUSE_DIRECT_IO_RELAX (1ULL << 36) 452 413 453 414 /** 454 415 * CUSE INIT request/reply flags ··· 616 575 FUSE_REMOVEMAPPING = 49, 617 576 FUSE_SYNCFS = 50, 618 577 FUSE_TMPFILE = 51, 578 + FUSE_STATX = 52, 619 579 620 580 /* CUSE specific operations */ 621 581 CUSE_INIT = 4096, ··· 679 637 uint32_t attr_valid_nsec; 680 638 uint32_t dummy; 681 639 struct fuse_attr attr; 640 + }; 641 + 642 + struct fuse_statx_in { 643 + uint32_t getattr_flags; 644 + uint32_t reserved; 645 + uint64_t fh; 646 + uint32_t sx_flags; 647 + uint32_t sx_mask; 648 + }; 649 + 650 + struct fuse_statx_out { 651 + uint64_t attr_valid; /* Cache timeout for the attributes */ 652 + uint32_t attr_valid_nsec; 653 + uint32_t flags; 654 + uint64_t spare[2]; 655 + struct fuse_statx stat; 682 656 }; 683 657 684 658 #define FUSE_COMPAT_MKNOD_IN_SIZE 8