Pull vfs fixes from Christian Brauner: - netfs: - fix the decision when to disallow write-streaming with fscache in use, handling of asynchronous cache object creation, a double fput in cachefiles, clearing S_KERNEL_FILE without the inode lock held, page extraction bugs in the iov_iter helpers (a potential underflow, a missing allocation failure check, a memory leak, and a folio offset miscalculation), writeback error and ENOMEM handling, DIO write retry for filesystems without a ->prepare_write() method, and the replacement of the wb_lock mutex with a bit lock plus writethrough collection offload so that multiple asynchronous writebacks don't interfere with each other. - Fix the barriering when walking the netfs subrequest list during retries as it was possible to see a subrequest that was just added by the application thread. - iomap: - Change iomap to submit read bios after each extent instead of building them up across extents. The old behavior was considered problematic for a while and now caused an actual erofs bug. - Guard the ioend io_size EOF trim in iomap against underflow when a concurrent truncate moves EOF below the start of the ioend, wrapping io_size to a huge value. - overlayfs - Fix a stale overlayfs comment about the locking order. - Store the linked-in upper dentry instead of the disconnected O_TMPFILE dentry during overlayfs tmpfile copy-up. With a FUSE or virtiofs upper layer ->d_revalidate() would try to look up "/" in the workdir and fail, causing persistent ESTALE errors that broke dpkg and apt. - vfs-bpf: Have the bpf_real_data_inode() kfunc take a struct file instead of a dentry so it is usable from the bprm_check_security, mmap_file, and file_mprotect hooks, and rename it from bpf_real_inode() to make the data-inode semantics explicit. The kfunc landed this cycle so the change is safe. - afs: NULL pointer dereferences in the callback service and in afs_get_tree(), several memory and refcount leaks, missing locking around the dynamic root inode numbers and premature cell exposure through /afs, a netns destruction hang caused by a misplaced increment of net->cells_outstanding, a bulk lookup malfunction caused by the dir_emit() API change, inode (re)initialisation issues, and assorted smaller fixes to error codes, seqlock handling, and debug output. - vfs: Refuse O_TMPFILE creation with an unmapped fsuid or fsgid and add a selftest for it. - vboxsf: Add Jori Koolstra as vboxsf maintainer, taking over from Hans de Goede. - dio: Release the pages attached to a short atomic dio bio; the REQ_ATOMIC size check error path leaked them. - procfs: Only bump the parent directory link count when registering directories in procfs. Registering regular files inflated the count and leaked a link on every create and remove cycle. - minix: Avoid an unsigned overflow in the minix bitmap block count calculation that let crafted images with huge inode or zone counts pass superblock validation and crash the kernel during mount. - cachefiles: Fix a double unlock in the cachefiles nomem_d_alloc error path left over from the start_creating() conversion. - fat: Stop fat from reading directory entries past the 0x00 end-of-directory marker. If the trailing on-disk slots aren't zero-filled the driver surfaced arbitrary garbage as directory entries. - freexvfs: Don't BUG() on unknown typed-extent types in freevxfs, reachable via ioctl(FIBMAP) on a crafted image; fail with an I/O error instead. - orangefs: Keep the readdir entry size 64-bit in orangefs fill_from_part(). Truncating it to __u32 bypassed the bounds check and led to out-of-bounds reads triggerable by the userspace client. - xfs: Fix the error unwind in xfs_open_devices() which released the rt device file twice and left dangling buftarg pointers behind that were freed again when the failed mount was torn down. - exec: Fix an off-by-one in the comment documenting the maximum binfmt rewrite depth in exec_binprm(). The code allows five rewrites, not four; restricting the code would break userspace so the comment is fixed instead. - file handles: Reject detached mounts in capable_wrt_mount(). A detached mount can be dissolved concurrently, leaving a NULL mount namespace that open_by_handle_at() would dereference. * tag 'vfs-7.2-rc2.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: (57 commits) netfs: Fix barriering when walking subrequest list iomap: submit read bio after each extent fuse: call fuse_send_readpages explicitly from fuse_readahead iomap: consolidate bio submission fhandle: reject detached mounts in capable_wrt_mount() netfs: Fix DIO write retry for filesystems without a ->prepare_write() netfs: Fix folio state after ENOMEM whilst under writeback iteration netfs: Fix writeback error handling netfs: Fix writethrough to use collection offload netfs: Replace wb_lock with a bit lock for asynchronicity netfs: Fix kdoc warning scatterlist: Fix offset in folio calc in extract_xarray_to_sg() iov_iter: Remove unused variable in kunit_iov_iter.c iov_iter: Fix a memory leak in iov_iter_extract_user_pages() iov_iter: Fix missing alloc fail check in iov_iter_extract_bvec_pages() iov_iter: Fix potential underflow in iov_iter_extract_xarray_pages() cachefiles: Fix file burial to take lock when unsetting S_KERNEL_FILE cachefiles: Fix double fput netfs: Fix netfs_create_write_req() to handle async cache object creation netfs: Fix decision whether to disallow write-streaming due to fscache use ...
Unified · Split
| @@ -28725,7 +28725,7 @@ F: include/linux/vbox_utils.h · 28724 unmodified lines | ||
| 28725 | 28725 | F: include/uapi/linux/vbox*.h |
| 28726 | 28726 | |
| 28727 | 28727 | VIRTUAL BOX SHARED FOLDER VFS DRIVER |
| 28728 | −M: Hans de Goede <hansg@kernel.org> | |
| 28728 | +M: Jori Koolstra <jkoolstra@xs4all.nl> | |
| 28729 | 28729 | L: linux-fsdevel@vger.kernel.org |
| 28730 | 28730 | S: Maintained |
| 28731 | 28731 | F: fs/vboxsf/* |
| @@ -113,16 +113,12 @@ static struct afs_volume *afs_lookup_volume_rcu(struct afs_cell *cell, · 112 unmodified lines | ||
| 113 | 113 | { |
| 114 | 114 | struct afs_volume *volume = NULL; |
| 115 | 115 | struct rb_node *p; |
| 116 | − int seq = 1; | |
| 117 | 116 | |
| 118 | − for (;;) { | |
| 117 | + scoped_seqlock_read(&cell->volume_lock, ss_lock) { | |
| 119 | 118 | /* Unfortunately, rbtree walking doesn't give reliable results |
| 120 | 119 | * under just the RCU read lock, so we have to check for |
| 121 | 120 | * changes. |
| 122 | 121 | */ |
| 123 | − seq++; /* 2 on the 1st/lockless path, otherwise odd */ | |
| 124 | − read_seqbegin_or_lock(&cell->volume_lock, &seq); | |
| 125 | − | |
| 126 | 122 | p = rcu_dereference_raw(cell->volumes.rb_node); |
| 127 | 123 | while (p) { |
| 128 | 124 | volume = rb_entry(p, struct afs_volume, cell_node); |
| @@ -138,12 +134,9 @@ static struct afs_volume *afs_lookup_volume_rcu(struct afs_cell *cell, · 9 unmodified lines | ||
| 138 | 134 | |
| 139 | 135 | if (volume && afs_try_get_volume(volume, afs_volume_trace_get_callback)) |
| 140 | 136 | break; |
| 141 | − if (!need_seqretry(&cell->volume_lock, seq)) | |
| 142 | − break; | |
| 143 | − seq |= 1; /* Want a lock next time */ | |
| 137 | + volume = NULL; | |
| 144 | 138 | } |
| 145 | 139 | |
| 146 | − done_seqretry(&cell->volume_lock, seq); | |
| 147 | 140 | return volume; |
| 148 | 141 | } |
| 149 | 142 | |
| @@ -221,7 +214,11 @@ static void afs_break_some_callbacks(struct afs_server *server, · 71 unmodified lines | ||
| 221 | 214 | |
| 222 | 215 | rcu_read_lock(); |
| 223 | 216 | volume = afs_lookup_volume_rcu(server->cell, vid); |
| 224 | − if (cbb->fid.vnode == 0 && cbb->fid.unique == 0) { | |
| 217 | + if (!volume) { | |
| 218 | + /* Ignore breaks on unknown volumes. */ | |
| 219 | + rcu_read_unlock(); | |
| 220 | + *_count = 0; | |
| 221 | + } else if (cbb->fid.vnode == 0 && cbb->fid.unique == 0) { | |
| 225 | 222 | afs_break_volume_callback(server, volume); |
| 226 | 223 | *_count -= 1; |
| 227 | 224 | if (*_count) |
| @@ -206,11 +206,6 @@ static struct afs_cell *afs_alloc_cell(struct afs_net *net, · 205 unmodified lines | ||
| 206 | 206 | cell->dns_status = vllist->status; |
| 207 | 207 | smp_store_release(&cell->dns_lookup_count, 1); /* vs source/status */ |
| 208 | 208 | atomic_inc(&net->cells_outstanding); |
| 209 | − ret = idr_alloc_cyclic(&net->cells_dyn_ino, cell, | |
| 210 | − 2, INT_MAX / 2, GFP_KERNEL); | |
| 211 | − if (ret < 0) | |
| 212 | − goto error; | |
| 213 | − cell->dynroot_ino = ret; | |
| 214 | 209 | cell->debug_id = atomic_inc_return(&cell_debug_id); |
| 215 | 210 | |
| 216 | 211 | trace_afs_cell(cell->debug_id, 1, 0, afs_cell_trace_alloc); |
| @@ -304,6 +299,13 @@ struct afs_cell *afs_lookup_cell(struct afs_net *net, · 87 unmodified lines | ||
| 304 | 299 | goto cell_already_exists; |
| 305 | 300 | } |
| 306 | 301 | |
| 302 | + ret = idr_alloc_cyclic(&net->cells_dyn_ino, candidate, | |
| 303 | + 2, INT_MAX / 2, GFP_KERNEL); | |
| 304 | + if (ret < 0) | |
| 305 | + goto cant_alloc_ino; | |
| 306 | + candidate->dynroot_ino = ret; | |
| 307 | + set_bit(AFS_CELL_FL_HAVE_INO, &candidate->flags); | |
| 308 | + | |
| 307 | 309 | cell = candidate; |
| 308 | 310 | candidate = NULL; |
| 309 | 311 | afs_use_cell(cell, trace); |
| @@ -378,6 +380,11 @@ no_wait: · 68 unmodified lines | ||
| 378 | 380 | _leave(" = %p [cell]", cell); |
| 379 | 381 | return cell; |
| 380 | 382 | |
| 383 | +cant_alloc_ino: | |
| 384 | + up_write(&net->cells_lock); | |
| 385 | + afs_put_cell(candidate, afs_cell_trace_put_candidate); | |
| 386 | + goto error_noput; | |
| 387 | + | |
| 381 | 388 | cell_already_exists: |
| 382 | 389 | _debug("cell exists"); |
| 383 | 390 | cell = cursor; |
| @@ -547,6 +554,8 @@ static int afs_update_cell(struct afs_cell *cell) · 163 unmodified lines | ||
| 547 | 554 | rcu_assign_pointer(cell->vl_servers, vllist); |
| 548 | 555 | cell->dns_source = vllist->source; |
| 549 | 556 | old = p; |
| 557 | + } else { | |
| 558 | + old = vllist; | |
| 550 | 559 | } |
| 551 | 560 | write_unlock(&cell->vl_servers_lock); |
| 552 | 561 | afs_put_vlserverlist(cell->net, old); |
| @@ -577,7 +586,6 @@ static void afs_cell_destroy(struct rcu_head *rcu) · 24 unmodified lines | ||
| 577 | 586 | afs_put_vlserverlist(net, rcu_access_pointer(cell->vl_servers)); |
| 578 | 587 | afs_unuse_cell(cell->alias_of, afs_cell_trace_unuse_alias); |
| 579 | 588 | key_put(cell->anonymous_key); |
| 580 | − idr_remove(&net->cells_dyn_ino, cell->dynroot_ino); | |
| 581 | 589 | kfree(cell->name - 1); |
| 582 | 590 | kfree(cell); |
| 583 | 591 | |
| @@ -592,6 +600,13 @@ static void afs_destroy_cell_work(struct work_struct *work) · 8 unmodified lines | ||
| 592 | 600 | afs_see_cell(cell, afs_cell_trace_destroy); |
| 593 | 601 | timer_delete_sync(&cell->management_timer); |
| 594 | 602 | cancel_work_sync(&cell->manager); |
| 603 | + | |
| 604 | + if (test_bit(AFS_CELL_FL_HAVE_INO, &cell->flags)) { | |
| 605 | + down_write(&cell->net->cells_lock); | |
| 606 | + idr_remove(&cell->net->cells_dyn_ino, cell->dynroot_ino); | |
| 607 | + up_write(&cell->net->cells_lock); | |
| 608 | + } | |
| 609 | + | |
| 595 | 610 | call_rcu(&cell->rcu, afs_cell_destroy); |
| 596 | 611 | } |
| 597 | 612 | |
| @@ -334,7 +334,6 @@ static int afs_deliver_cb_init_call_back_state3(struct afs_call *call) · 333 unmodified lines | ||
| 334 | 334 | ret = afs_extract_data(call, false); |
| 335 | 335 | switch (ret) { |
| 336 | 336 | case 0: break; |
| 337 | − case -EAGAIN: return 0; | |
| 338 | 337 | default: return ret; |
| 339 | 338 | } |
| 340 | 339 | |
| @@ -364,6 +363,11 @@ static int afs_deliver_cb_init_call_back_state3(struct afs_call *call) · 23 unmodified lines | ||
| 364 | 363 | if (!afs_check_call_state(call, AFS_CALL_SV_REPLYING)) |
| 365 | 364 | return afs_io_error(call, afs_io_error_cm_reply); |
| 366 | 365 | |
| 366 | + if (!call->server) { | |
| 367 | + trace_afs_cm_no_server_u(call, call->request); | |
| 368 | + return 0; | |
| 369 | + } | |
| 370 | + | |
| 367 | 371 | if (memcmp(call->request, &call->server->_uuid, sizeof(call->server->_uuid)) != 0) { |
| 368 | 372 | pr_notice("Callback UUID does not match fileserver UUID\n"); |
| 369 | 373 | trace_afs_cm_no_server_u(call, call->request); |
| @@ -451,7 +455,6 @@ static int afs_deliver_cb_probe_uuid(struct afs_call *call) · 81 unmodified lines | ||
| 451 | 455 | ret = afs_extract_data(call, false); |
| 452 | 456 | switch (ret) { |
| 453 | 457 | case 0: break; |
| 454 | − case -EAGAIN: return 0; | |
| 455 | 458 | default: return ret; |
| 456 | 459 | } |
| 457 | 460 | |
| @@ -28,9 +28,11 @@ static int afs_d_revalidate(struct inode *dir, const struct qstr *name, · 27 unmodified lines | ||
| 28 | 28 | static int afs_d_delete(const struct dentry *dentry); |
| 29 | 29 | static void afs_d_iput(struct dentry *dentry, struct inode *inode); |
| 30 | 30 | static bool afs_lookup_one_filldir(struct dir_context *ctx, const char *name, int nlen, |
| 31 | − loff_t fpos, u64 ino, unsigned dtype); | |
| 31 | + u64 ino, u32 uniquifier); | |
| 32 | +#define AFS_LOOKUP_ONE ((filldir_t)0x123UL) | |
| 32 | 33 | static bool afs_lookup_filldir(struct dir_context *ctx, const char *name, int nlen, |
| 33 | − loff_t fpos, u64 ino, unsigned dtype); | |
| 34 | + u64 ino, u32 uniquifier); | |
| 35 | +#define AFS_LOOKUP ((filldir_t)0x137UL) | |
| 34 | 36 | static int afs_create(struct mnt_idmap *idmap, struct inode *dir, |
| 35 | 37 | struct dentry *dentry, umode_t mode, bool excl); |
| 36 | 38 | static struct dentry *afs_mkdir(struct mnt_idmap *idmap, struct inode *dir, |
| @@ -421,11 +423,18 @@ static int afs_dir_iterate_block(struct afs_vnode *dvnode, · 384 unmodified lines | ||
| 421 | 423 | } |
| 422 | 424 | |
| 423 | 425 | /* found the next entry */ |
| 424 | − if (!dir_emit(ctx, dire->u.name, nlen, | |
| 425 | − ntohl(dire->u.vnode), | |
| 426 | − (ctx->actor == afs_lookup_filldir || | |
| 427 | − ctx->actor == afs_lookup_one_filldir)? | |
| 428 | − ntohl(dire->u.unique) : DT_UNKNOWN)) { | |
| 426 | + if (ctx->actor == AFS_LOOKUP) { | |
| 427 | + if (!afs_lookup_filldir(ctx, dire->u.name, nlen, | |
| 428 | + ntohl(dire->u.vnode), | |
| 429 | + ntohl(dire->u.unique))) | |
| 430 | + return 0; | |
| 431 | + } else if (ctx->actor == AFS_LOOKUP_ONE) { | |
| 432 | + if (!afs_lookup_one_filldir(ctx, dire->u.name, nlen, | |
| 433 | + ntohl(dire->u.vnode), | |
| 434 | + ntohl(dire->u.unique))) | |
| 435 | + return 0; | |
| 436 | + } else if (!dir_emit(ctx, dire->u.name, nlen, | |
| 437 | + ntohl(dire->u.vnode), DT_UNKNOWN)) { | |
| 429 | 438 | _leave(" = 0 [full]"); |
| 430 | 439 | return 0; |
| 431 | 440 | } |
| @@ -545,6 +554,7 @@ static int afs_readdir(struct file *file, struct dir_context *ctx) · 113 unmodified lines | ||
| 545 | 554 | { |
| 546 | 555 | afs_dataversion_t dir_version; |
| 547 | 556 | |
| 557 | + ctx->dt_flags_mask = UINT_MAX; | |
| 548 | 558 | return afs_dir_iterate(file_inode(file), ctx, file, &dir_version); |
| 549 | 559 | } |
| 550 | 560 | |
| @@ -554,14 +564,14 @@ static int afs_readdir(struct file *file, struct dir_context *ctx) · 3 unmodified lines | ||
| 554 | 564 | * uniquifier through dtype |
| 555 | 565 | */ |
| 556 | 566 | static bool afs_lookup_one_filldir(struct dir_context *ctx, const char *name, |
| 557 | − int nlen, loff_t fpos, u64 ino, unsigned dtype) | |
| 567 | + int nlen, u64 ino, u32 uniquifier) | |
| 558 | 568 | { |
| 559 | 569 | struct afs_lookup_one_cookie *cookie = |
| 560 | 570 | container_of(ctx, struct afs_lookup_one_cookie, ctx); |
| 561 | 571 | |
| 562 | 572 | _enter("{%s,%u},%s,%u,,%llu,%u", |
| 563 | 573 | cookie->name.name, cookie->name.len, name, nlen, |
| 564 | − (unsigned long long) ino, dtype); | |
| 574 | + (unsigned long long) ino, uniquifier); | |
| 565 | 575 | |
| 566 | 576 | /* insanity checks first */ |
| 567 | 577 | BUILD_BUG_ON(sizeof(union afs_xdr_dir_block) != 2048); |
| @@ -574,7 +584,7 @@ static bool afs_lookup_one_filldir(struct dir_context *ctx, const char *name, · 6 unmodified lines | ||
| 574 | 584 | } |
| 575 | 585 | |
| 576 | 586 | cookie->fid.vnode = ino; |
| 577 | − cookie->fid.unique = dtype; | |
| 587 | + cookie->fid.unique = uniquifier; | |
| 578 | 588 | cookie->found = 1; |
| 579 | 589 | |
| 580 | 590 | _leave(" = false [found]"); |
| @@ -591,7 +601,7 @@ static int afs_do_lookup_one(struct inode *dir, const struct qstr *name, · 10 unmodified lines | ||
| 591 | 601 | { |
| 592 | 602 | struct afs_super_info *as = dir->i_sb->s_fs_info; |
| 593 | 603 | struct afs_lookup_one_cookie cookie = { |
| 594 | − .ctx.actor = afs_lookup_one_filldir, | |
| 604 | + .ctx.actor = AFS_LOOKUP_ONE, | |
| 595 | 605 | .name = *name, |
| 596 | 606 | .fid.vid = as->volume->vid |
| 597 | 607 | }; |
| @@ -622,14 +632,14 @@ static int afs_do_lookup_one(struct inode *dir, const struct qstr *name, · 24 unmodified lines | ||
| 622 | 632 | * uniquifier through dtype |
| 623 | 633 | */ |
| 624 | 634 | static bool afs_lookup_filldir(struct dir_context *ctx, const char *name, |
| 625 | − int nlen, loff_t fpos, u64 ino, unsigned dtype) | |
| 635 | + int nlen, u64 ino, u32 uniquifier) | |
| 626 | 636 | { |
| 627 | 637 | struct afs_lookup_cookie *cookie = |
| 628 | 638 | container_of(ctx, struct afs_lookup_cookie, ctx); |
| 629 | 639 | |
| 630 | 640 | _enter("{%s,%u},%s,%u,,%llu,%u", |
| 631 | 641 | cookie->name.name, cookie->name.len, name, nlen, |
| 632 | − (unsigned long long) ino, dtype); | |
| 642 | + (unsigned long long) ino, uniquifier); | |
| 633 | 643 | |
| 634 | 644 | /* insanity checks first */ |
| 635 | 645 | BUILD_BUG_ON(sizeof(union afs_xdr_dir_block) != 2048); |
| @@ -637,7 +647,7 @@ static bool afs_lookup_filldir(struct dir_context *ctx, const char *name, · 1 unmodified line | ||
| 637 | 647 | |
| 638 | 648 | if (cookie->nr_fids < 50) { |
| 639 | 649 | cookie->fids[cookie->nr_fids].vnode = ino; |
| 640 | − cookie->fids[cookie->nr_fids].unique = dtype; | |
| 650 | + cookie->fids[cookie->nr_fids].unique = uniquifier; | |
| 641 | 651 | cookie->nr_fids++; |
| 642 | 652 | } |
| 643 | 653 | |
| @@ -778,7 +788,7 @@ static struct inode *afs_do_lookup(struct inode *dir, struct dentry *dentry) · 134 unmodified lines | ||
| 778 | 788 | |
| 779 | 789 | for (i = 0; i < ARRAY_SIZE(cookie->fids); i++) |
| 780 | 790 | cookie->fids[i].vid = dvnode->fid.vid; |
| 781 | − cookie->ctx.actor = afs_lookup_filldir; | |
| 791 | + cookie->ctx.actor = AFS_LOOKUP; | |
| 782 | 792 | cookie->name = dentry->d_name; |
| 783 | 793 | cookie->nr_fids = 2; /* slot 1 is saved for the fid we actually want |
| 784 | 794 | * and slot 0 for the directory */ |
| @@ -278,7 +278,7 @@ static struct dentry *afs_lookup_atcell(struct inode *dir, struct dentry *dentry · 277 unmodified lines | ||
| 278 | 278 | } |
| 279 | 279 | |
| 280 | 280 | /* |
| 281 | − * Transcribe the cell database into readdir content under the RCU read lock. | |
| 281 | + * Transcribe the cell database into readdir content under net->cells_lock. | |
| 282 | 282 | * Each cell produces two entries, one prefixed with a dot and one not. |
| 283 | 283 | */ |
| 284 | 284 | static int afs_dynroot_readdir_cells(struct afs_net *net, struct dir_context *ctx) |
| @@ -348,7 +348,7 @@ int afs_put_operation(struct afs_operation *op) · 347 unmodified lines | ||
| 348 | 348 | for (i = 0; i < op->nr_files - 2; i++) |
| 349 | 349 | if (op->more_files[i].put_vnode) |
| 350 | 350 | iput(&op->more_files[i].vnode->netfs.inode); |
| 351 | − kfree(op->more_files); | |
| 351 | + kvfree(op->more_files); | |
| 352 | 352 | } |
| 353 | 353 | |
| 354 | 354 | if (op->estate) { |
| @@ -52,9 +52,9 @@ static noinline void dump_vnode(struct afs_vnode *vnode, struct afs_vnode *paren · 51 unmodified lines | ||
| 52 | 52 | /* |
| 53 | 53 | * Set parameters for the netfs library |
| 54 | 54 | */ |
| 55 | −static void afs_set_netfs_context(struct afs_vnode *vnode) | |
| 55 | +static void afs_set_netfs_context(struct afs_vnode *vnode, bool is_file) | |
| 56 | 56 | { |
| 57 | − netfs_inode_init(&vnode->netfs, &afs_req_ops, true); | |
| 57 | + netfs_inode_init(&vnode->netfs, &afs_req_ops, is_file); | |
| 58 | 58 | } |
| 59 | 59 | |
| 60 | 60 | /* |
| @@ -93,6 +93,10 @@ static int afs_inode_init_from_status(struct afs_operation *op, · 32 unmodified lines | ||
| 93 | 93 | inode->i_gid = make_kgid(&init_user_ns, status->group); |
| 94 | 94 | set_nlink(&vnode->netfs.inode, status->nlink); |
| 95 | 95 | |
| 96 | + i_size_write(inode, status->size); | |
| 97 | + inode_set_bytes(inode, status->size); | |
| 98 | + afs_set_netfs_context(vnode, status->type == AFS_FTYPE_FILE); | |
| 99 | + | |
| 96 | 100 | switch (status->type) { |
| 97 | 101 | case AFS_FTYPE_FILE: |
| 98 | 102 | inode->i_mode = S_IFREG | (status->mode & S_IALLUGO); |
| @@ -126,7 +130,6 @@ static int afs_inode_init_from_status(struct afs_operation *op, · 27 unmodified lines | ||
| 126 | 130 | } |
| 127 | 131 | inode->i_mapping->a_ops = &afs_symlink_aops; |
| 128 | 132 | inode_nohighmem(inode); |
| 129 | − mapping_set_release_always(inode->i_mapping); | |
| 130 | 133 | break; |
| 131 | 134 | default: |
| 132 | 135 | dump_vnode(vnode, op->file[0].vnode != vnode ? op->file[0].vnode : NULL); |
| @@ -134,10 +137,6 @@ static int afs_inode_init_from_status(struct afs_operation *op, · 1 unmodified line | ||
| 134 | 137 | return afs_protocol_error(NULL, afs_eproto_file_type); |
| 135 | 138 | } |
| 136 | 139 | |
| 137 | − i_size_write(inode, status->size); | |
| 138 | − inode_set_bytes(inode, status->size); | |
| 139 | − afs_set_netfs_context(vnode); | |
| 140 | − | |
| 141 | 140 | vnode->invalid_before = status->data_version; |
| 142 | 141 | trace_afs_set_dv(vnode, status->data_version); |
| 143 | 142 | inode_set_iversion_raw(&vnode->netfs.inode, status->data_version); |
| @@ -566,7 +565,6 @@ struct inode *afs_root_iget(struct super_block *sb, struct key *key) · 422 unmodified lines | ||
| 566 | 565 | |
| 567 | 566 | vnode = AFS_FS_I(inode); |
| 568 | 567 | vnode->cb_v_check = atomic_read(&as->volume->cb_v_break); |
| 569 | − afs_set_netfs_context(vnode); | |
| 570 | 568 | |
| 571 | 569 | op = afs_alloc_operation(key, as->volume); |
| 572 | 570 | if (IS_ERR(op)) { |
| @@ -682,6 +680,7 @@ void afs_evict_inode(struct inode *inode) · 109 unmodified lines | ||
| 682 | 680 | inode->i_mapping->a_ops->writepages(inode->i_mapping, &wbc); |
| 683 | 681 | } |
| 684 | 682 | |
| 683 | + flush_delayed_work(&vnode->lock_work); | |
| 685 | 684 | netfs_wait_for_outstanding_io(inode); |
| 686 | 685 | truncate_inode_pages_final(&inode->i_data); |
| 687 | 686 | netfs_free_folioq_buffer(vnode->directory); |
| @@ -388,6 +388,7 @@ struct afs_cell { · 387 unmodified lines | ||
| 388 | 388 | #define AFS_CELL_FL_NO_GC 0 /* The cell was added manually, don't auto-gc */ |
| 389 | 389 | #define AFS_CELL_FL_DO_LOOKUP 1 /* DNS lookup requested */ |
| 390 | 390 | #define AFS_CELL_FL_CHECK_ALIAS 2 /* Need to check for aliases */ |
| 391 | +#define AFS_CELL_FL_HAVE_INO 3 /* Have dynroot_ino */ | |
| 391 | 392 | enum afs_cell_state state; |
| 392 | 393 | short error; |
| 393 | 394 | enum dns_record_source dns_source:8; /* Latest source of data from lookup */ |
| @@ -750,8 +751,6 @@ static inline void afs_vnode_set_cache(struct afs_vnode *vnode, · 356 unmodified lines | ||
| 750 | 751 | { |
| 751 | 752 | #ifdef CONFIG_AFS_FSCACHE |
| 752 | 753 | vnode->netfs.cache = cookie; |
| 753 | − if (cookie) | |
| 754 | − mapping_set_release_always(vnode->netfs.inode.i_mapping); | |
| 755 | 754 | #endif |
| 756 | 755 | } |
| 757 | 756 | |
| @@ -587,7 +587,8 @@ static int afs_get_tree(struct fs_context *fc) · 586 unmodified lines | ||
| 587 | 587 | } |
| 588 | 588 | |
| 589 | 589 | fc->root = dget(sb->s_root); |
| 590 | − trace_afs_get_tree(as->cell, as->volume); | |
| 590 | + if (!ctx->dyn_root) | |
| 591 | + trace_afs_get_tree(as->cell, as->volume); | |
| 591 | 592 | _leave(" = 0 [%p]", sb); |
| 592 | 593 | return 0; |
| 593 | 594 | |
| @@ -659,7 +660,6 @@ static void afs_i_init_once(void *_vnode) · 65 unmodified lines | ||
| 659 | 660 | INIT_LIST_HEAD(&vnode->wb_keys); |
| 660 | 661 | INIT_LIST_HEAD(&vnode->pending_locks); |
| 661 | 662 | INIT_LIST_HEAD(&vnode->granted_locks); |
| 662 | − INIT_DELAYED_WORK(&vnode->lock_work, afs_lock_work); | |
| 663 | 663 | INIT_LIST_HEAD(&vnode->cb_mmap_link); |
| 664 | 664 | seqlock_init(&vnode->cb_lock); |
| 665 | 665 | } |
| @@ -693,6 +693,7 @@ static struct inode *afs_alloc_inode(struct super_block *sb) · 27 unmodified lines | ||
| 693 | 693 | |
| 694 | 694 | init_rwsem(&vnode->rmdir_lock); |
| 695 | 695 | INIT_WORK(&vnode->cb_work, afs_invalidate_mmap_work); |
| 696 | + INIT_DELAYED_WORK(&vnode->lock_work, afs_lock_work); | |
| 696 | 697 | |
| 697 | 698 | _leave(" = %p", &vnode->netfs.inode); |
| 698 | 699 | return &vnode->netfs.inode; |
| @@ -255,11 +255,11 @@ int afs_symlink_writepages(struct address_space *mapping, · 254 unmodified lines | ||
| 255 | 255 | } |
| 256 | 256 | |
| 257 | 257 | if (ret == 0) { |
| 258 | − mutex_lock(&vnode->netfs.wb_lock); | |
| 258 | + netfs_wb_begin(&vnode->netfs, false); | |
| 259 | 259 | netfs_free_folioq_buffer(vnode->directory); |
| 260 | 260 | vnode->directory = NULL; |
| 261 | 261 | vnode->directory_size = 0; |
| 262 | − mutex_unlock(&vnode->netfs.wb_lock); | |
| 262 | + netfs_wb_end(&vnode->netfs); | |
| 263 | 263 | } else if (ret == 1) { |
| 264 | 264 | ret = 0; /* Skipped write due to lock conflict. */ |
| 265 | 265 | } |
| @@ -92,7 +92,7 @@ static struct afs_addr_list *afs_extract_vl_addrs(struct afs_net *net, · 91 unmodified lines | ||
| 92 | 92 | { |
| 93 | 93 | struct afs_addr_list *alist; |
| 94 | 94 | const u8 *b = *_b; |
| 95 | − int ret = -EINVAL; | |
| 95 | + int ret; | |
| 96 | 96 | |
| 97 | 97 | alist = afs_alloc_addrlist(nr_addrs); |
| 98 | 98 | if (!alist) |
| @@ -110,6 +110,7 @@ static struct afs_addr_list *afs_extract_vl_addrs(struct afs_net *net, · 11 unmodified lines | ||
| 110 | 110 | case DNS_ADDRESS_IS_IPV4: |
| 111 | 111 | if (end - b < 4) { |
| 112 | 112 | _leave(" = -EINVAL [short inet]"); |
| 113 | + ret = -EINVAL; | |
| 113 | 114 | goto error; |
| 114 | 115 | } |
| 115 | 116 | memcpy(x, b, 4); |
| @@ -122,6 +123,7 @@ static struct afs_addr_list *afs_extract_vl_addrs(struct afs_net *net, · 6 unmodified lines | ||
| 122 | 123 | case DNS_ADDRESS_IS_IPV6: |
| 123 | 124 | if (end - b < 16) { |
| 124 | 125 | _leave(" = -EINVAL [short inet6]"); |
| 126 | + ret = -EINVAL; | |
| 125 | 127 | goto error; |
| 126 | 128 | } |
| 127 | 129 | memcpy(x, b, 16); |
| @@ -198,6 +200,8 @@ struct afs_vlserver_list *afs_extract_vlserver_list(struct afs_cell *cell, · 70 unmodified lines | ||
| 198 | 200 | |
| 199 | 201 | b += sizeof(*hdr); |
| 200 | 202 | while (end - b >= sizeof(bs)) { |
| 203 | + int nlen; | |
| 204 | + | |
| 201 | 205 | bs.name_len = afs_extract_le16(&b); |
| 202 | 206 | bs.priority = afs_extract_le16(&b); |
| 203 | 207 | bs.weight = afs_extract_le16(&b); |
| @@ -207,10 +211,12 @@ struct afs_vlserver_list *afs_extract_vlserver_list(struct afs_cell *cell, · 3 unmodified lines | ||
| 207 | 211 | bs.protocol = *b++; |
| 208 | 212 | bs.nr_addrs = *b++; |
| 209 | 213 | |
| 214 | + nlen = min3(bs.name_len, end - b, 255); | |
| 215 | + | |
| 210 | 216 | _debug("extract %u %u %u %u %u %u %*.*s", |
| 211 | 217 | bs.name_len, bs.priority, bs.weight, |
| 212 | 218 | bs.port, bs.protocol, bs.nr_addrs, |
| 213 | − bs.name_len, bs.name_len, b); | |
| 219 | + bs.name_len, nlen, b); | |
| 214 | 220 | |
| 215 | 221 | if (end - b < bs.name_len) |
| 216 | 222 | break; |
| @@ -287,8 +293,20 @@ struct afs_vlserver_list *afs_extract_vlserver_list(struct afs_cell *cell, · 70 unmodified lines | ||
| 287 | 293 | afs_put_addrlist(old, afs_alist_trace_put_vlserver_old); |
| 288 | 294 | } |
| 289 | 295 | |
| 296 | + /* Check for duplicates in the server list */ | |
| 297 | + for (j = 0; j < vllist->nr_servers; j++) { | |
| 298 | + struct afs_vlserver *s = vllist->servers[j].server; | |
| 290 | 299 | |
| 291 | − /* TODO: Might want to check for duplicates */ | |
| 300 | + if (s->name_len == server->name_len && | |
| 301 | + s->port == server->port && | |
| 302 | + strncasecmp(s->name, server->name, server->name_len) == 0) { | |
| 303 | + afs_put_vlserver(cell->net, server); | |
| 304 | + server = NULL; | |
| 305 | + break; | |
| 306 | + } | |
| 307 | + } | |
| 308 | + if (!server) | |
| 309 | + continue; | |
| 292 | 310 | |
| 293 | 311 | /* Insertion-sort by priority and weight */ |
| 294 | 312 | for (j = 0; j < vllist->nr_servers; j++) { |
| @@ -40,7 +40,7 @@ static struct afs_volume *afs_insert_volume_into_cell(struct afs_cell *cell, · 39 unmodified lines | ||
| 40 | 40 | goto found; |
| 41 | 41 | } |
| 42 | 42 | |
| 43 | − set_bit(AFS_VOLUME_RM_TREE, &volume->flags); | |
| 43 | + set_bit(AFS_VOLUME_RM_TREE, &p->flags); | |
| 44 | 44 | rb_replace_node_rcu(&p->cell_node, &volume->cell_node, &cell->volumes); |
| 45 | 45 | } |
| 46 | 46 | } |
| @@ -360,18 +360,23 @@ __bpf_kfunc int bpf_cgroup_read_xattr(struct cgroup *cgroup, const char *name__s · 359 unmodified lines | ||
| 360 | 360 | #endif /* CONFIG_CGROUPS */ |
| 361 | 361 | |
| 362 | 362 | /** |
| 363 | − * bpf_real_inode - get the real inode backing a dentry | |
| 364 | − * @dentry: dentry to resolve | |
| 363 | + * bpf_real_data_inode - get the real inode hosting a file's data | |
| 364 | + * @file: file to resolve | |
| 365 | 365 | * |
| 366 | − * If the dentry is on a union/overlay filesystem, return the underlying, real | |
| 367 | − * inode that hosts the data. Otherwise return the inode attached to the | |
| 368 | − * dentry itself. | |
| 366 | + * Resolve @file to the inode that hosts its data. For a regular file on a | |
| 367 | + * union/overlay filesystem this is the underlying (upper or lower) inode that | |
| 368 | + * stores the data, not the overlay inode. | |
| 369 | 369 | * |
| 370 | − * Return: The real inode backing the dentry, or NULL for a negative dentry. | |
| 370 | + * Data resolution only applies to regular files. For a non-regular file (e.g. | |
| 371 | + * a device node, fifo or socket) on a union/overlay filesystem the overlay | |
| 372 | + * inode itself is returned; for any file on a non-union filesystem the inode | |
| 373 | + * attached to @file is returned. | |
| 374 | + * | |
| 375 | + * Return: The inode hosting @file's data, or NULL. | |
| 371 | 376 | */ |
| 372 | −__bpf_kfunc struct inode *bpf_real_inode(struct dentry *dentry) | |
| 377 | +__bpf_kfunc struct inode *bpf_real_data_inode(struct file *file) | |
| 373 | 378 | { |
| 374 | − return d_real_inode(dentry); | |
| 379 | + return d_real_inode(file_dentry(file)); | |
| 375 | 380 | } |
| 376 | 381 | |
| 377 | 382 | __bpf_kfunc_end_defs(); |
| @@ -384,7 +389,7 @@ BTF_ID_FLAGS(func, bpf_get_dentry_xattr, KF_SLEEPABLE) · 6 unmodified lines | ||
| 384 | 389 | BTF_ID_FLAGS(func, bpf_get_file_xattr, KF_SLEEPABLE) |
| 385 | 390 | BTF_ID_FLAGS(func, bpf_set_dentry_xattr, KF_SLEEPABLE) |
| 386 | 391 | BTF_ID_FLAGS(func, bpf_remove_dentry_xattr, KF_SLEEPABLE) |
| 387 | −BTF_ID_FLAGS(func, bpf_real_inode, KF_SLEEPABLE | KF_RET_NULL) | |
| 392 | +BTF_ID_FLAGS(func, bpf_real_data_inode, KF_SLEEPABLE | KF_RET_NULL) | |
| 388 | 393 | BTF_KFUNCS_END(bpf_fs_kfunc_set_ids) |
| 389 | 394 | |
| 390 | 395 | static int bpf_fs_kfuncs_filter(const struct bpf_prog *prog, u32 kfunc_id) |
| @@ -209,7 +209,6 @@ lookup_error: · 208 unmodified lines | ||
| 209 | 209 | return ERR_PTR(ret); |
| 210 | 210 | |
| 211 | 211 | nomem_d_alloc: |
| 212 | − inode_unlock(d_inode(dir)); | |
| 213 | 212 | _leave(" = -ENOMEM"); |
| 214 | 213 | return ERR_PTR(-ENOMEM); |
| 215 | 214 | } |
| @@ -375,7 +374,7 @@ try_again: · 159 unmodified lines | ||
| 375 | 374 | "Rename failed with error %d", ret); |
| 376 | 375 | } |
| 377 | 376 | |
| 378 | − __cachefiles_unmark_inode_in_use(object, d_inode(rep)); | |
| 377 | + cachefiles_do_unmark_inode_in_use(object, d_inode(rep)); | |
| 379 | 378 | end_renaming(&rd); |
| 380 | 379 | _leave(" = 0"); |
| 381 | 380 | return 0; |
| @@ -467,7 +466,6 @@ struct file *cachefiles_create_tmpfile(struct cachefiles_object *object) · 85 unmodified lines | ||
| 467 | 466 | ret = -EINVAL; |
| 468 | 467 | if (unlikely(!file->f_op->read_iter) || |
| 469 | 468 | unlikely(!file->f_op->write_iter)) { |
| 470 | − fput(file); | |
| 471 | 469 | pr_notice("Cache does not support read_iter and write_iter\n"); |
| 472 | 470 | goto err_unuse; |
| 473 | 471 | } |
| @@ -1717,7 +1717,7 @@ static int exec_binprm(struct linux_binprm *bprm) · 1716 unmodified lines | ||
| 1717 | 1717 | old_vpid = task_pid_nr_ns(current, task_active_pid_ns(current->parent)); |
| 1718 | 1718 | rcu_read_unlock(); |
| 1719 | 1719 | |
| 1720 | − /* This allows 4 levels of binfmt rewrites before failing hard. */ | |
| 1720 | + /* This allows 5 levels of binfmt rewrites before failing hard. */ | |
| 1721 | 1721 | for (depth = 0;; depth++) { |
| 1722 | 1722 | struct file *exec; |
| 1723 | 1723 | if (depth > 5) |
| @@ -253,10 +253,7 @@ static void exfat_iomap_read_end_io(struct bio *bio) · 252 unmodified lines | ||
| 253 | 253 | static void exfat_iomap_bio_submit_read(const struct iomap_iter *iter, |
| 254 | 254 | struct iomap_read_folio_ctx *ctx) |
| 255 | 255 | { |
| 256 | − struct bio *bio = ctx->read_ctx; | |
| 257 | − | |
| 258 | − bio->bi_end_io = exfat_iomap_read_end_io; | |
| 259 | − submit_bio(bio); | |
| 256 | + iomap_bio_submit_read_endio(iter, ctx, exfat_iomap_read_end_io); | |
| 260 | 257 | } |
| 261 | 258 | |
| 262 | 259 | const struct iomap_read_ops exfat_iomap_bio_read_ops = { |
| @@ -130,6 +130,31 @@ static inline int fat_get_entry(struct inode *dir, loff_t *pos, · 129 unmodified lines | ||
| 130 | 130 | return fat__get_entry(dir, pos, bh, de); |
| 131 | 131 | } |
| 132 | 132 | |
| 133 | +/* | |
| 134 | + * Like fat_get_entry(), but honour the FAT end-of-directory marker: | |
| 135 | + * a dirent whose first name byte is NUL terminates iteration per the | |
| 136 | + * spec, which also guarantees that every following slot is zeroed. | |
| 137 | + * Skip straight to the end of the directory so the next call returns | |
| 138 | + * -1 from fat_bmap() without re-reading the trailing zero slots, and | |
| 139 | + * so callers that persist *pos across invocations (e.g. readdir's | |
| 140 | + * ctx->pos) keep reporting EOD. Release *bh and set it to NULL to | |
| 141 | + * match fat_get_entry()'s contract that *bh is NULL on the -1 return. | |
| 142 | + */ | |
| 143 | +static int fat_get_entry_eod(struct inode *dir, loff_t *pos, | |
| 144 | + struct buffer_head **bh, | |
| 145 | + struct msdos_dir_entry **de) | |
| 146 | +{ | |
| 147 | + int err = fat_get_entry(dir, pos, bh, de); | |
| 148 | + | |
| 149 | + if (err == 0 && (*de)->name[0] == 0) { | |
| 150 | + brelse(*bh); | |
| 151 | + *bh = NULL; | |
| 152 | + *pos = dir->i_size; | |
| 153 | + return -1; | |
| 154 | + } | |
| 155 | + return err; | |
| 156 | +} | |
| 157 | + | |
| 133 | 158 | /* |
| 134 | 159 | * Convert Unicode 16 to UTF-8, translated Unicode, or ASCII. |
| 135 | 160 | * If uni_xlate is enabled and we can't get a 1:1 conversion, use a |
| @@ -327,7 +352,7 @@ parse_long: · 191 unmodified lines | ||
| 327 | 352 | |
| 328 | 353 | if (ds->id & 0x40) |
| 329 | 354 | (*unicode)[offset + 13] = 0; |
| 330 | − if (fat_get_entry(dir, pos, bh, de) < 0) | |
| 355 | + if (fat_get_entry_eod(dir, pos, bh, de) < 0) | |
| 331 | 356 | return PARSE_EOF; |
| 332 | 357 | if (slot == 0) |
| 333 | 358 | break; |
| @@ -489,7 +514,7 @@ int fat_search_long(struct inode *inode, const unsigned char *name, · 155 unmodified lines | ||
| 489 | 514 | |
| 490 | 515 | err = -ENOENT; |
| 491 | 516 | while (1) { |
| 492 | − if (fat_get_entry(inode, &cpos, &bh, &de) == -1) | |
| 517 | + if (fat_get_entry_eod(inode, &cpos, &bh, &de) == -1) | |
| 493 | 518 | goto end_of_dir; |
| 494 | 519 | parse_record: |
| 495 | 520 | nr_slots = 0; |
| @@ -601,7 +626,7 @@ static int __fat_readdir(struct inode *inode, struct file *file, · 105 unmodified lines | ||
| 601 | 626 | |
| 602 | 627 | bh = NULL; |
| 603 | 628 | get_new: |
| 604 | − if (fat_get_entry(inode, &cpos, &bh, &de) == -1) | |
| 629 | + if (fat_get_entry_eod(inode, &cpos, &bh, &de) == -1) | |
| 605 | 630 | goto end_of_dir; |
| 606 | 631 | parse_record: |
| 607 | 632 | nr_slots = 0; |
| @@ -885,7 +910,7 @@ static int fat_get_short_entry(struct inode *dir, loff_t *pos, · 277 unmodified lines | ||
| 885 | 910 | struct buffer_head **bh, |
| 886 | 911 | struct msdos_dir_entry **de) |
| 887 | 912 | { |
| 888 | − while (fat_get_entry(dir, pos, bh, de) >= 0) { | |
| 913 | + while (fat_get_entry_eod(dir, pos, bh, de) >= 0) { | |
| 889 | 914 | /* free entry or long name entry or volume label */ |
| 890 | 915 | if (!IS_FREE((*de)->name) && !((*de)->attr & ATTR_VOLUME)) |
| 891 | 916 | return 0; |
| @@ -1302,6 +1327,7 @@ int fat_add_entries(struct inode *dir, void *slots, int nr_slots, · 410 unmodified lines | ||
| 1302 | 1327 | struct msdos_dir_entry *de; |
| 1303 | 1328 | int err, free_slots, i, nr_bhs; |
| 1304 | 1329 | loff_t pos; |
| 1330 | + bool saw_eod; | |
| 1305 | 1331 | |
| 1306 | 1332 | sinfo->nr_slots = nr_slots; |
| 1307 | 1333 | |
| @@ -1310,12 +1336,15 @@ int fat_add_entries(struct inode *dir, void *slots, int nr_slots, · 2 unmodified lines | ||
| 1310 | 1336 | bh = prev = NULL; |
| 1311 | 1337 | pos = 0; |
| 1312 | 1338 | err = -ENOSPC; |
| 1339 | + saw_eod = false; | |
| 1313 | 1340 | while (fat_get_entry(dir, &pos, &bh, &de) > -1) { |
| 1314 | 1341 | /* check the maximum size of directory */ |
| 1315 | 1342 | if (pos >= FAT_MAX_DIR_SIZE) |
| 1316 | 1343 | goto error; |
| 1317 | 1344 | |
| 1318 | 1345 | if (IS_FREE(de->name)) { |
| 1346 | + if (de->name[0] == 0) | |
| 1347 | + saw_eod = true; | |
| 1319 | 1348 | if (prev != bh) { |
| 1320 | 1349 | get_bh(bh); |
| 1321 | 1350 | bhs[nr_bhs] = prev = bh; |
| @@ -1325,6 +1354,13 @@ int fat_add_entries(struct inode *dir, void *slots, int nr_slots, · 3 unmodified lines | ||
| 1325 | 1354 | if (free_slots == nr_slots) |
| 1326 | 1355 | goto found; |
| 1327 | 1356 | } else { |
| 1357 | + if (saw_eod) { | |
| 1358 | + fat_fs_error_ratelimit(sb, | |
| 1359 | + "allocated dir entry found after end-of-directory marker (i_pos %lld)", | |
| 1360 | + MSDOS_I(dir)->i_pos); | |
| 1361 | + err = -EIO; | |
| 1362 | + goto error; | |
| 1363 | + } | |
| 1328 | 1364 | for (i = 0; i < nr_bhs; i++) |
| 1329 | 1365 | brelse(bhs[i]); |
| 1330 | 1366 | prev = NULL; |
| @@ -295,7 +295,7 @@ static bool capable_wrt_mount(struct mount *mount) · 294 unmodified lines | ||
| 295 | 295 | */ |
| 296 | 296 | guard(rcu)(); |
| 297 | 297 | mnt_ns = READ_ONCE(mount->mnt_ns); |
| 298 | − return ns_capable(mnt_ns->user_ns, CAP_SYS_ADMIN); | |
| 298 | + return mnt_ns && ns_capable(mnt_ns->user_ns, CAP_SYS_ADMIN); | |
| 299 | 299 | } |
| 300 | 300 | |
| 301 | 301 | static inline int may_decode_fh(struct handle_to_path_ctx *ctx, |
| @@ -227,7 +227,8 @@ vxfs_bmap_typed(struct inode *ip, long iblock) · 226 unmodified lines | ||
| 227 | 227 | return 0; |
| 228 | 228 | } |
| 229 | 229 | default: |
| 230 | − BUG(); | |
| 230 | + WARN_ON_ONCE(1); | |
| 231 | + return 0; | |
| 231 | 232 | } |
| 232 | 233 | } |
| 233 | 234 | |
| @@ -981,19 +981,8 @@ static int fuse_iomap_read_folio_range_async(const struct iomap_iter *iter, · 980 unmodified lines | ||
| 981 | 981 | return ret; |
| 982 | 982 | } |
| 983 | 983 | |
| 984 | −static void fuse_iomap_submit_read(const struct iomap_iter *iter, | |
| 985 | − struct iomap_read_folio_ctx *ctx) | |
| 986 | −{ | |
| 987 | − struct fuse_fill_read_data *data = ctx->read_ctx; | |
| 988 | − | |
| 989 | − if (data->ia) | |
| 990 | − fuse_send_readpages(data->ia, data->file, data->nr_bytes, | |
| 991 | − data->fc->async_read); | |
| 992 | −} | |
| 993 | − | |
| 994 | 984 | static const struct iomap_read_ops fuse_iomap_read_ops = { |
| 995 | 985 | .read_folio_range = fuse_iomap_read_folio_range_async, |
| 996 | − .submit_read = fuse_iomap_submit_read, | |
| 997 | 986 | }; |
| 998 | 987 | |
| 999 | 988 | static int fuse_read_folio(struct file *file, struct folio *folio) |
| @@ -1116,6 +1105,9 @@ static void fuse_readahead(struct readahead_control *rac) · 116 unmodified lines | ||
| 1116 | 1105 | return; |
| 1117 | 1106 | |
| 1118 | 1107 | iomap_readahead(&fuse_iomap_ops, &ctx, NULL); |
| 1108 | + if (data.ia) | |
| 1109 | + fuse_send_readpages(data.ia, data.file, data.nr_bytes, | |
| 1110 | + fc->async_read); | |
| 1119 | 1111 | } |
| 1120 | 1112 | |
| 1121 | 1113 | static ssize_t fuse_cache_read_iter(struct kiocb *iocb, struct iov_iter *to) |
| @@ -78,14 +78,24 @@ u32 iomap_finish_ioend_buffered_read(struct iomap_ioend *ioend) · 77 unmodified lines | ||
| 78 | 78 | return __iomap_read_end_io(&ioend->io_bio, ioend->io_error); |
| 79 | 79 | } |
| 80 | 80 | |
| 81 | −static void iomap_bio_submit_read(const struct iomap_iter *iter, | |
| 82 | − struct iomap_read_folio_ctx *ctx) | |
| 81 | +void iomap_bio_submit_read_endio(const struct iomap_iter *iter, | |
| 82 | + struct iomap_read_folio_ctx *ctx, bio_end_io_t end_io) | |
| 83 | 83 | { |
| 84 | 84 | struct bio *bio = ctx->read_ctx; |
| 85 | 85 | |
| 86 | + bio->bi_end_io = end_io; | |
| 86 | 87 | if (iter->iomap.flags & IOMAP_F_INTEGRITY) |
| 87 | 88 | fs_bio_integrity_alloc(bio); |
| 88 | 89 | submit_bio(bio); |
| 90 | + | |
| 91 | + ctx->read_ctx = NULL; | |
| 92 | +} | |
| 93 | +EXPORT_SYMBOL_GPL(iomap_bio_submit_read_endio); | |
| 94 | + | |
| 95 | +static void iomap_bio_submit_read(const struct iomap_iter *iter, | |
| 96 | + struct iomap_read_folio_ctx *ctx) | |
| 97 | +{ | |
| 98 | + return iomap_bio_submit_read_endio(iter, ctx, iomap_read_end_io); | |
| 89 | 99 | } |
| 90 | 100 | |
| 91 | 101 | static struct bio_set *iomap_read_bio_set(struct iomap_read_folio_ctx *ctx) |
| @@ -127,7 +137,6 @@ static void iomap_read_alloc_bio(const struct iomap_iter *iter, · 35 unmodified lines | ||
| 127 | 137 | if (ctx->rac) |
| 128 | 138 | bio->bi_opf |= REQ_RAHEAD; |
| 129 | 139 | bio->bi_iter.bi_sector = iomap_sector(iomap, iter->pos); |
| 130 | − bio->bi_end_io = iomap_read_end_io; | |
| 131 | 140 | bio_add_folio_nofail(bio, folio, plen, |
| 132 | 141 | offset_in_folio(folio, iter->pos)); |
| 133 | 142 | ctx->read_ctx = bio; |
| @@ -642,12 +642,12 @@ void iomap_read_folio(const struct iomap_ops *ops, · 641 unmodified lines | ||
| 642 | 642 | fsverity_readahead(ctx->vi, folio->index, |
| 643 | 643 | folio_nr_pages(folio)); |
| 644 | 644 | |
| 645 | − while ((ret = iomap_iter(&iter, ops)) > 0) | |
| 645 | + while ((ret = iomap_iter(&iter, ops)) > 0) { | |
| 646 | 646 | iter.status = iomap_read_folio_iter(&iter, ctx, |
| 647 | 647 | &bytes_submitted); |
| 648 | − | |
| 649 | − if (ctx->read_ctx && ctx->ops->submit_read) | |
| 650 | − ctx->ops->submit_read(&iter, ctx); | |
| 648 | + if (ctx->read_ctx && ctx->ops->submit_read) | |
| 649 | + ctx->ops->submit_read(&iter, ctx); | |
| 650 | + } | |
| 651 | 651 | |
| 652 | 652 | if (ctx->cur_folio) |
| 653 | 653 | iomap_read_end(ctx->cur_folio, bytes_submitted); |
| @@ -718,12 +718,12 @@ void iomap_readahead(const struct iomap_ops *ops, · 64 unmodified lines | ||
| 718 | 718 | fsverity_readahead(ctx->vi, readahead_index(rac), |
| 719 | 719 | readahead_count(rac)); |
| 720 | 720 | |
| 721 | − while (iomap_iter(&iter, ops) > 0) | |
| 721 | + while (iomap_iter(&iter, ops) > 0) { | |
| 722 | 722 | iter.status = iomap_readahead_iter(&iter, ctx, |
| 723 | 723 | &cur_bytes_submitted); |
| 724 | − | |
| 725 | − if (ctx->read_ctx && ctx->ops->submit_read) | |
| 726 | − ctx->ops->submit_read(&iter, ctx); | |
| 724 | + if (ctx->read_ctx && ctx->ops->submit_read) | |
| 725 | + ctx->ops->submit_read(&iter, ctx); | |
| 726 | + } | |
| 727 | 727 | |
| 728 | 728 | if (ctx->cur_folio) |
| 729 | 729 | iomap_read_end(ctx->cur_folio, cur_bytes_submitted); |
| @@ -369,7 +369,7 @@ static ssize_t iomap_dio_bio_iter_one(struct iomap_iter *iter, · 368 unmodified lines | ||
| 369 | 369 | */ |
| 370 | 370 | if ((op & REQ_ATOMIC) && WARN_ON_ONCE(ret != iomap_length(iter))) { |
| 371 | 371 | ret = -EINVAL; |
| 372 | − goto out_put_bio; | |
| 372 | + goto out_bio_release_pages; | |
| 373 | 373 | } |
| 374 | 374 | |
| 375 | 375 | if (iter->iomap.flags & IOMAP_F_INTEGRITY) { |
| @@ -393,6 +393,11 @@ static ssize_t iomap_dio_bio_iter_one(struct iomap_iter *iter, · 17 unmodified lines | ||
| 393 | 393 | iomap_dio_submit_bio(iter, dio, bio, pos); |
| 394 | 394 | return ret; |
| 395 | 395 | |
| 396 | +out_bio_release_pages: | |
| 397 | + if (dio->flags & IOMAP_DIO_BOUNCE) | |
| 398 | + bio_iov_iter_unbounce(bio, true, false); | |
| 399 | + else | |
| 400 | + bio_release_pages(bio, false); | |
| 396 | 401 | out_put_bio: |
| 397 | 402 | bio_put(bio); |
| 398 | 403 | return ret; |
| @@ -298,8 +298,12 @@ new_ioend: · 297 unmodified lines | ||
| 298 | 298 | * appending writes. |
| 299 | 299 | */ |
| 300 | 300 | ioend->io_size += map_len; |
| 301 | − if (ioend->io_offset + ioend->io_size > end_pos) | |
| 302 | − ioend->io_size = end_pos - ioend->io_offset; | |
| 301 | + if (ioend->io_offset + ioend->io_size > end_pos) { | |
| 302 | + if (ioend->io_offset >= end_pos) | |
| 303 | + ioend->io_size = 0; | |
| 304 | + else | |
| 305 | + ioend->io_size = end_pos - ioend->io_offset; | |
| 306 | + } | |
| 303 | 307 | |
| 304 | 308 | wbc_account_cgroup_owner(wpc->wbc, folio, map_len); |
| 305 | 309 | return map_len; |
| @@ -97,7 +97,7 @@ static inline struct minix_inode_info *minix_i(struct inode *inode) · 96 unmodified lines | ||
| 97 | 97 | |
| 98 | 98 | static inline unsigned minix_blocks_needed(unsigned bits, unsigned blocksize) |
| 99 | 99 | { |
| 100 | − return DIV_ROUND_UP(bits, blocksize * 8); | |
| 100 | + return DIV_ROUND_UP_POW2(bits, blocksize * 8); | |
| 101 | 101 | } |
| 102 | 102 | |
| 103 | 103 | #if defined(CONFIG_MINIX_FS_NATIVE_ENDIAN) && \ |
| @@ -4736,6 +4736,10 @@ int vfs_tmpfile(struct mnt_idmap *idmap, · 4735 unmodified lines | ||
| 4736 | 4736 | int error; |
| 4737 | 4737 | int open_flag = file->f_flags; |
| 4738 | 4738 | |
| 4739 | + /* A tmpfile is I_LINKABLE, so guard its owner like may_o_create(). */ | |
| 4740 | + if (!fsuidgid_has_mapping(dir->i_sb, idmap)) | |
| 4741 | + return -EOVERFLOW; | |
| 4742 | + | |
| 4739 | 4743 | /* we want directory to be writable */ |
| 4740 | 4744 | error = inode_permission(idmap, dir, MAY_WRITE | MAY_EXEC); |
| 4741 | 4745 | if (error) |
| @@ -659,7 +659,7 @@ retry: · 658 unmodified lines | ||
| 659 | 659 | * within the cache granule containing the EOF, in which case we need |
| 660 | 660 | * to preload the granule. |
| 661 | 661 | */ |
| 662 | − if (!netfs_is_cache_enabled(ctx) && | |
| 662 | + if (!netfs_is_cache_maybe_enabled(ctx) && | |
| 663 | 663 | netfs_skip_folio_read(folio, pos, len, false)) { |
| 664 | 664 | netfs_stat(&netfs_n_rh_write_zskip); |
| 665 | 665 | goto have_folio_no_wait; |
| @@ -277,7 +277,7 @@ ssize_t netfs_perform_write(struct kiocb *iocb, struct iov_iter *iter, · 276 unmodified lines | ||
| 277 | 277 | * caching service temporarily because the backing store got |
| 278 | 278 | * culled. |
| 279 | 279 | */ |
| 280 | − if (netfs_is_cache_enabled(ctx)) { | |
| 280 | + if (netfs_is_cache_maybe_enabled(ctx)) { | |
| 281 | 281 | if (finfo) { |
| 282 | 282 | netfs_stat(&netfs_n_wh_wstream_conflict); |
| 283 | 283 | goto flush_content; |
| @@ -166,13 +166,16 @@ static int netfs_unbuffered_write(struct netfs_io_request *wreq) · 165 unmodified lines | ||
| 166 | 166 | */ |
| 167 | 167 | subreq->error = -EAGAIN; |
| 168 | 168 | trace_netfs_sreq(subreq, netfs_sreq_trace_retry); |
| 169 | − if (subreq->transferred > 0) | |
| 169 | + if (subreq->transferred > 0) { | |
| 170 | 170 | iov_iter_advance(&wreq->buffer.iter, subreq->transferred); |
| 171 | + wreq->transferred += subreq->transferred; | |
| 172 | + } | |
| 171 | 173 | |
| 172 | 174 | if (stream->source == NETFS_UPLOAD_TO_SERVER && |
| 173 | 175 | wreq->netfs_ops->retry_request) |
| 174 | 176 | wreq->netfs_ops->retry_request(wreq, stream); |
| 175 | 177 | |
| 178 | + __clear_bit(NETFS_SREQ_MADE_PROGRESS, &subreq->flags); | |
| 176 | 179 | __clear_bit(NETFS_SREQ_NEED_RETRY, &subreq->flags); |
| 177 | 180 | __clear_bit(NETFS_SREQ_BOUNDARY, &subreq->flags); |
| 178 | 181 | __clear_bit(NETFS_SREQ_FAILED, &subreq->flags); |
| @@ -186,17 +189,10 @@ static int netfs_unbuffered_write(struct netfs_io_request *wreq) · 7 unmodified lines | ||
| 186 | 189 | |
| 187 | 190 | netfs_get_subrequest(subreq, netfs_sreq_trace_get_resubmit); |
| 188 | 191 | |
| 189 | − if (stream->prepare_write) { | |
| 192 | + if (stream->prepare_write) | |
| 190 | 193 | stream->prepare_write(subreq); |
| 191 | − __set_bit(NETFS_SREQ_IN_PROGRESS, &subreq->flags); | |
| 192 | − netfs_stat(&netfs_n_wh_retry_write_subreq); | |
| 193 | − } else { | |
| 194 | − struct iov_iter source; | |
| 195 | − | |
| 196 | − netfs_reset_iter(subreq); | |
| 197 | − source = subreq->io_iter; | |
| 198 | − netfs_reissue_write(stream, subreq, &source); | |
| 199 | − } | |
| 194 | + __set_bit(NETFS_SREQ_IN_PROGRESS, &subreq->flags); | |
| 195 | + netfs_stat(&netfs_n_wh_retry_write_subreq); | |
| 200 | 196 | } |
| 201 | 197 | |
| 202 | 198 | netfs_unbuffered_write_done(wreq); |
| @@ -239,6 +239,18 @@ static inline bool netfs_is_cache_enabled(struct netfs_inode *ctx) · 238 unmodified lines | ||
| 239 | 239 | #endif |
| 240 | 240 | } |
| 241 | 241 | |
| 242 | +static inline bool netfs_is_cache_maybe_enabled(struct netfs_inode *ctx) | |
| 243 | +{ | |
| 244 | +#if IS_ENABLED(CONFIG_FSCACHE) | |
| 245 | + struct fscache_cookie *cookie = ctx->cache; | |
| 246 | + | |
| 247 | + return fscache_cookie_valid(cookie) && | |
| 248 | + test_bit(FSCACHE_COOKIE_IS_CACHING, &cookie->flags); | |
| 249 | +#else | |
| 250 | + return false; | |
| 251 | +#endif | |
| 252 | +} | |
| 253 | + | |
| 242 | 254 | /* |
| 243 | 255 | * Get a ref on a netfs group attached to a dirty page (e.g. a ceph snap). |
| 244 | 256 | */ |
| @@ -9,6 +9,11 @@ · 8 unmodified lines | ||
| 9 | 9 | #include <linux/netfs.h> |
| 10 | 10 | #include "internal.h" |
| 11 | 11 | |
| 12 | +struct netfs_wb_waiter { | |
| 13 | + struct list_head link; /* Link in ictx->wb_queue */ | |
| 14 | + struct task_struct *waiter; /* Waiter task; cleared when lock granted */ | |
| 15 | +}; | |
| 16 | + | |
| 12 | 17 | /* |
| 13 | 18 | * inode_dio_wait_interruptible - wait for outstanding DIO requests to finish |
| 14 | 19 | * @inode: inode to wait for |
| @@ -203,3 +208,93 @@ void netfs_end_io_direct(struct inode *inode) · 188 unmodified lines | ||
| 203 | 208 | up_read(&inode->i_rwsem); |
| 204 | 209 | } |
| 205 | 210 | EXPORT_SYMBOL(netfs_end_io_direct); |
| 211 | + | |
| 212 | +/* | |
| 213 | + * Wait to have exclusive access to writeback. | |
| 214 | + */ | |
| 215 | +static bool netfs_wb_begin_wait(struct netfs_inode *ictx) | |
| 216 | +{ | |
| 217 | + struct netfs_wb_waiter waiter = {}; | |
| 218 | + struct task_struct *tsk = current; | |
| 219 | + bool got = false; | |
| 220 | + | |
| 221 | + spin_lock(&ictx->lock); | |
| 222 | + | |
| 223 | + if (test_and_set_bit_lock(NETFS_ICTX_WB_LOCK, &ictx->flags)) { | |
| 224 | + get_task_struct(tsk); | |
| 225 | + waiter.waiter = tsk; | |
| 226 | + list_add_tail(&waiter.link, &ictx->wb_queue); | |
| 227 | + } else { | |
| 228 | + got = true; | |
| 229 | + } | |
| 230 | + spin_unlock(&ictx->lock); | |
| 231 | + | |
| 232 | + if (!got) { | |
| 233 | + for (;;) { | |
| 234 | + set_current_state(TASK_UNINTERRUPTIBLE); | |
| 235 | + /* Read waiter before accessing inode state. */ | |
| 236 | + if (smp_load_acquire(&waiter.waiter) == NULL) | |
| 237 | + break; | |
| 238 | + schedule(); | |
| 239 | + } | |
| 240 | + } | |
| 241 | + __set_current_state(TASK_RUNNING); | |
| 242 | + return true; | |
| 243 | +} | |
| 244 | + | |
| 245 | +/** | |
| 246 | + * netfs_wb_begin - Begin writeback, waiting if need be | |
| 247 | + * @ictx: The inode to get writeback access on | |
| 248 | + * @nowait: Return failure immediately rather than waiting if true | |
| 249 | + * | |
| 250 | + * Begin writeback to an inode, waiting for exclusive access if @nowait is | |
| 251 | + * false. This prevents collection from being done out of order with respect | |
| 252 | + * to the issuance of write subrequests. | |
| 253 | + * | |
| 254 | + * Note that writeback may be ended in a different process (e.g. the collection | |
| 255 | + * function on a workqueue) than started it. | |
| 256 | + * | |
| 257 | + * Return: True if can proceed, false if denied. | |
| 258 | + */ | |
| 259 | +bool netfs_wb_begin(struct netfs_inode *ictx, bool nowait) | |
| 260 | +{ | |
| 261 | + if (!test_and_set_bit_lock(NETFS_ICTX_WB_LOCK, &ictx->flags)) | |
| 262 | + return true; | |
| 263 | + if (nowait) { | |
| 264 | + netfs_stat(&netfs_n_wb_lock_skip); | |
| 265 | + return false; | |
| 266 | + } | |
| 267 | + netfs_stat(&netfs_n_wb_lock_wait); | |
| 268 | + return netfs_wb_begin_wait(ictx); | |
| 269 | +} | |
| 270 | +EXPORT_SYMBOL(netfs_wb_begin); | |
| 271 | + | |
| 272 | +/* netfs_wb_end - End writeback | |
| 273 | + * @ictx: The inode we have writeback access to | |
| 274 | + * | |
| 275 | + * End writeback access on an inode, waking up the next writeback request. | |
| 276 | + */ | |
| 277 | +void netfs_wb_end(struct netfs_inode *ictx) | |
| 278 | +{ | |
| 279 | + struct netfs_wb_waiter *waiter; | |
| 280 | + struct task_struct *tsk; | |
| 281 | + | |
| 282 | + WARN_ON_ONCE(!test_bit(NETFS_ICTX_WB_LOCK, &ictx->flags)); | |
| 283 | + | |
| 284 | + spin_lock(&ictx->lock); | |
| 285 | + | |
| 286 | + waiter = list_first_entry_or_null(&ictx->wb_queue, struct netfs_wb_waiter, link); | |
| 287 | + if (waiter) { | |
| 288 | + list_del(&waiter->link); | |
| 289 | + tsk = waiter->waiter; | |
| 290 | + /* Write inode state before clearing waiter. */ | |
| 291 | + smp_store_release(&waiter->waiter, NULL); | |
| 292 | + wake_up_process(tsk); | |
| 293 | + put_task_struct(tsk); | |
| 294 | + } else { | |
| 295 | + clear_bit_unlock(NETFS_ICTX_WB_LOCK, &ictx->flags); | |
| 296 | + } | |
| 297 | + | |
| 298 | + spin_unlock(&ictx->lock); | |
| 299 | +} | |
| 300 | +EXPORT_SYMBOL(netfs_wb_end); | |
| @@ -98,7 +98,12 @@ static void netfs_retry_read_subrequests(struct netfs_io_request *rreq) · 97 unmodified lines | ||
| 98 | 98 | goto abandon; |
| 99 | 99 | } |
| 100 | 100 | |
| 101 | − list_for_each_continue(next, &stream->subrequests) { | |
| 101 | + for (;;) { | |
| 102 | + /* Read pointer to subreq before reading subreq state. */ | |
| 103 | + next = smp_load_acquire(&next->next); | |
| 104 | + if (next == &stream->subrequests) | |
| 105 | + break; | |
| 106 | + | |
| 102 | 107 | subreq = list_entry(next, struct netfs_io_subrequest, rreq_link); |
| 103 | 108 | if (subreq->start + subreq->transferred != start + len || |
| 104 | 109 | test_bit(NETFS_SREQ_BOUNDARY, &subreq->flags) || |
| @@ -408,6 +408,16 @@ bool netfs_write_collection(struct netfs_io_request *wreq) · 407 unmodified lines | ||
| 408 | 408 | netfs_wake_rreq_flag(wreq, NETFS_RREQ_IN_PROGRESS, netfs_rreq_trace_wake_ip); |
| 409 | 409 | /* As we cleared NETFS_RREQ_IN_PROGRESS, we acquired its ref. */ |
| 410 | 410 | |
| 411 | + switch (wreq->origin) { | |
| 412 | + case NETFS_WRITEBACK: | |
| 413 | + case NETFS_WRITEBACK_SINGLE: | |
| 414 | + case NETFS_WRITETHROUGH: | |
| 415 | + netfs_wb_end(ictx); | |
| 416 | + break; | |
| 417 | + default: | |
| 418 | + break; | |
| 419 | + } | |
| 420 | + | |
| 411 | 421 | if (wreq->iocb) { |
| 412 | 422 | size_t written = min(wreq->transferred, wreq->len); |
| 413 | 423 | wreq->iocb->ki_pos += written; |
| @@ -106,7 +106,7 @@ struct netfs_io_request *netfs_create_write_req(struct address_space *mapping, · 105 unmodified lines | ||
| 106 | 106 | _enter("R=%x", wreq->debug_id); |
| 107 | 107 | |
| 108 | 108 | ictx = netfs_inode(wreq->inode); |
| 109 | − if (is_cacheable && netfs_is_cache_enabled(ictx)) | |
| 109 | + if (is_cacheable) | |
| 110 | 110 | fscache_begin_write_operation(&wreq->cache_resources, netfs_i_cookie(ictx)); |
| 111 | 111 | if (rolling_buffer_init(&wreq->buffer, wreq->debug_id, ITER_SOURCE) < 0) |
| 112 | 112 | goto nomem; |
| @@ -551,14 +551,8 @@ int netfs_writepages(struct address_space *mapping, · 438 unmodified lines | ||
| 551 | 551 | struct folio *folio; |
| 552 | 552 | int error = 0; |
| 553 | 553 | |
| 554 | − if (!mutex_trylock(&ictx->wb_lock)) { | |
| 555 | − if (wbc->sync_mode == WB_SYNC_NONE) { | |
| 556 | − netfs_stat(&netfs_n_wb_lock_skip); | |
| 557 | − return 0; | |
| 558 | − } | |
| 559 | − netfs_stat(&netfs_n_wb_lock_wait); | |
| 560 | − mutex_lock(&ictx->wb_lock); | |
| 561 | − } | |
| 554 | + if (!netfs_wb_begin(ictx, wbc->sync_mode == WB_SYNC_NONE)) | |
| 555 | + return 0; | |
| 562 | 556 | |
| 563 | 557 | /* Need the first folio to be able to set up the op. */ |
| 564 | 558 | folio = writeback_iter(mapping, wbc, NULL, &error); |
| @@ -588,13 +582,13 @@ int netfs_writepages(struct address_space *mapping, · 23 unmodified lines | ||
| 588 | 582 | } |
| 589 | 583 | |
| 590 | 584 | error = netfs_write_folio(wreq, wbc, folio); |
| 591 | − if (error < 0) | |
| 592 | − break; | |
| 585 | + if (error == -ENOMEM) { | |
| 586 | + folio_redirty_for_writepage(wbc, folio); | |
| 587 | + folio_unlock(folio); | |
| 588 | + } | |
| 593 | 589 | } while ((folio = writeback_iter(mapping, wbc, folio, &error))); |
| 594 | 590 | |
| 595 | 591 | netfs_end_issue_write(wreq); |
| 596 | − | |
| 597 | − mutex_unlock(&ictx->wb_lock); | |
| 598 | 592 | netfs_wake_collector(wreq); |
| 599 | 593 | |
| 600 | 594 | netfs_put_request(wreq, netfs_rreq_trace_put_return); |
| @@ -602,9 +596,16 @@ int netfs_writepages(struct address_space *mapping, · 1 unmodified line | ||
| 602 | 596 | return error; |
| 603 | 597 | |
| 604 | 598 | couldnt_start: |
| 605 | − netfs_kill_dirty_pages(mapping, wbc, folio); | |
| 599 | + if (error == -ENOMEM) { | |
| 600 | + folio_redirty_for_writepage(wbc, folio); | |
| 601 | + folio_unlock(folio); | |
| 602 | + folio = writeback_iter(mapping, wbc, folio, &error); | |
| 603 | + WARN_ON_ONCE(folio != NULL); | |
| 604 | + } else { | |
| 605 | + netfs_kill_dirty_pages(mapping, wbc, folio); | |
| 606 | + } | |
| 606 | 607 | out: |
| 607 | − mutex_unlock(&ictx->wb_lock); | |
| 608 | + netfs_wb_end(ictx); | |
| 608 | 609 | _leave(" = %d", error); |
| 609 | 610 | return error; |
| 610 | 611 | } |
| @@ -618,16 +619,17 @@ struct netfs_io_request *netfs_begin_writethrough(struct kiocb *iocb, size_t len · 7 unmodified lines | ||
| 618 | 619 | struct netfs_io_request *wreq = NULL; |
| 619 | 620 | struct netfs_inode *ictx = netfs_inode(file_inode(iocb->ki_filp)); |
| 620 | 621 | |
| 621 | − mutex_lock(&ictx->wb_lock); | |
| 622 | + netfs_wb_begin(ictx, false); | |
| 622 | 623 | |
| 623 | 624 | wreq = netfs_create_write_req(iocb->ki_filp->f_mapping, iocb->ki_filp, |
| 624 | 625 | iocb->ki_pos, NETFS_WRITETHROUGH); |
| 625 | 626 | if (IS_ERR(wreq)) { |
| 626 | − mutex_unlock(&ictx->wb_lock); | |
| 627 | + netfs_wb_end(ictx); | |
| 627 | 628 | return wreq; |
| 628 | 629 | } |
| 629 | 630 | |
| 630 | 631 | wreq->io_streams[0].avail = true; |
| 632 | + __set_bit(NETFS_RREQ_OFFLOAD_COLLECTION, &wreq->flags); | |
| 631 | 633 | trace_netfs_write(wreq, netfs_write_trace_writethrough); |
| 632 | 634 | return wreq; |
| 633 | 635 | } |
| @@ -685,7 +687,6 @@ int netfs_advance_writethrough(struct netfs_io_request *wreq, struct writeback_c · 51 unmodified lines | ||
| 685 | 687 | ssize_t netfs_end_writethrough(struct netfs_io_request *wreq, struct writeback_control *wbc, |
| 686 | 688 | struct folio *writethrough_cache) |
| 687 | 689 | { |
| 688 | − struct netfs_inode *ictx = netfs_inode(wreq->inode); | |
| 689 | 690 | ssize_t ret; |
| 690 | 691 | |
| 691 | 692 | _enter("R=%x", wreq->debug_id); |
| @@ -699,8 +700,6 @@ ssize_t netfs_end_writethrough(struct netfs_io_request *wreq, struct writeback_c · 7 unmodified lines | ||
| 699 | 700 | |
| 700 | 701 | netfs_end_issue_write(wreq); |
| 701 | 702 | |
| 702 | − mutex_unlock(&ictx->wb_lock); | |
| 703 | − | |
| 704 | 703 | if (wreq->iocb) |
| 705 | 704 | ret = -EIOCBQUEUED; |
| 706 | 705 | else |
| @@ -847,15 +846,10 @@ int netfs_writeback_single(struct address_space *mapping, · 140 unmodified lines | ||
| 847 | 846 | if (WARN_ON_ONCE(!iov_iter_is_folioq(iter))) |
| 848 | 847 | return -EIO; |
| 849 | 848 | |
| 850 | − if (!mutex_trylock(&ictx->wb_lock)) { | |
| 851 | − if (wbc->sync_mode == WB_SYNC_NONE) { | |
| 852 | − /* The VFS will have undirtied the inode. */ | |
| 853 | − netfs_single_mark_inode_dirty(&ictx->inode); | |
| 854 | − netfs_stat(&netfs_n_wb_lock_skip); | |
| 855 | − return 1; | |
| 856 | − } | |
| 857 | − netfs_stat(&netfs_n_wb_lock_wait); | |
| 858 | − mutex_lock(&ictx->wb_lock); | |
| 849 | + if (!netfs_wb_begin(ictx, wbc->sync_mode == WB_SYNC_NONE)) { | |
| 850 | + /* The VFS will have undirtied the inode. */ | |
| 851 | + netfs_single_mark_inode_dirty(&ictx->inode); | |
| 852 | + return 1; | |
| 859 | 853 | } |
| 860 | 854 | |
| 861 | 855 | wreq = netfs_create_write_req(mapping, NULL, 0, NETFS_WRITEBACK_SINGLE); |
| @@ -893,7 +887,6 @@ stop: · 31 unmodified lines | ||
| 893 | 887 | smp_wmb(); /* Write lists before ALL_QUEUED. */ |
| 894 | 888 | set_bit(NETFS_RREQ_ALL_QUEUED, &wreq->flags); |
| 895 | 889 | |
| 896 | − mutex_unlock(&ictx->wb_lock); | |
| 897 | 890 | netfs_wake_collector(wreq); |
| 898 | 891 | |
| 899 | 892 | netfs_put_request(wreq, netfs_rreq_trace_put_return); |
| @@ -901,7 +894,7 @@ stop: · 1 unmodified line | ||
| 901 | 894 | return ret; |
| 902 | 895 | |
| 903 | 896 | couldnt_start: |
| 904 | − mutex_unlock(&ictx->wb_lock); | |
| 897 | + netfs_wb_end(ictx); | |
| 905 | 898 | _leave(" = %d", ret); |
| 906 | 899 | return ret; |
| 907 | 900 | } |
| @@ -72,7 +72,12 @@ static void netfs_retry_write_stream(struct netfs_io_request *wreq, · 71 unmodified lines | ||
| 72 | 72 | !test_bit(NETFS_SREQ_NEED_RETRY, &from->flags)) |
| 73 | 73 | return; |
| 74 | 74 | |
| 75 | − list_for_each_continue(next, &stream->subrequests) { | |
| 75 | + for (;;) { | |
| 76 | + /* Read pointer to subreq before reading subreq state. */ | |
| 77 | + next = smp_load_acquire(&next->next); | |
| 78 | + if (next == &stream->subrequests) | |
| 79 | + break; | |
| 80 | + | |
| 76 | 81 | subreq = list_entry(next, struct netfs_io_subrequest, rreq_link); |
| 77 | 82 | if (subreq->start + subreq->transferred != start + len || |
| 78 | 83 | test_bit(NETFS_SREQ_BOUNDARY, &subreq->flags) || |
| @@ -38,11 +38,9 @@ static void ntfs_iomap_read_end_io(struct bio *bio) · 37 unmodified lines | ||
| 38 | 38 | } |
| 39 | 39 | |
| 40 | 40 | static void ntfs_iomap_bio_submit_read(const struct iomap_iter *iter, |
| 41 | − struct iomap_read_folio_ctx *ctx) | |
| 41 | + struct iomap_read_folio_ctx *ctx) | |
| 42 | 42 | { |
| 43 | − struct bio *bio = ctx->read_ctx; | |
| 44 | − bio->bi_end_io = ntfs_iomap_read_end_io; | |
| 45 | − submit_bio(bio); | |
| 43 | + iomap_bio_submit_read_endio(iter, ctx, ntfs_iomap_read_end_io); | |
| 46 | 44 | } |
| 47 | 45 | |
| 48 | 46 | static const struct iomap_read_ops ntfs_iomap_bio_read_ops = { |
| @@ -608,10 +608,7 @@ static void ntfs_iomap_read_end_io(struct bio *bio) · 607 unmodified lines | ||
| 608 | 608 | static void ntfs_iomap_bio_submit_read(const struct iomap_iter *iter, |
| 609 | 609 | struct iomap_read_folio_ctx *ctx) |
| 610 | 610 | { |
| 611 | − struct bio *bio = ctx->read_ctx; | |
| 612 | − | |
| 613 | − bio->bi_end_io = ntfs_iomap_read_end_io; | |
| 614 | − submit_bio(bio); | |
| 611 | + iomap_bio_submit_read_endio(iter, ctx, ntfs_iomap_read_end_io); | |
| 615 | 612 | } |
| 616 | 613 | |
| 617 | 614 | static const struct iomap_read_ops ntfs_iomap_bio_read_ops = { |
| @@ -191,7 +191,8 @@ static int fill_from_part(struct orangefs_dir_part *part, · 190 unmodified lines | ||
| 191 | 191 | { |
| 192 | 192 | const int offset = sizeof(struct orangefs_readdir_response_s); |
| 193 | 193 | struct orangefs_khandle *khandle; |
| 194 | − __u32 *len, padlen; | |
| 194 | + __u32 *len; | |
| 195 | + u64 padlen; | |
| 195 | 196 | loff_t i; |
| 196 | 197 | char *s; |
| 197 | 198 | i = ctx->pos & ~PART_MASK; |
| @@ -215,8 +216,8 @@ static int fill_from_part(struct orangefs_dir_part *part, · 17 unmodified lines | ||
| 215 | 216 | * len is the size of the string itself. padlen is the |
| 216 | 217 | * total size of the encoded string. |
| 217 | 218 | */ |
| 218 | − padlen = (sizeof *len + *len + 1) + | |
| 219 | − (8 - (sizeof *len + *len + 1)%8)%8; | |
| 219 | + padlen = (u64)sizeof *len + *len + 1; | |
| 220 | + padlen += (8 - padlen % 8) % 8; | |
| 220 | 221 | if (part->len < i + padlen + sizeof *khandle) |
| 221 | 222 | goto next; |
| 222 | 223 | s = (void *)part + offset + i + sizeof *len; |
| @@ -853,7 +853,7 @@ static int ovl_copy_up_tmpfile(struct ovl_copy_up_ctx *c) · 852 unmodified lines | ||
| 853 | 853 | { |
| 854 | 854 | struct ovl_fs *ofs = OVL_FS(c->dentry->d_sb); |
| 855 | 855 | struct inode *udir = d_inode(c->destdir); |
| 856 | − struct dentry *temp, *upper; | |
| 856 | + struct dentry *temp, *upper, *newdentry = NULL; | |
| 857 | 857 | struct file *tmpfile; |
| 858 | 858 | int err; |
| 859 | 859 | |
| @@ -889,6 +889,14 @@ static int ovl_copy_up_tmpfile(struct ovl_copy_up_ctx *c) · 29 unmodified lines | ||
| 889 | 889 | err = PTR_ERR(upper); |
| 890 | 890 | if (!IS_ERR(upper)) { |
| 891 | 891 | err = ovl_do_link(ofs, temp, udir, upper); |
| 892 | + if (!err) { | |
| 893 | + /* | |
| 894 | + * Record the linked dentry -- not the disconnected | |
| 895 | + * O_TMPFILE dentry -- so that ->d_revalidate() on | |
| 896 | + * the upper fs sees the real parent/name. | |
| 897 | + */ | |
| 898 | + newdentry = dget(upper); | |
| 899 | + } | |
| 892 | 900 | end_creating(upper); |
| 893 | 901 | } |
| 894 | 902 | |
| @@ -903,7 +911,7 @@ static int ovl_copy_up_tmpfile(struct ovl_copy_up_ctx *c) · 8 unmodified lines | ||
| 903 | 911 | |
| 904 | 912 | if (!c->metacopy) |
| 905 | 913 | ovl_set_upperdata(d_inode(c->dentry)); |
| 906 | − ovl_inode_update(d_inode(c->dentry), dget(temp)); | |
| 914 | + ovl_inode_update(d_inode(c->dentry), newdentry); | |
| 907 | 915 | |
| 908 | 916 | out: |
| 909 | 917 | ovl_end_write(c->dentry); |
| @@ -783,8 +783,8 @@ static const struct address_space_operations ovl_aops = { · 782 unmodified lines | ||
| 783 | 783 | * |
| 784 | 784 | * This chain is valid: |
| 785 | 785 | * - inode->i_rwsem (inode_lock[2]) |
| 786 | − * - upper_mnt->mnt_sb->s_writers (ovl_want_write[0]) | |
| 787 | 786 | * - OVL_I(inode)->lock (ovl_inode_lock[2]) |
| 787 | + * - upper_mnt->mnt_sb->s_writers (ovl_want_write[0]) | |
| 788 | 788 | * - OVL_I(lowerinode)->lock (ovl_inode_lock[1]) |
| 789 | 789 | * |
| 790 | 790 | * And this chain is valid: |
| @@ -797,8 +797,8 @@ static const struct address_space_operations ovl_aops = { · 6 unmodified lines | ||
| 797 | 797 | * held, because it is in reverse order of the non-nested case using the same |
| 798 | 798 | * upper fs: |
| 799 | 799 | * - inode->i_rwsem (inode_lock[1]) |
| 800 | − * - upper_mnt->mnt_sb->s_writers (ovl_want_write[0]) | |
| 801 | 800 | * - OVL_I(inode)->lock (ovl_inode_lock[1]) |
| 801 | + * - upper_mnt->mnt_sb->s_writers (ovl_want_write[0]) | |
| 802 | 802 | */ |
| 803 | 803 | #define OVL_MAX_NESTING FILESYSTEM_MAX_STACK_DEPTH |
| 804 | 804 | |
| @@ -112,6 +112,8 @@ static bool pde_subdir_insert(struct proc_dir_entry *dir, · 111 unmodified lines | ||
| 112 | 112 | /* Add new node and rebalance tree. */ |
| 113 | 113 | rb_link_node(&de->subdir_node, parent, new); |
| 114 | 114 | rb_insert_color(&de->subdir_node, root); |
| 115 | + if (S_ISDIR(de->mode)) | |
| 116 | + dir->nlink++; | |
| 115 | 117 | return true; |
| 116 | 118 | } |
| 117 | 119 | |
| @@ -404,7 +406,6 @@ struct proc_dir_entry *proc_register(struct proc_dir_entry *dir, · 286 unmodified lines | ||
| 404 | 406 | write_unlock(&proc_subdir_lock); |
| 405 | 407 | goto out_free_inum; |
| 406 | 408 | } |
| 407 | − dir->nlink++; | |
| 408 | 409 | write_unlock(&proc_subdir_lock); |
| 409 | 410 | |
| 410 | 411 | return dp; |
| @@ -706,6 +707,8 @@ static void pde_erase(struct proc_dir_entry *pde, struct proc_dir_entry *parent) · 295 unmodified lines | ||
| 706 | 707 | { |
| 707 | 708 | rb_erase(&pde->subdir_node, &parent->subdir); |
| 708 | 709 | RB_CLEAR_NODE(&pde->subdir_node); |
| 710 | + if (S_ISDIR(pde->mode)) | |
| 711 | + parent->nlink--; | |
| 709 | 712 | } |
| 710 | 713 | |
| 711 | 714 | /* |
| @@ -731,8 +734,6 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent) · 19 unmodified lines | ||
| 731 | 734 | de = NULL; |
| 732 | 735 | } else { |
| 733 | 736 | pde_erase(de, parent); |
| 734 | − if (S_ISDIR(de->mode)) | |
| 735 | − parent->nlink--; | |
| 736 | 737 | } |
| 737 | 738 | } |
| 738 | 739 | write_unlock(&proc_subdir_lock); |
| @@ -791,8 +792,6 @@ int remove_proc_subtree(const char *name, struct proc_dir_entry *parent) · 52 unmodified lines | ||
| 791 | 792 | continue; |
| 792 | 793 | } |
| 793 | 794 | next = de->parent; |
| 794 | − if (S_ISDIR(de->mode)) | |
| 795 | − next->nlink--; | |
| 796 | 795 | write_unlock(&proc_subdir_lock); |
| 797 | 796 | |
| 798 | 797 | proc_entry_rundown(de); |
| @@ -764,8 +764,7 @@ xfs_bio_submit_read( · 763 unmodified lines | ||
| 764 | 764 | |
| 765 | 765 | /* defer read completions to the ioend workqueue */ |
| 766 | 766 | iomap_init_ioend(iter->inode, bio, ctx->read_ctx_file_offset, 0); |
| 767 | − bio->bi_end_io = xfs_end_bio; | |
| 768 | − submit_bio(bio); | |
| 767 | + iomap_bio_submit_read_endio(iter, ctx, xfs_end_bio); | |
| 769 | 768 | } |
| 770 | 769 | |
| 771 | 770 | static const struct iomap_read_ops xfs_iomap_read_ops = { |
| @@ -534,8 +534,11 @@ xfs_open_devices( · 533 unmodified lines | ||
| 534 | 534 | out_free_rtdev_targ: |
| 535 | 535 | if (mp->m_rtdev_targp) |
| 536 | 536 | xfs_free_buftarg(mp->m_rtdev_targp); |
| 537 | + mp->m_rtdev_targp = NULL; | |
| 538 | + rtdev_file = NULL; /* released by xfs_free_buftarg() */ | |
| 537 | 539 | out_free_ddev_targ: |
| 538 | 540 | xfs_free_buftarg(mp->m_ddev_targp); |
| 541 | + mp->m_ddev_targp = NULL; | |
| 539 | 542 | out_close_rtdev: |
| 540 | 543 | if (rtdev_file) |
| 541 | 544 | bdev_fput(rtdev_file); |
| @@ -622,6 +622,8 @@ extern struct bio_set iomap_ioend_bioset; · 621 unmodified lines | ||
| 622 | 622 | #ifdef CONFIG_BLOCK |
| 623 | 623 | int iomap_bio_read_folio_range(const struct iomap_iter *iter, |
| 624 | 624 | struct iomap_read_folio_ctx *ctx, size_t plen); |
| 625 | +void iomap_bio_submit_read_endio(const struct iomap_iter *iter, | |
| 626 | + struct iomap_read_folio_ctx *ctx, bio_end_io_t end_io); | |
| 625 | 627 | |
| 626 | 628 | extern const struct iomap_read_ops iomap_bio_read_ops; |
| 627 | 629 | |
| @@ -61,14 +61,16 @@ struct netfs_inode { · 60 unmodified lines | ||
| 61 | 61 | #if IS_ENABLED(CONFIG_FSCACHE) |
| 62 | 62 | struct fscache_cookie *cache; |
| 63 | 63 | #endif |
| 64 | − struct mutex wb_lock; /* Writeback serialisation */ | |
| 64 | + struct list_head wb_queue; /* Queue of processes wanting to do writeback */ | |
| 65 | 65 | loff_t _remote_i_size; /* Size of the remote file */ |
| 66 | 66 | loff_t _zero_point; /* Size after which we assume there's no data |
| 67 | 67 | * on the server */ |
| 68 | + spinlock_t lock; /* Lock covering wb_queue */ | |
| 68 | 69 | atomic_t io_count; /* Number of outstanding reqs */ |
| 69 | 70 | unsigned long flags; |
| 70 | 71 | #define NETFS_ICTX_ODIRECT 0 /* The file has DIO in progress */ |
| 71 | 72 | #define NETFS_ICTX_UNBUFFERED 1 /* I/O should not use the pagecache */ |
| 73 | +#define NETFS_ICTX_WB_LOCK 2 /* Writeback serialisation lock */ | |
| 72 | 74 | #define NETFS_ICTX_MODIFIED_ATTR 3 /* Indicate change in mtime/ctime */ |
| 73 | 75 | #define NETFS_ICTX_SINGLE_NO_UPLOAD 4 /* Monolithic payload, cache but no upload */ |
| 74 | 76 | }; |
| @@ -462,6 +464,10 @@ int netfs_alloc_folioq_buffer(struct address_space *mapping, · 387 unmodified lines | ||
| 462 | 464 | size_t *_cur_size, ssize_t size, gfp_t gfp); |
| 463 | 465 | void netfs_free_folioq_buffer(struct folio_queue *fq); |
| 464 | 466 | |
| 467 | +/* Writeback exclusion API. */ | |
| 468 | +bool netfs_wb_begin(struct netfs_inode *ictx, bool nowait); | |
| 469 | +void netfs_wb_end(struct netfs_inode *ictx); | |
| 470 | + | |
| 465 | 471 | /** |
| 466 | 472 | * netfs_inode - Get the netfs inode context from the inode |
| 467 | 473 | * @inode: The inode to query |
| @@ -743,7 +749,8 @@ static inline void netfs_inode_init(struct netfs_inode *ctx, · 275 unmodified lines | ||
| 743 | 749 | #if IS_ENABLED(CONFIG_FSCACHE) |
| 744 | 750 | ctx->cache = NULL; |
| 745 | 751 | #endif |
| 746 | − mutex_init(&ctx->wb_lock); | |
| 752 | + INIT_LIST_HEAD(&ctx->wb_queue); | |
| 753 | + spin_lock_init(&ctx->lock); | |
| 747 | 754 | /* ->releasepage() drives zero_point */ |
| 748 | 755 | if (use_zero_point) { |
| 749 | 756 | ctx->_zero_point = ctx->_remote_i_size; |
| @@ -753,7 +760,7 @@ static inline void netfs_inode_init(struct netfs_inode *ctx, · 3 unmodified lines | ||
| 753 | 760 | |
| 754 | 761 | /** |
| 755 | 762 | * netfs_resize_file - Note that a file got resized |
| 756 | − * @ctx: The netfs inode being resized | |
| 763 | + * @ictx: The netfs inode being resized | |
| 757 | 764 | * @new_i_size: The new file size |
| 758 | 765 | * @changed_on_server: The change was applied to the server |
| 759 | 766 | * |
| @@ -1568,6 +1568,7 @@ static ssize_t iov_iter_extract_xarray_pages(struct iov_iter *i, · 1567 unmodified lines | ||
| 1568 | 1568 | struct folio *folio; |
| 1569 | 1569 | unsigned int nr = 0, offset; |
| 1570 | 1570 | loff_t pos = i->xarray_start + i->iov_offset; |
| 1571 | + bool will_alloc = !*pages; | |
| 1571 | 1572 | XA_STATE(xas, i->xarray, pos >> PAGE_SHIFT); |
| 1572 | 1573 | |
| 1573 | 1574 | offset = pos & ~PAGE_MASK; |
| @@ -1595,6 +1596,14 @@ static ssize_t iov_iter_extract_xarray_pages(struct iov_iter *i, · 21 unmodified lines | ||
| 1595 | 1596 | } |
| 1596 | 1597 | rcu_read_unlock(); |
| 1597 | 1598 | |
| 1599 | + if (!nr) { | |
| 1600 | + if (will_alloc) { | |
| 1601 | + kvfree(*pages); | |
| 1602 | + *pages = NULL; | |
| 1603 | + } | |
| 1604 | + return 0; | |
| 1605 | + } | |
| 1606 | + | |
| 1598 | 1607 | maxsize = min_t(size_t, nr * PAGE_SIZE - offset, maxsize); |
| 1599 | 1608 | iov_iter_advance(i, maxsize); |
| 1600 | 1609 | return maxsize; |
| @@ -1628,6 +1637,8 @@ static ssize_t iov_iter_extract_bvec_pages(struct iov_iter *i, · 27 unmodified lines | ||
| 1628 | 1637 | bi.bi_bvec_done = skip; |
| 1629 | 1638 | |
| 1630 | 1639 | maxpages = want_pages_array(pages, maxsize, skip, maxpages); |
| 1640 | + if (!maxpages) | |
| 1641 | + return -ENOMEM; | |
| 1631 | 1642 | |
| 1632 | 1643 | while (bi.bi_size && bi.bi_idx < i->nr_segs) { |
| 1633 | 1644 | struct bio_vec bv = bvec_iter_bvec(i->bvec, bi); |
| @@ -1745,6 +1756,7 @@ static ssize_t iov_iter_extract_user_pages(struct iov_iter *i, · 111 unmodified lines | ||
| 1745 | 1756 | unsigned long addr; |
| 1746 | 1757 | unsigned int gup_flags = 0; |
| 1747 | 1758 | size_t offset; |
| 1759 | + bool will_alloc = !*pages; | |
| 1748 | 1760 | int res; |
| 1749 | 1761 | |
| 1750 | 1762 | if (i->data_source == ITER_DEST) |
| @@ -1761,8 +1773,14 @@ static ssize_t iov_iter_extract_user_pages(struct iov_iter *i, · 10 unmodified lines | ||
| 1761 | 1773 | if (!maxpages) |
| 1762 | 1774 | return -ENOMEM; |
| 1763 | 1775 | res = pin_user_pages_fast(addr, maxpages, gup_flags, *pages); |
| 1764 | − if (unlikely(res <= 0)) | |
| 1776 | + if (unlikely(res <= 0)) { | |
| 1777 | + if (will_alloc) { | |
| 1778 | + kvfree(*pages); | |
| 1779 | + *pages = NULL; | |
| 1780 | + } | |
| 1765 | 1781 | return res; |
| 1782 | + } | |
| 1783 | + | |
| 1766 | 1784 | maxsize = min_t(size_t, maxsize, res * PAGE_SIZE - offset); |
| 1767 | 1785 | iov_iter_advance(i, maxsize); |
| 1768 | 1786 | return maxsize; |
| @@ -1366,6 +1366,7 @@ static ssize_t extract_xarray_to_sg(struct iov_iter *iter, · 1365 unmodified lines | ||
| 1366 | 1366 | sg_max--; |
| 1367 | 1367 | |
| 1368 | 1368 | maxsize -= len; |
| 1369 | + start += len; | |
| 1369 | 1370 | ret += len; |
| 1370 | 1371 | if (maxsize <= 0 || sg_max == 0) |
| 1371 | 1372 | break; |
| @@ -283,7 +283,7 @@ static void __init iov_kunit_copy_to_bvec(struct kunit *test) · 282 unmodified lines | ||
| 283 | 283 | struct page **spages, **bpages; |
| 284 | 284 | u8 *scratch, *buffer; |
| 285 | 285 | size_t bufsize, npages, size, copied; |
| 286 | − int i, b, patt; | |
| 286 | + int i, patt; | |
| 287 | 287 | |
| 288 | 288 | bufsize = 0x100000; |
| 289 | 289 | npages = bufsize / PAGE_SIZE; |
| @@ -306,10 +306,9 @@ static void __init iov_kunit_copy_to_bvec(struct kunit *test) · 16 unmodified lines | ||
| 306 | 306 | KUNIT_EXPECT_EQ(test, iter.nr_segs, 0); |
| 307 | 307 | |
| 308 | 308 | /* Build the expected image in the scratch buffer. */ |
| 309 | − b = 0; | |
| 310 | 309 | patt = 0; |
| 311 | 310 | memset(scratch, 0, bufsize); |
| 312 | − for (pr = bvec_test_ranges; pr->from >= 0; pr++, b++) { | |
| 311 | + for (pr = bvec_test_ranges; pr->from >= 0; pr++) { | |
| 313 | 312 | u8 *p = scratch + pr->page * PAGE_SIZE; |
| 314 | 313 | |
| 315 | 314 | for (i = pr->from; i < pr->to; i++) |
| @@ -5,3 +5,4 @@ fclog · 4 unmodified lines | ||
| 5 | 5 | file_stressor |
| 6 | 6 | anon_inode_test |
| 7 | 7 | kernfs_test |
| 8 | +idmapped_tmpfile | |
| @@ -2,6 +2,10 @@ · 1 unmodified line | ||
| 2 | 2 | |
| 3 | 3 | CFLAGS += $(KHDR_INCLUDES) |
| 4 | 4 | TEST_GEN_PROGS := devpts_pts file_stressor anon_inode_test kernfs_test fclog |
| 5 | +TEST_GEN_PROGS += idmapped_tmpfile | |
| 5 | 6 | TEST_GEN_PROGS_EXTENDED := dnotify_test |
| 6 | 7 | |
| 7 | 8 | include ../lib.mk |
| 9 | + | |
| 10 | +$(OUTPUT)/idmapped_tmpfile: LDLIBS += -lcap | |
| 11 | +$(OUTPUT)/idmapped_tmpfile: utils.c | |
| @@ -0,0 +1,168 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 2 | +#define _GNU_SOURCE | |
| 3 | + | |
| 4 | +#include <errno.h> | |
| 5 | +#include <fcntl.h> | |
| 6 | +#include <limits.h> | |
| 7 | +#include <sched.h> | |
| 8 | +#include <stdio.h> | |
| 9 | +#include <unistd.h> | |
| 10 | +#include <sys/fsuid.h> | |
| 11 | +#include <sys/stat.h> | |
| 12 | +#include <sys/syscall.h> | |
| 13 | + | |
| 14 | +#include <linux/mount.h> | |
| 15 | +#include <linux/types.h> | |
| 16 | + | |
| 17 | +#include "kselftest_harness.h" | |
| 18 | +#include "wrappers.h" | |
| 19 | +#include "utils.h" | |
| 20 | + | |
| 21 | +/* | |
| 22 | + * The test mount maps caller-visible ids [0, MAP_RANGE) onto the on-disk range | |
| 23 | + * [MAP_HOST, MAP_HOST + MAP_RANGE). An id outside [0, MAP_RANGE) therefore has | |
| 24 | + * no mapping in the mount and is not representable in the filesystem. | |
| 25 | + */ | |
| 26 | +#define MAP_HOST 10000 | |
| 27 | +#define MAP_RANGE 10000 | |
| 28 | +#define UNMAPPED 50000 | |
| 29 | + | |
| 30 | +#ifndef MOUNT_ATTR_IDMAP | |
| 31 | +#define MOUNT_ATTR_IDMAP 0x00100000 | |
| 32 | +#endif | |
| 33 | + | |
| 34 | +#ifndef __NR_mount_setattr | |
| 35 | +#define __NR_mount_setattr 442 | |
| 36 | +#endif | |
| 37 | + | |
| 38 | +static inline int sys_mount_setattr(int dfd, const char *path, | |
| 39 | + unsigned int flags, | |
| 40 | + struct mount_attr *attr, size_t size) | |
| 41 | +{ | |
| 42 | + return syscall(__NR_mount_setattr, dfd, path, flags, attr, size); | |
| 43 | +} | |
| 44 | + | |
| 45 | +/* | |
| 46 | + * Clone @path into a detached mount idmapped so that caller-visible ids | |
| 47 | + * [0, MAP_RANGE) map onto the on-disk ids [MAP_HOST, MAP_HOST + MAP_RANGE). | |
| 48 | + * Returns the mount fd, or -1 if idmapped mounts are not available. | |
| 49 | + */ | |
| 50 | +static int idmapped_clone(const char *path) | |
| 51 | +{ | |
| 52 | + struct mount_attr attr = { | |
| 53 | + .attr_set = MOUNT_ATTR_IDMAP, | |
| 54 | + }; | |
| 55 | + int fd_tree, userns_fd, ret; | |
| 56 | + | |
| 57 | + fd_tree = sys_open_tree(AT_FDCWD, path, | |
| 58 | + OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC); | |
| 59 | + if (fd_tree < 0) | |
| 60 | + return -1; | |
| 61 | + | |
| 62 | + userns_fd = get_userns_fd(MAP_HOST, 0, MAP_RANGE); | |
| 63 | + if (userns_fd < 0) { | |
| 64 | + close(fd_tree); | |
| 65 | + return -1; | |
| 66 | + } | |
| 67 | + | |
| 68 | + attr.userns_fd = userns_fd; | |
| 69 | + ret = sys_mount_setattr(fd_tree, "", AT_EMPTY_PATH, &attr, sizeof(attr)); | |
| 70 | + close(userns_fd); | |
| 71 | + if (ret) { | |
| 72 | + close(fd_tree); | |
| 73 | + return -1; | |
| 74 | + } | |
| 75 | + | |
| 76 | + return fd_tree; | |
| 77 | +} | |
| 78 | + | |
| 79 | +FIXTURE(idmapped_tmpfile) { | |
| 80 | + char dir[64]; /* non-idmapped path to the layer directory */ | |
| 81 | +}; | |
| 82 | + | |
| 83 | +FIXTURE_SETUP(idmapped_tmpfile) | |
| 84 | +{ | |
| 85 | + /* Private mount namespace so test mounts need no cleanup. */ | |
| 86 | + ASSERT_EQ(unshare(CLONE_NEWNS), 0); | |
| 87 | + ASSERT_EQ(sys_mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL), 0); | |
| 88 | + ASSERT_EQ(sys_mount("tmpfs", "/tmp", "tmpfs", 0, NULL), 0); | |
| 89 | + | |
| 90 | + snprintf(self->dir, sizeof(self->dir), "/tmp/d"); | |
| 91 | + ASSERT_EQ(mkdir(self->dir, 0777), 0); | |
| 92 | + /* World-writable so an unmapped caller still passes permission(). */ | |
| 93 | + ASSERT_EQ(chmod(self->dir, 0777), 0); | |
| 94 | +} | |
| 95 | + | |
| 96 | +FIXTURE_TEARDOWN(idmapped_tmpfile) | |
| 97 | +{ | |
| 98 | +} | |
| 99 | + | |
| 100 | +/* | |
| 101 | + * A caller whose fsuid/fsgid have no mapping in the idmapped mount must not be | |
| 102 | + * able to create an O_TMPFILE. Without the check in vfs_tmpfile() the inode | |
| 103 | + * would be created owned by (uid_t)-1 and could then be linked into the | |
| 104 | + * namespace. | |
| 105 | + */ | |
| 106 | +TEST_F(idmapped_tmpfile, unmapped_caller_is_refused) | |
| 107 | +{ | |
| 108 | + int mfd, fd; | |
| 109 | + | |
| 110 | + mfd = idmapped_clone(self->dir); | |
| 111 | + if (mfd < 0) | |
| 112 | + SKIP(return, "idmapped mounts not supported"); | |
| 113 | + | |
| 114 | + /* Become a caller outside the mount's [0, MAP_RANGE) range. */ | |
| 115 | + setfsgid(UNMAPPED); | |
| 116 | + setfsuid(UNMAPPED); | |
| 117 | + ASSERT_EQ(setfsuid(-1), UNMAPPED); | |
| 118 | + | |
| 119 | + fd = openat(mfd, ".", O_TMPFILE | O_WRONLY, 0644); | |
| 120 | + ASSERT_LT(fd, 0); | |
| 121 | + EXPECT_EQ(errno, EOVERFLOW); | |
| 122 | + if (fd >= 0) | |
| 123 | + close(fd); | |
| 124 | + | |
| 125 | + EXPECT_EQ(close(mfd), 0); | |
| 126 | +} | |
| 127 | + | |
| 128 | +/* | |
| 129 | + * A mapped caller can create an O_TMPFILE and link it into the namespace; the | |
| 130 | + * ownership round-trips through the mount idmap. This is what makes refusing | |
| 131 | + * the unmapped case above necessary in the first place. | |
| 132 | + */ | |
| 133 | +TEST_F(idmapped_tmpfile, mapped_caller_creates_and_links) | |
| 134 | +{ | |
| 135 | + char path[PATH_MAX]; | |
| 136 | + struct stat st; | |
| 137 | + int mfd, fd; | |
| 138 | + | |
| 139 | + mfd = idmapped_clone(self->dir); | |
| 140 | + if (mfd < 0) | |
| 141 | + SKIP(return, "idmapped mounts not supported"); | |
| 142 | + | |
| 143 | + /* Caller is uid/gid 0, which maps to MAP_HOST through the mount. */ | |
| 144 | + fd = openat(mfd, ".", O_TMPFILE | O_RDWR, 0600); | |
| 145 | + ASSERT_GE(fd, 0); | |
| 146 | + | |
| 147 | + ASSERT_EQ(fstat(fd, &st), 0); | |
| 148 | + EXPECT_EQ(st.st_uid, 0); | |
| 149 | + EXPECT_EQ(st.st_gid, 0); | |
| 150 | + | |
| 151 | + /* The tmpfile is linkable: splice it into the directory. */ | |
| 152 | + ASSERT_EQ(linkat(fd, "", mfd, "linked", AT_EMPTY_PATH), 0); | |
| 153 | + EXPECT_EQ(close(fd), 0); | |
| 154 | + | |
| 155 | + ASSERT_EQ(fstatat(mfd, "linked", &st, 0), 0); | |
| 156 | + EXPECT_EQ(st.st_uid, 0); | |
| 157 | + EXPECT_EQ(st.st_gid, 0); | |
| 158 | + | |
| 159 | + /* On the underlying, non-idmapped tmpfs it is stored as MAP_HOST. */ | |
| 160 | + snprintf(path, sizeof(path), "%s/linked", self->dir); | |
| 161 | + ASSERT_EQ(stat(path, &st), 0); | |
| 162 | + EXPECT_EQ(st.st_uid, MAP_HOST); | |
| 163 | + EXPECT_EQ(st.st_gid, MAP_HOST); | |
| 164 | + | |
| 165 | + EXPECT_EQ(close(mfd), 0); | |
| 166 | +} | |
| 167 | + | |
| 168 | +TEST_HARNESS_MAIN | |