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-fixes-4.20-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse

Pull fuse fixes from Miklos Szeredi:
"There's one patch fixing a minor but long lived bug, the others are
fixing regressions introduced in this cycle"

* tag 'fuse-fixes-4.20-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse:
fuse: continue to send FUSE_RELEASEDIR when FUSE_OPEN returns ENOSYS
fuse: Fix memory leak in fuse_dev_free()
fuse: fix revalidation of attributes for permission check
fuse: fix fsync on directory
fuse: Add bad inode check in fuse_destroy_inode()

+60 -37
+23 -3
fs/fuse/dir.c
··· 1119 1119 if (fc->default_permissions || 1120 1120 ((mask & MAY_EXEC) && S_ISREG(inode->i_mode))) { 1121 1121 struct fuse_inode *fi = get_fuse_inode(inode); 1122 + u32 perm_mask = STATX_MODE | STATX_UID | STATX_GID; 1122 1123 1123 - if (time_before64(fi->i_time, get_jiffies_64())) { 1124 + if (perm_mask & READ_ONCE(fi->inval_mask) || 1125 + time_before64(fi->i_time, get_jiffies_64())) { 1124 1126 refreshed = true; 1125 1127 1126 1128 err = fuse_perm_getattr(inode, mask); ··· 1243 1241 1244 1242 static int fuse_dir_release(struct inode *inode, struct file *file) 1245 1243 { 1246 - fuse_release_common(file, FUSE_RELEASEDIR); 1244 + fuse_release_common(file, true); 1247 1245 1248 1246 return 0; 1249 1247 } ··· 1251 1249 static int fuse_dir_fsync(struct file *file, loff_t start, loff_t end, 1252 1250 int datasync) 1253 1251 { 1254 - return fuse_fsync_common(file, start, end, datasync, 1); 1252 + struct inode *inode = file->f_mapping->host; 1253 + struct fuse_conn *fc = get_fuse_conn(inode); 1254 + int err; 1255 + 1256 + if (is_bad_inode(inode)) 1257 + return -EIO; 1258 + 1259 + if (fc->no_fsyncdir) 1260 + return 0; 1261 + 1262 + inode_lock(inode); 1263 + err = fuse_fsync_common(file, start, end, datasync, FUSE_FSYNCDIR); 1264 + if (err == -ENOSYS) { 1265 + fc->no_fsyncdir = 1; 1266 + err = 0; 1267 + } 1268 + inode_unlock(inode); 1269 + 1270 + return err; 1255 1271 } 1256 1272 1257 1273 static long fuse_dir_ioctl(struct file *file, unsigned int cmd,
+33 -31
fs/fuse/file.c
··· 89 89 iput(req->misc.release.inode); 90 90 } 91 91 92 - static void fuse_file_put(struct fuse_file *ff, bool sync) 92 + static void fuse_file_put(struct fuse_file *ff, bool sync, bool isdir) 93 93 { 94 94 if (refcount_dec_and_test(&ff->count)) { 95 95 struct fuse_req *req = ff->reserved_req; 96 96 97 - if (ff->fc->no_open) { 97 + if (ff->fc->no_open && !isdir) { 98 98 /* 99 99 * Drop the release request when client does not 100 100 * implement 'open' ··· 247 247 req->in.args[0].value = inarg; 248 248 } 249 249 250 - void fuse_release_common(struct file *file, int opcode) 250 + void fuse_release_common(struct file *file, bool isdir) 251 251 { 252 252 struct fuse_file *ff = file->private_data; 253 253 struct fuse_req *req = ff->reserved_req; 254 + int opcode = isdir ? FUSE_RELEASEDIR : FUSE_RELEASE; 254 255 255 256 fuse_prepare_release(ff, file->f_flags, opcode); 256 257 ··· 273 272 * synchronous RELEASE is allowed (and desirable) in this case 274 273 * because the server can be trusted not to screw up. 275 274 */ 276 - fuse_file_put(ff, ff->fc->destroy_req != NULL); 275 + fuse_file_put(ff, ff->fc->destroy_req != NULL, isdir); 277 276 } 278 277 279 278 static int fuse_open(struct inode *inode, struct file *file) ··· 289 288 if (fc->writeback_cache) 290 289 write_inode_now(inode, 1); 291 290 292 - fuse_release_common(file, FUSE_RELEASE); 291 + fuse_release_common(file, false); 293 292 294 293 /* return value is ignored by VFS */ 295 294 return 0; ··· 303 302 * iput(NULL) is a no-op and since the refcount is 1 and everything's 304 303 * synchronous, we are fine with not doing igrab() here" 305 304 */ 306 - fuse_file_put(ff, true); 305 + fuse_file_put(ff, true, false); 307 306 } 308 307 EXPORT_SYMBOL_GPL(fuse_sync_release); 309 308 ··· 442 441 } 443 442 444 443 int fuse_fsync_common(struct file *file, loff_t start, loff_t end, 445 - int datasync, int isdir) 444 + int datasync, int opcode) 446 445 { 447 446 struct inode *inode = file->f_mapping->host; 448 447 struct fuse_conn *fc = get_fuse_conn(inode); 449 448 struct fuse_file *ff = file->private_data; 450 449 FUSE_ARGS(args); 451 450 struct fuse_fsync_in inarg; 451 + 452 + memset(&inarg, 0, sizeof(inarg)); 453 + inarg.fh = ff->fh; 454 + inarg.fsync_flags = datasync ? 1 : 0; 455 + args.in.h.opcode = opcode; 456 + args.in.h.nodeid = get_node_id(inode); 457 + args.in.numargs = 1; 458 + args.in.args[0].size = sizeof(inarg); 459 + args.in.args[0].value = &inarg; 460 + return fuse_simple_request(fc, &args); 461 + } 462 + 463 + static int fuse_fsync(struct file *file, loff_t start, loff_t end, 464 + int datasync) 465 + { 466 + struct inode *inode = file->f_mapping->host; 467 + struct fuse_conn *fc = get_fuse_conn(inode); 452 468 int err; 453 469 454 470 if (is_bad_inode(inode)) ··· 497 479 if (err) 498 480 goto out; 499 481 500 - if ((!isdir && fc->no_fsync) || (isdir && fc->no_fsyncdir)) 482 + if (fc->no_fsync) 501 483 goto out; 502 484 503 - memset(&inarg, 0, sizeof(inarg)); 504 - inarg.fh = ff->fh; 505 - inarg.fsync_flags = datasync ? 1 : 0; 506 - args.in.h.opcode = isdir ? FUSE_FSYNCDIR : FUSE_FSYNC; 507 - args.in.h.nodeid = get_node_id(inode); 508 - args.in.numargs = 1; 509 - args.in.args[0].size = sizeof(inarg); 510 - args.in.args[0].value = &inarg; 511 - err = fuse_simple_request(fc, &args); 485 + err = fuse_fsync_common(file, start, end, datasync, FUSE_FSYNC); 512 486 if (err == -ENOSYS) { 513 - if (isdir) 514 - fc->no_fsyncdir = 1; 515 - else 516 - fc->no_fsync = 1; 487 + fc->no_fsync = 1; 517 488 err = 0; 518 489 } 519 490 out: 520 491 inode_unlock(inode); 521 - return err; 522 - } 523 492 524 - static int fuse_fsync(struct file *file, loff_t start, loff_t end, 525 - int datasync) 526 - { 527 - return fuse_fsync_common(file, start, end, datasync, 0); 493 + return err; 528 494 } 529 495 530 496 void fuse_read_fill(struct fuse_req *req, struct file *file, loff_t pos, ··· 809 807 put_page(page); 810 808 } 811 809 if (req->ff) 812 - fuse_file_put(req->ff, false); 810 + fuse_file_put(req->ff, false, false); 813 811 } 814 812 815 813 static void fuse_send_readpages(struct fuse_req *req, struct file *file) ··· 1462 1460 __free_page(req->pages[i]); 1463 1461 1464 1462 if (req->ff) 1465 - fuse_file_put(req->ff, false); 1463 + fuse_file_put(req->ff, false, false); 1466 1464 } 1467 1465 1468 1466 static void fuse_writepage_finish(struct fuse_conn *fc, struct fuse_req *req) ··· 1621 1619 ff = __fuse_write_file_get(fc, fi); 1622 1620 err = fuse_flush_times(inode, ff); 1623 1621 if (ff) 1624 - fuse_file_put(ff, 0); 1622 + fuse_file_put(ff, false, false); 1625 1623 1626 1624 return err; 1627 1625 } ··· 1942 1940 err = 0; 1943 1941 } 1944 1942 if (data.ff) 1945 - fuse_file_put(data.ff, false); 1943 + fuse_file_put(data.ff, false, false); 1946 1944 1947 1945 kfree(data.orig_pages); 1948 1946 out:
+2 -2
fs/fuse/fuse_i.h
··· 822 822 /** 823 823 * Send RELEASE or RELEASEDIR request 824 824 */ 825 - void fuse_release_common(struct file *file, int opcode); 825 + void fuse_release_common(struct file *file, bool isdir); 826 826 827 827 /** 828 828 * Send FSYNC or FSYNCDIR request 829 829 */ 830 830 int fuse_fsync_common(struct file *file, loff_t start, loff_t end, 831 - int datasync, int isdir); 831 + int datasync, int opcode); 832 832 833 833 /** 834 834 * Notify poll wakeup
+2 -1
fs/fuse/inode.c
··· 115 115 static void fuse_destroy_inode(struct inode *inode) 116 116 { 117 117 struct fuse_inode *fi = get_fuse_inode(inode); 118 - if (S_ISREG(inode->i_mode)) { 118 + if (S_ISREG(inode->i_mode) && !is_bad_inode(inode)) { 119 119 WARN_ON(!list_empty(&fi->write_files)); 120 120 WARN_ON(!list_empty(&fi->queued_writes)); 121 121 } ··· 1068 1068 1069 1069 fuse_conn_put(fc); 1070 1070 } 1071 + kfree(fud->pq.processing); 1071 1072 kfree(fud); 1072 1073 } 1073 1074 EXPORT_SYMBOL_GPL(fuse_dev_free);