From b41e6396af0248c52fafcb35390e4d323f316dbd Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Tue, 18 Jun 2024 07:20:54 -0400 Subject: [PATCH] Fixes for 5.10 Signed-off-by: Sasha Levin --- ...f-in-bpf_task_fd_query-use-fget_task.patch | 82 + ...tify-use-fsnotify-group-lock-helpers.patch | 99 ++ ...d-missing-documentation-for-export_o.patch | 55 + ...ec-don-t-open-code-get_close_on_exec.patch | 46 + ...e_files-to-fix-posix-file-locking-du.patch | 204 +++ .../exec-remove-reset_files_struct.patch | 61 + queue-5.10/exec-simplify-unshare_files.patch | 126 ++ queue-5.10/exit-implement-kthread_exit.patch | 114 ++ ...le_put_and_exit-to-module_put_and_kt.patch | 216 +++ ...unction-to-return-the-raw-output-fro.patch | 99 ++ ...debug-for-unreachable-debug-statemen.patch | 60 + ...pers-to-decide-whether-to-report-fid.patch | 97 ++ ...dd-pidfd-support-to-the-fanotify-api.patch | 294 ++++ ...ile-handle-encoding-for-unhashed-eve.patch | 45 + ...users-to-request-fan_fs_error-events.patch | 78 + ...s-for-fanotify_mark-input-validation.patch | 138 ++ ...notify-configurable-limits-via-sysfs.patch | 468 +++++ ...eate-helper-fanotify_mark_user_flags.patch | 68 + ...allow-setting-dirent-events-in-mask-.patch | 72 + ...t-generic-error-info-for-error-event.patch | 147 ++ ...anotify-enable-evictable-inode-marks.patch | 50 + ...empty-file-handle-when-no-inode-is-p.patch | 55 + ...out-helper-fanotify_mark_update_flag.patch | 130 ++ ...fanotify-fix-incorrect-fmode_t-casts.patch | 54 + ...rmission-model-of-unprivileged-group.patch | 148 ++ ...ent-size-calculation-to-its-own-func.patch | 110 ++ ...tify-implement-evictable-inode-marks.patch | 160 ++ ...ce-a-generic-info-record-copying-hel.patch | 258 +++ .../fanotify-introduce-fan_mark_ignore.patch | 273 +++ ...uce-group-flag-fan_report_target_fid.patch | 178 ++ ...number-of-event-merge-attempts.patch-30929 | 58 + ...r-cosmetic-adjustments-to-fid-labels.patch | 120 ++ ...ent-info-and-pid-into-merge-key-hash.patch | 273 +++ ...fy-pre-allocate-pool-of-error-events.patch | 158 ++ ...-for-setting-event-flags-in-ignore-m.patch | 399 +++++ ...either-old-name-new-name-or-both-for.patch | 149 ++ ...old-and-new-parent-and-name-in-fan_r.patch | 152 ++ ...reduce-event-objectid-to-29-bit-hash.patch | 195 +++ ...the-validation-checks-on-non-dir-ino.patch | 121 ++ ...ve-obsoleted-fanotify_event_has_path.patch | 43 + ...ify-remove-variable-set-but-not-used.patch | 54 + ...fid-info-for-file-related-file-syste.patch | 134 ++ ...old-and-or-new-parent-name-in-fan_re.patch | 207 +++ ...equire-fid_mode-for-any-non-fd-event.patch | 69 + ...y-reserve-uapi-bits-for-fan_fs_error.patch | 52 + ...sid-check-from-other-fid-mode-checks.patch | 104 ++ ...y-support-enqueueing-of-error-events.patch | 123 ++ ...-limited-functionality-for-unprivile.patch | 161 ++ ...tify-support-merging-of-error-events.patch | 123 ++ ...-null-inode-event-in-fanotify_dfid_i.patch | 41 + ...-secondary-dir-fh-and-name-in-fanoti.patch | 248 +++ ...tify-use-fsnotify-group-lock-helpers.patch | 113 ++ ...lpers-to-parcel-fanotify_info-buffer.patch | 130 ++ ...ros-to-get-the-offset-to-fanotify_in.patch | 126 ++ ...rn_on-against-too-large-file-handles.patch | 56 + .../fanotify-wire-up-fan_rename-event.patch | 82 + ...ject_fh-inline-space-in-a-creator-ma.patch | 54 + ...ser-use-upper_32_bits-to-verify-mask.patch | 40 + ...s_lookup_fd_locked-out-of-fcheck_fil.patch | 122 ++ .../file-implement-task_lookup_fd_rcu.patch | 65 + ...le-implement-task_lookup_next_fd_rcu.patch | 89 + ...e-in-f_dupfd-read-rlimit_nofile-once.patch | 60 + .../file-merge-__alloc_fd-into-alloc_fd.patch | 77 + ...e-merge-__fd_install-into-fd_install.patch | 105 ++ ...ose_fd-to-close_fd-and-remove-the-fi.patch | 127 ++ ..._fcheck_files-to-files_lookup_fd_raw.patch | 89 + .../file-rename-fcheck-lookup_fd_rcu.patch | 107 ++ ...check_files-with-files_lookup_fd_rcu.patch | 168 ++ ...ile-replace-ksys_close-with-close_fd.patch | 74 + ...ew-locks_inode_context-accessor-func.patch | 174 ++ ...dd-file-and-path-permissions-helpers.patch | 256 +++ ...-inotify-fix-typo-in-inotify-comment.patch | 36 + ...llbacks-to-lock_manager_operations-t.patch | 167 ++ ...er-locks_owner_has_blockers-to-check.patch | 90 + ...ation-cleanup.-replace-inode-i_lock-.patch | 46 + .../fs-lockd-convert-comma-to-semicolon.patch | 35 + queue-5.10/fs-notify-constify-path.patch | 80 + ...-add-helper-to-detect-overflow_event.patch | 58 + ...dd-wrapper-around-fsnotify_add_event.patch | 120 ++ ...dding-an-inode-mark-without-pinning-.patch | 217 +++ ...snotify_-peek-remove-_first_event-wi.patch | 207 +++ ...rify-contract-for-create-event-hooks.patch | 114 ++ ...snotify-clarify-object-type-argument.patch | 275 +++ ...ent-behavior-for-parent-not-watching.patch | 131 ++ ...all-objects-with-attached-connectors.patch | 155 ++ ..._fsnotify_inode_refs-for-attached-co.patch | 100 ++ ...te-helpers-for-group-mark_mutex-lock.patch | 221 +++ ...nsert-unmergeable-events-in-hashtabl.patch | 54 + queue-5.10/fsnotify-fix-comment-typo.patch | 36 + ...fix-merge-with-parent-s-ignored-mask.patch | 144 ++ .../fsnotify-fix-sb_connectors-leak.patch | 44 + ...e-fs_rename-event-with-rich-informat.patch | 226 +++ ...snotify-introduce-mark-type-iterator.patch | 243 +++ ...e-allow_dups-a-property-of-the-group.patch | 156 ++ ...e-fs_modify-events-with-no-ignored-m.patch | 154 ++ ...ize-the-case-of-no-marks-of-any-type.patch | 61 + ...tify-pass-data_type-to-fsnotify_name.patch | 91 + ...fy-pass-dentry-instead-of-inode-data.patch | 98 ++ ...ags-argument-to-fsnotify_alloc_group.patch | 207 +++ ...fy-pass-group-argument-to-free_event.patch | 98 ++ ...-fsnotify_handle_inode_event-from-no.patch | 72 + ...-remove-redundant-parameter-judgment.patch | 48 + .../fsnotify-remove-unused-declaration.patch | 40 + ...-igrab-with-ihold-on-attach-connecto.patch | 42 + ...ieve-super-block-from-the-data-field.patch | 89 + ...e-mark-iterator-type-from-object-typ.patch | 247 +++ ...fsnotify-support-fs_error-event-type.patch | 122 ++ ...e-hash-table-for-faster-events-merge.patch | 359 ++++ .../inotify-don-t-force-fs_in_ignored.patch | 52 + ...-default-inotify.max_user_watches-li.patch | 102 ++ ...-account-inotify-instances-to-kmemcg.patch | 130 ++ ...ontrol-flags-from-mask-to-mark-flags.patch | 228 +++ ...tify-use-fsnotify-group-lock-helpers.patch | 46 + ...ild-module_-kallsyms_on_each_symbol-.patch | 146 ++ ...ctor-module_-kallsyms_on_each_symbol.patch | 113 ++ ..._file_raw_ptr-use-task_lookup_fd_rcu.patch | 49 + ...p-in-kcmp_epoll_target-use-fget_task.patch | 71 + ...ead-and-write-fds-with-each-nlm_file.patch | 450 +++++ ...lement-additional-checks-upon-pidfd_.patch | 60 + ...ove-static-qualifier-from-pidfd_crea.patch | 59 + ...e-proc_handler-for-nsm_use_hostnames.patch | 43 + queue-5.10/lockd-common-nlm-xdr-helpers.patch | 181 ++ ...implified-.vs_dispatch-method-for-nl.patch | 98 ++ ...-reject-lock-arguments-that-overflow.patch | 128 ++ ...empt-blocking-locks-on-nfs-reexports.patch | 76 + ...nappropriate-svc_get-from-locked_get.patch | 57 + ...use-the-correct-file-descriptor-when.patch | 45 + ...-fix-failure-to-cleanup-client-locks.patch | 46 + ...e-selection-in-nlmsvc_cancel_blocked.patch | 43 + queue-5.10/lockd-fix-nlm_close_files.patch | 44 + ...-crash-on-reboot-of-client-holding-l.patch | 62 + queue-5.10/lockd-introduce-lockd_put.patch | 127 ++ queue-5.10/lockd-introduce-nlmsvc_serv.patch | 152 ++ ...strlcpy-with-unused-retval-to-strscp.patch | 37 + ..._start_svc-call-into-lockd_create_sv.patch | 105 ++ ...move-svc_exit_thread-into-the-thread.patch | 106 ++ queue-5.10/lockd-remove-stale-comments.patch | 55 + ...rename-lockd_create_svc-to-lockd_get.patch | 71 + ...ock-start-and-end-when-decoding-nlm4.patch | 105 ++ ...kd-set-fl_owner-when-unlocking-files.patch | 54 + ...g-fl_flags-field-when-retrieving-arg.patch | 44 + ...-missing-fields-when-unlocking-files.patch | 69 + ...anagement-of-network-status-notifier.patch | 157 ++ ...ate-nlm_lookup_file-reexport-comment.patch | 38 + ...-nlmv1-cancel-arguments-decoder-to-u.patch | 75 + ...-nlmv1-free_all-arguments-decoder-to.patch | 67 + ...-nlmv1-lock-arguments-decoder-to-use.patch | 84 + ...-nlmv1-nlm_res-arguments-decoder-to-.patch | 64 + ...-nlmv1-nlm_res-results-encoder-to-us.patch | 56 + ...-nlmv1-share-arguments-decoder-to-us.patch | 166 ++ ...-nlmv1-share-results-encoder-to-use-.patch | 65 + ...-nlmv1-sm_notify-arguments-decoder-t.patch | 78 + ...-nlmv1-test-arguments-decoder-to-use.patch | 125 ++ ...-nlmv1-test-results-encoder-to-use-s.patch | 127 ++ ...-nlmv1-unlock-arguments-decoder-to-u.patch | 101 ++ ...-nlmv1-void-argument-decoder-to-use-.patch | 64 + ...-nlmv1-void-results-encoder-to-use-s.patch | 52 + ...-nlmv4-cancel-arguments-decoder-to-u.patch | 74 + ...-nlmv4-free_all-arguments-decoder-to.patch | 67 + ...-nlmv4-lock-arguments-decoder-to-use.patch | 84 + ...-nlmv4-nlm_res-arguments-decoder-to-.patch | 64 + ...-nlmv4-nlm_res-results-encoder-to-us.patch | 56 + ...-nlmv4-share-arguments-decoder-to-us.patch | 162 ++ ...-nlmv4-share-results-encoder-to-use-.patch | 61 + ...-nlmv4-sm_notify-arguments-decoder-t.patch | 78 + ...-nlmv4-test-arguments-decoder-to-use.patch | 125 ++ ...-nlmv4-test-results-encoder-to-use-s.patch | 126 ++ ...-nlmv4-unlock-arguments-decoder-to-u.patch | 101 ++ ...-nlmv4-void-arguments-decoder-to-use.patch | 64 + ...-nlmv4-void-results-encoder-to-use-s.patch | 52 + ...lockd-use-locks_inode_context-helper.patch | 49 + ...t_num_threads-for-thread-start-and-s.patch | 189 ++ ...nexport-find_module-and-module_mutex.patch | 44 + ...e-use-rcu-to-synchronize-find_module.patch | 101 ++ .../namei-introduce-struct-renamedata.patch | 196 +++ ...e-local-dispatcher-for-nfsv4-callbac.patch | 64 + ...notification-on-fs-with-its-own-lock.patch | 184 ++ .../nfs-don-t-allow-reexport-reclaims.patch | 99 ++ ...empt-blocking-locks-on-nfs-reexports.patch | 98 ++ queue-5.10/nfs-fix-nfs_fetch_iversion.patch | 49 + ...-remove-unused-callback-void-decoder.patch | 52 + ...estore-module-put-when-manager-exits.patch | 46 + ...-callback-service-back-to-non-pooled.patch | 40 + ...-change-attribute-for-nfs-re-exports.patch | 101 ++ ...-is-not-needed-after-a-switch-statem.patch | 32 + ...le-more-nfsd_clid_expired-call-sites.patch | 87 + ...r-that-encodes-nfsv3-directory-offse.patch | 132 ++ ...-encodes-nfsv3-directory-offse.patch-18644 | 84 + ...dd-a-helper-to-decode-channel_attrs4.patch | 109 ++ ...-add-a-helper-to-decode-nfs_impl_id4.patch | 105 ++ ...-a-helper-to-decode-state_protect4_a.patch | 119 ++ ...-mechanism-to-wait-for-a-delegreturn.patch | 145 ++ ...xport_op_nowcc-flag-to-struct-export.patch | 219 +++ ...-add-a-nfsd4_file_hash_remove-helper.patch | 66 + ...-a-separate-decoder-for-ssv_sp_parms.patch | 115 ++ ...ate-decoder-to-handle-state_protect_.patch | 115 ++ ...point-for-errors-in-nfsd4_clone_file.patch | 158 ++ ...point-to-record-directory-entry-enco.patch | 102 ++ ...-add-an-nfsd4_encode_nfstime4-helper.patch | 97 ++ .../nfsd-add-an-nfsd4_read-rd_eof-field.patch | 97 ++ ...-add-an-nfsd_cb_lm_notify-tracepoint.patch | 81 + ...sd-add-an-nfsd_cb_offload-tracepoint.patch | 90 + ...nfsd-add-an-nfsd_cb_probe-tracepoint.patch | 49 + ...sd-add-an-nfsd_file_fsync-tracepoint.patch | 93 + ..._file_gc-flag-to-enable-nfsd_file-ga.patch | 266 +++ ...authflavor-tracepoint-display-helper.patch | 49 + ...stream-based-decoder-for-nfsv2-3-acl.patch | 92 + ...stream-based-encoder-for-nfsv2-3-acl.patch | 114 ++ queue-5.10/nfsd-add-cb_lost-tracepoint.patch | 48 + ...helpers-to-decode-void-args-and-enco.patch | 406 +++++ ...us-server-support-for-thread-with-on.patch | 278 +++ ...ion-reaper-to-react-to-low-memory-co.patch | 213 +++ ...ting-comment-for-nfsd4_release_locko.patch | 72 + ...nfsd-add-errno-mapping-for-eremoteio.patch | 36 + ...nfsd-add-helper-for-decoding-locker4.patch | 135 ++ ...add-helper-to-decode-nfsv4-verifiers.patch | 65 + ...to-decode-open-s-createhow4-argument.patch | 116 ++ ...to-decode-open-s-open_claim4-argumen.patch | 186 ++ ...-to-decode-open-s-openflag4-argument.patch | 76 + ...to-set-up-the-pages-where-the-dirlis.patch | 152 ++ ...-up-the-pages-where-the-dirlis.patch-28629 | 108 ++ ...-to-decode-a-clientid4-and-an-nfsv4-.patch | 74 + .../nfsd-add-nfsd4_send_cb_offload.patch | 82 + ...d-add-nfsd_clid_confirmed-tracepoint.patch | 68 + ...d-nfsd_clid_cred_mismatch-tracepoint.patch | 114 ++ ...d-add-nfsd_clid_destroyed-tracepoint.patch | 47 + ...fsd_clid_reclaim_complete-tracepoint.patch | 45 + ...d-nfsd_clid_verf_mismatch-tracepoint.patch | 98 ++ ...dd-nfsd_file_lru_dispose_list-helper.patch | 73 + ...-add-posix-acls-to-struct-nfsd_attrs.patch | 298 ++++ ...-security-label-to-struct-nfsd_attrs.patch | 210 +++ ...r-to-reap-courtesy-clients-on-low-me.patch | 239 +++ ...ome-comments-to-nfsd_file_do_acquire.patch | 39 + ...-add-spdx-header-for-fs-nfsd-trace.c.patch | 32 + ...-for-lock-conflict-to-courteous-serv.patch | 145 ++ ...dd-support-for-sending-cb_recall_any.patch | 177 ++ ...-for-share-reservation-conflict-to-c.patch | 205 +++ ...support-for-the-birth-time-attribute.patch | 67 + ...racepoints-for-exchangeid-edge-cases.patch | 84 + ...acepoints-for-setclientid-edge-cases.patch | 151 ++ ...ints-in-nfsd4_decode-encode_compound.patch | 150 ++ ...fsd-add-tracepoints-in-nfsd_dispatch.patch | 146 ++ ...ints-to-report-nfsv4-callback-comple.patch | 139 ++ ...d-vfs_fsync-after-async-copy-is-done.patch | 87 + .../nfsd-adjust-cb_shutdown-tracepoint.patch | 45 + ...llow-disabling-nfsv2-at-compile-time.patch | 156 ++ ...ystems-to-opt-out-of-subtree-checkin.patch | 92 + ...file_get-to-sanely-handle-a-null-poi.patch | 61 + ...-reaping-files-still-under-writeback.patch | 95 + ...s-drop-directory-lock-in-nfsd_unlink.patch | 94 + ...ng-fh_drop_write-twice-in-do_nfsd_cr.patch | 49 + ...ing-opdesc-with-ops-opnum-op_illegal.patch | 54 + ...d-avoid-clashing-function-prototypes.patch | 1534 +++++++++++++++++ .../nfsd-avoid-some-useless-tests.patch | 56 + ...tch-release-pages-during-splice-read.patch | 46 + ...sd_last_thread-before-final-nfsd_put.patch | 83 + ...ease-even-when-op_func-returns-an-er.patch | 69 + ...bop-result-based-on-send-buffer-size.patch | 145 ++ ...sd-capture-every-cb-state-transition.patch | 106 ++ ..._create-nfsd_symlink-to-unlock-direc.patch | 144 ++ ...way-the-expected-length-of-a-fattr4-.patch | 172 ++ .../nfsd-clean-up-_lm_-operation-names.patch | 60 + ...up-after-updating-nfsv2-acl-decoders.patch | 67 + ...up-after-updating-nfsv2-acl-encoders.patch | 113 ++ ...up-after-updating-nfsv3-acl-decoders.patch | 63 + ...up-after-updating-nfsv3-acl-encoders.patch | 143 ++ .../nfsd-clean-up-find_or_add_file.patch | 128 ++ ...-clean-up-mounted_on_fileid-handling.patch | 79 + ...fs4_preprocess_stateid_op-call-sites.patch | 111 ++ ...-clean-up-nfs4svc_encode_compoundres.patch | 42 + .../nfsd-clean-up-nfsd3_proc_create.patch | 59 + .../nfsd-clean-up-nfsd4_encode_readlink.patch | 67 + .../nfsd-clean-up-nfsd4_init_file.patch | 66 + queue-5.10/nfsd-clean-up-nfsd_file_put.patch | 51 + .../nfsd-clean-up-nfsd_open_verified.patch | 82 + .../nfsd-clean-up-nfsd_splice_actor.patch | 52 + queue-5.10/nfsd-clean-up-nfsd_vfs_write.patch | 54 + ...nfsd-clean-up-nfsddbg_facility-macro.patch | 49 + ...tential-nfsd_file-refcount-leaks-in-.patch | 108 ++ queue-5.10/nfsd-clean-up-splice-actor.patch | 67 + ...an-up-splice_ok-in-nfsd4_encode_read.patch | 58 + ...an-up-the-nfsd_net-nfssvc_boot-field.patch | 173 ++ ...fsd-clean-up-the-show_nf_flags-macro.patch | 38 + .../nfsd-clean-up-the-show_nf_may-macro.patch | 112 ++ ...used-code-after-rhashtable-conversio.patch | 132 ++ .../nfsd-clean-up-write-arg-decoders.patch | 54 + ...d-files-prior-to-a-remove-or-rename-.patch | 155 ++ .../nfsd-combine-xdr-error-tracepoints.patch | 70 + ...ations-must-not-return-nfs-err_inval.patch | 181 ++ ...onstify-fh-argument-of-knfsd_fh_hash.patch | 45 + .../nfsd-convert-filecache-to-rhltable.patch | 578 +++++++ ...vert-the-filecache-to-use-rhashtable.patch | 545 ++++++ ...ole-verifier-in-nfsd_copy_write_veri.patch | 36 + ...-length-0-should-copy-to-end-of-file.patch | 39 + ...-instead-of-pages-in-the-nfsv2-readd.patch | 72 + ...-instead-of-pages-in-the-nfsv3-readd.patch | 114 ++ ...-cstate-session-se_client-cstate-clp.patch | 110 ++ ...sd-de-duplicate-hash-bucket-indexing.patch | 83 + ...te-net_generic-nf-nf_net-nfsd_net_id.patch | 67 + ...e-net_generic-svc_net-rqstp-nfsd_net.patch | 58 + ...sd-de-duplicate-nfsd4_decode_bitmap4.patch | 51 + ...sd-decode-nfsv4-birth-time-attribute.patch | 83 + ...nt-source-s-export-after-inter-serve.patch | 402 +++++ .../nfsd-demote-a-warn-to-a-pr_warn.patch | 38 + .../nfsd-deprecate-nfs_offset_max.patch | 69 + ...cpu-stats-counters-after-reply-cache.patch | 50 + ...fh_locked-flag-and-fh_lock-fh_unlock.patch | 189 ++ ...t-allow-nfsd-threads-to-be-signalled.patch | 210 +++ ...locks_release_private-twice-concurre.patch | 57 + ...oy-global-nfs4_file-table-in-per-net.patch | 47 + ...files-unconditionally-in-__nfsd_file.patch | 121 ++ ...don-t-fsync-nfsd_files-on-last-close.patch | 176 ++ ...out-delegation-on-setuid-files-being.patch | 96 ++ ...don-t-ignore-high-bits-of-copy-count.patch | 37 + ...nfsd_files-because-of-lease-break-er.patch | 101 ++ ...on-t-open-code-clear_and_wake_up_bit.patch | 34 + ...ce-page-in-rq_pages-if-it-s-a-contin.patch | 65 + ...-take-fi_lock-in-nfsd_break_deleg_cb.patch | 97 ++ ...put-an-extra-reference-when-putting-.patch | 38 + ...op-fh-argument-from-alloc_init_deleg.patch | 94 + ...and-flen-args-from-nfsd_create_locke.patch | 79 + ...drop-support-for-ancient-filehandles.patch | 324 ++++ .../nfsd-drop-the-nfsd_put-helper.patch | 132 ++ ...define_enum-for-nfsd4_cb_-state-macr.patch | 38 + ...eliminate-the-nfsd_file_break_-flags.patch | 119 ++ ...ehandle-check-for-source-file-in-cop.patch | 43 + ...sd-enhance-inter-server-copy-cleanup.patch | 345 ++++ ...enhance-the-nfsd_cb_setup-tracepoint.patch | 83 + ...nsure-nf_inode-is-never-dereferenced.patch | 86 + ...cks-when-freeing-delegation-stateids.patch | 42 + ...xtract-the-svcxdr_init_encode-helper.patch | 683 ++++++++ .../nfsd-find_cpntf_state-cleanup.patch | 69 + ...erting-the-nfsv2-getacl-result-encod.patch | 56 + ...erting-the-nfsv3-getacl-result-encod.patch | 73 + ...fsd-fix-a-regression-in-nfsd_setattr.patch | 91 + ...-a-warning-for-nfsd_file_close_inode.patch | 32 + ...d-fix-a-write-performance-regression.patch | 86 + .../nfsd-fix-boolreturn.cocci-warning.patch | 40 + ...s-about-spinlock-handling-with-deleg.patch | 40 + ...y-client-with-deny-mode-handling-in-.patch | 62 + ...-on-copy_notify-with-special-stateid.patch | 57 + ...ix-creation-time-serialization-order.patch | 66 + ...uble-fget-bug-in-__write_ports_addfd.patch | 123 ++ ...eturn-code-in-nfsd4_interssc_connect.patch | 38 + ...-return-code-in-nfsd_file_cache_init.patch | 35 + ...-fix-exposure-in-nfsd4_decode_bitmap.patch | 50 + ...-fix-fall-through-warnings-for-clang.patch | 49 + ...g-of-cached-open-files-in-nfsd4_open.patch | 273 +++ ...g-of-oversized-nfsv4-compound-reques.patch | 125 ++ queue-5.10/nfsd-fix-ia_size-underflow.patch | 45 + .../nfsd-fix-inconsistent-indenting.patch | 40 + ...ernel-test-robot-warning-in-ssc-code.patch | 60 + ...reference-count-of-nfsd4_ssc_umount_.patch | 54 + ...-fix-licensing-header-in-filecache.c.patch | 34 + ...espace-logic-in-__nfsd_file_cache_pu.patch | 42 + ...fsd-fix-nfsd_file_unhash_and_dispose.patch | 125 ++ ...etattr-create-s-handling-of-large-fi.patch | 44 + ...reference-in-nfs3svc_encode_getaclre.patch | 54 + ...ix-null-ptr-deref-in-nfsd_fill_super.patch | 105 ++ ...e-oops-when-nfsd-pool_stats-is-close.patch | 54 + ...tial-use-after-free-in-nfsd_file_put.patch | 44 + ...-of-commit-and-nfs4err_delay-in-infi.patch | 48 + ...s-with-cleanup-on-errors-in-nfsd4_co.patch | 97 ++ .../nfsd-fix-readdir-buffer-overflow.patch | 112 ++ ...ith-a-non-zero-offset-that-don-t-end.patch | 50 + ...fsd-fix-regression-with-setting-acls.patch | 85 + queue-5.10/nfsd-fix-release_lockowner.patch | 149 ++ ...d-fix-returned-readdir-offset-cookie.patch | 57 + .../nfsd-fix-space-and-spelling-mistake.patch | 44 + .../nfsd-fix-sparse-warning-in-nfssvc.c.patch | 73 + queue-5.10/nfsd-fix-sparse-warning.patch | 35 + .../nfsd-fix-strncpy-fortify-warning.patch | 58 + ...the-behavior-of-read-near-offset_max.patch | 122 ++ .../nfsd-fix-the-filecache-lru-shrinker.patch | 57 + queue-5.10/nfsd-fix-typo-accesible.patch | 53 + ...-to-ensure-that-timeout-errors-don-t.patch | 52 + ...-the-filecache-laundrette-scheduling.patch | 58 + ...se-after-free-in-nfsd4_ssc_setup_dul.patch | 38 + ...er-free-in-nfsd_file_do_acquire-trac.patch | 41 + ...sing-the-correct-variable-for-sizeof.patch | 36 + queue-5.10/nfsd-fix-whitespace.patch | 84 + .../nfsd-fix-zero-length-nfsv3-writes.patch | 92 + ...-documenting-comment-for-filecache.c.patch | 59 + ...delegations-to-clients-holding-write.patch | 156 ++ ...e-errors-better-in-write_ports_addfd.patch | 36 + ...nfsd-hash-nfs4_files-by-inode-number.patch | 141 ++ ...-nfsd-write-decoders-use-xdr_stream_.patch | 214 +++ ...r-for-laundromat-expiry-calculations.patch | 140 ++ ...nfsd-hook-up-the-filecache-stat-file.patch | 65 + ...ests-to-disable-unsupported-versions.patch | 40 + ...stateid-access-bitmask-documentation.patch | 73 + ...d-increase-nfsd_max_ops_per_compound.patch | 82 + ...pointer-ni-with-null-and-not-plain-i.patch | 50 + ...-a-struct-file-when-creating-a-regul.patch | 318 ++++ .../nfsd-introduce-struct-nfsd_attrs.patch | 434 +++++ ...encode_result_payload-in-read-nfsd-e.patch | 249 +++ ...of-the-number-of-courtesy-clients-in.patch | 100 ++ ...of-the-number-of-v4-clients-in-the-s.patch | 92 + ...-open-files-out-of-the-filecache-lru.patch | 160 ++ ...umber-of-v4-clients-to-1024-per-1gb-.patch | 135 ++ ...tracking-type-log-message-as-info-in.patch | 75 + ...-of-struct-iattr-before-calling-noti.patch | 50 + ...sible-to-use-svc_set_num_threads_syn.patch | 190 ++ .../nfsd-make-nfs4_put_copy-static.patch | 46 + .../nfsd-make-nfsd4_ops-opnum-a-u32.patch | 73 + ...remove-wait-before-returning-nfs4err.patch | 52 + ...rename-wait-before-returning-nfs4err.patch | 53 + ...-nfsd4_run_cb-a-bool-return-function.patch | 96 ++ ...setattr-wait-before-returning-nfs4er.patch | 54 + ...nfsd-make-nfsd_stats.th_cnt-atomic_t.patch | 87 + queue-5.10/nfsd-map-ebadf.patch | 72 + ...minor-nfsd4_change_attribute-cleanup.patch | 77 + ...sd-modernize-nfsd4_release_lockowner.patch | 85 + ...ffload-callback-arguments-into-a-sep.patch | 233 +++ ...-destroy-of-laundry_wq-to-init_nfsd-.patch | 129 ++ ...nting-comment-for-nfsd4_process_open.patch | 63 + ...ndle-format-declarations-out-of-uapi.patch | 292 ++++ ...-move-fill_pre_wcc-and-fill_post_wcc.patch | 290 ++++ ...trlcpy-with-unused-retval-to-strscpy.patch | 85 + ...fy-on-client-creation-outside-spinlo.patch | 65 + ...ove-nfsd_file_trace_alloc-tracepoint.patch | 85 + queue-5.10/nfsd-move-nfserrno-to-vfs.c.patch | 250 +++ ...ommit_metadata-s-outside-the-inode-l.patch | 59 + ...rv_ops-svo_function-into-struct-svc_.patch | 268 +++ ...nfsd_mutex-protection-in-nfsd-thread.patch | 67 + ...all-nfsd_file_gc-in-foreground-paths.patch | 87 + ...remove-unused-macro-nfsd3_fhandleres.patch | 39 + ...file_hash_remove-can-compute-hashval.patch | 58 + ...ey_inode-only-needs-to-find-gc-ed-en.patch | 55 + queue-5.10/nfsd-nfsd_file_put-can-sleep.patch | 39 + ...nhash-can-compute-hashval-from-nf-nf.patch | 45 + ...sd-nfserrno-enomem-is-nfserr_jukebox.patch | 41 + ...-should-release-an-nfsd_file-immedia.patch | 85 + ...r-record-nf_hashval-in-the-trace-log.patch | 212 +++ ...nly-call-fh_unlock-once-in-nfsd_link.patch | 71 + ...node_query_iversion-in-the-i_version.patch | 105 ++ ...ut-return-pointer-on-success-in-nfsd.patch | 56 + .../nfsd-optimize-drc-bucket-pruning.patch | 116 ++ .../nfsd-optimize-nfsd4_encode_fattr.patch | 65 + ...nfsd-optimize-nfsd4_encode_operation.patch | 40 + .../nfsd-optimize-nfsd4_encode_readv.patch | 78 + .../nfsd-pack-struct-nfsd4_compoundres.patch | 34 + ...end-to-vfs_fsync_range-instead-of-co.patch | 48 + ...-the-target-nfsd_file-to-nfsd_commit.patch | 153 ++ ...ossible-oops-in-the-nfs_dirent-trace.patch | 37 + ...ncation-of-an-unlinked-inode-from-bl.patch | 57 + ...ome-error-code-returned-by-memdup_us.patch | 55 + ...-protect-against-filesystem-freezing.patch | 42 + ...inst-send-buffer-overflow-in-nfsv2-r.patch | 43 + ...end-buffer-overflow-in-nfsv2-r.patch-22138 | 50 + ...inst-send-buffer-overflow-in-nfsv3-r.patch | 64 + ...end-buffer-overflow-in-nfsv3-r.patch-26809 | 60 + ...current-access-to-nfsd-stats-counter.patch | 513 ++++++ ...ort-reference-in-nfsd4_verify_deleg_.patch | 37 + ...4-pre-post-op-attributes-as-non-atom.patch | 96 ++ .../nfsd-record-number-of-flush-calls.patch | 71 + ...nt-of-struct-nfsd4_compoundargs-that.patch | 390 +++++ .../nfsd-reduce-locking-in-nfsd_lookup.patch | 210 +++ ...rqst-rq_pages-churn-during-readdir-o.patch | 61 + ...fsd-refactor-__nfsd_file_close_inode.patch | 179 ++ ...r-common-code-out-of-dirlist-helpers.patch | 115 ++ queue-5.10/nfsd-refactor-find_file.patch | 85 + ...refactor-nfsd4_cleanup_inter_ssc-1-2.patch | 66 + ...refactor-nfsd4_cleanup_inter_ssc-2-2.patch | 64 + queue-5.10/nfsd-refactor-nfsd4_do_copy.patch | 84 + .../nfsd-refactor-nfsd_create_setattr.patch | 163 ++ queue-5.10/nfsd-refactor-nfsd_file_gc.patch | 38 + .../nfsd-refactor-nfsd_file_lru_scan.patch | 62 + queue-5.10/nfsd-refactor-nfsd_setattr.patch | 145 ++ queue-5.10/nfsd-refactor-nfsv3-create.patch | 183 ++ .../nfsd-refactor-nfsv4-open-create.patch | 216 +++ queue-5.10/nfsd-refactor-set_client.patch | 82 + ...-courtesy_client_reaper-to-a-generic.patch | 94 + ...-v4-specific-code-to-a-helper-in-nfs.patch | 88 + ...register-of-nfsd-client-shrinker-at-.patch | 147 ++ .../nfsd-relocate-nfsd4_decode_opaque.patch | 82 + ...ment-length-checking-in-nfsd_dispatc.patch | 74 + ...e-be32_to_cpu-from-drc-hash-function.patch | 46 + queue-5.10/nfsd-remove-config_nfsd_v3.patch | 269 +++ queue-5.10/nfsd-remove-do_nfsd_create.patch | 210 +++ ...ntk-call-sites-from-tail-of-nfsd4_op.patch | 39 + ...ra-0x-in-tracepoint-format-specifier.patch | 60 + ...ne-directives-on-op_rsize_bop-helper.patch | 374 ++++ ...ove-kmalloc-from-nfsd4_do_async_copy.patch | 80 + ...dep-assertion-from-unhash_and_releas.patch | 35 + ...emove-macros-that-are-no-longer-used.patch | 107 ++ ...-nfsd4_prepare_cb_recall-declaration.patch | 35 + .../nfsd-remove-nfsd_file-nf_hashval.patch | 66 + ...redundant-assignment-to-pointer-this.patch | 38 + ...ndant-assignment-to-variable-host_er.patch | 39 + ...redundant-assignment-to-variable-len.patch | 38 + ...fsd-remove-redundant-variable-status.patch | 80 + .../nfsd-remove-svc_serv_ops-svo_module.patch | 179 ++ ...nfsd_cb_work-and-nfsd_cb_done-tracep.patch | 114 ++ ...pages_flushed-statistic-from-filecac.patch | 75 + ...fsd-remove-trace_nfsd_clid_inuse_err.patch | 58 + queue-5.10/nfsd-remove-unused-function.patch | 45 + ...ed-nfsd4_compoundargs-cachetype-fiel.patch | 33 + ...nused-nfsv2-directory-entry-encoders.patch | 139 ++ ...nused-nfsv3-directory-entry-encoders.patch | 279 +++ ...sd-remove-unused-set_client-argument.patch | 107 ++ .../nfsd-remove-unused-stats-counters.patch | 122 ++ queue-5.10/nfsd-remove-vanity-comments.patch | 48 + ...sed-argument-in-nfsd_startup_generic.patch | 62 + .../nfsd-rename-boot-verifier-functions.patch | 188 ++ ...sd-rename-lookup_clientid-set_client.patch | 100 ++ ...-rename-the-fields-in-copy_stateid_t.patch | 170 ++ ...eorder-the-fields-in-struct-nfsd4_op.patch | 48 + queue-5.10/nfsd-reorganize-filecache.c.patch | 239 +++ ...-boolean-fields-in-struct-nfsd4_copy.patch | 276 +++ ...ayed_work-with-work_struct-for-nfsd_.patch | 81 + ...e-read-macros-in-nfsd4_decode_access.patch | 60 + ...d-macros-in-nfsd4_decode_backchannel.patch | 54 + ...d-macros-in-nfsd4_decode_bind_conn_t.patch | 87 + ...e-read-macros-in-nfsd4_decode_cb_sec.patch | 224 +++ ...ce-read-macros-in-nfsd4_decode_clone.patch | 95 + ...ce-read-macros-in-nfsd4_decode_close.patch | 59 + ...e-read-macros-in-nfsd4_decode_commit.patch | 74 + ...read-macros-in-nfsd4_decode_compound.patch | 154 ++ ...ace-read-macros-in-nfsd4_decode_copy.patch | 117 ++ ...d-macros-in-nfsd4_decode_copy_notify.patch | 56 + ...e-read-macros-in-nfsd4_decode_create.patch | 127 ++ ...d-macros-in-nfsd4_decode_create_sess.patch | 61 + ...d-macros-in-nfsd4_decode_delegreturn.patch | 31 + ...d-macros-in-nfsd4_decode_destroy_cli.patch | 52 + ...d-macros-in-nfsd4_decode_destroy_ses.patch | 35 + ...ead-macros-in-nfsd4_decode_fallocate.patch | 47 + ...ce-read-macros-in-nfsd4_decode_fattr.patch | 169 ++ ...d-macros-in-nfsd4_decode_free_statei.patch | 37 + ...-read-macros-in-nfsd4_decode_getattr.patch | 32 + ...d-macros-in-nfsd4_decode_getdevicein.patch | 86 + ...d-macros-in-nfsd4_decode_layoutcommi.patch | 170 ++ ...ead-macros-in-nfsd4_decode_layoutget.patch | 64 + ...d-macros-in-nfsd4_decode_layoutretur.patch | 108 ++ ...ace-read-macros-in-nfsd4_decode_link.patch | 40 + ...ad-macros-in-nfsd4_decode_listxattrs.patch | 55 + ...ace-read-macros-in-nfsd4_decode_lock.patch | 54 + ...ce-read-macros-in-nfsd4_decode_lockt.patch | 53 + ...ce-read-macros-in-nfsd4_decode_locku.patch | 56 + ...e-read-macros-in-nfsd4_decode_lookup.patch | 40 + ...ad-macros-in-nfsd4_decode_nl4_server.patch | 79 + ...d-macros-in-nfsd4_decode_offload_sta.patch | 31 + ...ace-read-macros-in-nfsd4_decode_open.patch | 69 + ...d-macros-in-nfsd4_decode_open_confir.patch | 46 + ...d-macros-in-nfsd4_decode_open_downgr.patch | 51 + ...ce-read-macros-in-nfsd4_decode_putfh.patch | 51 + ...ace-read-macros-in-nfsd4_decode_read.patch | 46 + ...-read-macros-in-nfsd4_decode_readdir.patch | 54 + ...d-macros-in-nfsd4_decode_reclaim_com.patch | 54 + ...d-macros-in-nfsd4_decode_release_loc.patch | 50 + ...e-read-macros-in-nfsd4_decode_remove.patch | 40 + ...e-read-macros-in-nfsd4_decode_rename.patch | 49 + ...ce-read-macros-in-nfsd4_decode_renew.patch | 39 + ...-read-macros-in-nfsd4_decode_secinfo.patch | 40 + ...d-macros-in-nfsd4_decode_secinfo_no_.patch | 55 + ...ace-read-macros-in-nfsd4_decode_seek.patch | 47 + ...read-macros-in-nfsd4_decode_sequence.patch | 72 + ...-read-macros-in-nfsd4_decode_setattr.patch | 31 + ...d-macros-in-nfsd4_decode_setclientid.patch | 85 + ...os-in-nfsd4_decode_setclientid.patch-10977 | 44 + ...read-macros-in-nfsd4_decode_setxattr.patch | 63 + ...d-macros-in-nfsd4_decode_share_acces.patch | 44 + ...ad-macros-in-nfsd4_decode_share_deny.patch | 43 + ...d-macros-in-nfsd4_decode_test_statei.patch | 97 ++ ...e-read-macros-in-nfsd4_decode_verify.patch | 58 + ...ce-read-macros-in-nfsd4_decode_write.patch | 56 + ...ad-macros-in-nfsd4_decode_xattr_name.patch | 72 + ...d-macros-that-decode-the-fattr4-acl-.patch | 145 ++ ...d-macros-that-decode-the-fattr4-mode.patch | 36 + ...d-macros-that-decode-the-fattr4-owne.patch | 44 + ...os-that-decode-the-fattr4-owne.patch-23903 | 45 + ...d-macros-that-decode-the-fattr4-secu.patch | 93 + ...d-macros-that-decode-the-fattr4-size.patch | 36 + ...d-macros-that-decode-the-fattr4-time.patch | 94 + ...d-macros-that-decode-the-fattr4-umas.patch | 53 + ...nfsd-replace-the-init-once-mechanism.patch | 144 ++ ...-the-internals-of-the-read_buf-macro.patch | 411 +++++ ...lace-the-nfsd_deleg_break-tracepoint.patch | 89 + ...eport-average-age-of-filecache-items.patch | 95 + ...ent-confirmation-status-in-info-file.patch | 178 ++ ...-count-of-calls-to-nfsd_file_acquire.patch | 74 + ...eport-count-of-freed-filecache-items.patch | 67 + .../nfsd-report-filecache-lru-size.patch | 51 + queue-5.10/nfsd-report-per-export-stats.patch | 325 ++++ ...number-of-items-evicted-by-the-lru-w.patch | 127 ++ queue-5.10/nfsd-reshuffle-some-code.patch | 285 +++ ...sv4-decoding-s-savemem-functionality.patch | 154 ++ ...in-nfsd_open-on-an-eopenstale-return.patch | 71 + ...sd-return-error-if-nfs4_setacl-fails.patch | 39 + ...-nfsv4-close-should-release-an-nfsd_.patch | 96 ++ ...table-handling-in-nfsd_do_file_acqui.patch | 125 ++ ...nfsd-rework-refcounting-in-filecache.patch | 668 +++++++ ...nfsd-rpc_peeraddr2str-needs-rcu-lock.patch | 38 + ...ve-location-of-nfsv4-compound-status.patch | 85 + ...arate-nfsd_last_thread-from-nfsd_put.patch | 181 ++ ...e-tracepoints-for-acquire-and-create.patch | 164 ++ ...et-attributes-when-creating-symlinks.patch | 176 ++ ...l_throttle-on-local-filesystems-only.patch | 98 ++ ...t-up-an-rhashtable-for-the-filecache.patch | 247 +++ ...te-of-courtesy-client-in-client-info.patch | 46 + ...fsd-shrink-size-of-struct-nfsd4_copy.patch | 103 ++ ...ink-size-of-struct-nfsd4_copy_notify.patch | 96 ++ ...traneous-printk-on-nfsd.ko-insertion.patch | 36 + ...de-around-svc_exit_thread-call-in-nf.patch | 89 + ...implify-locking-for-network-notifier.patch | 188 ++ .../nfsd-simplify-nfsd4_change_info.patch | 80 + ...sd-simplify-nfsd4_check_open_reclaim.patch | 86 + queue-5.10/nfsd-simplify-nfsd_renew.patch | 44 + ...mplify-per-net-file-cache-management.patch | 187 ++ queue-5.10/nfsd-simplify-process_lock.patch | 47 + queue-5.10/nfsd-simplify-read_plus.patch | 210 +++ queue-5.10/nfsd-simplify-starting_len.patch | 54 + queue-5.10/nfsd-simplify-struct-nfsfh.patch | 334 ++++ ...st_bit-return-in-nfsd_file_key_full-.patch | 35 + ...plify-the-delayed-disposal-list-code.patch | 119 ++ ...xtra-computation-for-rc_nocache-case.patch | 52 + ...ome-unnecessary-stats-in-the-v4-case.patch | 108 ++ .../nfsd-streamline-the-rare-found-case.patch | 51 + .../nfsd-trace-boot-verifier-resets.patch | 120 ++ .../nfsd-trace-delegation-revocations.patch | 111 ++ .../nfsd-trace-filecache-lru-activity.patch | 160 ++ queue-5.10/nfsd-trace-filecache-opens.patch | 79 + ...ce-stateids-returned-via-delegreturn.patch | 49 + ...ck-filehandle-aliasing-in-nfs4_files.patch | 102 ++ ...er-shrinker-when-nfsd_init_net-fails.patch | 51 + ...the-cld-notifier-when-laundry_wq-cre.patch | 41 + ...ss3arg-decoder-to-use-struct-xdr_str.patch | 56 + ...comment-over-__nfsd_file_cache_purge.patch | 33 + ...it3arg-decoder-to-use-struct-xdr_str.patch | 45 + .../nfsd-update-create-verifier-comment.patch | 39 + .../nfsd-update-file_hashtbl-helpers.patch | 45 + ...ttr3args-decoder-to-use-struct-xdr_s.patch | 114 ++ .../nfsd-update-nfsd_cb_args-tracepoint.patch | 40 + ...2-diropargs-decoding-to-use-struct-x.patch | 77 + ...3-readdir-entry-encoders-to-use-stru.patch | 358 ++++ ...3arg-decoder-to-use-struct-xdr_strea.patch | 126 ++ ...dir3args-decoders-to-use-struct-xdr_.patch | 97 ++ ...link3arg-decoder-to-use-struct-xdr_s.patch | 107 ++ ...create3args-decoder-to-use-struct-xd.patch | 59 + ...getattr3res-encoder-to-use-struct-xd.patch | 216 +++ ...link3args-decoder-to-use-struct-xdr_.patch | 41 + ...mkdir3args-decoder-to-use-struct-xdr.patch | 41 + ...mknod3args-decoder-to-use-struct-xdr.patch | 162 ++ ...nfsv2-acl-access-argument-decoder-to.patch | 44 + ...nfsv2-acl-access-result-encoder-to-u.patch | 52 + ...nfsv2-acl-getattr-argument-decoder-t.patch | 52 + ...nfsv2-acl-getattr-result-encoder-to-.patch | 68 + ...nfsv2-attrstat-encoder-to-use-struct.patch | 189 ++ ...nfsv2-create-argument-decoder-to-use.patch | 42 + ...nfsv2-diropres-encoder-to-use-struct.patch | 99 ++ ...nfsv2-getacl-argument-decoder-to-use.patch | 95 + ...nfsv2-getacl-result-encoder-to-use-s.patch | 147 ++ ...nfsv2-getattr-argument-decoder-to-us.patch | 111 ++ ...nfsv2-link-argument-decoder-to-use-s.patch | 41 + ...nfsv2-read-argument-decoder-to-use-s.patch | 140 ++ ...nfsv2-read-result-encoder-to-use-str.patch | 91 + ...nfsv2-readdir-argument-decoder-to-us.patch | 49 + ...nfsv2-readdir-entry-encoder-to-use-s.patch | 214 +++ ...nfsv2-readdir-result-encoder-to-use-.patch | 67 + ...nfsv2-readlink-argument-decoder-to-u.patch | 108 ++ ...nfsv2-readlink-result-encoder-to-use.patch | 95 + ...nfsv2-rename-argument-decoder-to-use.patch | 44 + ...nfsv2-setacl-argument-decoder-to-use.patch | 78 + ...setacl-argument-decoder-to-use.patch-31348 | 65 + ...nfsv2-setacl-result-encoder-to-use-s.patch | 36 + ...nfsv2-setattr-argument-decoder-to-us.patch | 121 ++ ...nfsv2-stat-encoder-to-use-struct-xdr.patch | 122 ++ ...nfsv2-statfs-result-encoder-to-use-s.patch | 58 + ...nfsv2-symlink-argument-decoder-to-us.patch | 163 ++ ...nfsv2-write-argument-decoder-to-use-.patch | 91 + ...nfsv3-access3res-encoder-to-use-stru.patch | 102 ++ ...nfsv3-commit3res-encoder-to-use-stru.patch | 103 ++ ...nfsv3-create-family-of-encoders-to-u.patch | 75 + ...nfsv3-diropargs-decoder-to-use-struc.patch | 78 + ...nfsv3-fsinfo3res-encoder-to-use-stru.patch | 106 ++ ...nfsv3-fsstat3res-encoder-to-use-stru.patch | 101 ++ ...nfsv3-getacl-argument-decoder-to-use.patch | 85 + ...nfsv3-getacl-result-encoder-to-use-s.patch | 130 ++ ...nfsv3-link3res-encoder-to-use-struct.patch | 39 + ...nfsv3-lookup3res-encoder-to-use-stru.patch | 115 ++ ...nfsv3-pathconf3res-encoder-to-use-st.patch | 118 ++ ...nfsv3-read3res-encode-to-use-struct-.patch | 134 ++ ...nfsv3-readdir3res-encoder-to-use-str.patch | 120 ++ ...nfsv3-readlink3res-encoder-to-use-st.patch | 103 ++ ...nfsv3-renamev3res-encoder-to-use-str.patch | 39 + ...nfsv3-setacl-result-encoder-to-use-s.patch | 37 + ...nfsv3-wccstat-result-encoder-to-use-.patch | 114 ++ ...nfsv3-write3res-encoder-to-use-struc.patch | 79 + ...rename3args-decoder-to-use-struct-xd.patch | 43 + ...setattr3args-decoder-to-use-struct-x.patch | 202 +++ ...symlink3args-decoder-to-use-struct-x.patch | 67 + ...e3arg-decoder-to-use-struct-xdr_stre.patch | 99 ++ ...ointers-as-parameters-to-fh_-helpers.patch | 66 + ...proc_show_attribute-to-define-nfsd_p.patch | 53 + ...show_attribute-to-define-client_info.patch | 56 + ...show_attribute-to-define-export_feat.patch | 84 + ...show_attribute-to-define-nfsd_file_c.patch | 83 + ...show_attribute-to-define-nfsd_reply_.patch | 96 ++ ...fsd-use-define_spinlock-for-spinlock.patch | 44 + ...plicit-lock-unlock-for-directory-ops.patch | 265 +++ ...nfsd-use-fsnotify-group-lock-helpers.patch | 75 + .../nfsd-use-locks_inode_context-helper.patch | 56 + ..._dropme-to-signal-the-need-to-drop-a.patch | 61 + ...table-for-managing-nfs4_file-objects.patch | 251 +++ queue-5.10/nfsd-use-set_bit-rq_dropme.patch | 46 + ...-struct_size-helper-in-alloc_session.patch | 44 + ..._inode-instead-of-fh_-un-lock-for-fi.patch | 217 +++ ...line_decode-to-decode-nfsv3-symlinks.patch | 57 + queue-5.10/nfsd-use-xdr_pad_size.patch | 52 + ...opened-dentry-after-setting-a-delega.patch | 169 ++ ...reeing-an-item-still-linked-via-nf_l.patch | 63 + ...sd-write-verifier-might-go-backwards.patch | 38 + ...rs-when-the-filecache-is-re-initiali.patch | 51 + ...-add-refcount-for-nfsd4_blocked_lock.patch | 138 ++ ...query-change-attribute-in-v2-v3-case.patch | 82 + ...-callback-address-and-state-of-each-.patch | 58 + .../nfsd4-remove-obselete-comment.patch | 37 + .../nfsd4-simplify-process_lookup1.patch | 38 + ...d_splice_actor-handle-compound-pages.patch | 57 + ...fdef-config_nfsd-from-nfsv4.2-client.patch | 99 ++ ...ssc-helper-should-use-its-own-config.patch | 160 ++ ...st-file_lock-changes-after-vfs_test_.patch | 144 ++ queue-5.10/nlm-fix-svcxdr_encode_owner.patch | 52 + ...inor-nlm_lookup_file-argument-change.patch | 116 ++ queue-5.10/nlm-minor-refactoring.patch | 93 + ...o-seq_show-don-t-use-get_files_struc.patch | 74 + ...roc-fd-in-proc_fd_link-use-fget_task.patch | 78 + ...readfd_common-use-task_lookup_next_f.patch | 95 + ...n-tid_fd_mode-use-task_lookup_fd_rcu.patch | 62 + ...limit-number-of-event-merge-attempts.patch | 50 + ...ify-and-improve-__fget_files-impleme.patch | 110 ++ ...-some-unnecessary-stats-in-the-v4-ca.patch | 141 ++ ...4-support-change_attr_type-attribute.patch | 91 + ...e-rmw-bitops-in-single-threaded-hot-.patch | 176 ++ queue-5.10/series | 770 +++++++++ .../sunrpc-add-svc_rqst-rq_auth_stat.patch | 421 +++++ ...sunrpc-add-svc_rqst_replace_page-api.patch | 112 ++ ...et_scratch_page-and-xdr_reset_scratc.patch | 308 ++++ ...ays-treat-sv_nrpools-1-as-not-pooled.patch | 164 ++ ...ange-return-value-type-of-.pc_decode.patch | 1350 +++++++++++++++ ...ange-return-value-type-of-.pc_encode.patch | 1038 +++++++++++ ...rpc-change-svc_get-to-return-the-svc.patch | 85 + ...vo_setup-and-rename-svc_set_num_thre.patch | 215 +++ ...pc-procedure-names-instead-of-proc-n.patch | 75 + ...sunrpc-eliminate-the-rq_autherr-flag.patch | 129 ++ .../sunrpc-export-svc_xprt_received.patch | 89 + queue-5.10/sunrpc-fix-xdr_encode_bool.patch | 44 + ...e_svc_process-display-the-rpc-proced.patch | 873 ++++++++++ ..._do_enqueue_xprt-into-svc_enqueue_xp.patch | 99 ++ .../sunrpc-move-definition-of-xdr_unit.patch | 82 + ...pool_map-definitions-back-into-svc.c.patch | 143 ++ ...nrpc-nfsd-clean-up-get-put-functions.patch | 331 ++++ .../sunrpc-optimize-xdr_reserve_space.patch | 109 ++ ...ze-how-much-of-argsize-should-be-zer.patch | 887 ++++++++++ ...or-xdr_stream-style-decoding-on-the-.patch | 102 ++ .../sunrpc-remove-svc_shutdown_net.patch | 152 ++ .../sunrpc-remove-svo_shutdown-method.patch | 105 ++ ...-remove-the-.svo_enqueue_xprt-method.patch | 157 ++ queue-5.10/sunrpc-rename-svc_close_xprt.patch | 104 ++ .../sunrpc-rename-svc_create_xprt.patch | 185 ++ ...unrpc-rename-svc_encode_read_payload.patch | 193 +++ ...the-__be32-p-parameter-to-.pc_decode.patch | 849 +++++++++ ...the-__be32-p-parameter-to-.pc_encode.patch | 693 ++++++++ ...ue-false-not-1-0-from-bool-functions.patch | 96 ++ ...th_stat-in-the-pg_authenticate-callo.patch | 137 ++ ...top-using-sv_nrthreads-as-a-refcount.patch | 356 ++++ ...sunrpc-trace-calls-to-.rpc_call_done.patch | 153 ++ ...-bitops-in-single-threaded-hot-paths.patch | 173 ++ ...ck-to-protect-updates-to-sv_nrthread.patch | 81 + ...troduce-new-proc-handler-proc_dobool.patch | 114 ++ ...lace-one-element-array-with-flexible.patch | 132 ++ 771 files changed, 89445 insertions(+) create mode 100644 queue-5.10/bpf-in-bpf_task_fd_query-use-fget_task.patch create mode 100644 queue-5.10/dnotify-use-fsnotify-group-lock-helpers.patch create mode 100644 queue-5.10/documentation-add-missing-documentation-for-export_o.patch create mode 100644 queue-5.10/exec-don-t-open-code-get_close_on_exec.patch create mode 100644 queue-5.10/exec-move-unshare_files-to-fix-posix-file-locking-du.patch create mode 100644 queue-5.10/exec-remove-reset_files_struct.patch create mode 100644 queue-5.10/exec-simplify-unshare_files.patch create mode 100644 queue-5.10/exit-implement-kthread_exit.patch create mode 100644 queue-5.10/exit-rename-module_put_and_exit-to-module_put_and_kt.patch create mode 100644 queue-5.10/exportfs-add-a-function-to-return-the-raw-output-fro.patch create mode 100644 queue-5.10/exportfs-use-pr_debug-for-unreachable-debug-statemen.patch create mode 100644 queue-5.10/fanotify-add-helpers-to-decide-whether-to-report-fid.patch create mode 100644 queue-5.10/fanotify-add-pidfd-support-to-the-fanotify-api.patch create mode 100644 queue-5.10/fanotify-allow-file-handle-encoding-for-unhashed-eve.patch create mode 100644 queue-5.10/fanotify-allow-users-to-request-fan_fs_error-events.patch create mode 100644 queue-5.10/fanotify-cleanups-for-fanotify_mark-input-validation.patch create mode 100644 queue-5.10/fanotify-configurable-limits-via-sysfs.patch create mode 100644 queue-5.10/fanotify-create-helper-fanotify_mark_user_flags.patch create mode 100644 queue-5.10/fanotify-do-not-allow-setting-dirent-events-in-mask-.patch create mode 100644 queue-5.10/fanotify-emit-generic-error-info-for-error-event.patch create mode 100644 queue-5.10/fanotify-enable-evictable-inode-marks.patch create mode 100644 queue-5.10/fanotify-encode-empty-file-handle-when-no-inode-is-p.patch create mode 100644 queue-5.10/fanotify-factor-out-helper-fanotify_mark_update_flag.patch create mode 100644 queue-5.10/fanotify-fix-incorrect-fmode_t-casts.patch create mode 100644 queue-5.10/fanotify-fix-permission-model-of-unprivileged-group.patch create mode 100644 queue-5.10/fanotify-fold-event-size-calculation-to-its-own-func.patch create mode 100644 queue-5.10/fanotify-implement-evictable-inode-marks.patch create mode 100644 queue-5.10/fanotify-introduce-a-generic-info-record-copying-hel.patch create mode 100644 queue-5.10/fanotify-introduce-fan_mark_ignore.patch create mode 100644 queue-5.10/fanotify-introduce-group-flag-fan_report_target_fid.patch create mode 100644 queue-5.10/fanotify-limit-number-of-event-merge-attempts.patch-30929 create mode 100644 queue-5.10/fanotify-minor-cosmetic-adjustments-to-fid-labels.patch create mode 100644 queue-5.10/fanotify-mix-event-info-and-pid-into-merge-key-hash.patch create mode 100644 queue-5.10/fanotify-pre-allocate-pool-of-error-events.patch create mode 100644 queue-5.10/fanotify-prepare-for-setting-event-flags-in-ignore-m.patch create mode 100644 queue-5.10/fanotify-record-either-old-name-new-name-or-both-for.patch create mode 100644 queue-5.10/fanotify-record-old-and-new-parent-and-name-in-fan_r.patch create mode 100644 queue-5.10/fanotify-reduce-event-objectid-to-29-bit-hash.patch create mode 100644 queue-5.10/fanotify-refine-the-validation-checks-on-non-dir-ino.patch create mode 100644 queue-5.10/fanotify-remove-obsoleted-fanotify_event_has_path.patch create mode 100644 queue-5.10/fanotify-remove-variable-set-but-not-used.patch create mode 100644 queue-5.10/fanotify-report-fid-info-for-file-related-file-syste.patch create mode 100644 queue-5.10/fanotify-report-old-and-or-new-parent-name-in-fan_re.patch create mode 100644 queue-5.10/fanotify-require-fid_mode-for-any-non-fd-event.patch create mode 100644 queue-5.10/fanotify-reserve-uapi-bits-for-fan_fs_error.patch create mode 100644 queue-5.10/fanotify-split-fsid-check-from-other-fid-mode-checks.patch create mode 100644 queue-5.10/fanotify-support-enqueueing-of-error-events.patch create mode 100644 queue-5.10/fanotify-support-limited-functionality-for-unprivile.patch create mode 100644 queue-5.10/fanotify-support-merging-of-error-events.patch create mode 100644 queue-5.10/fanotify-support-null-inode-event-in-fanotify_dfid_i.patch create mode 100644 queue-5.10/fanotify-support-secondary-dir-fh-and-name-in-fanoti.patch create mode 100644 queue-5.10/fanotify-use-fsnotify-group-lock-helpers.patch create mode 100644 queue-5.10/fanotify-use-helpers-to-parcel-fanotify_info-buffer.patch create mode 100644 queue-5.10/fanotify-use-macros-to-get-the-offset-to-fanotify_in.patch create mode 100644 queue-5.10/fanotify-warn_on-against-too-large-file-handles.patch create mode 100644 queue-5.10/fanotify-wire-up-fan_rename-event.patch create mode 100644 queue-5.10/fanotify-wrap-object_fh-inline-space-in-a-creator-ma.patch create mode 100644 queue-5.10/fanotify_user-use-upper_32_bits-to-verify-mask.patch create mode 100644 queue-5.10/file-factor-files_lookup_fd_locked-out-of-fcheck_fil.patch create mode 100644 queue-5.10/file-implement-task_lookup_fd_rcu.patch create mode 100644 queue-5.10/file-implement-task_lookup_next_fd_rcu.patch create mode 100644 queue-5.10/file-in-f_dupfd-read-rlimit_nofile-once.patch create mode 100644 queue-5.10/file-merge-__alloc_fd-into-alloc_fd.patch create mode 100644 queue-5.10/file-merge-__fd_install-into-fd_install.patch create mode 100644 queue-5.10/file-rename-__close_fd-to-close_fd-and-remove-the-fi.patch create mode 100644 queue-5.10/file-rename-__fcheck_files-to-files_lookup_fd_raw.patch create mode 100644 queue-5.10/file-rename-fcheck-lookup_fd_rcu.patch create mode 100644 queue-5.10/file-replace-fcheck_files-with-files_lookup_fd_rcu.patch create mode 100644 queue-5.10/file-replace-ksys_close-with-close_fd.patch create mode 100644 queue-5.10/filelock-add-a-new-locks_inode_context-accessor-func.patch create mode 100644 queue-5.10/fs-add-file-and-path-permissions-helpers.patch create mode 100644 queue-5.10/fs-inotify-fix-typo-in-inotify-comment.patch create mode 100644 queue-5.10/fs-lock-add-2-callbacks-to-lock_manager_operations-t.patch create mode 100644 queue-5.10/fs-lock-add-helper-locks_owner_has_blockers-to-check.patch create mode 100644 queue-5.10/fs-lock-documentation-cleanup.-replace-inode-i_lock-.patch create mode 100644 queue-5.10/fs-lockd-convert-comma-to-semicolon.patch create mode 100644 queue-5.10/fs-notify-constify-path.patch create mode 100644 queue-5.10/fsnotify-add-helper-to-detect-overflow_event.patch create mode 100644 queue-5.10/fsnotify-add-wrapper-around-fsnotify_add_event.patch create mode 100644 queue-5.10/fsnotify-allow-adding-an-inode-mark-without-pinning-.patch create mode 100644 queue-5.10/fsnotify-allow-fsnotify_-peek-remove-_first_event-wi.patch create mode 100644 queue-5.10/fsnotify-clarify-contract-for-create-event-hooks.patch create mode 100644 queue-5.10/fsnotify-clarify-object-type-argument.patch create mode 100644 queue-5.10/fsnotify-consistent-behavior-for-parent-not-watching.patch create mode 100644 queue-5.10/fsnotify-count-all-objects-with-attached-connectors.patch create mode 100644 queue-5.10/fsnotify-count-s_fsnotify_inode_refs-for-attached-co.patch create mode 100644 queue-5.10/fsnotify-create-helpers-for-group-mark_mutex-lock.patch create mode 100644 queue-5.10/fsnotify-don-t-insert-unmergeable-events-in-hashtabl.patch create mode 100644 queue-5.10/fsnotify-fix-comment-typo.patch create mode 100644 queue-5.10/fsnotify-fix-merge-with-parent-s-ignored-mask.patch create mode 100644 queue-5.10/fsnotify-fix-sb_connectors-leak.patch create mode 100644 queue-5.10/fsnotify-generate-fs_rename-event-with-rich-informat.patch create mode 100644 queue-5.10/fsnotify-introduce-mark-type-iterator.patch create mode 100644 queue-5.10/fsnotify-make-allow_dups-a-property-of-the-group.patch create mode 100644 queue-5.10/fsnotify-optimize-fs_modify-events-with-no-ignored-m.patch create mode 100644 queue-5.10/fsnotify-optimize-the-case-of-no-marks-of-any-type.patch create mode 100644 queue-5.10/fsnotify-pass-data_type-to-fsnotify_name.patch create mode 100644 queue-5.10/fsnotify-pass-dentry-instead-of-inode-data.patch create mode 100644 queue-5.10/fsnotify-pass-flags-argument-to-fsnotify_alloc_group.patch create mode 100644 queue-5.10/fsnotify-pass-group-argument-to-free_event.patch create mode 100644 queue-5.10/fsnotify-protect-fsnotify_handle_inode_event-from-no.patch create mode 100644 queue-5.10/fsnotify-remove-redundant-parameter-judgment.patch create mode 100644 queue-5.10/fsnotify-remove-unused-declaration.patch create mode 100644 queue-5.10/fsnotify-replace-igrab-with-ihold-on-attach-connecto.patch create mode 100644 queue-5.10/fsnotify-retrieve-super-block-from-the-data-field.patch create mode 100644 queue-5.10/fsnotify-separate-mark-iterator-type-from-object-typ.patch create mode 100644 queue-5.10/fsnotify-support-fs_error-event-type.patch create mode 100644 queue-5.10/fsnotify-use-hash-table-for-faster-events-merge.patch create mode 100644 queue-5.10/inotify-don-t-force-fs_in_ignored.patch create mode 100644 queue-5.10/inotify-increase-default-inotify.max_user_watches-li.patch create mode 100644 queue-5.10/inotify-memcg-account-inotify-instances-to-kmemcg.patch create mode 100644 queue-5.10/inotify-move-control-flags-from-mask-to-mark-flags.patch create mode 100644 queue-5.10/inotify-use-fsnotify-group-lock-helpers.patch create mode 100644 queue-5.10/kallsyms-only-build-module_-kallsyms_on_each_symbol-.patch create mode 100644 queue-5.10/kallsyms-refactor-module_-kallsyms_on_each_symbol.patch create mode 100644 queue-5.10/kcmp-in-get_file_raw_ptr-use-task_lookup_fd_rcu.patch create mode 100644 queue-5.10/kcmp-in-kcmp_epoll_target-use-fget_task.patch create mode 100644 queue-5.10/keep-read-and-write-fds-with-each-nlm_file.patch create mode 100644 queue-5.10/kernel-pid.c-implement-additional-checks-upon-pidfd_.patch create mode 100644 queue-5.10/kernel-pid.c-remove-static-qualifier-from-pidfd_crea.patch create mode 100644 queue-5.10/lockd-change-the-proc_handler-for-nsm_use_hostnames.patch create mode 100644 queue-5.10/lockd-common-nlm-xdr-helpers.patch create mode 100644 queue-5.10/lockd-create-a-simplified-.vs_dispatch-method-for-nl.patch create mode 100644 queue-5.10/lockd-detect-and-reject-lock-arguments-that-overflow.patch create mode 100644 queue-5.10/lockd-don-t-attempt-blocking-locks-on-nfs-reexports.patch create mode 100644 queue-5.10/lockd-drop-inappropriate-svc_get-from-locked_get.patch create mode 100644 queue-5.10/lockd-ensure-we-use-the-correct-file-descriptor-when.patch create mode 100644 queue-5.10/lockd-fix-failure-to-cleanup-client-locks.patch create mode 100644 queue-5.10/lockd-fix-file-selection-in-nlmsvc_cancel_blocked.patch create mode 100644 queue-5.10/lockd-fix-nlm_close_files.patch create mode 100644 queue-5.10/lockd-fix-server-crash-on-reboot-of-client-holding-l.patch create mode 100644 queue-5.10/lockd-introduce-lockd_put.patch create mode 100644 queue-5.10/lockd-introduce-nlmsvc_serv.patch create mode 100644 queue-5.10/lockd-move-from-strlcpy-with-unused-retval-to-strscp.patch create mode 100644 queue-5.10/lockd-move-lockd_start_svc-call-into-lockd_create_sv.patch create mode 100644 queue-5.10/lockd-move-svc_exit_thread-into-the-thread.patch create mode 100644 queue-5.10/lockd-remove-stale-comments.patch create mode 100644 queue-5.10/lockd-rename-lockd_create_svc-to-lockd_get.patch create mode 100644 queue-5.10/lockd-set-file_lock-start-and-end-when-decoding-nlm4.patch create mode 100644 queue-5.10/lockd-set-fl_owner-when-unlocking-files.patch create mode 100644 queue-5.10/lockd-set-missing-fl_flags-field-when-retrieving-arg.patch create mode 100644 queue-5.10/lockd-set-other-missing-fields-when-unlocking-files.patch create mode 100644 queue-5.10/lockd-simplify-management-of-network-status-notifier.patch create mode 100644 queue-5.10/lockd-update-nlm_lookup_file-reexport-comment.patch create mode 100644 queue-5.10/lockd-update-the-nlmv1-cancel-arguments-decoder-to-u.patch create mode 100644 queue-5.10/lockd-update-the-nlmv1-free_all-arguments-decoder-to.patch create mode 100644 queue-5.10/lockd-update-the-nlmv1-lock-arguments-decoder-to-use.patch create mode 100644 queue-5.10/lockd-update-the-nlmv1-nlm_res-arguments-decoder-to-.patch create mode 100644 queue-5.10/lockd-update-the-nlmv1-nlm_res-results-encoder-to-us.patch create mode 100644 queue-5.10/lockd-update-the-nlmv1-share-arguments-decoder-to-us.patch create mode 100644 queue-5.10/lockd-update-the-nlmv1-share-results-encoder-to-use-.patch create mode 100644 queue-5.10/lockd-update-the-nlmv1-sm_notify-arguments-decoder-t.patch create mode 100644 queue-5.10/lockd-update-the-nlmv1-test-arguments-decoder-to-use.patch create mode 100644 queue-5.10/lockd-update-the-nlmv1-test-results-encoder-to-use-s.patch create mode 100644 queue-5.10/lockd-update-the-nlmv1-unlock-arguments-decoder-to-u.patch create mode 100644 queue-5.10/lockd-update-the-nlmv1-void-argument-decoder-to-use-.patch create mode 100644 queue-5.10/lockd-update-the-nlmv1-void-results-encoder-to-use-s.patch create mode 100644 queue-5.10/lockd-update-the-nlmv4-cancel-arguments-decoder-to-u.patch create mode 100644 queue-5.10/lockd-update-the-nlmv4-free_all-arguments-decoder-to.patch create mode 100644 queue-5.10/lockd-update-the-nlmv4-lock-arguments-decoder-to-use.patch create mode 100644 queue-5.10/lockd-update-the-nlmv4-nlm_res-arguments-decoder-to-.patch create mode 100644 queue-5.10/lockd-update-the-nlmv4-nlm_res-results-encoder-to-us.patch create mode 100644 queue-5.10/lockd-update-the-nlmv4-share-arguments-decoder-to-us.patch create mode 100644 queue-5.10/lockd-update-the-nlmv4-share-results-encoder-to-use-.patch create mode 100644 queue-5.10/lockd-update-the-nlmv4-sm_notify-arguments-decoder-t.patch create mode 100644 queue-5.10/lockd-update-the-nlmv4-test-arguments-decoder-to-use.patch create mode 100644 queue-5.10/lockd-update-the-nlmv4-test-results-encoder-to-use-s.patch create mode 100644 queue-5.10/lockd-update-the-nlmv4-unlock-arguments-decoder-to-u.patch create mode 100644 queue-5.10/lockd-update-the-nlmv4-void-arguments-decoder-to-use.patch create mode 100644 queue-5.10/lockd-update-the-nlmv4-void-results-encoder-to-use-s.patch create mode 100644 queue-5.10/lockd-use-locks_inode_context-helper.patch create mode 100644 queue-5.10/lockd-use-svc_set_num_threads-for-thread-start-and-s.patch create mode 100644 queue-5.10/module-unexport-find_module-and-module_mutex.patch create mode 100644 queue-5.10/module-use-rcu-to-synchronize-find_module.patch create mode 100644 queue-5.10/namei-introduce-struct-renamedata.patch create mode 100644 queue-5.10/nfs-add-a-private-local-dispatcher-for-nfsv4-callbac.patch create mode 100644 queue-5.10/nfs-block-notification-on-fs-with-its-own-lock.patch create mode 100644 queue-5.10/nfs-don-t-allow-reexport-reclaims.patch create mode 100644 queue-5.10/nfs-don-t-atempt-blocking-locks-on-nfs-reexports.patch create mode 100644 queue-5.10/nfs-fix-nfs_fetch_iversion.patch create mode 100644 queue-5.10/nfs-remove-unused-callback-void-decoder.patch create mode 100644 queue-5.10/nfs-restore-module-put-when-manager-exits.patch create mode 100644 queue-5.10/nfs-switch-the-callback-service-back-to-non-pooled.patch create mode 100644 queue-5.10/nfs-use-change-attribute-for-nfs-re-exports.patch create mode 100644 queue-5.10/nfsd-a-semicolon-is-not-needed-after-a-switch-statem.patch create mode 100644 queue-5.10/nfsd-add-a-couple-more-nfsd_clid_expired-call-sites.patch create mode 100644 queue-5.10/nfsd-add-a-helper-that-encodes-nfsv3-directory-offse.patch create mode 100644 queue-5.10/nfsd-add-a-helper-that-encodes-nfsv3-directory-offse.patch-18644 create mode 100644 queue-5.10/nfsd-add-a-helper-to-decode-channel_attrs4.patch create mode 100644 queue-5.10/nfsd-add-a-helper-to-decode-nfs_impl_id4.patch create mode 100644 queue-5.10/nfsd-add-a-helper-to-decode-state_protect4_a.patch create mode 100644 queue-5.10/nfsd-add-a-mechanism-to-wait-for-a-delegreturn.patch create mode 100644 queue-5.10/nfsd-add-a-new-export_op_nowcc-flag-to-struct-export.patch create mode 100644 queue-5.10/nfsd-add-a-nfsd4_file_hash_remove-helper.patch create mode 100644 queue-5.10/nfsd-add-a-separate-decoder-for-ssv_sp_parms.patch create mode 100644 queue-5.10/nfsd-add-a-separate-decoder-to-handle-state_protect_.patch create mode 100644 queue-5.10/nfsd-add-a-tracepoint-for-errors-in-nfsd4_clone_file.patch create mode 100644 queue-5.10/nfsd-add-a-tracepoint-to-record-directory-entry-enco.patch create mode 100644 queue-5.10/nfsd-add-an-nfsd4_encode_nfstime4-helper.patch create mode 100644 queue-5.10/nfsd-add-an-nfsd4_read-rd_eof-field.patch create mode 100644 queue-5.10/nfsd-add-an-nfsd_cb_lm_notify-tracepoint.patch create mode 100644 queue-5.10/nfsd-add-an-nfsd_cb_offload-tracepoint.patch create mode 100644 queue-5.10/nfsd-add-an-nfsd_cb_probe-tracepoint.patch create mode 100644 queue-5.10/nfsd-add-an-nfsd_file_fsync-tracepoint.patch create mode 100644 queue-5.10/nfsd-add-an-nfsd_file_gc-flag-to-enable-nfsd_file-ga.patch create mode 100644 queue-5.10/nfsd-add-an-rpc-authflavor-tracepoint-display-helper.patch create mode 100644 queue-5.10/nfsd-add-an-xdr_stream-based-decoder-for-nfsv2-3-acl.patch create mode 100644 queue-5.10/nfsd-add-an-xdr_stream-based-encoder-for-nfsv2-3-acl.patch create mode 100644 queue-5.10/nfsd-add-cb_lost-tracepoint.patch create mode 100644 queue-5.10/nfsd-add-common-helpers-to-decode-void-args-and-enco.patch create mode 100644 queue-5.10/nfsd-add-courteous-server-support-for-thread-with-on.patch create mode 100644 queue-5.10/nfsd-add-delegation-reaper-to-react-to-low-memory-co.patch create mode 100644 queue-5.10/nfsd-add-documenting-comment-for-nfsd4_release_locko.patch create mode 100644 queue-5.10/nfsd-add-errno-mapping-for-eremoteio.patch create mode 100644 queue-5.10/nfsd-add-helper-for-decoding-locker4.patch create mode 100644 queue-5.10/nfsd-add-helper-to-decode-nfsv4-verifiers.patch create mode 100644 queue-5.10/nfsd-add-helper-to-decode-open-s-createhow4-argument.patch create mode 100644 queue-5.10/nfsd-add-helper-to-decode-open-s-open_claim4-argumen.patch create mode 100644 queue-5.10/nfsd-add-helper-to-decode-open-s-openflag4-argument.patch create mode 100644 queue-5.10/nfsd-add-helper-to-set-up-the-pages-where-the-dirlis.patch create mode 100644 queue-5.10/nfsd-add-helper-to-set-up-the-pages-where-the-dirlis.patch-28629 create mode 100644 queue-5.10/nfsd-add-helpers-to-decode-a-clientid4-and-an-nfsv4-.patch create mode 100644 queue-5.10/nfsd-add-nfsd4_send_cb_offload.patch create mode 100644 queue-5.10/nfsd-add-nfsd_clid_confirmed-tracepoint.patch create mode 100644 queue-5.10/nfsd-add-nfsd_clid_cred_mismatch-tracepoint.patch create mode 100644 queue-5.10/nfsd-add-nfsd_clid_destroyed-tracepoint.patch create mode 100644 queue-5.10/nfsd-add-nfsd_clid_reclaim_complete-tracepoint.patch create mode 100644 queue-5.10/nfsd-add-nfsd_clid_verf_mismatch-tracepoint.patch create mode 100644 queue-5.10/nfsd-add-nfsd_file_lru_dispose_list-helper.patch create mode 100644 queue-5.10/nfsd-add-posix-acls-to-struct-nfsd_attrs.patch create mode 100644 queue-5.10/nfsd-add-security-label-to-struct-nfsd_attrs.patch create mode 100644 queue-5.10/nfsd-add-shrinker-to-reap-courtesy-clients-on-low-me.patch create mode 100644 queue-5.10/nfsd-add-some-comments-to-nfsd_file_do_acquire.patch create mode 100644 queue-5.10/nfsd-add-spdx-header-for-fs-nfsd-trace.c.patch create mode 100644 queue-5.10/nfsd-add-support-for-lock-conflict-to-courteous-serv.patch create mode 100644 queue-5.10/nfsd-add-support-for-sending-cb_recall_any.patch create mode 100644 queue-5.10/nfsd-add-support-for-share-reservation-conflict-to-c.patch create mode 100644 queue-5.10/nfsd-add-support-for-the-birth-time-attribute.patch create mode 100644 queue-5.10/nfsd-add-tracepoints-for-exchangeid-edge-cases.patch create mode 100644 queue-5.10/nfsd-add-tracepoints-for-setclientid-edge-cases.patch create mode 100644 queue-5.10/nfsd-add-tracepoints-in-nfsd4_decode-encode_compound.patch create mode 100644 queue-5.10/nfsd-add-tracepoints-in-nfsd_dispatch.patch create mode 100644 queue-5.10/nfsd-add-tracepoints-to-report-nfsv4-callback-comple.patch create mode 100644 queue-5.10/nfsd-add-vfs_fsync-after-async-copy-is-done.patch create mode 100644 queue-5.10/nfsd-adjust-cb_shutdown-tracepoint.patch create mode 100644 queue-5.10/nfsd-allow-disabling-nfsv2-at-compile-time.patch create mode 100644 queue-5.10/nfsd-allow-filesystems-to-opt-out-of-subtree-checkin.patch create mode 100644 queue-5.10/nfsd-allow-nfsd_file_get-to-sanely-handle-a-null-poi.patch create mode 100644 queue-5.10/nfsd-allow-reaping-files-still-under-writeback.patch create mode 100644 queue-5.10/nfsd-always-drop-directory-lock-in-nfsd_unlink.patch create mode 100644 queue-5.10/nfsd-avoid-calling-fh_drop_write-twice-in-do_nfsd_cr.patch create mode 100644 queue-5.10/nfsd-avoid-calling-opdesc-with-ops-opnum-op_illegal.patch create mode 100644 queue-5.10/nfsd-avoid-clashing-function-prototypes.patch create mode 100644 queue-5.10/nfsd-avoid-some-useless-tests.patch create mode 100644 queue-5.10/nfsd-batch-release-pages-during-splice-read.patch create mode 100644 queue-5.10/nfsd-call-nfsd_last_thread-before-final-nfsd_put.patch create mode 100644 queue-5.10/nfsd-call-op_release-even-when-op_func-returns-an-er.patch create mode 100644 queue-5.10/nfsd-cap-rsize_bop-result-based-on-send-buffer-size.patch create mode 100644 queue-5.10/nfsd-capture-every-cb-state-transition.patch create mode 100644 queue-5.10/nfsd-change-nfsd_create-nfsd_symlink-to-unlock-direc.patch create mode 100644 queue-5.10/nfsd-change-the-way-the-expected-length-of-a-fattr4-.patch create mode 100644 queue-5.10/nfsd-clean-up-_lm_-operation-names.patch create mode 100644 queue-5.10/nfsd-clean-up-after-updating-nfsv2-acl-decoders.patch create mode 100644 queue-5.10/nfsd-clean-up-after-updating-nfsv2-acl-encoders.patch create mode 100644 queue-5.10/nfsd-clean-up-after-updating-nfsv3-acl-decoders.patch create mode 100644 queue-5.10/nfsd-clean-up-after-updating-nfsv3-acl-encoders.patch create mode 100644 queue-5.10/nfsd-clean-up-find_or_add_file.patch create mode 100644 queue-5.10/nfsd-clean-up-mounted_on_fileid-handling.patch create mode 100644 queue-5.10/nfsd-clean-up-nfs4_preprocess_stateid_op-call-sites.patch create mode 100644 queue-5.10/nfsd-clean-up-nfs4svc_encode_compoundres.patch create mode 100644 queue-5.10/nfsd-clean-up-nfsd3_proc_create.patch create mode 100644 queue-5.10/nfsd-clean-up-nfsd4_encode_readlink.patch create mode 100644 queue-5.10/nfsd-clean-up-nfsd4_init_file.patch create mode 100644 queue-5.10/nfsd-clean-up-nfsd_file_put.patch create mode 100644 queue-5.10/nfsd-clean-up-nfsd_open_verified.patch create mode 100644 queue-5.10/nfsd-clean-up-nfsd_splice_actor.patch create mode 100644 queue-5.10/nfsd-clean-up-nfsd_vfs_write.patch create mode 100644 queue-5.10/nfsd-clean-up-nfsddbg_facility-macro.patch create mode 100644 queue-5.10/nfsd-clean-up-potential-nfsd_file-refcount-leaks-in-.patch create mode 100644 queue-5.10/nfsd-clean-up-splice-actor.patch create mode 100644 queue-5.10/nfsd-clean-up-splice_ok-in-nfsd4_encode_read.patch create mode 100644 queue-5.10/nfsd-clean-up-the-nfsd_net-nfssvc_boot-field.patch create mode 100644 queue-5.10/nfsd-clean-up-the-show_nf_flags-macro.patch create mode 100644 queue-5.10/nfsd-clean-up-the-show_nf_may-macro.patch create mode 100644 queue-5.10/nfsd-clean-up-unused-code-after-rhashtable-conversio.patch create mode 100644 queue-5.10/nfsd-clean-up-write-arg-decoders.patch create mode 100644 queue-5.10/nfsd-close-cached-files-prior-to-a-remove-or-rename-.patch create mode 100644 queue-5.10/nfsd-combine-xdr-error-tracepoints.patch create mode 100644 queue-5.10/nfsd-commit-operations-must-not-return-nfs-err_inval.patch create mode 100644 queue-5.10/nfsd-constify-fh-argument-of-knfsd_fh_hash.patch create mode 100644 queue-5.10/nfsd-convert-filecache-to-rhltable.patch create mode 100644 queue-5.10/nfsd-convert-the-filecache-to-use-rhashtable.patch create mode 100644 queue-5.10/nfsd-copy-the-whole-verifier-in-nfsd_copy_write_veri.patch create mode 100644 queue-5.10/nfsd-copy-with-length-0-should-copy-to-end-of-file.patch create mode 100644 queue-5.10/nfsd-count-bytes-instead-of-pages-in-the-nfsv2-readd.patch create mode 100644 queue-5.10/nfsd-count-bytes-instead-of-pages-in-the-nfsv3-readd.patch create mode 100644 queue-5.10/nfsd-cstate-session-se_client-cstate-clp.patch create mode 100644 queue-5.10/nfsd-de-duplicate-hash-bucket-indexing.patch create mode 100644 queue-5.10/nfsd-de-duplicate-net_generic-nf-nf_net-nfsd_net_id.patch create mode 100644 queue-5.10/nfsd-de-duplicate-net_generic-svc_net-rqstp-nfsd_net.patch create mode 100644 queue-5.10/nfsd-de-duplicate-nfsd4_decode_bitmap4.patch create mode 100644 queue-5.10/nfsd-decode-nfsv4-birth-time-attribute.patch create mode 100644 queue-5.10/nfsd-delay-unmount-source-s-export-after-inter-serve.patch create mode 100644 queue-5.10/nfsd-demote-a-warn-to-a-pr_warn.patch create mode 100644 queue-5.10/nfsd-deprecate-nfs_offset_max.patch create mode 100644 queue-5.10/nfsd-destroy-percpu-stats-counters-after-reply-cache.patch create mode 100644 queue-5.10/nfsd-discard-fh_locked-flag-and-fh_lock-fh_unlock.patch create mode 100644 queue-5.10/nfsd-don-t-allow-nfsd-threads-to-be-signalled.patch create mode 100644 queue-5.10/nfsd-don-t-call-locks_release_private-twice-concurre.patch create mode 100644 queue-5.10/nfsd-don-t-destroy-global-nfs4_file-table-in-per-net.patch create mode 100644 queue-5.10/nfsd-don-t-free-files-unconditionally-in-__nfsd_file.patch create mode 100644 queue-5.10/nfsd-don-t-fsync-nfsd_files-on-last-close.patch create mode 100644 queue-5.10/nfsd-don-t-hand-out-delegation-on-setuid-files-being.patch create mode 100644 queue-5.10/nfsd-don-t-ignore-high-bits-of-copy-count.patch create mode 100644 queue-5.10/nfsd-don-t-kill-nfsd_files-because-of-lease-break-er.patch create mode 100644 queue-5.10/nfsd-don-t-open-code-clear_and_wake_up_bit.patch create mode 100644 queue-5.10/nfsd-don-t-replace-page-in-rq_pages-if-it-s-a-contin.patch create mode 100644 queue-5.10/nfsd-don-t-take-fi_lock-in-nfsd_break_deleg_cb.patch create mode 100644 queue-5.10/nfsd-don-t-take-put-an-extra-reference-when-putting-.patch create mode 100644 queue-5.10/nfsd-drop-fh-argument-from-alloc_init_deleg.patch create mode 100644 queue-5.10/nfsd-drop-fname-and-flen-args-from-nfsd_create_locke.patch create mode 100644 queue-5.10/nfsd-drop-support-for-ancient-filehandles.patch create mode 100644 queue-5.10/nfsd-drop-the-nfsd_put-helper.patch create mode 100644 queue-5.10/nfsd-drop-trace_define_enum-for-nfsd4_cb_-state-macr.patch create mode 100644 queue-5.10/nfsd-eliminate-the-nfsd_file_break_-flags.patch create mode 100644 queue-5.10/nfsd-enforce-filehandle-check-for-source-file-in-cop.patch create mode 100644 queue-5.10/nfsd-enhance-inter-server-copy-cleanup.patch create mode 100644 queue-5.10/nfsd-enhance-the-nfsd_cb_setup-tracepoint.patch create mode 100644 queue-5.10/nfsd-ensure-nf_inode-is-never-dereferenced.patch create mode 100644 queue-5.10/nfsd-extra-checks-when-freeing-delegation-stateids.patch create mode 100644 queue-5.10/nfsd-extract-the-svcxdr_init_encode-helper.patch create mode 100644 queue-5.10/nfsd-find_cpntf_state-cleanup.patch create mode 100644 queue-5.10/nfsd-finish-converting-the-nfsv2-getacl-result-encod.patch create mode 100644 queue-5.10/nfsd-finish-converting-the-nfsv3-getacl-result-encod.patch create mode 100644 queue-5.10/nfsd-fix-a-regression-in-nfsd_setattr.patch create mode 100644 queue-5.10/nfsd-fix-a-warning-for-nfsd_file_close_inode.patch create mode 100644 queue-5.10/nfsd-fix-a-write-performance-regression.patch create mode 100644 queue-5.10/nfsd-fix-boolreturn.cocci-warning.patch create mode 100644 queue-5.10/nfsd-fix-comments-about-spinlock-handling-with-deleg.patch create mode 100644 queue-5.10/nfsd-fix-courtesy-client-with-deny-mode-handling-in-.patch create mode 100644 queue-5.10/nfsd-fix-crash-on-copy_notify-with-special-stateid.patch create mode 100644 queue-5.10/nfsd-fix-creation-time-serialization-order.patch create mode 100644 queue-5.10/nfsd-fix-double-fget-bug-in-__write_ports_addfd.patch create mode 100644 queue-5.10/nfsd-fix-error-return-code-in-nfsd4_interssc_connect.patch create mode 100644 queue-5.10/nfsd-fix-error-return-code-in-nfsd_file_cache_init.patch create mode 100644 queue-5.10/nfsd-fix-exposure-in-nfsd4_decode_bitmap.patch create mode 100644 queue-5.10/nfsd-fix-fall-through-warnings-for-clang.patch create mode 100644 queue-5.10/nfsd-fix-handling-of-cached-open-files-in-nfsd4_open.patch create mode 100644 queue-5.10/nfsd-fix-handling-of-oversized-nfsv4-compound-reques.patch create mode 100644 queue-5.10/nfsd-fix-ia_size-underflow.patch create mode 100644 queue-5.10/nfsd-fix-inconsistent-indenting.patch create mode 100644 queue-5.10/nfsd-fix-kernel-test-robot-warning-in-ssc-code.patch create mode 100644 queue-5.10/nfsd-fix-leaked-reference-count-of-nfsd4_ssc_umount_.patch create mode 100644 queue-5.10/nfsd-fix-licensing-header-in-filecache.c.patch create mode 100644 queue-5.10/nfsd-fix-net-namespace-logic-in-__nfsd_file_cache_pu.patch create mode 100644 queue-5.10/nfsd-fix-nfsd_file_unhash_and_dispose.patch create mode 100644 queue-5.10/nfsd-fix-nfsv3-setattr-create-s-handling-of-large-fi.patch create mode 100644 queue-5.10/nfsd-fix-null-dereference-in-nfs3svc_encode_getaclre.patch create mode 100644 queue-5.10/nfsd-fix-null-ptr-deref-in-nfsd_fill_super.patch create mode 100644 queue-5.10/nfsd-fix-possible-oops-when-nfsd-pool_stats-is-close.patch create mode 100644 queue-5.10/nfsd-fix-potential-use-after-free-in-nfsd_file_put.patch create mode 100644 queue-5.10/nfsd-fix-problem-of-commit-and-nfs4err_delay-in-infi.patch create mode 100644 queue-5.10/nfsd-fix-problems-with-cleanup-on-errors-in-nfsd4_co.patch create mode 100644 queue-5.10/nfsd-fix-readdir-buffer-overflow.patch create mode 100644 queue-5.10/nfsd-fix-reads-with-a-non-zero-offset-that-don-t-end.patch create mode 100644 queue-5.10/nfsd-fix-regression-with-setting-acls.patch create mode 100644 queue-5.10/nfsd-fix-release_lockowner.patch create mode 100644 queue-5.10/nfsd-fix-returned-readdir-offset-cookie.patch create mode 100644 queue-5.10/nfsd-fix-space-and-spelling-mistake.patch create mode 100644 queue-5.10/nfsd-fix-sparse-warning-in-nfssvc.c.patch create mode 100644 queue-5.10/nfsd-fix-sparse-warning.patch create mode 100644 queue-5.10/nfsd-fix-strncpy-fortify-warning.patch create mode 100644 queue-5.10/nfsd-fix-the-behavior-of-read-near-offset_max.patch create mode 100644 queue-5.10/nfsd-fix-the-filecache-lru-shrinker.patch create mode 100644 queue-5.10/nfsd-fix-typo-accesible.patch create mode 100644 queue-5.10/nfsd-fix-up-nfsd-to-ensure-that-timeout-errors-don-t.patch create mode 100644 queue-5.10/nfsd-fix-up-the-filecache-laundrette-scheduling.patch create mode 100644 queue-5.10/nfsd-fix-use-after-free-in-nfsd4_ssc_setup_dul.patch create mode 100644 queue-5.10/nfsd-fix-use-after-free-in-nfsd_file_do_acquire-trac.patch create mode 100644 queue-5.10/nfsd-fix-using-the-correct-variable-for-sizeof.patch create mode 100644 queue-5.10/nfsd-fix-whitespace.patch create mode 100644 queue-5.10/nfsd-fix-zero-length-nfsv3-writes.patch create mode 100644 queue-5.10/nfsd-flesh-out-a-documenting-comment-for-filecache.c.patch create mode 100644 queue-5.10/nfsd-grant-read-delegations-to-clients-holding-write.patch create mode 100644 queue-5.10/nfsd-handle-errors-better-in-write_ports_addfd.patch create mode 100644 queue-5.10/nfsd-hash-nfs4_files-by-inode-number.patch create mode 100644 queue-5.10/nfsd-have-legacy-nfsd-write-decoders-use-xdr_stream_.patch create mode 100644 queue-5.10/nfsd-helper-for-laundromat-expiry-calculations.patch create mode 100644 queue-5.10/nfsd-hook-up-the-filecache-stat-file.patch create mode 100644 queue-5.10/nfsd-ignore-requests-to-disable-unsupported-versions.patch create mode 100644 queue-5.10/nfsd-improve-stateid-access-bitmask-documentation.patch create mode 100644 queue-5.10/nfsd-increase-nfsd_max_ops_per_compound.patch create mode 100644 queue-5.10/nfsd-initialize-pointer-ni-with-null-and-not-plain-i.patch create mode 100644 queue-5.10/nfsd-instantiate-a-struct-file-when-creating-a-regul.patch create mode 100644 queue-5.10/nfsd-introduce-struct-nfsd_attrs.patch create mode 100644 queue-5.10/nfsd-invoke-svc_encode_result_payload-in-read-nfsd-e.patch create mode 100644 queue-5.10/nfsd-keep-track-of-the-number-of-courtesy-clients-in.patch create mode 100644 queue-5.10/nfsd-keep-track-of-the-number-of-v4-clients-in-the-s.patch create mode 100644 queue-5.10/nfsd-leave-open-files-out-of-the-filecache-lru.patch create mode 100644 queue-5.10/nfsd-limit-the-number-of-v4-clients-to-1024-per-1gb-.patch create mode 100644 queue-5.10/nfsd-log-client-tracking-type-log-message-as-info-in.patch create mode 100644 queue-5.10/nfsd-make-a-copy-of-struct-iattr-before-calling-noti.patch create mode 100644 queue-5.10/nfsd-make-it-possible-to-use-svc_set_num_threads_syn.patch create mode 100644 queue-5.10/nfsd-make-nfs4_put_copy-static.patch create mode 100644 queue-5.10/nfsd-make-nfsd4_ops-opnum-a-u32.patch create mode 100644 queue-5.10/nfsd-make-nfsd4_remove-wait-before-returning-nfs4err.patch create mode 100644 queue-5.10/nfsd-make-nfsd4_rename-wait-before-returning-nfs4err.patch create mode 100644 queue-5.10/nfsd-make-nfsd4_run_cb-a-bool-return-function.patch create mode 100644 queue-5.10/nfsd-make-nfsd4_setattr-wait-before-returning-nfs4er.patch create mode 100644 queue-5.10/nfsd-make-nfsd_stats.th_cnt-atomic_t.patch create mode 100644 queue-5.10/nfsd-map-ebadf.patch create mode 100644 queue-5.10/nfsd-minor-nfsd4_change_attribute-cleanup.patch create mode 100644 queue-5.10/nfsd-modernize-nfsd4_release_lockowner.patch create mode 100644 queue-5.10/nfsd-move-copy-offload-callback-arguments-into-a-sep.patch create mode 100644 queue-5.10/nfsd-move-create-destroy-of-laundry_wq-to-init_nfsd-.patch create mode 100644 queue-5.10/nfsd-move-documenting-comment-for-nfsd4_process_open.patch create mode 100644 queue-5.10/nfsd-move-filehandle-format-declarations-out-of-uapi.patch create mode 100644 queue-5.10/nfsd-move-fill_pre_wcc-and-fill_post_wcc.patch create mode 100644 queue-5.10/nfsd-move-from-strlcpy-with-unused-retval-to-strscpy.patch create mode 100644 queue-5.10/nfsd-move-fsnotify-on-client-creation-outside-spinlo.patch create mode 100644 queue-5.10/nfsd-move-nfsd_file_trace_alloc-tracepoint.patch create mode 100644 queue-5.10/nfsd-move-nfserrno-to-vfs.c.patch create mode 100644 queue-5.10/nfsd-move-some-commit_metadata-s-outside-the-inode-l.patch create mode 100644 queue-5.10/nfsd-move-svc_serv_ops-svo_function-into-struct-svc_.patch create mode 100644 queue-5.10/nfsd-narrow-nfsd_mutex-protection-in-nfsd-thread.patch create mode 100644 queue-5.10/nfsd-never-call-nfsd_file_gc-in-foreground-paths.patch create mode 100644 queue-5.10/nfsd-nfs3-remove-unused-macro-nfsd3_fhandleres.patch create mode 100644 queue-5.10/nfsd-nfsd_file_hash_remove-can-compute-hashval.patch create mode 100644 queue-5.10/nfsd-nfsd_file_key_inode-only-needs-to-find-gc-ed-en.patch create mode 100644 queue-5.10/nfsd-nfsd_file_put-can-sleep.patch create mode 100644 queue-5.10/nfsd-nfsd_file_unhash-can-compute-hashval-from-nf-nf.patch create mode 100644 queue-5.10/nfsd-nfserrno-enomem-is-nfserr_jukebox.patch create mode 100644 queue-5.10/nfsd-nfsv4-close-should-release-an-nfsd_file-immedia.patch create mode 100644 queue-5.10/nfsd-no-longer-record-nf_hashval-in-the-trace-log.patch create mode 100644 queue-5.10/nfsd-only-call-fh_unlock-once-in-nfsd_link.patch create mode 100644 queue-5.10/nfsd-only-call-inode_query_iversion-in-the-i_version.patch create mode 100644 queue-5.10/nfsd-only-fill-out-return-pointer-on-success-in-nfsd.patch create mode 100644 queue-5.10/nfsd-optimize-drc-bucket-pruning.patch create mode 100644 queue-5.10/nfsd-optimize-nfsd4_encode_fattr.patch create mode 100644 queue-5.10/nfsd-optimize-nfsd4_encode_operation.patch create mode 100644 queue-5.10/nfsd-optimize-nfsd4_encode_readv.patch create mode 100644 queue-5.10/nfsd-pack-struct-nfsd4_compoundres.patch create mode 100644 queue-5.10/nfsd-pass-range-end-to-vfs_fsync_range-instead-of-co.patch create mode 100644 queue-5.10/nfsd-pass-the-target-nfsd_file-to-nfsd_commit.patch create mode 100644 queue-5.10/nfsd-prevent-a-possible-oops-in-the-nfs_dirent-trace.patch create mode 100644 queue-5.10/nfsd-prevent-truncation-of-an-unlinked-inode-from-bl.patch create mode 100644 queue-5.10/nfsd-propagate-some-error-code-returned-by-memdup_us.patch create mode 100644 queue-5.10/nfsd-protect-against-filesystem-freezing.patch create mode 100644 queue-5.10/nfsd-protect-against-send-buffer-overflow-in-nfsv2-r.patch create mode 100644 queue-5.10/nfsd-protect-against-send-buffer-overflow-in-nfsv2-r.patch-22138 create mode 100644 queue-5.10/nfsd-protect-against-send-buffer-overflow-in-nfsv3-r.patch create mode 100644 queue-5.10/nfsd-protect-against-send-buffer-overflow-in-nfsv3-r.patch-26809 create mode 100644 queue-5.10/nfsd-protect-concurrent-access-to-nfsd-stats-counter.patch create mode 100644 queue-5.10/nfsd-put-the-export-reference-in-nfsd4_verify_deleg_.patch create mode 100644 queue-5.10/nfsd-record-nfsv4-pre-post-op-attributes-as-non-atom.patch create mode 100644 queue-5.10/nfsd-record-number-of-flush-calls.patch create mode 100644 queue-5.10/nfsd-reduce-amount-of-struct-nfsd4_compoundargs-that.patch create mode 100644 queue-5.10/nfsd-reduce-locking-in-nfsd_lookup.patch create mode 100644 queue-5.10/nfsd-reduce-svc_rqst-rq_pages-churn-during-readdir-o.patch create mode 100644 queue-5.10/nfsd-refactor-__nfsd_file_close_inode.patch create mode 100644 queue-5.10/nfsd-refactor-common-code-out-of-dirlist-helpers.patch create mode 100644 queue-5.10/nfsd-refactor-find_file.patch create mode 100644 queue-5.10/nfsd-refactor-nfsd4_cleanup_inter_ssc-1-2.patch create mode 100644 queue-5.10/nfsd-refactor-nfsd4_cleanup_inter_ssc-2-2.patch create mode 100644 queue-5.10/nfsd-refactor-nfsd4_do_copy.patch create mode 100644 queue-5.10/nfsd-refactor-nfsd_create_setattr.patch create mode 100644 queue-5.10/nfsd-refactor-nfsd_file_gc.patch create mode 100644 queue-5.10/nfsd-refactor-nfsd_file_lru_scan.patch create mode 100644 queue-5.10/nfsd-refactor-nfsd_setattr.patch create mode 100644 queue-5.10/nfsd-refactor-nfsv3-create.patch create mode 100644 queue-5.10/nfsd-refactor-nfsv4-open-create.patch create mode 100644 queue-5.10/nfsd-refactor-set_client.patch create mode 100644 queue-5.10/nfsd-refactoring-courtesy_client_reaper-to-a-generic.patch create mode 100644 queue-5.10/nfsd-refactoring-v4-specific-code-to-a-helper-in-nfs.patch create mode 100644 queue-5.10/nfsd-register-unregister-of-nfsd-client-shrinker-at-.patch create mode 100644 queue-5.10/nfsd-relocate-nfsd4_decode_opaque.patch create mode 100644 queue-5.10/nfsd-remove-argument-length-checking-in-nfsd_dispatc.patch create mode 100644 queue-5.10/nfsd-remove-be32_to_cpu-from-drc-hash-function.patch create mode 100644 queue-5.10/nfsd-remove-config_nfsd_v3.patch create mode 100644 queue-5.10/nfsd-remove-do_nfsd_create.patch create mode 100644 queue-5.10/nfsd-remove-dprintk-call-sites-from-tail-of-nfsd4_op.patch create mode 100644 queue-5.10/nfsd-remove-extra-0x-in-tracepoint-format-specifier.patch create mode 100644 queue-5.10/nfsd-remove-inline-directives-on-op_rsize_bop-helper.patch create mode 100644 queue-5.10/nfsd-remove-kmalloc-from-nfsd4_do_async_copy.patch create mode 100644 queue-5.10/nfsd-remove-lockdep-assertion-from-unhash_and_releas.patch create mode 100644 queue-5.10/nfsd-remove-macros-that-are-no-longer-used.patch create mode 100644 queue-5.10/nfsd-remove-nfsd4_prepare_cb_recall-declaration.patch create mode 100644 queue-5.10/nfsd-remove-nfsd_file-nf_hashval.patch create mode 100644 queue-5.10/nfsd-remove-redundant-assignment-to-pointer-this.patch create mode 100644 queue-5.10/nfsd-remove-redundant-assignment-to-variable-host_er.patch create mode 100644 queue-5.10/nfsd-remove-redundant-assignment-to-variable-len.patch create mode 100644 queue-5.10/nfsd-remove-redundant-variable-status.patch create mode 100644 queue-5.10/nfsd-remove-svc_serv_ops-svo_module.patch create mode 100644 queue-5.10/nfsd-remove-the-nfsd_cb_work-and-nfsd_cb_done-tracep.patch create mode 100644 queue-5.10/nfsd-remove-the-pages_flushed-statistic-from-filecac.patch create mode 100644 queue-5.10/nfsd-remove-trace_nfsd_clid_inuse_err.patch create mode 100644 queue-5.10/nfsd-remove-unused-function.patch create mode 100644 queue-5.10/nfsd-remove-unused-nfsd4_compoundargs-cachetype-fiel.patch create mode 100644 queue-5.10/nfsd-remove-unused-nfsv2-directory-entry-encoders.patch create mode 100644 queue-5.10/nfsd-remove-unused-nfsv3-directory-entry-encoders.patch create mode 100644 queue-5.10/nfsd-remove-unused-set_client-argument.patch create mode 100644 queue-5.10/nfsd-remove-unused-stats-counters.patch create mode 100644 queue-5.10/nfsd-remove-vanity-comments.patch create mode 100644 queue-5.10/nfsd-removed-unused-argument-in-nfsd_startup_generic.patch create mode 100644 queue-5.10/nfsd-rename-boot-verifier-functions.patch create mode 100644 queue-5.10/nfsd-rename-lookup_clientid-set_client.patch create mode 100644 queue-5.10/nfsd-rename-the-fields-in-copy_stateid_t.patch create mode 100644 queue-5.10/nfsd-reorder-the-fields-in-struct-nfsd4_op.patch create mode 100644 queue-5.10/nfsd-reorganize-filecache.c.patch create mode 100644 queue-5.10/nfsd-replace-boolean-fields-in-struct-nfsd4_copy.patch create mode 100644 queue-5.10/nfsd-replace-delayed_work-with-work_struct-for-nfsd_.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_access.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_backchannel.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_bind_conn_t.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_cb_sec.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_clone.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_close.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_commit.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_compound.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_copy.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_copy_notify.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_create.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_create_sess.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_delegreturn.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_destroy_cli.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_destroy_ses.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_fallocate.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_fattr.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_free_statei.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_getattr.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_getdevicein.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_layoutcommi.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_layoutget.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_layoutretur.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_link.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_listxattrs.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_lock.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_lockt.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_locku.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_lookup.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_nl4_server.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_offload_sta.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_open.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_open_confir.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_open_downgr.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_putfh.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_read.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_readdir.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_reclaim_com.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_release_loc.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_remove.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_rename.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_renew.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_secinfo.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_secinfo_no_.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_seek.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_sequence.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_setattr.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_setclientid.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_setclientid.patch-10977 create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_setxattr.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_share_acces.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_share_deny.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_test_statei.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_verify.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_write.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_xattr_name.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-that-decode-the-fattr4-acl-.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-that-decode-the-fattr4-mode.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-that-decode-the-fattr4-owne.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-that-decode-the-fattr4-owne.patch-23903 create mode 100644 queue-5.10/nfsd-replace-read-macros-that-decode-the-fattr4-secu.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-that-decode-the-fattr4-size.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-that-decode-the-fattr4-time.patch create mode 100644 queue-5.10/nfsd-replace-read-macros-that-decode-the-fattr4-umas.patch create mode 100644 queue-5.10/nfsd-replace-the-init-once-mechanism.patch create mode 100644 queue-5.10/nfsd-replace-the-internals-of-the-read_buf-macro.patch create mode 100644 queue-5.10/nfsd-replace-the-nfsd_deleg_break-tracepoint.patch create mode 100644 queue-5.10/nfsd-report-average-age-of-filecache-items.patch create mode 100644 queue-5.10/nfsd-report-client-confirmation-status-in-info-file.patch create mode 100644 queue-5.10/nfsd-report-count-of-calls-to-nfsd_file_acquire.patch create mode 100644 queue-5.10/nfsd-report-count-of-freed-filecache-items.patch create mode 100644 queue-5.10/nfsd-report-filecache-lru-size.patch create mode 100644 queue-5.10/nfsd-report-per-export-stats.patch create mode 100644 queue-5.10/nfsd-report-the-number-of-items-evicted-by-the-lru-w.patch create mode 100644 queue-5.10/nfsd-reshuffle-some-code.patch create mode 100644 queue-5.10/nfsd-restore-nfsv4-decoding-s-savemem-functionality.patch create mode 100644 queue-5.10/nfsd-retry-once-in-nfsd_open-on-an-eopenstale-return.patch create mode 100644 queue-5.10/nfsd-return-error-if-nfs4_setacl-fails.patch create mode 100644 queue-5.10/nfsd-revert-nfsd-nfsv4-close-should-release-an-nfsd_.patch create mode 100644 queue-5.10/nfsd-rework-hashtable-handling-in-nfsd_do_file_acqui.patch create mode 100644 queue-5.10/nfsd-rework-refcounting-in-filecache.patch create mode 100644 queue-5.10/nfsd-rpc_peeraddr2str-needs-rcu-lock.patch create mode 100644 queue-5.10/nfsd-save-location-of-nfsv4-compound-status.patch create mode 100644 queue-5.10/nfsd-separate-nfsd_last_thread-from-nfsd_put.patch create mode 100644 queue-5.10/nfsd-separate-tracepoints-for-acquire-and-create.patch create mode 100644 queue-5.10/nfsd-set-attributes-when-creating-symlinks.patch create mode 100644 queue-5.10/nfsd-set-pf_local_throttle-on-local-filesystems-only.patch create mode 100644 queue-5.10/nfsd-set-up-an-rhashtable-for-the-filecache.patch create mode 100644 queue-5.10/nfsd-show-state-of-courtesy-client-in-client-info.patch create mode 100644 queue-5.10/nfsd-shrink-size-of-struct-nfsd4_copy.patch create mode 100644 queue-5.10/nfsd-shrink-size-of-struct-nfsd4_copy_notify.patch create mode 100644 queue-5.10/nfsd-silence-extraneous-printk-on-nfsd.ko-insertion.patch create mode 100644 queue-5.10/nfsd-simplify-code-around-svc_exit_thread-call-in-nf.patch create mode 100644 queue-5.10/nfsd-simplify-locking-for-network-notifier.patch create mode 100644 queue-5.10/nfsd-simplify-nfsd4_change_info.patch create mode 100644 queue-5.10/nfsd-simplify-nfsd4_check_open_reclaim.patch create mode 100644 queue-5.10/nfsd-simplify-nfsd_renew.patch create mode 100644 queue-5.10/nfsd-simplify-per-net-file-cache-management.patch create mode 100644 queue-5.10/nfsd-simplify-process_lock.patch create mode 100644 queue-5.10/nfsd-simplify-read_plus.patch create mode 100644 queue-5.10/nfsd-simplify-starting_len.patch create mode 100644 queue-5.10/nfsd-simplify-struct-nfsfh.patch create mode 100644 queue-5.10/nfsd-simplify-test_bit-return-in-nfsd_file_key_full-.patch create mode 100644 queue-5.10/nfsd-simplify-the-delayed-disposal-list-code.patch create mode 100644 queue-5.10/nfsd-skip-extra-computation-for-rc_nocache-case.patch create mode 100644 queue-5.10/nfsd-skip-some-unnecessary-stats-in-the-v4-case.patch create mode 100644 queue-5.10/nfsd-streamline-the-rare-found-case.patch create mode 100644 queue-5.10/nfsd-trace-boot-verifier-resets.patch create mode 100644 queue-5.10/nfsd-trace-delegation-revocations.patch create mode 100644 queue-5.10/nfsd-trace-filecache-lru-activity.patch create mode 100644 queue-5.10/nfsd-trace-filecache-opens.patch create mode 100644 queue-5.10/nfsd-trace-stateids-returned-via-delegreturn.patch create mode 100644 queue-5.10/nfsd-track-filehandle-aliasing-in-nfs4_files.patch create mode 100644 queue-5.10/nfsd-unregister-shrinker-when-nfsd_init_net-fails.patch create mode 100644 queue-5.10/nfsd-unregister-the-cld-notifier-when-laundry_wq-cre.patch create mode 100644 queue-5.10/nfsd-update-access3arg-decoder-to-use-struct-xdr_str.patch create mode 100644 queue-5.10/nfsd-update-comment-over-__nfsd_file_cache_purge.patch create mode 100644 queue-5.10/nfsd-update-commit3arg-decoder-to-use-struct-xdr_str.patch create mode 100644 queue-5.10/nfsd-update-create-verifier-comment.patch create mode 100644 queue-5.10/nfsd-update-file_hashtbl-helpers.patch create mode 100644 queue-5.10/nfsd-update-getattr3args-decoder-to-use-struct-xdr_s.patch create mode 100644 queue-5.10/nfsd-update-nfsd_cb_args-tracepoint.patch create mode 100644 queue-5.10/nfsd-update-nfsv2-diropargs-decoding-to-use-struct-x.patch create mode 100644 queue-5.10/nfsd-update-nfsv3-readdir-entry-encoders-to-use-stru.patch create mode 100644 queue-5.10/nfsd-update-read3arg-decoder-to-use-struct-xdr_strea.patch create mode 100644 queue-5.10/nfsd-update-readdir3args-decoders-to-use-struct-xdr_.patch create mode 100644 queue-5.10/nfsd-update-readlink3arg-decoder-to-use-struct-xdr_s.patch create mode 100644 queue-5.10/nfsd-update-the-create3args-decoder-to-use-struct-xd.patch create mode 100644 queue-5.10/nfsd-update-the-getattr3res-encoder-to-use-struct-xd.patch create mode 100644 queue-5.10/nfsd-update-the-link3args-decoder-to-use-struct-xdr_.patch create mode 100644 queue-5.10/nfsd-update-the-mkdir3args-decoder-to-use-struct-xdr.patch create mode 100644 queue-5.10/nfsd-update-the-mknod3args-decoder-to-use-struct-xdr.patch create mode 100644 queue-5.10/nfsd-update-the-nfsv2-acl-access-argument-decoder-to.patch create mode 100644 queue-5.10/nfsd-update-the-nfsv2-acl-access-result-encoder-to-u.patch create mode 100644 queue-5.10/nfsd-update-the-nfsv2-acl-getattr-argument-decoder-t.patch create mode 100644 queue-5.10/nfsd-update-the-nfsv2-acl-getattr-result-encoder-to-.patch create mode 100644 queue-5.10/nfsd-update-the-nfsv2-attrstat-encoder-to-use-struct.patch create mode 100644 queue-5.10/nfsd-update-the-nfsv2-create-argument-decoder-to-use.patch create mode 100644 queue-5.10/nfsd-update-the-nfsv2-diropres-encoder-to-use-struct.patch create mode 100644 queue-5.10/nfsd-update-the-nfsv2-getacl-argument-decoder-to-use.patch create mode 100644 queue-5.10/nfsd-update-the-nfsv2-getacl-result-encoder-to-use-s.patch create mode 100644 queue-5.10/nfsd-update-the-nfsv2-getattr-argument-decoder-to-us.patch create mode 100644 queue-5.10/nfsd-update-the-nfsv2-link-argument-decoder-to-use-s.patch create mode 100644 queue-5.10/nfsd-update-the-nfsv2-read-argument-decoder-to-use-s.patch create mode 100644 queue-5.10/nfsd-update-the-nfsv2-read-result-encoder-to-use-str.patch create mode 100644 queue-5.10/nfsd-update-the-nfsv2-readdir-argument-decoder-to-us.patch create mode 100644 queue-5.10/nfsd-update-the-nfsv2-readdir-entry-encoder-to-use-s.patch create mode 100644 queue-5.10/nfsd-update-the-nfsv2-readdir-result-encoder-to-use-.patch create mode 100644 queue-5.10/nfsd-update-the-nfsv2-readlink-argument-decoder-to-u.patch create mode 100644 queue-5.10/nfsd-update-the-nfsv2-readlink-result-encoder-to-use.patch create mode 100644 queue-5.10/nfsd-update-the-nfsv2-rename-argument-decoder-to-use.patch create mode 100644 queue-5.10/nfsd-update-the-nfsv2-setacl-argument-decoder-to-use.patch create mode 100644 queue-5.10/nfsd-update-the-nfsv2-setacl-argument-decoder-to-use.patch-31348 create mode 100644 queue-5.10/nfsd-update-the-nfsv2-setacl-result-encoder-to-use-s.patch create mode 100644 queue-5.10/nfsd-update-the-nfsv2-setattr-argument-decoder-to-us.patch create mode 100644 queue-5.10/nfsd-update-the-nfsv2-stat-encoder-to-use-struct-xdr.patch create mode 100644 queue-5.10/nfsd-update-the-nfsv2-statfs-result-encoder-to-use-s.patch create mode 100644 queue-5.10/nfsd-update-the-nfsv2-symlink-argument-decoder-to-us.patch create mode 100644 queue-5.10/nfsd-update-the-nfsv2-write-argument-decoder-to-use-.patch create mode 100644 queue-5.10/nfsd-update-the-nfsv3-access3res-encoder-to-use-stru.patch create mode 100644 queue-5.10/nfsd-update-the-nfsv3-commit3res-encoder-to-use-stru.patch create mode 100644 queue-5.10/nfsd-update-the-nfsv3-create-family-of-encoders-to-u.patch create mode 100644 queue-5.10/nfsd-update-the-nfsv3-diropargs-decoder-to-use-struc.patch create mode 100644 queue-5.10/nfsd-update-the-nfsv3-fsinfo3res-encoder-to-use-stru.patch create mode 100644 queue-5.10/nfsd-update-the-nfsv3-fsstat3res-encoder-to-use-stru.patch create mode 100644 queue-5.10/nfsd-update-the-nfsv3-getacl-argument-decoder-to-use.patch create mode 100644 queue-5.10/nfsd-update-the-nfsv3-getacl-result-encoder-to-use-s.patch create mode 100644 queue-5.10/nfsd-update-the-nfsv3-link3res-encoder-to-use-struct.patch create mode 100644 queue-5.10/nfsd-update-the-nfsv3-lookup3res-encoder-to-use-stru.patch create mode 100644 queue-5.10/nfsd-update-the-nfsv3-pathconf3res-encoder-to-use-st.patch create mode 100644 queue-5.10/nfsd-update-the-nfsv3-read3res-encode-to-use-struct-.patch create mode 100644 queue-5.10/nfsd-update-the-nfsv3-readdir3res-encoder-to-use-str.patch create mode 100644 queue-5.10/nfsd-update-the-nfsv3-readlink3res-encoder-to-use-st.patch create mode 100644 queue-5.10/nfsd-update-the-nfsv3-renamev3res-encoder-to-use-str.patch create mode 100644 queue-5.10/nfsd-update-the-nfsv3-setacl-result-encoder-to-use-s.patch create mode 100644 queue-5.10/nfsd-update-the-nfsv3-wccstat-result-encoder-to-use-.patch create mode 100644 queue-5.10/nfsd-update-the-nfsv3-write3res-encoder-to-use-struc.patch create mode 100644 queue-5.10/nfsd-update-the-rename3args-decoder-to-use-struct-xd.patch create mode 100644 queue-5.10/nfsd-update-the-setattr3args-decoder-to-use-struct-x.patch create mode 100644 queue-5.10/nfsd-update-the-symlink3args-decoder-to-use-struct-x.patch create mode 100644 queue-5.10/nfsd-update-write3arg-decoder-to-use-struct-xdr_stre.patch create mode 100644 queue-5.10/nfsd-use-const-pointers-as-parameters-to-fh_-helpers.patch create mode 100644 queue-5.10/nfsd-use-define_proc_show_attribute-to-define-nfsd_p.patch create mode 100644 queue-5.10/nfsd-use-define_show_attribute-to-define-client_info.patch create mode 100644 queue-5.10/nfsd-use-define_show_attribute-to-define-export_feat.patch create mode 100644 queue-5.10/nfsd-use-define_show_attribute-to-define-nfsd_file_c.patch create mode 100644 queue-5.10/nfsd-use-define_show_attribute-to-define-nfsd_reply_.patch create mode 100644 queue-5.10/nfsd-use-define_spinlock-for-spinlock.patch create mode 100644 queue-5.10/nfsd-use-explicit-lock-unlock-for-directory-ops.patch create mode 100644 queue-5.10/nfsd-use-fsnotify-group-lock-helpers.patch create mode 100644 queue-5.10/nfsd-use-locks_inode_context-helper.patch create mode 100644 queue-5.10/nfsd-use-only-rq_dropme-to-signal-the-need-to-drop-a.patch create mode 100644 queue-5.10/nfsd-use-rhashtable-for-managing-nfs4_file-objects.patch create mode 100644 queue-5.10/nfsd-use-set_bit-rq_dropme.patch create mode 100644 queue-5.10/nfsd-use-struct_size-helper-in-alloc_session.patch create mode 100644 queue-5.10/nfsd-use-un-lock_inode-instead-of-fh_-un-lock-for-fi.patch create mode 100644 queue-5.10/nfsd-use-xdr_inline_decode-to-decode-nfsv3-symlinks.patch create mode 100644 queue-5.10/nfsd-use-xdr_pad_size.patch create mode 100644 queue-5.10/nfsd-verify-the-opened-dentry-after-setting-a-delega.patch create mode 100644 queue-5.10/nfsd-warn-when-freeing-an-item-still-linked-via-nf_l.patch create mode 100644 queue-5.10/nfsd-write-verifier-might-go-backwards.patch create mode 100644 queue-5.10/nfsd-zero-counters-when-the-filecache-is-re-initiali.patch create mode 100644 queue-5.10/nfsd4-add-refcount-for-nfsd4_blocked_lock.patch create mode 100644 queue-5.10/nfsd4-don-t-query-change-attribute-in-v2-v3-case.patch create mode 100644 queue-5.10/nfsd4-expose-the-callback-address-and-state-of-each-.patch create mode 100644 queue-5.10/nfsd4-remove-obselete-comment.patch create mode 100644 queue-5.10/nfsd4-simplify-process_lookup1.patch create mode 100644 queue-5.10/nfsd_splice_actor-handle-compound-pages.patch create mode 100644 queue-5.10/nfsv4.2-remove-ifdef-config_nfsd-from-nfsv4.2-client.patch create mode 100644 queue-5.10/nfsv4_2-ssc-helper-should-use-its-own-config.patch create mode 100644 queue-5.10/nlm-defend-against-file_lock-changes-after-vfs_test_.patch create mode 100644 queue-5.10/nlm-fix-svcxdr_encode_owner.patch create mode 100644 queue-5.10/nlm-minor-nlm_lookup_file-argument-change.patch create mode 100644 queue-5.10/nlm-minor-refactoring.patch create mode 100644 queue-5.10/proc-fd-in-fdinfo-seq_show-don-t-use-get_files_struc.patch create mode 100644 queue-5.10/proc-fd-in-proc_fd_link-use-fget_task.patch create mode 100644 queue-5.10/proc-fd-in-proc_readfd_common-use-task_lookup_next_f.patch create mode 100644 queue-5.10/proc-fd-in-tid_fd_mode-use-task_lookup_fd_rcu.patch create mode 100644 queue-5.10/revert-fanotify-limit-number-of-event-merge-attempts.patch create mode 100644 queue-5.10/revert-fget-clarify-and-improve-__fget_files-impleme.patch create mode 100644 queue-5.10/revert-nfsd-skip-some-unnecessary-stats-in-the-v4-ca.patch create mode 100644 queue-5.10/revert-nfsd4-support-change_attr_type-attribute.patch create mode 100644 queue-5.10/revert-sunrpc-use-rmw-bitops-in-single-threaded-hot-.patch create mode 100644 queue-5.10/sunrpc-add-svc_rqst-rq_auth_stat.patch create mode 100644 queue-5.10/sunrpc-add-svc_rqst_replace_page-api.patch create mode 100644 queue-5.10/sunrpc-add-xdr_set_scratch_page-and-xdr_reset_scratc.patch create mode 100644 queue-5.10/sunrpc-always-treat-sv_nrpools-1-as-not-pooled.patch create mode 100644 queue-5.10/sunrpc-change-return-value-type-of-.pc_decode.patch create mode 100644 queue-5.10/sunrpc-change-return-value-type-of-.pc_encode.patch create mode 100644 queue-5.10/sunrpc-change-svc_get-to-return-the-svc.patch create mode 100644 queue-5.10/sunrpc-discard-svo_setup-and-rename-svc_set_num_thre.patch create mode 100644 queue-5.10/sunrpc-display-rpc-procedure-names-instead-of-proc-n.patch create mode 100644 queue-5.10/sunrpc-eliminate-the-rq_autherr-flag.patch create mode 100644 queue-5.10/sunrpc-export-svc_xprt_received.patch create mode 100644 queue-5.10/sunrpc-fix-xdr_encode_bool.patch create mode 100644 queue-5.10/sunrpc-make-trace_svc_process-display-the-rpc-proced.patch create mode 100644 queue-5.10/sunrpc-merge-svc_do_enqueue_xprt-into-svc_enqueue_xp.patch create mode 100644 queue-5.10/sunrpc-move-definition-of-xdr_unit.patch create mode 100644 queue-5.10/sunrpc-move-the-pool_map-definitions-back-into-svc.c.patch create mode 100644 queue-5.10/sunrpc-nfsd-clean-up-get-put-functions.patch create mode 100644 queue-5.10/sunrpc-optimize-xdr_reserve_space.patch create mode 100644 queue-5.10/sunrpc-parametrize-how-much-of-argsize-should-be-zer.patch create mode 100644 queue-5.10/sunrpc-prepare-for-xdr_stream-style-decoding-on-the-.patch create mode 100644 queue-5.10/sunrpc-remove-svc_shutdown_net.patch create mode 100644 queue-5.10/sunrpc-remove-svo_shutdown-method.patch create mode 100644 queue-5.10/sunrpc-remove-the-.svo_enqueue_xprt-method.patch create mode 100644 queue-5.10/sunrpc-rename-svc_close_xprt.patch create mode 100644 queue-5.10/sunrpc-rename-svc_create_xprt.patch create mode 100644 queue-5.10/sunrpc-rename-svc_encode_read_payload.patch create mode 100644 queue-5.10/sunrpc-replace-the-__be32-p-parameter-to-.pc_decode.patch create mode 100644 queue-5.10/sunrpc-replace-the-__be32-p-parameter-to-.pc_encode.patch create mode 100644 queue-5.10/sunrpc-return-true-false-not-1-0-from-bool-functions.patch create mode 100644 queue-5.10/sunrpc-set-rq_auth_stat-in-the-pg_authenticate-callo.patch create mode 100644 queue-5.10/sunrpc-stop-using-sv_nrthreads-as-a-refcount.patch create mode 100644 queue-5.10/sunrpc-trace-calls-to-.rpc_call_done.patch create mode 100644 queue-5.10/sunrpc-use-rmw-bitops-in-single-threaded-hot-paths.patch create mode 100644 queue-5.10/sunrpc-use-sv_lock-to-protect-updates-to-sv_nrthread.patch create mode 100644 queue-5.10/sysctl-introduce-new-proc-handler-proc_dobool.patch create mode 100644 queue-5.10/uapi-nfsfh.h-replace-one-element-array-with-flexible.patch diff --git a/queue-5.10/bpf-in-bpf_task_fd_query-use-fget_task.patch b/queue-5.10/bpf-in-bpf_task_fd_query-use-fget_task.patch new file mode 100644 index 00000000000..4666121f1b7 --- /dev/null +++ b/queue-5.10/bpf-in-bpf_task_fd_query-use-fget_task.patch @@ -0,0 +1,82 @@ +From 202ee117eebaca9d39e104672b4b690bda9c9c27 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Nov 2020 17:14:22 -0600 +Subject: bpf: In bpf_task_fd_query use fget_task + +From: Eric W. Biederman + +[ Upstream commit b48845af0152d790a54b8ab78cc2b7c07485fc98 ] + +Use the helper fget_task to simplify bpf_task_fd_query. + +As well as simplifying the code this removes one unnecessary increment of +struct files_struct. This unnecessary increment of files_struct.count can +result in exec unnecessarily unsharing files_struct and breaking posix +locks, and it can result in fget_light having to fallback to fget reducing +performance. + +This simplification comes from the observation that none of the +callers of get_files_struct actually need to call get_files_struct +that was made when discussing[1] exec and posix file locks. + +[1] https://lkml.kernel.org/r/20180915160423.GA31461@redhat.com +Suggested-by: Oleg Nesterov +v1: https://lkml.kernel.org/r/20200817220425.9389-5-ebiederm@xmission.com +Link: https://lkml.kernel.org/r/20201120231441.29911-5-ebiederm@xmission.com +Signed-off-by: Eric W. Biederman +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + kernel/bpf/syscall.c | 20 +++----------------- + 1 file changed, 3 insertions(+), 17 deletions(-) + +diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c +index e1bee8cd34044..fbe7f8e2b022c 100644 +--- a/kernel/bpf/syscall.c ++++ b/kernel/bpf/syscall.c +@@ -3929,7 +3929,6 @@ static int bpf_task_fd_query(const union bpf_attr *attr, + pid_t pid = attr->task_fd_query.pid; + u32 fd = attr->task_fd_query.fd; + const struct perf_event *event; +- struct files_struct *files; + struct task_struct *task; + struct file *file; + int err; +@@ -3949,23 +3948,11 @@ static int bpf_task_fd_query(const union bpf_attr *attr, + if (!task) + return -ENOENT; + +- files = get_files_struct(task); +- put_task_struct(task); +- if (!files) +- return -ENOENT; +- + err = 0; +- spin_lock(&files->file_lock); +- file = fcheck_files(files, fd); ++ file = fget_task(task, fd); ++ put_task_struct(task); + if (!file) +- err = -EBADF; +- else +- get_file(file); +- spin_unlock(&files->file_lock); +- put_files_struct(files); +- +- if (err) +- goto out; ++ return -EBADF; + + if (file->f_op == &bpf_link_fops) { + struct bpf_link *link = file->private_data; +@@ -4005,7 +3992,6 @@ static int bpf_task_fd_query(const union bpf_attr *attr, + err = -ENOTSUPP; + put_file: + fput(file); +-out: + return err; + } + +-- +2.43.0 + diff --git a/queue-5.10/dnotify-use-fsnotify-group-lock-helpers.patch b/queue-5.10/dnotify-use-fsnotify-group-lock-helpers.patch new file mode 100644 index 00000000000..ffb6806b60b --- /dev/null +++ b/queue-5.10/dnotify-use-fsnotify-group-lock-helpers.patch @@ -0,0 +1,99 @@ +From a1e903e35a58da7472e7a4cab2bceb5411829879 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 Apr 2022 15:03:21 +0300 +Subject: dnotify: use fsnotify group lock helpers + +From: Amir Goldstein + +[ Upstream commit aabb45fdcb31f00f1e7cae2bce83e83474a87c03 ] + +Before commit 9542e6a643fc6 ("nfsd: Containerise filecache laundrette") +nfsd would close open files in direct reclaim context. There is no +guarantee that others memory shrinkers don't do the same and no +guarantee that future shrinkers won't do that. + +For example, if overlayfs implements inode cache of fscache would +keep open files to cached objects, inode shrinkers could end up closing +open files to underlying fs. + +Direct reclaim from dnotify mark allocation context may try to close +open files that have dnotify marks of the same group and hit a deadlock +on mark_mutex. + +Set the FSNOTIFY_GROUP_NOFS flag to prevent going into direct reclaim +from allocations under dnotify group lock and use the safe group lock +helpers. + +Link: https://lore.kernel.org/r/20220422120327.3459282-11-amir73il@gmail.com +Suggested-by: Jan Kara +Link: https://lore.kernel.org/r/20220321112310.vpr7oxro2xkz5llh@quack3.lan/ +Signed-off-by: Amir Goldstein +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/dnotify/dnotify.c | 13 +++++++------ + 1 file changed, 7 insertions(+), 6 deletions(-) + +diff --git a/fs/notify/dnotify/dnotify.c b/fs/notify/dnotify/dnotify.c +index 6c586802c50e6..fa81c59a2ad41 100644 +--- a/fs/notify/dnotify/dnotify.c ++++ b/fs/notify/dnotify/dnotify.c +@@ -150,7 +150,7 @@ void dnotify_flush(struct file *filp, fl_owner_t id) + return; + dn_mark = container_of(fsn_mark, struct dnotify_mark, fsn_mark); + +- mutex_lock(&dnotify_group->mark_mutex); ++ fsnotify_group_lock(dnotify_group); + + spin_lock(&fsn_mark->lock); + prev = &dn_mark->dn; +@@ -173,7 +173,7 @@ void dnotify_flush(struct file *filp, fl_owner_t id) + free = true; + } + +- mutex_unlock(&dnotify_group->mark_mutex); ++ fsnotify_group_unlock(dnotify_group); + + if (free) + fsnotify_free_mark(fsn_mark); +@@ -306,7 +306,7 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg) + new_dn_mark->dn = NULL; + + /* this is needed to prevent the fcntl/close race described below */ +- mutex_lock(&dnotify_group->mark_mutex); ++ fsnotify_group_lock(dnotify_group); + + /* add the new_fsn_mark or find an old one. */ + fsn_mark = fsnotify_find_mark(&inode->i_fsnotify_marks, dnotify_group); +@@ -316,7 +316,7 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg) + } else { + error = fsnotify_add_inode_mark_locked(new_fsn_mark, inode, 0); + if (error) { +- mutex_unlock(&dnotify_group->mark_mutex); ++ fsnotify_group_unlock(dnotify_group); + goto out_err; + } + spin_lock(&new_fsn_mark->lock); +@@ -365,7 +365,7 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg) + + if (destroy) + fsnotify_detach_mark(fsn_mark); +- mutex_unlock(&dnotify_group->mark_mutex); ++ fsnotify_group_unlock(dnotify_group); + if (destroy) + fsnotify_free_mark(fsn_mark); + fsnotify_put_mark(fsn_mark); +@@ -383,7 +383,8 @@ static int __init dnotify_init(void) + SLAB_PANIC|SLAB_ACCOUNT); + dnotify_mark_cache = KMEM_CACHE(dnotify_mark, SLAB_PANIC|SLAB_ACCOUNT); + +- dnotify_group = fsnotify_alloc_group(&dnotify_fsnotify_ops, 0); ++ dnotify_group = fsnotify_alloc_group(&dnotify_fsnotify_ops, ++ FSNOTIFY_GROUP_NOFS); + if (IS_ERR(dnotify_group)) + panic("unable to allocate fsnotify group for dnotify\n"); + return 0; +-- +2.43.0 + diff --git a/queue-5.10/documentation-add-missing-documentation-for-export_o.patch b/queue-5.10/documentation-add-missing-documentation-for-export_o.patch new file mode 100644 index 00000000000..0f304aabe70 --- /dev/null +++ b/queue-5.10/documentation-add-missing-documentation-for-export_o.patch @@ -0,0 +1,55 @@ +From c6533fd33aac7f52491c47d5289233ee21e923b3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 25 Aug 2023 15:04:23 -0400 +Subject: Documentation: Add missing documentation for EXPORT_OP flags + +From: Chuck Lever + +[ Upstream commit b38a6023da6a12b561f0421c6a5a1f7624a1529c ] + +The commits that introduced these flags neglected to update the +Documentation/filesystems/nfs/exporting.rst file. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + Documentation/filesystems/nfs/exporting.rst | 26 +++++++++++++++++++++ + 1 file changed, 26 insertions(+) + +diff --git a/Documentation/filesystems/nfs/exporting.rst b/Documentation/filesystems/nfs/exporting.rst +index 0e98edd353b5f..6f59a364f84cd 100644 +--- a/Documentation/filesystems/nfs/exporting.rst ++++ b/Documentation/filesystems/nfs/exporting.rst +@@ -215,3 +215,29 @@ following flags are defined: + This flag causes nfsd to close any open files for this inode _before_ + calling into the vfs to do an unlink or a rename that would replace + an existing file. ++ ++ EXPORT_OP_REMOTE_FS - Backing storage for this filesystem is remote ++ PF_LOCAL_THROTTLE exists for loopback NFSD, where a thread needs to ++ write to one bdi (the final bdi) in order to free up writes queued ++ to another bdi (the client bdi). Such threads get a private balance ++ of dirty pages so that dirty pages for the client bdi do not imact ++ the daemon writing to the final bdi. For filesystems whose durable ++ storage is not local (such as exported NFS filesystems), this ++ constraint has negative consequences. EXPORT_OP_REMOTE_FS enables ++ an export to disable writeback throttling. ++ ++ EXPORT_OP_NOATOMIC_ATTR - Filesystem does not update attributes atomically ++ EXPORT_OP_NOATOMIC_ATTR indicates that the exported filesystem ++ cannot provide the semantics required by the "atomic" boolean in ++ NFSv4's change_info4. This boolean indicates to a client whether the ++ returned before and after change attributes were obtained atomically ++ with the respect to the requested metadata operation (UNLINK, ++ OPEN/CREATE, MKDIR, etc). ++ ++ EXPORT_OP_FLUSH_ON_CLOSE - Filesystem flushes file data on close(2) ++ On most filesystems, inodes can remain under writeback after the ++ file is closed. NFSD relies on client activity or local flusher ++ threads to handle writeback. Certain filesystems, such as NFS, flush ++ all of an inode's dirty data on last close. Exports that behave this ++ way should set EXPORT_OP_FLUSH_ON_CLOSE so that NFSD knows to skip ++ waiting for writeback when closing such files. +-- +2.43.0 + diff --git a/queue-5.10/exec-don-t-open-code-get_close_on_exec.patch b/queue-5.10/exec-don-t-open-code-get_close_on_exec.patch new file mode 100644 index 00000000000..cc3418a604a --- /dev/null +++ b/queue-5.10/exec-don-t-open-code-get_close_on_exec.patch @@ -0,0 +1,46 @@ +From 5f3a40a1192a3c8eaaf6a6f62ca5aeeaec147fe3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 9 Dec 2020 15:42:57 -0600 +Subject: exec: Don't open code get_close_on_exec + +From: Eric W. Biederman + +[ Upstream commit 878f12dbb8f514799d126544d59be4d2675caac3 ] + +Al Viro pointed out that using the phrase "close_on_exec(fd, +rcu_dereference_raw(current->files->fdt))" instead of wrapping it in +rcu_read_lock(), rcu_read_unlock() is a very questionable +optimization[1]. + +Once wrapped with rcu_read_lock()/rcu_read_unlock() that phrase +becomes equivalent the helper function get_close_on_exec so +simplify the code and make it more robust by simply using +get_close_on_exec. + +[1] https://lkml.kernel.org/r/20201207222214.GA4115853@ZenIV.linux.org.uk +Suggested-by: Al Viro +Link: https://lkml.kernel.org/r/87k0tqr6zi.fsf_-_@x220.int.ebiederm.org +Signed-off-by: Eric W. Biederman +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/exec.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/fs/exec.c b/fs/exec.c +index ebe9011955b9b..fb8813cc532d0 100644 +--- a/fs/exec.c ++++ b/fs/exec.c +@@ -1821,8 +1821,7 @@ static int bprm_execve(struct linux_binprm *bprm, + * inaccessible after exec. Relies on having exclusive access to + * current->files (due to unshare_files above). + */ +- if (bprm->fdpath && +- close_on_exec(fd, rcu_dereference_raw(current->files->fdt))) ++ if (bprm->fdpath && get_close_on_exec(fd)) + bprm->interp_flags |= BINPRM_FLAGS_PATH_INACCESSIBLE; + + /* Set the unchanging part of bprm->cred */ +-- +2.43.0 + diff --git a/queue-5.10/exec-move-unshare_files-to-fix-posix-file-locking-du.patch b/queue-5.10/exec-move-unshare_files-to-fix-posix-file-locking-du.patch new file mode 100644 index 00000000000..8a20be447e3 --- /dev/null +++ b/queue-5.10/exec-move-unshare_files-to-fix-posix-file-locking-du.patch @@ -0,0 +1,204 @@ +From f95bfe5ba3942aa8fc687a543398b78568205137 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Nov 2020 17:14:18 -0600 +Subject: exec: Move unshare_files to fix posix file locking during exec +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Eric W. Biederman + +[ Upstream commit b6043501289ebf169ae19b810a882d517377302f ] + +Many moons ago the binfmts were doing some very questionable things +with file descriptors and an unsharing of the file descriptor table +was added to make things better[1][2]. The helper steal_lockss was +added to avoid breaking the userspace programs[3][4][6]. + +Unfortunately it turned out that steal_locks did not work for network +file systems[5], so it was removed to see if anyone would +complain[7][8]. It was thought at the time that NPTL would not be +affected as the unshare_files happened after the other threads were +killed[8]. Unfortunately because there was an unshare_files in +binfmt_elf.c before the threads were killed this analysis was +incorrect. + +This unshare_files in binfmt_elf.c resulted in the unshares_files +happening whenever threads were present. Which led to unshare_files +being moved to the start of do_execve[9]. + +Later the problems were rediscovered and the suggested approach was to +readd steal_locks under a different name[10]. I happened to be +reviewing patches and I noticed that this approach was a step +backwards[11]. + +I proposed simply moving unshare_files[12] and it was pointed +out that moving unshare_files without auditing the code was +also unsafe[13]. + +There were then several attempts to solve this[14][15][16] and I even +posted this set of changes[17]. Unfortunately because auditing all of +execve is time consuming this change did not make it in at the time. + +Well now that I am cleaning up exec I have made the time to read +through all of the binfmts and the only playing with file descriptors +is either the security modules closing them in +security_bprm_committing_creds or is in the generic code in fs/exec.c. +None of it happens before begin_new_exec is called. + +So move unshare_files into begin_new_exec, after the point of no +return. If memory is very very very low and the application calling +exec is sharing file descriptor tables between processes we might fail +past the point of no return. Which is unfortunate but no different +than any of the other places where we allocate memory after the point +of no return. + +This movement allows another process that shares the file table, or +another thread of the same process and that closes files or changes +their close on exec behavior and races with execve to cause some +unexpected things to happen. There is only one time of check to time +of use race and it is just there so that execve fails instead of +an interpreter failing when it tries to open the file it is supposed +to be interpreting. Failing later if userspace is being silly is +not a problem. + +With this change it the following discription from the removal +of steal_locks[8] finally becomes true. + + Apps using NPTL are not affected, since all other threads are killed before + execve. + + Apps using LinuxThreads are only affected if they + + - have multiple threads during exec (LinuxThreads doesn't kill other + threads, the app may do it with pthread_kill_other_threads_np()) + - rely on POSIX locks being inherited across exec + + Both conditions are documented, but not their interaction. + + Apps using clone() natively are affected if they + + - use clone(CLONE_FILES) + - rely on POSIX locks being inherited across exec + +I have investigated some paths to make it possible to solve this +without moving unshare_files but they all look more complicated[18]. + +Reported-by: Daniel P. Berrangé +Reported-by: Jeff Layton +History-tree: git://git.kernel.org/pub/scm/linux/kernel/git/tglx/history.git +[1] 02cda956de0b ("[PATCH] unshare_files" +[2] 04e9bcb4d106 ("[PATCH] use new unshare_files helper") +[3] 088f5d7244de ("[PATCH] add steal_locks helper") +[4] 02c541ec8ffa ("[PATCH] use new steal_locks helper") +[5] https://lkml.kernel.org/r/E1FLIlF-0007zR-00@dorka.pomaz.szeredi.hu +[6] https://lkml.kernel.org/r/0060321191605.GB15997@sorel.sous-sol.org +[7] https://lkml.kernel.org/r/E1FLwjC-0000kJ-00@dorka.pomaz.szeredi.hu +[8] c89681ed7d0e ("[PATCH] remove steal_locks()") +[9] fd8328be874f ("[PATCH] sanitize handling of shared descriptor tables in failing execve()") +[10] https://lkml.kernel.org/r/20180317142520.30520-1-jlayton@kernel.org +[11] https://lkml.kernel.org/r/87r2nwqk73.fsf@xmission.com +[12] https://lkml.kernel.org/r/87bmfgvg8w.fsf@xmission.com +[13] https://lkml.kernel.org/r/20180322111424.GE30522@ZenIV.linux.org.uk +[14] https://lkml.kernel.org/r/20180827174722.3723-1-jlayton@kernel.org +[15] https://lkml.kernel.org/r/20180830172423.21964-1-jlayton@kernel.org +[16] https://lkml.kernel.org/r/20180914105310.6454-1-jlayton@kernel.org +[17] https://lkml.kernel.org/r/87a7ohs5ow.fsf@xmission.com +[18] https://lkml.kernel.org/r/87pn8c1uj6.fsf_-_@x220.int.ebiederm.org +Acked-by: Christian Brauner +v1: https://lkml.kernel.org/r/20200817220425.9389-1-ebiederm@xmission.com +Link: https://lkml.kernel.org/r/20201120231441.29911-1-ebiederm@xmission.com +Signed-off-by: Eric W. Biederman +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/exec.c | 29 +++++++++++++++-------------- + 1 file changed, 15 insertions(+), 14 deletions(-) + +diff --git a/fs/exec.c b/fs/exec.c +index fb8813cc532d0..42952cf90f4af 100644 +--- a/fs/exec.c ++++ b/fs/exec.c +@@ -1245,6 +1245,7 @@ void __set_task_comm(struct task_struct *tsk, const char *buf, bool exec) + int begin_new_exec(struct linux_binprm * bprm) + { + struct task_struct *me = current; ++ struct files_struct *displaced; + int retval; + + /* Once we are committed compute the creds */ +@@ -1264,6 +1265,13 @@ int begin_new_exec(struct linux_binprm * bprm) + if (retval) + goto out; + ++ /* Ensure the files table is not shared. */ ++ retval = unshare_files(&displaced); ++ if (retval) ++ goto out; ++ if (displaced) ++ put_files_struct(displaced); ++ + /* + * Must be called _before_ exec_mmap() as bprm->mm is + * not visibile until then. This also enables the update +@@ -1789,7 +1797,6 @@ static int bprm_execve(struct linux_binprm *bprm, + int fd, struct filename *filename, int flags) + { + struct file *file; +- struct files_struct *displaced; + int retval; + + /* +@@ -1797,13 +1804,9 @@ static int bprm_execve(struct linux_binprm *bprm, + */ + io_uring_task_cancel(); + +- retval = unshare_files(&displaced); +- if (retval) +- return retval; +- + retval = prepare_bprm_creds(bprm); + if (retval) +- goto out_files; ++ return retval; + + check_unsafe_exec(bprm); + current->in_execve = 1; +@@ -1818,8 +1821,12 @@ static int bprm_execve(struct linux_binprm *bprm, + bprm->file = file; + /* + * Record that a name derived from an O_CLOEXEC fd will be +- * inaccessible after exec. Relies on having exclusive access to +- * current->files (due to unshare_files above). ++ * inaccessible after exec. This allows the code in exec to ++ * choose to fail when the executable is not mmaped into the ++ * interpreter and an open file descriptor is not passed to ++ * the interpreter. This makes for a better user experience ++ * than having the interpreter start and then immediately fail ++ * when it finds the executable is inaccessible. + */ + if (bprm->fdpath && get_close_on_exec(fd)) + bprm->interp_flags |= BINPRM_FLAGS_PATH_INACCESSIBLE; +@@ -1839,8 +1846,6 @@ static int bprm_execve(struct linux_binprm *bprm, + rseq_execve(current); + acct_update_integrals(current); + task_numa_free(current, false); +- if (displaced) +- put_files_struct(displaced); + return retval; + + out: +@@ -1857,10 +1862,6 @@ static int bprm_execve(struct linux_binprm *bprm, + current->fs->in_exec = 0; + current->in_execve = 0; + +-out_files: +- if (displaced) +- reset_files_struct(displaced); +- + return retval; + } + +-- +2.43.0 + diff --git a/queue-5.10/exec-remove-reset_files_struct.patch b/queue-5.10/exec-remove-reset_files_struct.patch new file mode 100644 index 00000000000..b1a66fdada3 --- /dev/null +++ b/queue-5.10/exec-remove-reset_files_struct.patch @@ -0,0 +1,61 @@ +From 0fc2aacbb7358e72bfc95f2fc74ff5c6b5ebd7c3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Nov 2020 17:14:20 -0600 +Subject: exec: Remove reset_files_struct + +From: Eric W. Biederman + +[ Upstream commit 950db38ff2c01b7aabbd7ab4a50b7992750fa63d ] + +Now that exec no longer needs to restore the previous value of current->files +on error there are no more callers of reset_files_struct so remove it. + +Acked-by: Christian Brauner +v1: https://lkml.kernel.org/r/20200817220425.9389-3-ebiederm@xmission.com +Link: https://lkml.kernel.org/r/20201120231441.29911-3-ebiederm@xmission.com +Signed-off-by: Eric W. Biederman +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/file.c | 12 ------------ + include/linux/fdtable.h | 1 - + 2 files changed, 13 deletions(-) + +diff --git a/fs/file.c b/fs/file.c +index d6bc73960e4ac..5065252bb474e 100644 +--- a/fs/file.c ++++ b/fs/file.c +@@ -466,18 +466,6 @@ void put_files_struct(struct files_struct *files) + } + } + +-void reset_files_struct(struct files_struct *files) +-{ +- struct task_struct *tsk = current; +- struct files_struct *old; +- +- old = tsk->files; +- task_lock(tsk); +- tsk->files = files; +- task_unlock(tsk); +- put_files_struct(old); +-} +- + void exit_files(struct task_struct *tsk) + { + struct files_struct * files = tsk->files; +diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h +index b32ab2163dc2d..c0ca6fb3f0f95 100644 +--- a/include/linux/fdtable.h ++++ b/include/linux/fdtable.h +@@ -108,7 +108,6 @@ struct task_struct; + + struct files_struct *get_files_struct(struct task_struct *); + void put_files_struct(struct files_struct *fs); +-void reset_files_struct(struct files_struct *); + int unshare_files(void); + struct files_struct *dup_fd(struct files_struct *, unsigned, int *) __latent_entropy; + void do_close_on_exec(struct files_struct *); +-- +2.43.0 + diff --git a/queue-5.10/exec-simplify-unshare_files.patch b/queue-5.10/exec-simplify-unshare_files.patch new file mode 100644 index 00000000000..6c9398be61f --- /dev/null +++ b/queue-5.10/exec-simplify-unshare_files.patch @@ -0,0 +1,126 @@ +From d3fa9dc5e60e3e3955f04b51b6cac20d4ca7fa3c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Nov 2020 17:14:19 -0600 +Subject: exec: Simplify unshare_files + +From: Eric W. Biederman + +[ Upstream commit 1f702603e7125a390b5cdf5ce00539781cfcc86a ] + +Now that exec no longer needs to return the unshared files to their +previous value there is no reason to return displaced. + +Instead when unshare_fd creates a copy of the file table, call +put_files_struct before returning from unshare_files. + +Acked-by: Christian Brauner +v1: https://lkml.kernel.org/r/20200817220425.9389-2-ebiederm@xmission.com +Link: https://lkml.kernel.org/r/20201120231441.29911-2-ebiederm@xmission.com +Signed-off-by: Eric W. Biederman +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/coredump.c | 5 +---- + fs/exec.c | 5 +---- + include/linux/fdtable.h | 2 +- + kernel/fork.c | 12 ++++++------ + 4 files changed, 9 insertions(+), 15 deletions(-) + +diff --git a/fs/coredump.c b/fs/coredump.c +index 9d91e831ed0b2..7b085975ea163 100644 +--- a/fs/coredump.c ++++ b/fs/coredump.c +@@ -590,7 +590,6 @@ void do_coredump(const kernel_siginfo_t *siginfo) + int ispipe; + size_t *argv = NULL; + int argc = 0; +- struct files_struct *displaced; + /* require nonrelative corefile path and be extra careful */ + bool need_suid_safe = false; + bool core_dumped = false; +@@ -797,11 +796,9 @@ void do_coredump(const kernel_siginfo_t *siginfo) + } + + /* get us an unshared descriptor table; almost always a no-op */ +- retval = unshare_files(&displaced); ++ retval = unshare_files(); + if (retval) + goto close_fail; +- if (displaced) +- put_files_struct(displaced); + if (!dump_interrupted()) { + /* + * umh disabled with CONFIG_STATIC_USERMODEHELPER_PATH="" would +diff --git a/fs/exec.c b/fs/exec.c +index 42952cf90f4af..d5c8f085235bc 100644 +--- a/fs/exec.c ++++ b/fs/exec.c +@@ -1245,7 +1245,6 @@ void __set_task_comm(struct task_struct *tsk, const char *buf, bool exec) + int begin_new_exec(struct linux_binprm * bprm) + { + struct task_struct *me = current; +- struct files_struct *displaced; + int retval; + + /* Once we are committed compute the creds */ +@@ -1266,11 +1265,9 @@ int begin_new_exec(struct linux_binprm * bprm) + goto out; + + /* Ensure the files table is not shared. */ +- retval = unshare_files(&displaced); ++ retval = unshare_files(); + if (retval) + goto out; +- if (displaced) +- put_files_struct(displaced); + + /* + * Must be called _before_ exec_mmap() as bprm->mm is +diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h +index f1a99d3e55707..b32ab2163dc2d 100644 +--- a/include/linux/fdtable.h ++++ b/include/linux/fdtable.h +@@ -109,7 +109,7 @@ struct task_struct; + struct files_struct *get_files_struct(struct task_struct *); + void put_files_struct(struct files_struct *fs); + void reset_files_struct(struct files_struct *); +-int unshare_files(struct files_struct **); ++int unshare_files(void); + struct files_struct *dup_fd(struct files_struct *, unsigned, int *) __latent_entropy; + void do_close_on_exec(struct files_struct *); + int iterate_fd(struct files_struct *, unsigned, +diff --git a/kernel/fork.c b/kernel/fork.c +index 633b0af1d1a73..8b8a5a172b158 100644 +--- a/kernel/fork.c ++++ b/kernel/fork.c +@@ -3077,21 +3077,21 @@ SYSCALL_DEFINE1(unshare, unsigned long, unshare_flags) + * the exec layer of the kernel. + */ + +-int unshare_files(struct files_struct **displaced) ++int unshare_files(void) + { + struct task_struct *task = current; +- struct files_struct *copy = NULL; ++ struct files_struct *old, *copy = NULL; + int error; + + error = unshare_fd(CLONE_FILES, NR_OPEN_MAX, ©); +- if (error || !copy) { +- *displaced = NULL; ++ if (error || !copy) + return error; +- } +- *displaced = task->files; ++ ++ old = task->files; + task_lock(task); + task->files = copy; + task_unlock(task); ++ put_files_struct(old); + return 0; + } + +-- +2.43.0 + diff --git a/queue-5.10/exit-implement-kthread_exit.patch b/queue-5.10/exit-implement-kthread_exit.patch new file mode 100644 index 00000000000..e31505a5309 --- /dev/null +++ b/queue-5.10/exit-implement-kthread_exit.patch @@ -0,0 +1,114 @@ +From 504c5b3698d288c6bc3c3fad81ebe5e2d14a2543 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 22 Nov 2021 10:27:36 -0600 +Subject: exit: Implement kthread_exit + +From: Eric W. Biederman + +[ Upstream commit bbda86e988d4c124e4cfa816291cbd583ae8bfb1 ] + +The way the per task_struct exit_code is used by kernel threads is not +quite compatible how it is used by userspace applications. The low +byte of the userspace exit_code value encodes the exit signal. While +kthreads just use the value as an int holding ordinary kernel function +exit status like -EPERM. + +Add kthread_exit to clearly separate the two kinds of uses. + +Signed-off-by: "Eric W. Biederman" +Stable-dep-of: ca3574bd653a ("exit: Rename module_put_and_exit to module_put_and_kthread_exit") +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + include/linux/kthread.h | 1 + + kernel/kthread.c | 23 +++++++++++++++++++---- + tools/objtool/check.c | 1 + + 3 files changed, 21 insertions(+), 4 deletions(-) + +diff --git a/include/linux/kthread.h b/include/linux/kthread.h +index 2484ed97e72f5..9dae77a97a033 100644 +--- a/include/linux/kthread.h ++++ b/include/linux/kthread.h +@@ -68,6 +68,7 @@ void *kthread_probe_data(struct task_struct *k); + int kthread_park(struct task_struct *k); + void kthread_unpark(struct task_struct *k); + void kthread_parkme(void); ++void kthread_exit(long result) __noreturn; + + int kthreadd(void *unused); + extern struct task_struct *kthreadd_task; +diff --git a/kernel/kthread.c b/kernel/kthread.c +index 508fe52782857..9d6cc9c15a55e 100644 +--- a/kernel/kthread.c ++++ b/kernel/kthread.c +@@ -262,6 +262,21 @@ void kthread_parkme(void) + } + EXPORT_SYMBOL_GPL(kthread_parkme); + ++/** ++ * kthread_exit - Cause the current kthread return @result to kthread_stop(). ++ * @result: The integer value to return to kthread_stop(). ++ * ++ * While kthread_exit can be called directly, it exists so that ++ * functions which do some additional work in non-modular code such as ++ * module_put_and_kthread_exit can be implemented. ++ * ++ * Does not return. ++ */ ++void __noreturn kthread_exit(long result) ++{ ++ do_exit(result); ++} ++ + static int kthread(void *_create) + { + /* Copy data: it's on kthread's stack */ +@@ -279,13 +294,13 @@ static int kthread(void *_create) + done = xchg(&create->done, NULL); + if (!done) { + kfree(create); +- do_exit(-EINTR); ++ kthread_exit(-EINTR); + } + + if (!self) { + create->result = ERR_PTR(-ENOMEM); + complete(done); +- do_exit(-ENOMEM); ++ kthread_exit(-ENOMEM); + } + + self->threadfn = threadfn; +@@ -312,7 +327,7 @@ static int kthread(void *_create) + __kthread_parkme(self); + ret = threadfn(data); + } +- do_exit(ret); ++ kthread_exit(ret); + } + + /* called from do_fork() to get node information for about to be created task */ +@@ -621,7 +636,7 @@ EXPORT_SYMBOL_GPL(kthread_park); + * instead of calling wake_up_process(): the thread will exit without + * calling threadfn(). + * +- * If threadfn() may call do_exit() itself, the caller must ensure ++ * If threadfn() may call kthread_exit() itself, the caller must ensure + * task_struct can't go away. + * + * Returns the result of threadfn(), or %-EINTR if wake_up_process() +diff --git a/tools/objtool/check.c b/tools/objtool/check.c +index 059b78d08f7af..6afa1f8ca1614 100644 +--- a/tools/objtool/check.c ++++ b/tools/objtool/check.c +@@ -168,6 +168,7 @@ static bool __dead_end_function(struct objtool_file *file, struct symbol *func, + "panic", + "do_exit", + "do_task_dead", ++ "kthread_exit", + "make_task_dead", + "__module_put_and_exit", + "complete_and_exit", +-- +2.43.0 + diff --git a/queue-5.10/exit-rename-module_put_and_exit-to-module_put_and_kt.patch b/queue-5.10/exit-rename-module_put_and_exit-to-module_put_and_kt.patch new file mode 100644 index 00000000000..ca45761e85c --- /dev/null +++ b/queue-5.10/exit-rename-module_put_and_exit-to-module_put_and_kt.patch @@ -0,0 +1,216 @@ +From 103bfb245917d673beb738aed7c71a4e3e3f98fd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Dec 2021 11:00:19 -0600 +Subject: exit: Rename module_put_and_exit to module_put_and_kthread_exit + +From: Eric W. Biederman + +[ Upstream commit ca3574bd653aba234a4b31955f2778947403be16 ] + +Update module_put_and_exit to call kthread_exit instead of do_exit. + +Change the name to reflect this change in functionality. All of the +users of module_put_and_exit are causing the current kthread to exit +so this change makes it clear what is happening. There is no +functional change. + +Signed-off-by: "Eric W. Biederman" +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + crypto/algboss.c | 4 ++-- + fs/cifs/connect.c | 2 +- + fs/nfs/callback.c | 4 ++-- + fs/nfs/nfs4state.c | 2 +- + fs/nfsd/nfssvc.c | 2 +- + include/linux/module.h | 6 +++--- + kernel/module.c | 6 +++--- + net/bluetooth/bnep/core.c | 2 +- + net/bluetooth/cmtp/core.c | 2 +- + net/bluetooth/hidp/core.c | 2 +- + tools/objtool/check.c | 2 +- + 11 files changed, 17 insertions(+), 17 deletions(-) + +diff --git a/crypto/algboss.c b/crypto/algboss.c +index 5ebccbd6b74ed..b87f907bb1428 100644 +--- a/crypto/algboss.c ++++ b/crypto/algboss.c +@@ -74,7 +74,7 @@ static int cryptomgr_probe(void *data) + complete_all(¶m->larval->completion); + crypto_alg_put(¶m->larval->alg); + kfree(param); +- module_put_and_exit(0); ++ module_put_and_kthread_exit(0); + } + + static int cryptomgr_schedule_probe(struct crypto_larval *larval) +@@ -209,7 +209,7 @@ static int cryptomgr_test(void *data) + crypto_alg_tested(param->driver, err); + + kfree(param); +- module_put_and_exit(0); ++ module_put_and_kthread_exit(0); + } + + static int cryptomgr_schedule_test(struct crypto_alg *alg) +diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c +index 164b985407160..a3c0e6a4e4847 100644 +--- a/fs/cifs/connect.c ++++ b/fs/cifs/connect.c +@@ -1242,7 +1242,7 @@ cifs_demultiplex_thread(void *p) + } + + memalloc_noreclaim_restore(noreclaim_flag); +- module_put_and_exit(0); ++ module_put_and_kthread_exit(0); + } + + /* extract the host portion of the UNC string */ +diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c +index 86d856de1389b..3c86a559a321a 100644 +--- a/fs/nfs/callback.c ++++ b/fs/nfs/callback.c +@@ -93,7 +93,7 @@ nfs4_callback_svc(void *vrqstp) + svc_process(rqstp); + } + svc_exit_thread(rqstp); +- module_put_and_exit(0); ++ module_put_and_kthread_exit(0); + return 0; + } + +@@ -137,7 +137,7 @@ nfs41_callback_svc(void *vrqstp) + } + } + svc_exit_thread(rqstp); +- module_put_and_exit(0); ++ module_put_and_kthread_exit(0); + return 0; + } + +diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c +index afb617a4a7e42..d8fc5d72a161c 100644 +--- a/fs/nfs/nfs4state.c ++++ b/fs/nfs/nfs4state.c +@@ -2757,7 +2757,7 @@ static int nfs4_run_state_manager(void *ptr) + goto again; + + nfs_put_client(clp); +- module_put_and_exit(0); ++ module_put_and_kthread_exit(0); + return 0; + } + +diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c +index 408cff8fe32d3..0f84151011088 100644 +--- a/fs/nfsd/nfssvc.c ++++ b/fs/nfsd/nfssvc.c +@@ -986,7 +986,7 @@ nfsd(void *vrqstp) + + /* Release module */ + mutex_unlock(&nfsd_mutex); +- module_put_and_exit(0); ++ module_put_and_kthread_exit(0); + return 0; + } + +diff --git a/include/linux/module.h b/include/linux/module.h +index 59cbd8e1be2d6..a55a40c28568e 100644 +--- a/include/linux/module.h ++++ b/include/linux/module.h +@@ -604,9 +604,9 @@ int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type, + /* Look for this name: can be of form module:name. */ + unsigned long module_kallsyms_lookup_name(const char *name); + +-extern void __noreturn __module_put_and_exit(struct module *mod, ++extern void __noreturn __module_put_and_kthread_exit(struct module *mod, + long code); +-#define module_put_and_exit(code) __module_put_and_exit(THIS_MODULE, code) ++#define module_put_and_kthread_exit(code) __module_put_and_kthread_exit(THIS_MODULE, code) + + #ifdef CONFIG_MODULE_UNLOAD + int module_refcount(struct module *mod); +@@ -798,7 +798,7 @@ static inline int unregister_module_notifier(struct notifier_block *nb) + return 0; + } + +-#define module_put_and_exit(code) do_exit(code) ++#define module_put_and_kthread_exit(code) kthread_exit(code) + + static inline void print_modules(void) + { +diff --git a/kernel/module.c b/kernel/module.c +index 949d09d2d8297..9030ff8c08555 100644 +--- a/kernel/module.c ++++ b/kernel/module.c +@@ -336,12 +336,12 @@ static inline void add_taint_module(struct module *mod, unsigned flag, + * A thread that wants to hold a reference to a module only while it + * is running can call this to safely exit. nfsd and lockd use this. + */ +-void __noreturn __module_put_and_exit(struct module *mod, long code) ++void __noreturn __module_put_and_kthread_exit(struct module *mod, long code) + { + module_put(mod); +- do_exit(code); ++ kthread_exit(code); + } +-EXPORT_SYMBOL(__module_put_and_exit); ++EXPORT_SYMBOL(__module_put_and_kthread_exit); + + /* Find a module section: 0 means not found. */ + static unsigned int find_sec(const struct load_info *info, const char *name) +diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c +index 43c284158f63e..09b6d825124ee 100644 +--- a/net/bluetooth/bnep/core.c ++++ b/net/bluetooth/bnep/core.c +@@ -535,7 +535,7 @@ static int bnep_session(void *arg) + + up_write(&bnep_session_sem); + free_netdev(dev); +- module_put_and_exit(0); ++ module_put_and_kthread_exit(0); + return 0; + } + +diff --git a/net/bluetooth/cmtp/core.c b/net/bluetooth/cmtp/core.c +index 83eb84e8e688f..90d130588a3e5 100644 +--- a/net/bluetooth/cmtp/core.c ++++ b/net/bluetooth/cmtp/core.c +@@ -323,7 +323,7 @@ static int cmtp_session(void *arg) + up_write(&cmtp_session_sem); + + kfree(session); +- module_put_and_exit(0); ++ module_put_and_kthread_exit(0); + return 0; + } + +diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c +index b946a6379433a..3ff870599eb77 100644 +--- a/net/bluetooth/hidp/core.c ++++ b/net/bluetooth/hidp/core.c +@@ -1305,7 +1305,7 @@ static int hidp_session_thread(void *arg) + l2cap_unregister_user(session->conn, &session->user); + hidp_session_put(session); + +- module_put_and_exit(0); ++ module_put_and_kthread_exit(0); + return 0; + } + +diff --git a/tools/objtool/check.c b/tools/objtool/check.c +index 6afa1f8ca1614..0506a48f124c2 100644 +--- a/tools/objtool/check.c ++++ b/tools/objtool/check.c +@@ -170,7 +170,7 @@ static bool __dead_end_function(struct objtool_file *file, struct symbol *func, + "do_task_dead", + "kthread_exit", + "make_task_dead", +- "__module_put_and_exit", ++ "__module_put_and_kthread_exit", + "complete_and_exit", + "__reiserfs_panic", + "lbug_with_loc", +-- +2.43.0 + diff --git a/queue-5.10/exportfs-add-a-function-to-return-the-raw-output-fro.patch b/queue-5.10/exportfs-add-a-function-to-return-the-raw-output-fro.patch new file mode 100644 index 00000000000..718f477cc6d --- /dev/null +++ b/queue-5.10/exportfs-add-a-function-to-return-the-raw-output-fro.patch @@ -0,0 +1,99 @@ +From 95256f0cc6069928f642eb1ccf42575707cc3822 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Nov 2020 17:03:17 -0500 +Subject: exportfs: Add a function to return the raw output from fh_to_dentry() + +From: Trond Myklebust + +[ Upstream commit d045465fc6cbfa4acfb5a7d817a7c1a57a078109 ] + +In order to allow nfsd to accept return values that are not +acceptable to overlayfs and others, add a new function. + +Signed-off-by: Trond Myklebust +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/exportfs/expfs.c | 32 ++++++++++++++++++++++++-------- + include/linux/exportfs.h | 5 +++++ + 2 files changed, 29 insertions(+), 8 deletions(-) + +diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c +index 2dd55b172d57f..0106eba46d5af 100644 +--- a/fs/exportfs/expfs.c ++++ b/fs/exportfs/expfs.c +@@ -417,9 +417,11 @@ int exportfs_encode_fh(struct dentry *dentry, struct fid *fid, int *max_len, + } + EXPORT_SYMBOL_GPL(exportfs_encode_fh); + +-struct dentry *exportfs_decode_fh(struct vfsmount *mnt, struct fid *fid, +- int fh_len, int fileid_type, +- int (*acceptable)(void *, struct dentry *), void *context) ++struct dentry * ++exportfs_decode_fh_raw(struct vfsmount *mnt, struct fid *fid, int fh_len, ++ int fileid_type, ++ int (*acceptable)(void *, struct dentry *), ++ void *context) + { + const struct export_operations *nop = mnt->mnt_sb->s_export_op; + struct dentry *result, *alias; +@@ -432,10 +434,8 @@ struct dentry *exportfs_decode_fh(struct vfsmount *mnt, struct fid *fid, + if (!nop || !nop->fh_to_dentry) + return ERR_PTR(-ESTALE); + result = nop->fh_to_dentry(mnt->mnt_sb, fid, fh_len, fileid_type); +- if (PTR_ERR(result) == -ENOMEM) +- return ERR_CAST(result); + if (IS_ERR_OR_NULL(result)) +- return ERR_PTR(-ESTALE); ++ return result; + + /* + * If no acceptance criteria was specified by caller, a disconnected +@@ -561,10 +561,26 @@ struct dentry *exportfs_decode_fh(struct vfsmount *mnt, struct fid *fid, + + err_result: + dput(result); +- if (err != -ENOMEM) +- err = -ESTALE; + return ERR_PTR(err); + } ++EXPORT_SYMBOL_GPL(exportfs_decode_fh_raw); ++ ++struct dentry *exportfs_decode_fh(struct vfsmount *mnt, struct fid *fid, ++ int fh_len, int fileid_type, ++ int (*acceptable)(void *, struct dentry *), ++ void *context) ++{ ++ struct dentry *ret; ++ ++ ret = exportfs_decode_fh_raw(mnt, fid, fh_len, fileid_type, ++ acceptable, context); ++ if (IS_ERR_OR_NULL(ret)) { ++ if (ret == ERR_PTR(-ENOMEM)) ++ return ret; ++ return ERR_PTR(-ESTALE); ++ } ++ return ret; ++} + EXPORT_SYMBOL_GPL(exportfs_decode_fh); + + MODULE_LICENSE("GPL"); +diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h +index d829403ffd3bb..846df3c96730f 100644 +--- a/include/linux/exportfs.h ++++ b/include/linux/exportfs.h +@@ -223,6 +223,11 @@ extern int exportfs_encode_inode_fh(struct inode *inode, struct fid *fid, + int *max_len, struct inode *parent); + extern int exportfs_encode_fh(struct dentry *dentry, struct fid *fid, + int *max_len, int connectable); ++extern struct dentry *exportfs_decode_fh_raw(struct vfsmount *mnt, ++ struct fid *fid, int fh_len, ++ int fileid_type, ++ int (*acceptable)(void *, struct dentry *), ++ void *context); + extern struct dentry *exportfs_decode_fh(struct vfsmount *mnt, struct fid *fid, + int fh_len, int fileid_type, int (*acceptable)(void *, struct dentry *), + void *context); +-- +2.43.0 + diff --git a/queue-5.10/exportfs-use-pr_debug-for-unreachable-debug-statemen.patch b/queue-5.10/exportfs-use-pr_debug-for-unreachable-debug-statemen.patch new file mode 100644 index 00000000000..88d7c0d537c --- /dev/null +++ b/queue-5.10/exportfs-use-pr_debug-for-unreachable-debug-statemen.patch @@ -0,0 +1,60 @@ +From 41e85cd6ec2521a1e06079dacded603fd7d29ee1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 21 Oct 2022 14:24:14 +0200 +Subject: exportfs: use pr_debug for unreachable debug statements + +From: David Disseldorp + +[ Upstream commit 427505ffeaa464f683faba945a88d3e3248f6979 ] + +expfs.c has a bunch of dprintk statements which are unusable due to: + #define dprintk(fmt, args...) do{}while(0) +Use pr_debug so that they can be enabled dynamically. +Also make some minor changes to the debug statements to fix some +incorrect types, and remove __func__ which can be handled by dynamic +debug separately. + +Signed-off-by: David Disseldorp +Reviewed-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/exportfs/expfs.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c +index 0106eba46d5af..8c28bd1c9ed94 100644 +--- a/fs/exportfs/expfs.c ++++ b/fs/exportfs/expfs.c +@@ -18,7 +18,7 @@ + #include + #include + +-#define dprintk(fmt, args...) do{}while(0) ++#define dprintk(fmt, args...) pr_debug(fmt, ##args) + + + static int get_name(const struct path *path, char *name, struct dentry *child); +@@ -132,8 +132,8 @@ static struct dentry *reconnect_one(struct vfsmount *mnt, + inode_unlock(dentry->d_inode); + + if (IS_ERR(parent)) { +- dprintk("%s: get_parent of %ld failed, err %d\n", +- __func__, dentry->d_inode->i_ino, PTR_ERR(parent)); ++ dprintk("get_parent of %lu failed, err %ld\n", ++ dentry->d_inode->i_ino, PTR_ERR(parent)); + return parent; + } + +@@ -147,7 +147,7 @@ static struct dentry *reconnect_one(struct vfsmount *mnt, + dprintk("%s: found name: %s\n", __func__, nbuf); + tmp = lookup_one_len_unlocked(nbuf, parent, strlen(nbuf)); + if (IS_ERR(tmp)) { +- dprintk("%s: lookup failed: %d\n", __func__, PTR_ERR(tmp)); ++ dprintk("lookup failed: %ld\n", PTR_ERR(tmp)); + err = PTR_ERR(tmp); + goto out_err; + } +-- +2.43.0 + diff --git a/queue-5.10/fanotify-add-helpers-to-decide-whether-to-report-fid.patch b/queue-5.10/fanotify-add-helpers-to-decide-whether-to-report-fid.patch new file mode 100644 index 00000000000..2833dc7560a --- /dev/null +++ b/queue-5.10/fanotify-add-helpers-to-decide-whether-to-report-fid.patch @@ -0,0 +1,97 @@ +From f532613550c0a6169252313aa44b0a923a9e36fa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 Oct 2021 16:27:38 -0300 +Subject: fanotify: Add helpers to decide whether to report FID/DFID + +From: Gabriel Krisman Bertazi + +[ Upstream commit 4bd5a5c8e6e5cd964e9738e6ef87f6c2cb453edf ] + +Now that there is an event that reports FID records even for a zeroed +file handle, wrap the logic that deides whether to issue the records +into helper functions. This shouldn't have any impact on the code, but +simplifies further patches. + +Link: https://lore.kernel.org/r/20211025192746.66445-24-krisman@collabora.com +Reviewed-by: Jan Kara +Signed-off-by: Gabriel Krisman Bertazi +Reviewed-by: Amir Goldstein +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify.h | 10 ++++++++++ + fs/notify/fanotify/fanotify_user.c | 13 +++++++------ + 2 files changed, 17 insertions(+), 6 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify.h b/fs/notify/fanotify/fanotify.h +index 3510d06654ed0..80af269eebb89 100644 +--- a/fs/notify/fanotify/fanotify.h ++++ b/fs/notify/fanotify/fanotify.h +@@ -264,6 +264,16 @@ static inline int fanotify_event_dir_fh_len(struct fanotify_event *event) + return info ? fanotify_info_dir_fh_len(info) : 0; + } + ++static inline bool fanotify_event_has_object_fh(struct fanotify_event *event) ++{ ++ return fanotify_event_object_fh_len(event) > 0; ++} ++ ++static inline bool fanotify_event_has_dir_fh(struct fanotify_event *event) ++{ ++ return fanotify_event_dir_fh_len(event) > 0; ++} ++ + struct fanotify_path_event { + struct fanotify_event fae; + struct path path; +diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c +index 8a2b7941fc986..34ed30be0e4d4 100644 +--- a/fs/notify/fanotify/fanotify_user.c ++++ b/fs/notify/fanotify/fanotify_user.c +@@ -135,10 +135,9 @@ static size_t fanotify_event_len(unsigned int info_mode, + return event_len; + + info = fanotify_event_info(event); +- dir_fh_len = fanotify_event_dir_fh_len(event); +- fh_len = fanotify_event_object_fh_len(event); + +- if (dir_fh_len) { ++ if (fanotify_event_has_dir_fh(event)) { ++ dir_fh_len = fanotify_event_dir_fh_len(event); + event_len += fanotify_fid_info_len(dir_fh_len, info->name_len); + } else if ((info_mode & FAN_REPORT_NAME) && + (event->mask & FAN_ONDIR)) { +@@ -152,8 +151,10 @@ static size_t fanotify_event_len(unsigned int info_mode, + if (info_mode & FAN_REPORT_PIDFD) + event_len += FANOTIFY_PIDFD_INFO_HDR_LEN; + +- if (fh_len) ++ if (fanotify_event_has_object_fh(event)) { ++ fh_len = fanotify_event_object_fh_len(event); + event_len += fanotify_fid_info_len(fh_len, dot_len); ++ } + + return event_len; + } +@@ -446,7 +447,7 @@ static int copy_info_records_to_user(struct fanotify_event *event, + /* + * Event info records order is as follows: dir fid + name, child fid. + */ +- if (fanotify_event_dir_fh_len(event)) { ++ if (fanotify_event_has_dir_fh(event)) { + info_type = info->name_len ? FAN_EVENT_INFO_TYPE_DFID_NAME : + FAN_EVENT_INFO_TYPE_DFID; + ret = copy_fid_info_to_user(fanotify_event_fsid(event), +@@ -462,7 +463,7 @@ static int copy_info_records_to_user(struct fanotify_event *event, + total_bytes += ret; + } + +- if (fanotify_event_object_fh_len(event)) { ++ if (fanotify_event_has_object_fh(event)) { + const char *dot = NULL; + int dot_len = 0; + +-- +2.43.0 + diff --git a/queue-5.10/fanotify-add-pidfd-support-to-the-fanotify-api.patch b/queue-5.10/fanotify-add-pidfd-support-to-the-fanotify-api.patch new file mode 100644 index 00000000000..afd18daaa51 --- /dev/null +++ b/queue-5.10/fanotify-add-pidfd-support-to-the-fanotify-api.patch @@ -0,0 +1,294 @@ +From 37ef944bd76db17d771ceae92919c82f088bbe9b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 8 Aug 2021 15:26:25 +1000 +Subject: fanotify: add pidfd support to the fanotify API + +From: Matthew Bobrowski + +[ Upstream commit af579beb666aefb17e9a335c12c788c92932baf1 ] + +Introduce a new flag FAN_REPORT_PIDFD for fanotify_init(2) which +allows userspace applications to control whether a pidfd information +record containing a pidfd is to be returned alongside the generic +event metadata for each event. + +If FAN_REPORT_PIDFD is enabled for a notification group, an additional +struct fanotify_event_info_pidfd object type will be supplied +alongside the generic struct fanotify_event_metadata for a single +event. This functionality is analogous to that of FAN_REPORT_FID in +terms of how the event structure is supplied to a userspace +application. Usage of FAN_REPORT_PIDFD with +FAN_REPORT_FID/FAN_REPORT_DFID_NAME is permitted, and in this case a +struct fanotify_event_info_pidfd object will likely follow any struct +fanotify_event_info_fid object. + +Currently, the usage of the FAN_REPORT_TID flag is not permitted along +with FAN_REPORT_PIDFD as the pidfd API currently only supports the +creation of pidfds for thread-group leaders. Additionally, usage of +the FAN_REPORT_PIDFD flag is limited to privileged processes only +i.e. event listeners that are running with the CAP_SYS_ADMIN +capability. Attempting to supply the FAN_REPORT_TID initialization +flags with FAN_REPORT_PIDFD or creating a notification group without +CAP_SYS_ADMIN will result with -EINVAL being returned to the caller. + +In the event of a pidfd creation error, there are two types of error +values that can be reported back to the listener. There is +FAN_NOPIDFD, which will be reported in cases where the process +responsible for generating the event has terminated prior to the event +listener being able to read the event. Then there is FAN_EPIDFD, which +will be reported when a more generic pidfd creation error has occurred +when fanotify calls pidfd_create(). + +Link: https://lore.kernel.org/r/5f9e09cff7ed62bfaa51c1369e0f7ea5f16a91aa.1628398044.git.repnop@google.com +Signed-off-by: Matthew Bobrowski +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify_user.c | 85 ++++++++++++++++++++++++++++-- + include/linux/fanotify.h | 3 +- + include/uapi/linux/fanotify.h | 13 +++++ + 3 files changed, 96 insertions(+), 5 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c +index 83405949a71b2..10fb062065b69 100644 +--- a/fs/notify/fanotify/fanotify_user.c ++++ b/fs/notify/fanotify/fanotify_user.c +@@ -1,6 +1,7 @@ + // SPDX-License-Identifier: GPL-2.0 + #include + #include ++#include + #include + #include + #include +@@ -106,6 +107,8 @@ struct kmem_cache *fanotify_perm_event_cachep __read_mostly; + #define FANOTIFY_EVENT_ALIGN 4 + #define FANOTIFY_FID_INFO_HDR_LEN \ + (sizeof(struct fanotify_event_info_fid) + sizeof(struct file_handle)) ++#define FANOTIFY_PIDFD_INFO_HDR_LEN \ ++ sizeof(struct fanotify_event_info_pidfd) + + static int fanotify_fid_info_len(int fh_len, int name_len) + { +@@ -138,6 +141,9 @@ static int fanotify_event_info_len(unsigned int info_mode, + dot_len = 1; + } + ++ if (info_mode & FAN_REPORT_PIDFD) ++ info_len += FANOTIFY_PIDFD_INFO_HDR_LEN; ++ + if (fh_len) + info_len += fanotify_fid_info_len(fh_len, dot_len); + +@@ -401,13 +407,34 @@ static int copy_fid_info_to_user(__kernel_fsid_t *fsid, struct fanotify_fh *fh, + return info_len; + } + ++static int copy_pidfd_info_to_user(int pidfd, ++ char __user *buf, ++ size_t count) ++{ ++ struct fanotify_event_info_pidfd info = { }; ++ size_t info_len = FANOTIFY_PIDFD_INFO_HDR_LEN; ++ ++ if (WARN_ON_ONCE(info_len > count)) ++ return -EFAULT; ++ ++ info.hdr.info_type = FAN_EVENT_INFO_TYPE_PIDFD; ++ info.hdr.len = info_len; ++ info.pidfd = pidfd; ++ ++ if (copy_to_user(buf, &info, info_len)) ++ return -EFAULT; ++ ++ return info_len; ++} ++ + static int copy_info_records_to_user(struct fanotify_event *event, + struct fanotify_info *info, +- unsigned int info_mode, ++ unsigned int info_mode, int pidfd, + char __user *buf, size_t count) + { + int ret, total_bytes = 0, info_type = 0; + unsigned int fid_mode = info_mode & FANOTIFY_FID_BITS; ++ unsigned int pidfd_mode = info_mode & FAN_REPORT_PIDFD; + + /* + * Event info records order is as follows: dir fid + name, child fid. +@@ -478,6 +505,16 @@ static int copy_info_records_to_user(struct fanotify_event *event, + total_bytes += ret; + } + ++ if (pidfd_mode) { ++ ret = copy_pidfd_info_to_user(pidfd, buf, count); ++ if (ret < 0) ++ return ret; ++ ++ buf += ret; ++ count -= ret; ++ total_bytes += ret; ++ } ++ + return total_bytes; + } + +@@ -489,8 +526,9 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group, + struct path *path = fanotify_event_path(event); + struct fanotify_info *info = fanotify_event_info(event); + unsigned int info_mode = FAN_GROUP_FLAG(group, FANOTIFY_INFO_MODES); ++ unsigned int pidfd_mode = info_mode & FAN_REPORT_PIDFD; + struct file *f = NULL; +- int ret, fd = FAN_NOFD; ++ int ret, pidfd = FAN_NOPIDFD, fd = FAN_NOFD; + + pr_debug("%s: group=%p event=%p\n", __func__, group, event); + +@@ -524,6 +562,33 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group, + } + metadata.fd = fd; + ++ if (pidfd_mode) { ++ /* ++ * Complain if the FAN_REPORT_PIDFD and FAN_REPORT_TID mutual ++ * exclusion is ever lifted. At the time of incoporating pidfd ++ * support within fanotify, the pidfd API only supported the ++ * creation of pidfds for thread-group leaders. ++ */ ++ WARN_ON_ONCE(FAN_GROUP_FLAG(group, FAN_REPORT_TID)); ++ ++ /* ++ * The PIDTYPE_TGID check for an event->pid is performed ++ * preemptively in an attempt to catch out cases where the event ++ * listener reads events after the event generating process has ++ * already terminated. Report FAN_NOPIDFD to the event listener ++ * in those cases, with all other pidfd creation errors being ++ * reported as FAN_EPIDFD. ++ */ ++ if (metadata.pid == 0 || ++ !pid_has_task(event->pid, PIDTYPE_TGID)) { ++ pidfd = FAN_NOPIDFD; ++ } else { ++ pidfd = pidfd_create(event->pid, 0); ++ if (pidfd < 0) ++ pidfd = FAN_EPIDFD; ++ } ++ } ++ + ret = -EFAULT; + /* + * Sanity check copy size in case get_one_event() and +@@ -542,7 +607,7 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group, + FANOTIFY_PERM(event)->fd = fd; + + if (info_mode) { +- ret = copy_info_records_to_user(event, info, info_mode, ++ ret = copy_info_records_to_user(event, info, info_mode, pidfd, + buf, count); + if (ret < 0) + goto out_close_fd; +@@ -558,6 +623,10 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group, + put_unused_fd(fd); + fput(f); + } ++ ++ if (pidfd >= 0) ++ close_fd(pidfd); ++ + return ret; + } + +@@ -1103,6 +1172,14 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) + #endif + return -EINVAL; + ++ /* ++ * A pidfd can only be returned for a thread-group leader; thus ++ * FAN_REPORT_PIDFD and FAN_REPORT_TID need to remain mutually ++ * exclusive. ++ */ ++ if ((flags & FAN_REPORT_PIDFD) && (flags & FAN_REPORT_TID)) ++ return -EINVAL; ++ + if (event_f_flags & ~FANOTIFY_INIT_ALL_EVENT_F_BITS) + return -EINVAL; + +@@ -1522,7 +1599,7 @@ static int __init fanotify_user_setup(void) + FANOTIFY_DEFAULT_MAX_USER_MARKS); + + BUILD_BUG_ON(FANOTIFY_INIT_FLAGS & FANOTIFY_INTERNAL_GROUP_FLAGS); +- BUILD_BUG_ON(HWEIGHT32(FANOTIFY_INIT_FLAGS) != 10); ++ BUILD_BUG_ON(HWEIGHT32(FANOTIFY_INIT_FLAGS) != 11); + BUILD_BUG_ON(HWEIGHT32(FANOTIFY_MARK_FLAGS) != 9); + + fanotify_mark_cache = KMEM_CACHE(fsnotify_mark, +diff --git a/include/linux/fanotify.h b/include/linux/fanotify.h +index 10a7e26ddba6c..eec3b7c408115 100644 +--- a/include/linux/fanotify.h ++++ b/include/linux/fanotify.h +@@ -27,7 +27,7 @@ extern struct ctl_table fanotify_table[]; /* for sysctl */ + + #define FANOTIFY_FID_BITS (FAN_REPORT_FID | FAN_REPORT_DFID_NAME) + +-#define FANOTIFY_INFO_MODES (FANOTIFY_FID_BITS) ++#define FANOTIFY_INFO_MODES (FANOTIFY_FID_BITS | FAN_REPORT_PIDFD) + + /* + * fanotify_init() flags that require CAP_SYS_ADMIN. +@@ -37,6 +37,7 @@ extern struct ctl_table fanotify_table[]; /* for sysctl */ + */ + #define FANOTIFY_ADMIN_INIT_FLAGS (FANOTIFY_PERM_CLASSES | \ + FAN_REPORT_TID | \ ++ FAN_REPORT_PIDFD | \ + FAN_UNLIMITED_QUEUE | \ + FAN_UNLIMITED_MARKS) + +diff --git a/include/uapi/linux/fanotify.h b/include/uapi/linux/fanotify.h +index fbf9c5c7dd59a..64553df9d7350 100644 +--- a/include/uapi/linux/fanotify.h ++++ b/include/uapi/linux/fanotify.h +@@ -51,6 +51,7 @@ + #define FAN_ENABLE_AUDIT 0x00000040 + + /* Flags to determine fanotify event format */ ++#define FAN_REPORT_PIDFD 0x00000080 /* Report pidfd for event->pid */ + #define FAN_REPORT_TID 0x00000100 /* event->pid is thread id */ + #define FAN_REPORT_FID 0x00000200 /* Report unique file id */ + #define FAN_REPORT_DIR_FID 0x00000400 /* Report unique directory id */ +@@ -123,6 +124,7 @@ struct fanotify_event_metadata { + #define FAN_EVENT_INFO_TYPE_FID 1 + #define FAN_EVENT_INFO_TYPE_DFID_NAME 2 + #define FAN_EVENT_INFO_TYPE_DFID 3 ++#define FAN_EVENT_INFO_TYPE_PIDFD 4 + + /* Variable length info record following event metadata */ + struct fanotify_event_info_header { +@@ -148,6 +150,15 @@ struct fanotify_event_info_fid { + unsigned char handle[0]; + }; + ++/* ++ * This structure is used for info records of type FAN_EVENT_INFO_TYPE_PIDFD. ++ * It holds a pidfd for the pid that was responsible for generating an event. ++ */ ++struct fanotify_event_info_pidfd { ++ struct fanotify_event_info_header hdr; ++ __s32 pidfd; ++}; ++ + struct fanotify_response { + __s32 fd; + __u32 response; +@@ -160,6 +171,8 @@ struct fanotify_response { + + /* No fd set in event */ + #define FAN_NOFD -1 ++#define FAN_NOPIDFD FAN_NOFD ++#define FAN_EPIDFD -2 + + /* Helper functions to deal with fanotify_event_metadata buffers */ + #define FAN_EVENT_METADATA_LEN (sizeof(struct fanotify_event_metadata)) +-- +2.43.0 + diff --git a/queue-5.10/fanotify-allow-file-handle-encoding-for-unhashed-eve.patch b/queue-5.10/fanotify-allow-file-handle-encoding-for-unhashed-eve.patch new file mode 100644 index 00000000000..aed5c61e1e6 --- /dev/null +++ b/queue-5.10/fanotify-allow-file-handle-encoding-for-unhashed-eve.patch @@ -0,0 +1,45 @@ +From 2763ad5ae234a66cb614ff5b0afa1946b940dcf7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 Oct 2021 16:27:29 -0300 +Subject: fanotify: Allow file handle encoding for unhashed events + +From: Gabriel Krisman Bertazi + +[ Upstream commit 74fe4734897a2da2ae2a665a5e622cd490d36eaf ] + +Allow passing a NULL hash to fanotify_encode_fh and avoid calculating +the hash if not needed. + +Link: https://lore.kernel.org/r/20211025192746.66445-15-krisman@collabora.com +Reviewed-by: Jan Kara +Reviewed-by: Amir Goldstein +Signed-off-by: Gabriel Krisman Bertazi +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c +index 397ee623ff1e8..ec84fee7ad01c 100644 +--- a/fs/notify/fanotify/fanotify.c ++++ b/fs/notify/fanotify/fanotify.c +@@ -403,8 +403,12 @@ static int fanotify_encode_fh(struct fanotify_fh *fh, struct inode *inode, + fh->type = type; + fh->len = fh_len; + +- /* Mix fh into event merge key */ +- *hash ^= fanotify_hash_fh(fh); ++ /* ++ * Mix fh into event merge key. Hash might be NULL in case of ++ * unhashed FID events (i.e. FAN_FS_ERROR). ++ */ ++ if (hash) ++ *hash ^= fanotify_hash_fh(fh); + + return FANOTIFY_FH_HDR_LEN + fh_len; + +-- +2.43.0 + diff --git a/queue-5.10/fanotify-allow-users-to-request-fan_fs_error-events.patch b/queue-5.10/fanotify-allow-users-to-request-fan_fs_error-events.patch new file mode 100644 index 00000000000..70004693108 --- /dev/null +++ b/queue-5.10/fanotify-allow-users-to-request-fan_fs_error-events.patch @@ -0,0 +1,78 @@ +From af5df2734d357718c9c68237a4c1c7b1d5941a9a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 Oct 2021 16:27:43 -0300 +Subject: fanotify: Allow users to request FAN_FS_ERROR events + +From: Gabriel Krisman Bertazi + +[ Upstream commit 9709bd548f11a092d124698118013f66e1740f9b ] + +Wire up the FAN_FS_ERROR event in the fanotify_mark syscall, allowing +user space to request the monitoring of FAN_FS_ERROR events. + +These events are limited to filesystem marks, so check it is the +case in the syscall handler. + +Link: https://lore.kernel.org/r/20211025192746.66445-29-krisman@collabora.com +Reviewed-by: Amir Goldstein +Reviewed-by: Jan Kara +Signed-off-by: Gabriel Krisman Bertazi +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify.c | 2 +- + fs/notify/fanotify/fanotify_user.c | 4 ++++ + include/linux/fanotify.h | 6 +++++- + 3 files changed, 10 insertions(+), 2 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c +index af61425e6e3bf..b6091775aa6ef 100644 +--- a/fs/notify/fanotify/fanotify.c ++++ b/fs/notify/fanotify/fanotify.c +@@ -822,7 +822,7 @@ static int fanotify_handle_event(struct fsnotify_group *group, u32 mask, + BUILD_BUG_ON(FAN_OPEN_EXEC_PERM != FS_OPEN_EXEC_PERM); + BUILD_BUG_ON(FAN_FS_ERROR != FS_ERROR); + +- BUILD_BUG_ON(HWEIGHT32(ALL_FANOTIFY_EVENT_BITS) != 19); ++ BUILD_BUG_ON(HWEIGHT32(ALL_FANOTIFY_EVENT_BITS) != 20); + + mask = fanotify_group_event_mask(group, iter_info, mask, data, + data_type, dir); +diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c +index 3040c8669dfd1..e6860c55b3dcb 100644 +--- a/fs/notify/fanotify/fanotify_user.c ++++ b/fs/notify/fanotify/fanotify_user.c +@@ -1533,6 +1533,10 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, + group->priority == FS_PRIO_0) + goto fput_and_out; + ++ if (mask & FAN_FS_ERROR && ++ mark_type != FAN_MARK_FILESYSTEM) ++ goto fput_and_out; ++ + /* + * Events that do not carry enough information to report + * event->fd require a group that supports reporting fid. Those +diff --git a/include/linux/fanotify.h b/include/linux/fanotify.h +index 52d464802d99f..616af2ea20f30 100644 +--- a/include/linux/fanotify.h ++++ b/include/linux/fanotify.h +@@ -91,9 +91,13 @@ extern struct ctl_table fanotify_table[]; /* for sysctl */ + #define FANOTIFY_INODE_EVENTS (FANOTIFY_DIRENT_EVENTS | \ + FAN_ATTRIB | FAN_MOVE_SELF | FAN_DELETE_SELF) + ++/* Events that can only be reported with data type FSNOTIFY_EVENT_ERROR */ ++#define FANOTIFY_ERROR_EVENTS (FAN_FS_ERROR) ++ + /* Events that user can request to be notified on */ + #define FANOTIFY_EVENTS (FANOTIFY_PATH_EVENTS | \ +- FANOTIFY_INODE_EVENTS) ++ FANOTIFY_INODE_EVENTS | \ ++ FANOTIFY_ERROR_EVENTS) + + /* Events that require a permission response from user */ + #define FANOTIFY_PERM_EVENTS (FAN_OPEN_PERM | FAN_ACCESS_PERM | \ +-- +2.43.0 + diff --git a/queue-5.10/fanotify-cleanups-for-fanotify_mark-input-validation.patch b/queue-5.10/fanotify-cleanups-for-fanotify_mark-input-validation.patch new file mode 100644 index 00000000000..706704c02ac --- /dev/null +++ b/queue-5.10/fanotify-cleanups-for-fanotify_mark-input-validation.patch @@ -0,0 +1,138 @@ +From 1bdd2344354f038fd070b3d741cb087bf2adccdb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Jun 2022 17:42:09 +0300 +Subject: fanotify: cleanups for fanotify_mark() input validations + +From: Amir Goldstein + +[ Upstream commit 8afd7215aa97f8868d033f6e1d01a276ab2d29c0 ] + +Create helper fanotify_may_update_existing_mark() for checking for +conflicts between existing mark flags and fanotify_mark() flags. + +Use variable mark_cmd to make the checks for mark command bits +cleaner. + +Link: https://lore.kernel.org/r/20220629144210.2983229-3-amir73il@gmail.com +Signed-off-by: Amir Goldstein +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify_user.c | 30 +++++++++++++++++++++--------- + include/linux/fanotify.h | 9 +++++---- + 2 files changed, 26 insertions(+), 13 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c +index 0d61cb0e49075..715e41b344129 100644 +--- a/fs/notify/fanotify/fanotify_user.c ++++ b/fs/notify/fanotify/fanotify_user.c +@@ -1175,6 +1175,19 @@ static int fanotify_group_init_error_pool(struct fsnotify_group *group) + sizeof(struct fanotify_error_event)); + } + ++static int fanotify_may_update_existing_mark(struct fsnotify_mark *fsn_mark, ++ unsigned int fan_flags) ++{ ++ /* ++ * Non evictable mark cannot be downgraded to evictable mark. ++ */ ++ if (fan_flags & FAN_MARK_EVICTABLE && ++ !(fsn_mark->flags & FSNOTIFY_MARK_FLAG_NO_IREF)) ++ return -EEXIST; ++ ++ return 0; ++} ++ + static int fanotify_add_mark(struct fsnotify_group *group, + fsnotify_connp_t *connp, unsigned int obj_type, + __u32 mask, unsigned int fan_flags, +@@ -1196,13 +1209,11 @@ static int fanotify_add_mark(struct fsnotify_group *group, + } + + /* +- * Non evictable mark cannot be downgraded to evictable mark. ++ * Check if requested mark flags conflict with an existing mark flags. + */ +- if (fan_flags & FAN_MARK_EVICTABLE && +- !(fsn_mark->flags & FSNOTIFY_MARK_FLAG_NO_IREF)) { +- ret = -EEXIST; ++ ret = fanotify_may_update_existing_mark(fsn_mark, fan_flags); ++ if (ret) + goto out; +- } + + /* + * Error events are pre-allocated per group, only if strictly +@@ -1559,6 +1570,7 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, + __kernel_fsid_t __fsid, *fsid = NULL; + u32 valid_mask = FANOTIFY_EVENTS | FANOTIFY_EVENT_FLAGS; + unsigned int mark_type = flags & FANOTIFY_MARK_TYPE_BITS; ++ unsigned int mark_cmd = flags & FANOTIFY_MARK_CMD_BITS; + bool ignore = flags & FAN_MARK_IGNORED_MASK; + unsigned int obj_type, fid_mode; + u32 umask = 0; +@@ -1588,7 +1600,7 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, + return -EINVAL; + } + +- switch (flags & (FAN_MARK_ADD | FAN_MARK_REMOVE | FAN_MARK_FLUSH)) { ++ switch (mark_cmd) { + case FAN_MARK_ADD: + case FAN_MARK_REMOVE: + if (!mask) +@@ -1677,7 +1689,7 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, + if (mask & FAN_RENAME && !(fid_mode & FAN_REPORT_NAME)) + goto fput_and_out; + +- if (flags & FAN_MARK_FLUSH) { ++ if (mark_cmd == FAN_MARK_FLUSH) { + ret = 0; + if (mark_type == FAN_MARK_MOUNT) + fsnotify_clear_vfsmount_marks_by_group(group); +@@ -1693,7 +1705,7 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, + if (ret) + goto fput_and_out; + +- if (flags & FAN_MARK_ADD) { ++ if (mark_cmd == FAN_MARK_ADD) { + ret = fanotify_events_supported(group, &path, mask, flags); + if (ret) + goto path_put_and_out; +@@ -1731,7 +1743,7 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, + } + + /* create/update an inode mark */ +- switch (flags & (FAN_MARK_ADD | FAN_MARK_REMOVE)) { ++ switch (mark_cmd) { + case FAN_MARK_ADD: + if (mark_type == FAN_MARK_MOUNT) + ret = fanotify_add_vfsmount_mark(group, mnt, mask, +diff --git a/include/linux/fanotify.h b/include/linux/fanotify.h +index 4f6cbe6c6e235..c9e185407ebcb 100644 +--- a/include/linux/fanotify.h ++++ b/include/linux/fanotify.h +@@ -61,15 +61,16 @@ extern struct ctl_table fanotify_table[]; /* for sysctl */ + #define FANOTIFY_MARK_TYPE_BITS (FAN_MARK_INODE | FAN_MARK_MOUNT | \ + FAN_MARK_FILESYSTEM) + ++#define FANOTIFY_MARK_CMD_BITS (FAN_MARK_ADD | FAN_MARK_REMOVE | \ ++ FAN_MARK_FLUSH) ++ + #define FANOTIFY_MARK_FLAGS (FANOTIFY_MARK_TYPE_BITS | \ +- FAN_MARK_ADD | \ +- FAN_MARK_REMOVE | \ ++ FANOTIFY_MARK_CMD_BITS | \ + FAN_MARK_DONT_FOLLOW | \ + FAN_MARK_ONLYDIR | \ + FAN_MARK_IGNORED_MASK | \ + FAN_MARK_IGNORED_SURV_MODIFY | \ +- FAN_MARK_EVICTABLE | \ +- FAN_MARK_FLUSH) ++ FAN_MARK_EVICTABLE) + + /* + * Events that can be reported with data type FSNOTIFY_EVENT_PATH. +-- +2.43.0 + diff --git a/queue-5.10/fanotify-configurable-limits-via-sysfs.patch b/queue-5.10/fanotify-configurable-limits-via-sysfs.patch new file mode 100644 index 00000000000..dbe71c55da0 --- /dev/null +++ b/queue-5.10/fanotify-configurable-limits-via-sysfs.patch @@ -0,0 +1,468 @@ +From 66030e18910c5546390096d65391235f378e289f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Mar 2021 13:29:20 +0200 +Subject: fanotify: configurable limits via sysfs + +From: Amir Goldstein + +[ Upstream commit 5b8fea65d197f408bb00b251c70d842826d6b70b ] + +fanotify has some hardcoded limits. The only APIs to escape those limits +are FAN_UNLIMITED_QUEUE and FAN_UNLIMITED_MARKS. + +Allow finer grained tuning of the system limits via sysfs tunables under +/proc/sys/fs/fanotify, similar to tunables under /proc/sys/fs/inotify, +with some minor differences. + +- max_queued_events - global system tunable for group queue size limit. + Like the inotify tunable with the same name, it defaults to 16384 and + applies on initialization of a new group. + +- max_user_marks - user ns tunable for marks limit per user. + Like the inotify tunable named max_user_watches, on a machine with + sufficient RAM and it defaults to 1048576 in init userns and can be + further limited per containing user ns. + +- max_user_groups - user ns tunable for number of groups per user. + Like the inotify tunable named max_user_instances, it defaults to 128 + in init userns and can be further limited per containing user ns. + +The slightly different tunable names used for fanotify are derived from +the "group" and "mark" terminology used in the fanotify man pages and +throughout the code. + +Considering the fact that the default value for max_user_instances was +increased in kernel v5.10 from 8192 to 1048576, leaving the legacy +fanotify limit of 8192 marks per group in addition to the max_user_marks +limit makes little sense, so the per group marks limit has been removed. + +Note that when a group is initialized with FAN_UNLIMITED_MARKS, its own +marks are not accounted in the per user marks account, so in effect the +limit of max_user_marks is only for the collection of groups that are +not initialized with FAN_UNLIMITED_MARKS. + +Link: https://lore.kernel.org/r/20210304112921.3996419-2-amir73il@gmail.com +Suggested-by: Jan Kara +Signed-off-by: Amir Goldstein +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify.c | 16 ++-- + fs/notify/fanotify/fanotify_user.c | 123 ++++++++++++++++++++++++----- + fs/notify/group.c | 1 - + fs/notify/mark.c | 4 - + include/linux/fanotify.h | 3 + + include/linux/fsnotify_backend.h | 6 +- + include/linux/sched/user.h | 3 - + include/linux/user_namespace.h | 4 + + kernel/sysctl.c | 12 ++- + kernel/ucount.c | 4 + + 10 files changed, 137 insertions(+), 39 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c +index 754e27ead8742..057abd2cf8875 100644 +--- a/fs/notify/fanotify/fanotify.c ++++ b/fs/notify/fanotify/fanotify.c +@@ -801,12 +801,10 @@ static int fanotify_handle_event(struct fsnotify_group *group, u32 mask, + + static void fanotify_free_group_priv(struct fsnotify_group *group) + { +- struct user_struct *user; +- + kfree(group->fanotify_data.merge_hash); +- user = group->fanotify_data.user; +- atomic_dec(&user->fanotify_listeners); +- free_uid(user); ++ if (group->fanotify_data.ucounts) ++ dec_ucount(group->fanotify_data.ucounts, ++ UCOUNT_FANOTIFY_GROUPS); + } + + static void fanotify_free_path_event(struct fanotify_event *event) +@@ -862,6 +860,13 @@ static void fanotify_free_event(struct fsnotify_event *fsn_event) + } + } + ++static void fanotify_freeing_mark(struct fsnotify_mark *mark, ++ struct fsnotify_group *group) ++{ ++ if (!FAN_GROUP_FLAG(group, FAN_UNLIMITED_MARKS)) ++ dec_ucount(group->fanotify_data.ucounts, UCOUNT_FANOTIFY_MARKS); ++} ++ + static void fanotify_free_mark(struct fsnotify_mark *fsn_mark) + { + kmem_cache_free(fanotify_mark_cache, fsn_mark); +@@ -871,5 +876,6 @@ const struct fsnotify_ops fanotify_fsnotify_ops = { + .handle_event = fanotify_handle_event, + .free_group_priv = fanotify_free_group_priv, + .free_event = fanotify_free_event, ++ .freeing_mark = fanotify_freeing_mark, + .free_mark = fanotify_free_mark, + }; +diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c +index 1456470d0c4c6..74b4da6354e1c 100644 +--- a/fs/notify/fanotify/fanotify_user.c ++++ b/fs/notify/fanotify/fanotify_user.c +@@ -27,8 +27,61 @@ + #include "fanotify.h" + + #define FANOTIFY_DEFAULT_MAX_EVENTS 16384 +-#define FANOTIFY_DEFAULT_MAX_MARKS 8192 +-#define FANOTIFY_DEFAULT_MAX_LISTENERS 128 ++#define FANOTIFY_OLD_DEFAULT_MAX_MARKS 8192 ++#define FANOTIFY_DEFAULT_MAX_GROUPS 128 ++ ++/* ++ * Legacy fanotify marks limits (8192) is per group and we introduced a tunable ++ * limit of marks per user, similar to inotify. Effectively, the legacy limit ++ * of fanotify marks per user is * . ++ * This default limit (1M) also happens to match the increased limit of inotify ++ * max_user_watches since v5.10. ++ */ ++#define FANOTIFY_DEFAULT_MAX_USER_MARKS \ ++ (FANOTIFY_OLD_DEFAULT_MAX_MARKS * FANOTIFY_DEFAULT_MAX_GROUPS) ++ ++/* ++ * Most of the memory cost of adding an inode mark is pinning the marked inode. ++ * The size of the filesystem inode struct is not uniform across filesystems, ++ * so double the size of a VFS inode is used as a conservative approximation. ++ */ ++#define INODE_MARK_COST (2 * sizeof(struct inode)) ++ ++/* configurable via /proc/sys/fs/fanotify/ */ ++static int fanotify_max_queued_events __read_mostly; ++ ++#ifdef CONFIG_SYSCTL ++ ++#include ++ ++struct ctl_table fanotify_table[] = { ++ { ++ .procname = "max_user_groups", ++ .data = &init_user_ns.ucount_max[UCOUNT_FANOTIFY_GROUPS], ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = proc_dointvec_minmax, ++ .extra1 = SYSCTL_ZERO, ++ }, ++ { ++ .procname = "max_user_marks", ++ .data = &init_user_ns.ucount_max[UCOUNT_FANOTIFY_MARKS], ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = proc_dointvec_minmax, ++ .extra1 = SYSCTL_ZERO, ++ }, ++ { ++ .procname = "max_queued_events", ++ .data = &fanotify_max_queued_events, ++ .maxlen = sizeof(int), ++ .mode = 0644, ++ .proc_handler = proc_dointvec_minmax, ++ .extra1 = SYSCTL_ZERO ++ }, ++ { } ++}; ++#endif /* CONFIG_SYSCTL */ + + /* + * All flags that may be specified in parameter event_f_flags of fanotify_init. +@@ -847,24 +900,38 @@ static struct fsnotify_mark *fanotify_add_new_mark(struct fsnotify_group *group, + unsigned int type, + __kernel_fsid_t *fsid) + { ++ struct ucounts *ucounts = group->fanotify_data.ucounts; + struct fsnotify_mark *mark; + int ret; + +- if (atomic_read(&group->num_marks) > group->fanotify_data.max_marks) ++ /* ++ * Enforce per user marks limits per user in all containing user ns. ++ * A group with FAN_UNLIMITED_MARKS does not contribute to mark count ++ * in the limited groups account. ++ */ ++ if (!FAN_GROUP_FLAG(group, FAN_UNLIMITED_MARKS) && ++ !inc_ucount(ucounts->ns, ucounts->uid, UCOUNT_FANOTIFY_MARKS)) + return ERR_PTR(-ENOSPC); + + mark = kmem_cache_alloc(fanotify_mark_cache, GFP_KERNEL); +- if (!mark) +- return ERR_PTR(-ENOMEM); ++ if (!mark) { ++ ret = -ENOMEM; ++ goto out_dec_ucounts; ++ } + + fsnotify_init_mark(mark, group); + ret = fsnotify_add_mark_locked(mark, connp, type, 0, fsid); + if (ret) { + fsnotify_put_mark(mark); +- return ERR_PTR(ret); ++ goto out_dec_ucounts; + } + + return mark; ++ ++out_dec_ucounts: ++ if (!FAN_GROUP_FLAG(group, FAN_UNLIMITED_MARKS)) ++ dec_ucount(ucounts, UCOUNT_FANOTIFY_MARKS); ++ return ERR_PTR(ret); + } + + +@@ -963,7 +1030,6 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) + { + struct fsnotify_group *group; + int f_flags, fd; +- struct user_struct *user; + unsigned int fid_mode = flags & FANOTIFY_FID_BITS; + unsigned int class = flags & FANOTIFY_CLASS_BITS; + +@@ -1002,12 +1068,6 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) + if ((fid_mode & FAN_REPORT_NAME) && !(fid_mode & FAN_REPORT_DIR_FID)) + return -EINVAL; + +- user = get_current_user(); +- if (atomic_read(&user->fanotify_listeners) > FANOTIFY_DEFAULT_MAX_LISTENERS) { +- free_uid(user); +- return -EMFILE; +- } +- + f_flags = O_RDWR | FMODE_NONOTIFY; + if (flags & FAN_CLOEXEC) + f_flags |= O_CLOEXEC; +@@ -1017,13 +1077,19 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) + /* fsnotify_alloc_group takes a ref. Dropped in fanotify_release */ + group = fsnotify_alloc_user_group(&fanotify_fsnotify_ops); + if (IS_ERR(group)) { +- free_uid(user); + return PTR_ERR(group); + } + +- group->fanotify_data.user = user; ++ /* Enforce groups limits per user in all containing user ns */ ++ group->fanotify_data.ucounts = inc_ucount(current_user_ns(), ++ current_euid(), ++ UCOUNT_FANOTIFY_GROUPS); ++ if (!group->fanotify_data.ucounts) { ++ fd = -EMFILE; ++ goto out_destroy_group; ++ } ++ + group->fanotify_data.flags = flags; +- atomic_inc(&user->fanotify_listeners); + group->memcg = get_mem_cgroup_from_mm(current->mm); + + group->fanotify_data.merge_hash = fanotify_alloc_merge_hash(); +@@ -1064,16 +1130,13 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) + goto out_destroy_group; + group->max_events = UINT_MAX; + } else { +- group->max_events = FANOTIFY_DEFAULT_MAX_EVENTS; ++ group->max_events = fanotify_max_queued_events; + } + + if (flags & FAN_UNLIMITED_MARKS) { + fd = -EPERM; + if (!capable(CAP_SYS_ADMIN)) + goto out_destroy_group; +- group->fanotify_data.max_marks = UINT_MAX; +- } else { +- group->fanotify_data.max_marks = FANOTIFY_DEFAULT_MAX_MARKS; + } + + if (flags & FAN_ENABLE_AUDIT) { +@@ -1375,6 +1438,21 @@ SYSCALL32_DEFINE6(fanotify_mark, + */ + static int __init fanotify_user_setup(void) + { ++ struct sysinfo si; ++ int max_marks; ++ ++ si_meminfo(&si); ++ /* ++ * Allow up to 1% of addressable memory to be accounted for per user ++ * marks limited to the range [8192, 1048576]. mount and sb marks are ++ * a lot cheaper than inode marks, but there is no reason for a user ++ * to have many of those, so calculate by the cost of inode marks. ++ */ ++ max_marks = (((si.totalram - si.totalhigh) / 100) << PAGE_SHIFT) / ++ INODE_MARK_COST; ++ max_marks = clamp(max_marks, FANOTIFY_OLD_DEFAULT_MAX_MARKS, ++ FANOTIFY_DEFAULT_MAX_USER_MARKS); ++ + BUILD_BUG_ON(HWEIGHT32(FANOTIFY_INIT_FLAGS) != 10); + BUILD_BUG_ON(HWEIGHT32(FANOTIFY_MARK_FLAGS) != 9); + +@@ -1389,6 +1467,11 @@ static int __init fanotify_user_setup(void) + KMEM_CACHE(fanotify_perm_event, SLAB_PANIC); + } + ++ fanotify_max_queued_events = FANOTIFY_DEFAULT_MAX_EVENTS; ++ init_user_ns.ucount_max[UCOUNT_FANOTIFY_GROUPS] = ++ FANOTIFY_DEFAULT_MAX_GROUPS; ++ init_user_ns.ucount_max[UCOUNT_FANOTIFY_MARKS] = max_marks; ++ + return 0; + } + device_initcall(fanotify_user_setup); +diff --git a/fs/notify/group.c b/fs/notify/group.c +index ffd723ffe46de..fb89c351295d6 100644 +--- a/fs/notify/group.c ++++ b/fs/notify/group.c +@@ -122,7 +122,6 @@ static struct fsnotify_group *__fsnotify_alloc_group( + + /* set to 0 when there a no external references to this group */ + refcount_set(&group->refcnt, 1); +- atomic_set(&group->num_marks, 0); + atomic_set(&group->user_waits, 0); + + spin_lock_init(&group->notification_lock); +diff --git a/fs/notify/mark.c b/fs/notify/mark.c +index 5b44be5f93dd8..7af98a7c33c27 100644 +--- a/fs/notify/mark.c ++++ b/fs/notify/mark.c +@@ -391,8 +391,6 @@ void fsnotify_detach_mark(struct fsnotify_mark *mark) + list_del_init(&mark->g_list); + spin_unlock(&mark->lock); + +- atomic_dec(&group->num_marks); +- + /* Drop mark reference acquired in fsnotify_add_mark_locked() */ + fsnotify_put_mark(mark); + } +@@ -656,7 +654,6 @@ int fsnotify_add_mark_locked(struct fsnotify_mark *mark, + mark->flags |= FSNOTIFY_MARK_FLAG_ALIVE | FSNOTIFY_MARK_FLAG_ATTACHED; + + list_add(&mark->g_list, &group->marks_list); +- atomic_inc(&group->num_marks); + fsnotify_get_mark(mark); /* for g_list */ + spin_unlock(&mark->lock); + +@@ -674,7 +671,6 @@ int fsnotify_add_mark_locked(struct fsnotify_mark *mark, + FSNOTIFY_MARK_FLAG_ATTACHED); + list_del_init(&mark->g_list); + spin_unlock(&mark->lock); +- atomic_dec(&group->num_marks); + + fsnotify_put_mark(mark); + return ret; +diff --git a/include/linux/fanotify.h b/include/linux/fanotify.h +index 3e9c56ee651f7..031a97d8369ae 100644 +--- a/include/linux/fanotify.h ++++ b/include/linux/fanotify.h +@@ -2,8 +2,11 @@ + #ifndef _LINUX_FANOTIFY_H + #define _LINUX_FANOTIFY_H + ++#include + #include + ++extern struct ctl_table fanotify_table[]; /* for sysctl */ ++ + #define FAN_GROUP_FLAG(group, flag) \ + ((group)->fanotify_data.flags & (flag)) + +diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h +index 63fb766f0f3ec..1ce66748a2d29 100644 +--- a/include/linux/fsnotify_backend.h ++++ b/include/linux/fsnotify_backend.h +@@ -206,9 +206,6 @@ struct fsnotify_group { + + /* stores all fastpath marks assoc with this group so they can be cleaned on unregister */ + struct mutex mark_mutex; /* protect marks_list */ +- atomic_t num_marks; /* 1 for each mark and 1 for not being +- * past the point of no return when freeing +- * a group */ + atomic_t user_waits; /* Number of tasks waiting for user + * response */ + struct list_head marks_list; /* all inode marks for this group */ +@@ -240,8 +237,7 @@ struct fsnotify_group { + wait_queue_head_t access_waitq; + int flags; /* flags from fanotify_init() */ + int f_flags; /* event_f_flags from fanotify_init() */ +- unsigned int max_marks; +- struct user_struct *user; ++ struct ucounts *ucounts; + } fanotify_data; + #endif /* CONFIG_FANOTIFY */ + }; +diff --git a/include/linux/sched/user.h b/include/linux/sched/user.h +index a8ec3b6093fcb..3632c5d6ec559 100644 +--- a/include/linux/sched/user.h ++++ b/include/linux/sched/user.h +@@ -14,9 +14,6 @@ struct user_struct { + refcount_t __count; /* reference count */ + atomic_t processes; /* How many processes does this user have? */ + atomic_t sigpending; /* How many pending signals does this user have? */ +-#ifdef CONFIG_FANOTIFY +- atomic_t fanotify_listeners; +-#endif + #ifdef CONFIG_EPOLL + atomic_long_t epoll_watches; /* The number of file descriptors currently watched */ + #endif +diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h +index 7616c7bf4b241..0793951867aef 100644 +--- a/include/linux/user_namespace.h ++++ b/include/linux/user_namespace.h +@@ -49,6 +49,10 @@ enum ucount_type { + #ifdef CONFIG_INOTIFY_USER + UCOUNT_INOTIFY_INSTANCES, + UCOUNT_INOTIFY_WATCHES, ++#endif ++#ifdef CONFIG_FANOTIFY ++ UCOUNT_FANOTIFY_GROUPS, ++ UCOUNT_FANOTIFY_MARKS, + #endif + UCOUNT_COUNTS, + }; +diff --git a/kernel/sysctl.c b/kernel/sysctl.c +index 99a19190196e0..b29a9568ebbe4 100644 +--- a/kernel/sysctl.c ++++ b/kernel/sysctl.c +@@ -142,6 +142,9 @@ static unsigned long hung_task_timeout_max = (LONG_MAX/HZ); + #ifdef CONFIG_INOTIFY_USER + #include + #endif ++#ifdef CONFIG_FANOTIFY ++#include ++#endif + + #ifdef CONFIG_PROC_SYSCTL + +@@ -3330,7 +3333,14 @@ static struct ctl_table fs_table[] = { + .mode = 0555, + .child = inotify_table, + }, +-#endif ++#endif ++#ifdef CONFIG_FANOTIFY ++ { ++ .procname = "fanotify", ++ .mode = 0555, ++ .child = fanotify_table, ++ }, ++#endif + #ifdef CONFIG_EPOLL + { + .procname = "epoll", +diff --git a/kernel/ucount.c b/kernel/ucount.c +index 11b1596e2542a..8d8874f1c35e2 100644 +--- a/kernel/ucount.c ++++ b/kernel/ucount.c +@@ -73,6 +73,10 @@ static struct ctl_table user_table[] = { + #ifdef CONFIG_INOTIFY_USER + UCOUNT_ENTRY("max_inotify_instances"), + UCOUNT_ENTRY("max_inotify_watches"), ++#endif ++#ifdef CONFIG_FANOTIFY ++ UCOUNT_ENTRY("max_fanotify_groups"), ++ UCOUNT_ENTRY("max_fanotify_marks"), + #endif + { } + }; +-- +2.43.0 + diff --git a/queue-5.10/fanotify-create-helper-fanotify_mark_user_flags.patch b/queue-5.10/fanotify-create-helper-fanotify_mark_user_flags.patch new file mode 100644 index 00000000000..3a4cc5131b0 --- /dev/null +++ b/queue-5.10/fanotify-create-helper-fanotify_mark_user_flags.patch @@ -0,0 +1,68 @@ +From 37f99139de6ea7c18906f68b59173784260821f5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 Apr 2022 15:03:23 +0300 +Subject: fanotify: create helper fanotify_mark_user_flags() + +From: Amir Goldstein + +[ Upstream commit 4adce25ccfff215939ee465b8c0aa70526d5c352 ] + +To translate from fsnotify mark flags to user visible flags. + +Link: https://lore.kernel.org/r/20220422120327.3459282-13-amir73il@gmail.com +Signed-off-by: Amir Goldstein +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify.h | 10 ++++++++++ + fs/notify/fdinfo.c | 6 ++---- + 2 files changed, 12 insertions(+), 4 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify.h b/fs/notify/fanotify/fanotify.h +index a3d5b751cac5b..87142bc0131a4 100644 +--- a/fs/notify/fanotify/fanotify.h ++++ b/fs/notify/fanotify/fanotify.h +@@ -490,3 +490,13 @@ static inline unsigned int fanotify_event_hash_bucket( + { + return event->hash & FANOTIFY_HTABLE_MASK; + } ++ ++static inline unsigned int fanotify_mark_user_flags(struct fsnotify_mark *mark) ++{ ++ unsigned int mflags = 0; ++ ++ if (mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY) ++ mflags |= FAN_MARK_IGNORED_SURV_MODIFY; ++ ++ return mflags; ++} +diff --git a/fs/notify/fdinfo.c b/fs/notify/fdinfo.c +index 1f34c5c29fdbd..59fb40abe33d3 100644 +--- a/fs/notify/fdinfo.c ++++ b/fs/notify/fdinfo.c +@@ -14,6 +14,7 @@ + #include + + #include "inotify/inotify.h" ++#include "fanotify/fanotify.h" + #include "fdinfo.h" + #include "fsnotify.h" + +@@ -103,12 +104,9 @@ void inotify_show_fdinfo(struct seq_file *m, struct file *f) + + static void fanotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark) + { +- unsigned int mflags = 0; ++ unsigned int mflags = fanotify_mark_user_flags(mark); + struct inode *inode; + +- if (mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY) +- mflags |= FAN_MARK_IGNORED_SURV_MODIFY; +- + if (mark->connector->type == FSNOTIFY_OBJ_TYPE_INODE) { + inode = igrab(fsnotify_conn_inode(mark->connector)); + if (!inode) +-- +2.43.0 + diff --git a/queue-5.10/fanotify-do-not-allow-setting-dirent-events-in-mask-.patch b/queue-5.10/fanotify-do-not-allow-setting-dirent-events-in-mask-.patch new file mode 100644 index 00000000000..24fa9f85a8e --- /dev/null +++ b/queue-5.10/fanotify-do-not-allow-setting-dirent-events-in-mask-.patch @@ -0,0 +1,72 @@ +From ed7a1b93b668896400d168e509fd26a676ecd4ae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 May 2022 11:00:28 +0300 +Subject: fanotify: do not allow setting dirent events in mask of non-dir + +From: Amir Goldstein + +[ Upstream commit ceaf69f8eadcafb323392be88e7a5248c415d423 ] + +Dirent events (create/delete/move) are only reported on watched +directory inodes, but in fanotify as well as in legacy inotify, it was +always allowed to set them on non-dir inode, which does not result in +any meaningful outcome. + +Until kernel v5.17, dirent events in fanotify also differed from events +"on child" (e.g. FAN_OPEN) in the information provided in the event. +For example, FAN_OPEN could be set in the mask of a non-dir or the mask +of its parent and event would report the fid of the child regardless of +the marked object. +By contrast, FAN_DELETE is not reported if the child is marked and the +child fid was not reported in the events. + +Since kernel v5.17, with fanotify group flag FAN_REPORT_TARGET_FID, the +fid of the child is reported with dirent events, like events "on child", +which may create confusion for users expecting the same behavior as +events "on child" when setting events in the mask on a child. + +The desired semantics of setting dirent events in the mask of a child +are not clear, so for now, deny this action for a group initialized +with flag FAN_REPORT_TARGET_FID and for the new event FAN_RENAME. +We may relax this restriction in the future if we decide on the +semantics and implement them. + +Fixes: d61fd650e9d2 ("fanotify: introduce group flag FAN_REPORT_TARGET_FID") +Fixes: 8cc3b1ccd930 ("fanotify: wire up FAN_RENAME event") +Link: https://lore.kernel.org/linux-fsdevel/20220505133057.zm5t6vumc4xdcnsg@quack3.lan/ +Signed-off-by: Amir Goldstein +Signed-off-by: Jan Kara +Link: https://lore.kernel.org/r/20220507080028.219826-1-amir73il@gmail.com +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify_user.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c +index 64abec874d8e3..921ee7b08580d 100644 +--- a/fs/notify/fanotify/fanotify_user.c ++++ b/fs/notify/fanotify/fanotify_user.c +@@ -1663,6 +1663,19 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, + else + mnt = path.mnt; + ++ /* ++ * FAN_RENAME is not allowed on non-dir (for now). ++ * We shouldn't have allowed setting any dirent events in mask of ++ * non-dir, but because we always allowed it, error only if group ++ * was initialized with the new flag FAN_REPORT_TARGET_FID. ++ */ ++ ret = -ENOTDIR; ++ if (inode && !S_ISDIR(inode->i_mode) && ++ ((mask & FAN_RENAME) || ++ ((mask & FANOTIFY_DIRENT_EVENTS) && ++ FAN_GROUP_FLAG(group, FAN_REPORT_TARGET_FID)))) ++ goto path_put_and_out; ++ + /* Mask out FAN_EVENT_ON_CHILD flag for sb/mount/non-dir marks */ + if (mnt || !S_ISDIR(inode->i_mode)) { + mask &= ~FAN_EVENT_ON_CHILD; +-- +2.43.0 + diff --git a/queue-5.10/fanotify-emit-generic-error-info-for-error-event.patch b/queue-5.10/fanotify-emit-generic-error-info-for-error-event.patch new file mode 100644 index 00000000000..af47ef1e486 --- /dev/null +++ b/queue-5.10/fanotify-emit-generic-error-info-for-error-event.patch @@ -0,0 +1,147 @@ +From 410ffb7c27a2a56473f0340a0db59df38609564f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 Oct 2021 16:27:42 -0300 +Subject: fanotify: Emit generic error info for error event + +From: Gabriel Krisman Bertazi + +[ Upstream commit 130a3c742107acff985541c28360c8b40203559c ] + +The error info is a record sent to users on FAN_FS_ERROR events +documenting the type of error. It also carries an error count, +documenting how many errors were observed since the last reporting. + +Link: https://lore.kernel.org/r/20211025192746.66445-28-krisman@collabora.com +Reviewed-by: Amir Goldstein +Reviewed-by: Jan Kara +Signed-off-by: Gabriel Krisman Bertazi +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify.c | 1 + + fs/notify/fanotify/fanotify.h | 1 + + fs/notify/fanotify/fanotify_user.c | 36 ++++++++++++++++++++++++++++++ + include/uapi/linux/fanotify.h | 7 ++++++ + 4 files changed, 45 insertions(+) + +diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c +index 465f07e70e6dc..af61425e6e3bf 100644 +--- a/fs/notify/fanotify/fanotify.c ++++ b/fs/notify/fanotify/fanotify.c +@@ -621,6 +621,7 @@ static struct fanotify_event *fanotify_alloc_error_event( + return NULL; + + fee->fae.type = FANOTIFY_EVENT_TYPE_FS_ERROR; ++ fee->error = report->error; + fee->err_count = 1; + fee->fsid = *fsid; + +diff --git a/fs/notify/fanotify/fanotify.h b/fs/notify/fanotify/fanotify.h +index edd7587adcc59..d25f500bf7e79 100644 +--- a/fs/notify/fanotify/fanotify.h ++++ b/fs/notify/fanotify/fanotify.h +@@ -205,6 +205,7 @@ FANOTIFY_NE(struct fanotify_event *event) + + struct fanotify_error_event { + struct fanotify_event fae; ++ s32 error; /* Error reported by the Filesystem. */ + u32 err_count; /* Suppressed errors count */ + + __kernel_fsid_t fsid; /* FSID this error refers to. */ +diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c +index 0d36ac3ed7e99..3040c8669dfd1 100644 +--- a/fs/notify/fanotify/fanotify_user.c ++++ b/fs/notify/fanotify/fanotify_user.c +@@ -110,6 +110,8 @@ struct kmem_cache *fanotify_perm_event_cachep __read_mostly; + (sizeof(struct fanotify_event_info_fid) + sizeof(struct file_handle)) + #define FANOTIFY_PIDFD_INFO_HDR_LEN \ + sizeof(struct fanotify_event_info_pidfd) ++#define FANOTIFY_ERROR_INFO_LEN \ ++ (sizeof(struct fanotify_event_info_error)) + + static int fanotify_fid_info_len(int fh_len, int name_len) + { +@@ -134,6 +136,9 @@ static size_t fanotify_event_len(unsigned int info_mode, + if (!info_mode) + return event_len; + ++ if (fanotify_is_error_event(event->mask)) ++ event_len += FANOTIFY_ERROR_INFO_LEN; ++ + info = fanotify_event_info(event); + + if (fanotify_event_has_dir_fh(event)) { +@@ -319,6 +324,28 @@ static int process_access_response(struct fsnotify_group *group, + return -ENOENT; + } + ++static size_t copy_error_info_to_user(struct fanotify_event *event, ++ char __user *buf, int count) ++{ ++ struct fanotify_event_info_error info; ++ struct fanotify_error_event *fee = FANOTIFY_EE(event); ++ ++ info.hdr.info_type = FAN_EVENT_INFO_TYPE_ERROR; ++ info.hdr.pad = 0; ++ info.hdr.len = FANOTIFY_ERROR_INFO_LEN; ++ ++ if (WARN_ON(count < info.hdr.len)) ++ return -EFAULT; ++ ++ info.error = fee->error; ++ info.error_count = fee->err_count; ++ ++ if (copy_to_user(buf, &info, sizeof(info))) ++ return -EFAULT; ++ ++ return info.hdr.len; ++} ++ + static int copy_fid_info_to_user(__kernel_fsid_t *fsid, struct fanotify_fh *fh, + int info_type, const char *name, + size_t name_len, +@@ -525,6 +552,15 @@ static int copy_info_records_to_user(struct fanotify_event *event, + total_bytes += ret; + } + ++ if (fanotify_is_error_event(event->mask)) { ++ ret = copy_error_info_to_user(event, buf, count); ++ if (ret < 0) ++ return ret; ++ buf += ret; ++ count -= ret; ++ total_bytes += ret; ++ } ++ + return total_bytes; + } + +diff --git a/include/uapi/linux/fanotify.h b/include/uapi/linux/fanotify.h +index 2990731ddc8bc..bd1932c2074d5 100644 +--- a/include/uapi/linux/fanotify.h ++++ b/include/uapi/linux/fanotify.h +@@ -126,6 +126,7 @@ struct fanotify_event_metadata { + #define FAN_EVENT_INFO_TYPE_DFID_NAME 2 + #define FAN_EVENT_INFO_TYPE_DFID 3 + #define FAN_EVENT_INFO_TYPE_PIDFD 4 ++#define FAN_EVENT_INFO_TYPE_ERROR 5 + + /* Variable length info record following event metadata */ + struct fanotify_event_info_header { +@@ -160,6 +161,12 @@ struct fanotify_event_info_pidfd { + __s32 pidfd; + }; + ++struct fanotify_event_info_error { ++ struct fanotify_event_info_header hdr; ++ __s32 error; ++ __u32 error_count; ++}; ++ + struct fanotify_response { + __s32 fd; + __u32 response; +-- +2.43.0 + diff --git a/queue-5.10/fanotify-enable-evictable-inode-marks.patch b/queue-5.10/fanotify-enable-evictable-inode-marks.patch new file mode 100644 index 00000000000..16e477a0873 --- /dev/null +++ b/queue-5.10/fanotify-enable-evictable-inode-marks.patch @@ -0,0 +1,50 @@ +From c5c4ba260cce594d3e9784fa3991ad48774ddd5e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 Apr 2022 15:03:27 +0300 +Subject: fanotify: enable "evictable" inode marks + +From: Amir Goldstein + +[ Upstream commit 5f9d3bd520261fd7a850818c71809fd580e0f30c ] + +Now that the direct reclaim path is handled we can enable evictable +inode marks. + +Link: https://lore.kernel.org/r/20220422120327.3459282-17-amir73il@gmail.com +Signed-off-by: Amir Goldstein +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify_user.c | 2 +- + include/linux/fanotify.h | 1 + + 2 files changed, 2 insertions(+), 1 deletion(-) + +diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c +index ad520a2796181..3a1325c90ff86 100644 +--- a/fs/notify/fanotify/fanotify_user.c ++++ b/fs/notify/fanotify/fanotify_user.c +@@ -1806,7 +1806,7 @@ static int __init fanotify_user_setup(void) + + BUILD_BUG_ON(FANOTIFY_INIT_FLAGS & FANOTIFY_INTERNAL_GROUP_FLAGS); + BUILD_BUG_ON(HWEIGHT32(FANOTIFY_INIT_FLAGS) != 12); +- BUILD_BUG_ON(HWEIGHT32(FANOTIFY_MARK_FLAGS) != 9); ++ BUILD_BUG_ON(HWEIGHT32(FANOTIFY_MARK_FLAGS) != 10); + + fanotify_mark_cache = KMEM_CACHE(fsnotify_mark, + SLAB_PANIC|SLAB_ACCOUNT); +diff --git a/include/linux/fanotify.h b/include/linux/fanotify.h +index 3afdf339d53c9..81f45061c1b18 100644 +--- a/include/linux/fanotify.h ++++ b/include/linux/fanotify.h +@@ -68,6 +68,7 @@ extern struct ctl_table fanotify_table[]; /* for sysctl */ + FAN_MARK_ONLYDIR | \ + FAN_MARK_IGNORED_MASK | \ + FAN_MARK_IGNORED_SURV_MODIFY | \ ++ FAN_MARK_EVICTABLE | \ + FAN_MARK_FLUSH) + + /* +-- +2.43.0 + diff --git a/queue-5.10/fanotify-encode-empty-file-handle-when-no-inode-is-p.patch b/queue-5.10/fanotify-encode-empty-file-handle-when-no-inode-is-p.patch new file mode 100644 index 00000000000..65b8783837b --- /dev/null +++ b/queue-5.10/fanotify-encode-empty-file-handle-when-no-inode-is-p.patch @@ -0,0 +1,55 @@ +From 5ea43294ae0b4cf43b1fa58e2973de584549c8dd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 Oct 2021 16:27:30 -0300 +Subject: fanotify: Encode empty file handle when no inode is provided + +From: Gabriel Krisman Bertazi + +[ Upstream commit 272531ac619b374ab474e989eb387162fded553f ] + +Instead of failing, encode an invalid file handle in fanotify_encode_fh +if no inode is provided. This bogus file handle will be reported by +FAN_FS_ERROR for non-inode errors. + +Link: https://lore.kernel.org/r/20211025192746.66445-16-krisman@collabora.com +Reviewed-by: Amir Goldstein +Reviewed-by: Jan Kara +Signed-off-by: Gabriel Krisman Bertazi +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c +index ec84fee7ad01c..c64d61b673caf 100644 +--- a/fs/notify/fanotify/fanotify.c ++++ b/fs/notify/fanotify/fanotify.c +@@ -370,8 +370,14 @@ static int fanotify_encode_fh(struct fanotify_fh *fh, struct inode *inode, + fh->type = FILEID_ROOT; + fh->len = 0; + fh->flags = 0; ++ ++ /* ++ * Invalid FHs are used by FAN_FS_ERROR for errors not ++ * linked to any inode. The f_handle won't be reported ++ * back to userspace. ++ */ + if (!inode) +- return 0; ++ goto out; + + /* + * !gpf means preallocated variable size fh, but fh_len could +@@ -403,6 +409,7 @@ static int fanotify_encode_fh(struct fanotify_fh *fh, struct inode *inode, + fh->type = type; + fh->len = fh_len; + ++out: + /* + * Mix fh into event merge key. Hash might be NULL in case of + * unhashed FID events (i.e. FAN_FS_ERROR). +-- +2.43.0 + diff --git a/queue-5.10/fanotify-factor-out-helper-fanotify_mark_update_flag.patch b/queue-5.10/fanotify-factor-out-helper-fanotify_mark_update_flag.patch new file mode 100644 index 00000000000..f82b1599bb2 --- /dev/null +++ b/queue-5.10/fanotify-factor-out-helper-fanotify_mark_update_flag.patch @@ -0,0 +1,130 @@ +From de1534576020fcacc25007994752bbfe728204a2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 Apr 2022 15:03:24 +0300 +Subject: fanotify: factor out helper fanotify_mark_update_flags() + +From: Amir Goldstein + +[ Upstream commit 8998d110835e3781ccd3f1ae061a590b4aaba911 ] + +Handle FAN_MARK_IGNORED_SURV_MODIFY flag change in a helper that +is called after updating the mark mask. + +Replace the added and removed return values and help variables with +bool recalc return values and help variable, which makes the code a +bit easier to follow. + +Rename flags argument to fan_flags to emphasize the difference from +mark->flags. + +Link: https://lore.kernel.org/r/20220422120327.3459282-14-amir73il@gmail.com +Signed-off-by: Amir Goldstein +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify_user.c | 47 ++++++++++++++++-------------- + 1 file changed, 25 insertions(+), 22 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c +index 731bd7f64e018..f0206e3d11a75 100644 +--- a/fs/notify/fanotify/fanotify_user.c ++++ b/fs/notify/fanotify/fanotify_user.c +@@ -1069,42 +1069,45 @@ static int fanotify_remove_inode_mark(struct fsnotify_group *group, + flags, umask); + } + +-static void fanotify_mark_add_ignored_mask(struct fsnotify_mark *fsn_mark, +- __u32 mask, unsigned int flags, +- __u32 *removed) ++static bool fanotify_mark_update_flags(struct fsnotify_mark *fsn_mark, ++ unsigned int fan_flags) + { +- fsn_mark->ignored_mask |= mask; ++ bool recalc = false; + + /* + * Setting FAN_MARK_IGNORED_SURV_MODIFY for the first time may lead to + * the removal of the FS_MODIFY bit in calculated mask if it was set + * because of an ignored mask that is now going to survive FS_MODIFY. + */ +- if ((flags & FAN_MARK_IGNORED_SURV_MODIFY) && ++ if ((fan_flags & FAN_MARK_IGNORED_MASK) && ++ (fan_flags & FAN_MARK_IGNORED_SURV_MODIFY) && + !(fsn_mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY)) { + fsn_mark->flags |= FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY; + if (!(fsn_mark->mask & FS_MODIFY)) +- *removed = FS_MODIFY; ++ recalc = true; + } ++ ++ return recalc; + } + +-static __u32 fanotify_mark_add_to_mask(struct fsnotify_mark *fsn_mark, +- __u32 mask, unsigned int flags, +- __u32 *removed) ++static bool fanotify_mark_add_to_mask(struct fsnotify_mark *fsn_mark, ++ __u32 mask, unsigned int fan_flags) + { +- __u32 oldmask, newmask; ++ bool recalc; + + spin_lock(&fsn_mark->lock); +- oldmask = fsnotify_calc_mask(fsn_mark); +- if (!(flags & FAN_MARK_IGNORED_MASK)) { ++ if (!(fan_flags & FAN_MARK_IGNORED_MASK)) + fsn_mark->mask |= mask; +- } else { +- fanotify_mark_add_ignored_mask(fsn_mark, mask, flags, removed); +- } +- newmask = fsnotify_calc_mask(fsn_mark); ++ else ++ fsn_mark->ignored_mask |= mask; ++ ++ recalc = fsnotify_calc_mask(fsn_mark) & ++ ~fsnotify_conn_mask(fsn_mark->connector); ++ ++ recalc |= fanotify_mark_update_flags(fsn_mark, fan_flags); + spin_unlock(&fsn_mark->lock); + +- return newmask & ~oldmask; ++ return recalc; + } + + static struct fsnotify_mark *fanotify_add_new_mark(struct fsnotify_group *group, +@@ -1158,11 +1161,11 @@ static int fanotify_group_init_error_pool(struct fsnotify_group *group) + + static int fanotify_add_mark(struct fsnotify_group *group, + fsnotify_connp_t *connp, unsigned int obj_type, +- __u32 mask, unsigned int flags, ++ __u32 mask, unsigned int fan_flags, + __kernel_fsid_t *fsid) + { + struct fsnotify_mark *fsn_mark; +- __u32 added, removed = 0; ++ bool recalc; + int ret = 0; + + mutex_lock(&group->mark_mutex); +@@ -1179,14 +1182,14 @@ static int fanotify_add_mark(struct fsnotify_group *group, + * Error events are pre-allocated per group, only if strictly + * needed (i.e. FAN_FS_ERROR was requested). + */ +- if (!(flags & FAN_MARK_IGNORED_MASK) && (mask & FAN_FS_ERROR)) { ++ if (!(fan_flags & FAN_MARK_IGNORED_MASK) && (mask & FAN_FS_ERROR)) { + ret = fanotify_group_init_error_pool(group); + if (ret) + goto out; + } + +- added = fanotify_mark_add_to_mask(fsn_mark, mask, flags, &removed); +- if (removed || (added & ~fsnotify_conn_mask(fsn_mark->connector))) ++ recalc = fanotify_mark_add_to_mask(fsn_mark, mask, fan_flags); ++ if (recalc) + fsnotify_recalc_mask(fsn_mark->connector); + + out: +-- +2.43.0 + diff --git a/queue-5.10/fanotify-fix-incorrect-fmode_t-casts.patch b/queue-5.10/fanotify-fix-incorrect-fmode_t-casts.patch new file mode 100644 index 00000000000..d37d6087890 --- /dev/null +++ b/queue-5.10/fanotify-fix-incorrect-fmode_t-casts.patch @@ -0,0 +1,54 @@ +From e7046172e1b1f00ad77ef787d3dc1118ef3662fc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 22 May 2022 15:08:02 +0300 +Subject: fanotify: fix incorrect fmode_t casts + +From: Vasily Averin + +[ Upstream commit dccd855771b37820b6d976a99729c88259549f85 ] + +Fixes sparce warnings: +fs/notify/fanotify/fanotify_user.c:267:63: sparse: + warning: restricted fmode_t degrades to integer +fs/notify/fanotify/fanotify_user.c:1351:28: sparse: + warning: restricted fmode_t degrades to integer + +FMODE_NONTIFY have bitwise fmode_t type and requires __force attribute +for any casts. + +Signed-off-by: Vasily Averin +Reviewed-by: Christian Brauner (Microsoft) +Reviewed-by: Christoph Hellwig +Signed-off-by: Jan Kara +Link: https://lore.kernel.org/r/9adfd6ac-1b89-791e-796b-49ada3293985@openvz.org +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify_user.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c +index 3a1325c90ff86..f4a5e9074dd42 100644 +--- a/fs/notify/fanotify/fanotify_user.c ++++ b/fs/notify/fanotify/fanotify_user.c +@@ -252,7 +252,7 @@ static int create_fd(struct fsnotify_group *group, struct path *path, + * originally opened O_WRONLY. + */ + new_file = dentry_open(path, +- group->fanotify_data.f_flags | FMODE_NONOTIFY, ++ group->fanotify_data.f_flags | __FMODE_NONOTIFY, + current_cred()); + if (IS_ERR(new_file)) { + /* +@@ -1365,7 +1365,7 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) + (!(fid_mode & FAN_REPORT_NAME) || !(fid_mode & FAN_REPORT_FID))) + return -EINVAL; + +- f_flags = O_RDWR | FMODE_NONOTIFY; ++ f_flags = O_RDWR | __FMODE_NONOTIFY; + if (flags & FAN_CLOEXEC) + f_flags |= O_CLOEXEC; + if (flags & FAN_NONBLOCK) +-- +2.43.0 + diff --git a/queue-5.10/fanotify-fix-permission-model-of-unprivileged-group.patch b/queue-5.10/fanotify-fix-permission-model-of-unprivileged-group.patch new file mode 100644 index 00000000000..1a13ed0b93d --- /dev/null +++ b/queue-5.10/fanotify-fix-permission-model-of-unprivileged-group.patch @@ -0,0 +1,148 @@ +From 34eb839d60a1045b3867dd7f1a2a227c68f00ab9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 24 May 2021 16:53:21 +0300 +Subject: fanotify: fix permission model of unprivileged group + +From: Amir Goldstein + +[ Upstream commit a8b98c808eab3ec8f1b5a64be967b0f4af4cae43 ] + +Reporting event->pid should depend on the privileges of the user that +initialized the group, not the privileges of the user reading the +events. + +Use an internal group flag FANOTIFY_UNPRIV to record the fact that the +group was initialized by an unprivileged user. + +To be on the safe side, the premissions to setup filesystem and mount +marks now require that both the user that initialized the group and +the user setting up the mark have CAP_SYS_ADMIN. + +Link: https://lore.kernel.org/linux-fsdevel/CAOQ4uxiA77_P5vtv7e83g0+9d7B5W9ZTE4GfQEYbWmfT1rA=VA@mail.gmail.com/ +Fixes: 7cea2a3c505e ("fanotify: support limited functionality for unprivileged users") +Cc: # v5.12+ +Link: https://lore.kernel.org/r/20210524135321.2190062-1-amir73il@gmail.com +Reviewed-by: Matthew Bobrowski +Acked-by: Christian Brauner +Signed-off-by: Amir Goldstein +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify_user.c | 30 ++++++++++++++++++++++++------ + fs/notify/fdinfo.c | 2 +- + include/linux/fanotify.h | 4 ++++ + 3 files changed, 29 insertions(+), 7 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c +index 98289ace66fac..1c439e2fdcd80 100644 +--- a/fs/notify/fanotify/fanotify_user.c ++++ b/fs/notify/fanotify/fanotify_user.c +@@ -424,11 +424,18 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group, + * events generated by the listener process itself, without disclosing + * the pids of other processes. + */ +- if (!capable(CAP_SYS_ADMIN) && ++ if (FAN_GROUP_FLAG(group, FANOTIFY_UNPRIV) && + task_tgid(current) != event->pid) + metadata.pid = 0; + +- if (path && path->mnt && path->dentry) { ++ /* ++ * For now, fid mode is required for an unprivileged listener and ++ * fid mode does not report fd in events. Keep this check anyway ++ * for safety in case fid mode requirement is relaxed in the future ++ * to allow unprivileged listener to get events with no fd and no fid. ++ */ ++ if (!FAN_GROUP_FLAG(group, FANOTIFY_UNPRIV) && ++ path && path->mnt && path->dentry) { + fd = create_fd(group, path, &f); + if (fd < 0) + return fd; +@@ -1040,6 +1047,7 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) + int f_flags, fd; + unsigned int fid_mode = flags & FANOTIFY_FID_BITS; + unsigned int class = flags & FANOTIFY_CLASS_BITS; ++ unsigned int internal_flags = 0; + + pr_debug("%s: flags=%x event_f_flags=%x\n", + __func__, flags, event_f_flags); +@@ -1053,6 +1061,13 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) + */ + if ((flags & FANOTIFY_ADMIN_INIT_FLAGS) || !fid_mode) + return -EPERM; ++ ++ /* ++ * Setting the internal flag FANOTIFY_UNPRIV on the group ++ * prevents setting mount/filesystem marks on this group and ++ * prevents reporting pid and open fd in events. ++ */ ++ internal_flags |= FANOTIFY_UNPRIV; + } + + #ifdef CONFIG_AUDITSYSCALL +@@ -1105,7 +1120,7 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) + goto out_destroy_group; + } + +- group->fanotify_data.flags = flags; ++ group->fanotify_data.flags = flags | internal_flags; + group->memcg = get_mem_cgroup_from_mm(current->mm); + + group->fanotify_data.merge_hash = fanotify_alloc_merge_hash(); +@@ -1323,11 +1338,13 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, + group = f.file->private_data; + + /* +- * An unprivileged user is not allowed to watch a mount point nor +- * a filesystem. ++ * An unprivileged user is not allowed to setup mount nor filesystem ++ * marks. This also includes setting up such marks by a group that ++ * was initialized by an unprivileged user. + */ + ret = -EPERM; +- if (!capable(CAP_SYS_ADMIN) && ++ if ((!capable(CAP_SYS_ADMIN) || ++ FAN_GROUP_FLAG(group, FANOTIFY_UNPRIV)) && + mark_type != FAN_MARK_INODE) + goto fput_and_out; + +@@ -1478,6 +1495,7 @@ static int __init fanotify_user_setup(void) + max_marks = clamp(max_marks, FANOTIFY_OLD_DEFAULT_MAX_MARKS, + FANOTIFY_DEFAULT_MAX_USER_MARKS); + ++ BUILD_BUG_ON(FANOTIFY_INIT_FLAGS & FANOTIFY_INTERNAL_GROUP_FLAGS); + BUILD_BUG_ON(HWEIGHT32(FANOTIFY_INIT_FLAGS) != 10); + BUILD_BUG_ON(HWEIGHT32(FANOTIFY_MARK_FLAGS) != 9); + +diff --git a/fs/notify/fdinfo.c b/fs/notify/fdinfo.c +index 85b112bd88511..3451708fd035c 100644 +--- a/fs/notify/fdinfo.c ++++ b/fs/notify/fdinfo.c +@@ -137,7 +137,7 @@ void fanotify_show_fdinfo(struct seq_file *m, struct file *f) + struct fsnotify_group *group = f->private_data; + + seq_printf(m, "fanotify flags:%x event-flags:%x\n", +- group->fanotify_data.flags, ++ group->fanotify_data.flags & FANOTIFY_INIT_FLAGS, + group->fanotify_data.f_flags); + + show_fdinfo(m, f, fanotify_fdinfo); +diff --git a/include/linux/fanotify.h b/include/linux/fanotify.h +index bad41bcb25dfb..a16dbeced1528 100644 +--- a/include/linux/fanotify.h ++++ b/include/linux/fanotify.h +@@ -51,6 +51,10 @@ extern struct ctl_table fanotify_table[]; /* for sysctl */ + #define FANOTIFY_INIT_FLAGS (FANOTIFY_ADMIN_INIT_FLAGS | \ + FANOTIFY_USER_INIT_FLAGS) + ++/* Internal group flags */ ++#define FANOTIFY_UNPRIV 0x80000000 ++#define FANOTIFY_INTERNAL_GROUP_FLAGS (FANOTIFY_UNPRIV) ++ + #define FANOTIFY_MARK_TYPE_BITS (FAN_MARK_INODE | FAN_MARK_MOUNT | \ + FAN_MARK_FILESYSTEM) + +-- +2.43.0 + diff --git a/queue-5.10/fanotify-fold-event-size-calculation-to-its-own-func.patch b/queue-5.10/fanotify-fold-event-size-calculation-to-its-own-func.patch new file mode 100644 index 00000000000..d2f54aeb83a --- /dev/null +++ b/queue-5.10/fanotify-fold-event-size-calculation-to-its-own-func.patch @@ -0,0 +1,110 @@ +From 7b3ecf798530479d63749abde58a04b5aea8b6ca Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 Oct 2021 16:27:20 -0300 +Subject: fanotify: Fold event size calculation to its own function + +From: Gabriel Krisman Bertazi + +[ Upstream commit b9928e80dda84b349ba8de01780b9bef2fc36ffa ] + +Every time this function is invoked, it is immediately added to +FAN_EVENT_METADATA_LEN, since there is no need to just calculate the +length of info records. This minor clean up folds the rest of the +calculation into the function, which now operates in terms of events, +returning the size of the entire event, including metadata. + +Link: https://lore.kernel.org/r/20211025192746.66445-6-krisman@collabora.com +Reviewed-by: Amir Goldstein +Reviewed-by: Jan Kara +Signed-off-by: Gabriel Krisman Bertazi +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify_user.c | 35 +++++++++++++++++------------- + 1 file changed, 20 insertions(+), 15 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c +index 10fb062065b69..846e2a661526c 100644 +--- a/fs/notify/fanotify/fanotify_user.c ++++ b/fs/notify/fanotify/fanotify_user.c +@@ -121,17 +121,24 @@ static int fanotify_fid_info_len(int fh_len, int name_len) + FANOTIFY_EVENT_ALIGN); + } + +-static int fanotify_event_info_len(unsigned int info_mode, +- struct fanotify_event *event) ++static size_t fanotify_event_len(unsigned int info_mode, ++ struct fanotify_event *event) + { +- struct fanotify_info *info = fanotify_event_info(event); +- int dir_fh_len = fanotify_event_dir_fh_len(event); +- int fh_len = fanotify_event_object_fh_len(event); +- int info_len = 0; ++ size_t event_len = FAN_EVENT_METADATA_LEN; ++ struct fanotify_info *info; ++ int dir_fh_len; ++ int fh_len; + int dot_len = 0; + ++ if (!info_mode) ++ return event_len; ++ ++ info = fanotify_event_info(event); ++ dir_fh_len = fanotify_event_dir_fh_len(event); ++ fh_len = fanotify_event_object_fh_len(event); ++ + if (dir_fh_len) { +- info_len += fanotify_fid_info_len(dir_fh_len, info->name_len); ++ event_len += fanotify_fid_info_len(dir_fh_len, info->name_len); + } else if ((info_mode & FAN_REPORT_NAME) && + (event->mask & FAN_ONDIR)) { + /* +@@ -142,12 +149,12 @@ static int fanotify_event_info_len(unsigned int info_mode, + } + + if (info_mode & FAN_REPORT_PIDFD) +- info_len += FANOTIFY_PIDFD_INFO_HDR_LEN; ++ event_len += FANOTIFY_PIDFD_INFO_HDR_LEN; + + if (fh_len) +- info_len += fanotify_fid_info_len(fh_len, dot_len); ++ event_len += fanotify_fid_info_len(fh_len, dot_len); + +- return info_len; ++ return event_len; + } + + /* +@@ -176,7 +183,7 @@ static void fanotify_unhash_event(struct fsnotify_group *group, + static struct fanotify_event *get_one_event(struct fsnotify_group *group, + size_t count) + { +- size_t event_size = FAN_EVENT_METADATA_LEN; ++ size_t event_size; + struct fanotify_event *event = NULL; + struct fsnotify_event *fsn_event; + unsigned int info_mode = FAN_GROUP_FLAG(group, FANOTIFY_INFO_MODES); +@@ -189,8 +196,7 @@ static struct fanotify_event *get_one_event(struct fsnotify_group *group, + goto out; + + event = FANOTIFY_E(fsn_event); +- if (info_mode) +- event_size += fanotify_event_info_len(info_mode, event); ++ event_size = fanotify_event_len(info_mode, event); + + if (event_size > count) { + event = ERR_PTR(-EINVAL); +@@ -532,8 +538,7 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group, + + pr_debug("%s: group=%p event=%p\n", __func__, group, event); + +- metadata.event_len = FAN_EVENT_METADATA_LEN + +- fanotify_event_info_len(info_mode, event); ++ metadata.event_len = fanotify_event_len(info_mode, event); + metadata.metadata_len = FAN_EVENT_METADATA_LEN; + metadata.vers = FANOTIFY_METADATA_VERSION; + metadata.reserved = 0; +-- +2.43.0 + diff --git a/queue-5.10/fanotify-implement-evictable-inode-marks.patch b/queue-5.10/fanotify-implement-evictable-inode-marks.patch new file mode 100644 index 00000000000..eb878b6e0bd --- /dev/null +++ b/queue-5.10/fanotify-implement-evictable-inode-marks.patch @@ -0,0 +1,160 @@ +From 2b2d4b0462c9e9d0528c48d05c86e59d600f359f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 Apr 2022 15:03:25 +0300 +Subject: fanotify: implement "evictable" inode marks + +From: Amir Goldstein + +[ Upstream commit 7d5e005d982527e4029b0139823d179986e34cdc ] + +When an inode mark is created with flag FAN_MARK_EVICTABLE, it will not +pin the marked inode to inode cache, so when inode is evicted from cache +due to memory pressure, the mark will be lost. + +When an inode mark with flag FAN_MARK_EVICATBLE is updated without using +this flag, the marked inode is pinned to inode cache. + +When an inode mark is updated with flag FAN_MARK_EVICTABLE but an +existing mark already has the inode pinned, the mark update fails with +error EEXIST. + +Evictable inode marks can be used to setup inode marks with ignored mask +to suppress events from uninteresting files or directories in a lazy +manner, upon receiving the first event, without having to iterate all +the uninteresting files or directories before hand. + +The evictbale inode mark feature allows performing this lazy marks setup +without exhausting the system memory with pinned inodes. + +This change does not enable the feature yet. + +Link: https://lore.kernel.org/linux-fsdevel/CAOQ4uxiRDpuS=2uA6+ZUM7yG9vVU-u212tkunBmSnP_u=mkv=Q@mail.gmail.com/ +Link: https://lore.kernel.org/r/20220422120327.3459282-15-amir73il@gmail.com +Signed-off-by: Amir Goldstein +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify.h | 2 ++ + fs/notify/fanotify/fanotify_user.c | 38 ++++++++++++++++++++++++++++-- + include/uapi/linux/fanotify.h | 1 + + 3 files changed, 39 insertions(+), 2 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify.h b/fs/notify/fanotify/fanotify.h +index 87142bc0131a4..80e0ec95b1131 100644 +--- a/fs/notify/fanotify/fanotify.h ++++ b/fs/notify/fanotify/fanotify.h +@@ -497,6 +497,8 @@ static inline unsigned int fanotify_mark_user_flags(struct fsnotify_mark *mark) + + if (mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY) + mflags |= FAN_MARK_IGNORED_SURV_MODIFY; ++ if (mark->flags & FSNOTIFY_MARK_FLAG_NO_IREF) ++ mflags |= FAN_MARK_EVICTABLE; + + return mflags; + } +diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c +index f0206e3d11a75..ab7a13686b49d 100644 +--- a/fs/notify/fanotify/fanotify_user.c ++++ b/fs/notify/fanotify/fanotify_user.c +@@ -1072,6 +1072,7 @@ static int fanotify_remove_inode_mark(struct fsnotify_group *group, + static bool fanotify_mark_update_flags(struct fsnotify_mark *fsn_mark, + unsigned int fan_flags) + { ++ bool want_iref = !(fan_flags & FAN_MARK_EVICTABLE); + bool recalc = false; + + /* +@@ -1087,7 +1088,18 @@ static bool fanotify_mark_update_flags(struct fsnotify_mark *fsn_mark, + recalc = true; + } + +- return recalc; ++ if (fsn_mark->connector->type != FSNOTIFY_OBJ_TYPE_INODE || ++ want_iref == !(fsn_mark->flags & FSNOTIFY_MARK_FLAG_NO_IREF)) ++ return recalc; ++ ++ /* ++ * NO_IREF may be removed from a mark, but not added. ++ * When removed, fsnotify_recalc_mask() will take the inode ref. ++ */ ++ WARN_ON_ONCE(!want_iref); ++ fsn_mark->flags &= ~FSNOTIFY_MARK_FLAG_NO_IREF; ++ ++ return true; + } + + static bool fanotify_mark_add_to_mask(struct fsnotify_mark *fsn_mark, +@@ -1113,6 +1125,7 @@ static bool fanotify_mark_add_to_mask(struct fsnotify_mark *fsn_mark, + static struct fsnotify_mark *fanotify_add_new_mark(struct fsnotify_group *group, + fsnotify_connp_t *connp, + unsigned int obj_type, ++ unsigned int fan_flags, + __kernel_fsid_t *fsid) + { + struct ucounts *ucounts = group->fanotify_data.ucounts; +@@ -1135,6 +1148,9 @@ static struct fsnotify_mark *fanotify_add_new_mark(struct fsnotify_group *group, + } + + fsnotify_init_mark(mark, group); ++ if (fan_flags & FAN_MARK_EVICTABLE) ++ mark->flags |= FSNOTIFY_MARK_FLAG_NO_IREF; ++ + ret = fsnotify_add_mark_locked(mark, connp, obj_type, 0, fsid); + if (ret) { + fsnotify_put_mark(mark); +@@ -1171,13 +1187,23 @@ static int fanotify_add_mark(struct fsnotify_group *group, + mutex_lock(&group->mark_mutex); + fsn_mark = fsnotify_find_mark(connp, group); + if (!fsn_mark) { +- fsn_mark = fanotify_add_new_mark(group, connp, obj_type, fsid); ++ fsn_mark = fanotify_add_new_mark(group, connp, obj_type, ++ fan_flags, fsid); + if (IS_ERR(fsn_mark)) { + mutex_unlock(&group->mark_mutex); + return PTR_ERR(fsn_mark); + } + } + ++ /* ++ * Non evictable mark cannot be downgraded to evictable mark. ++ */ ++ if (fan_flags & FAN_MARK_EVICTABLE && ++ !(fsn_mark->flags & FSNOTIFY_MARK_FLAG_NO_IREF)) { ++ ret = -EEXIST; ++ goto out; ++ } ++ + /* + * Error events are pre-allocated per group, only if strictly + * needed (i.e. FAN_FS_ERROR was requested). +@@ -1607,6 +1633,14 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, + mark_type != FAN_MARK_FILESYSTEM) + goto fput_and_out; + ++ /* ++ * Evictable is only relevant for inode marks, because only inode object ++ * can be evicted on memory pressure. ++ */ ++ if (flags & FAN_MARK_EVICTABLE && ++ mark_type != FAN_MARK_INODE) ++ goto fput_and_out; ++ + /* + * Events that do not carry enough information to report + * event->fd require a group that supports reporting fid. Those +diff --git a/include/uapi/linux/fanotify.h b/include/uapi/linux/fanotify.h +index e8ac38cc2fd6d..f1f89132d60e2 100644 +--- a/include/uapi/linux/fanotify.h ++++ b/include/uapi/linux/fanotify.h +@@ -82,6 +82,7 @@ + #define FAN_MARK_IGNORED_SURV_MODIFY 0x00000040 + #define FAN_MARK_FLUSH 0x00000080 + /* FAN_MARK_FILESYSTEM is 0x00000100 */ ++#define FAN_MARK_EVICTABLE 0x00000200 + + /* These are NOT bitwise flags. Both bits can be used togther. */ + #define FAN_MARK_INODE 0x00000000 +-- +2.43.0 + diff --git a/queue-5.10/fanotify-introduce-a-generic-info-record-copying-hel.patch b/queue-5.10/fanotify-introduce-a-generic-info-record-copying-hel.patch new file mode 100644 index 00000000000..f5c9710fe9c --- /dev/null +++ b/queue-5.10/fanotify-introduce-a-generic-info-record-copying-hel.patch @@ -0,0 +1,258 @@ +From ab7ee415f6d8b5b76b302f302236e91541f38ee3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 8 Aug 2021 15:25:58 +1000 +Subject: fanotify: introduce a generic info record copying helper + +From: Matthew Bobrowski + +[ Upstream commit 0aca67bb7f0d8c997dfef8ff0bfeb0afb361f0e6 ] + +The copy_info_records_to_user() helper allows for the separation of +info record copying routines/conditionals from copy_event_to_user(), +which reduces the overall clutter within this function. This becomes +especially true as we start introducing additional info records in the +future i.e. struct fanotify_event_info_pidfd. On success, this helper +returns the total amount of bytes that have been copied into the user +supplied buffer and on error, a negative value is returned to the +caller. + +The newly defined macro FANOTIFY_INFO_MODES can be used to obtain info +record types that have been enabled for a specific notification +group. This macro becomes useful in the subsequent patch when the +FAN_REPORT_PIDFD initialization flag is introduced. + +Link: https://lore.kernel.org/r/8872947dfe12ce8ae6e9a7f2d49ea29bc8006af0.1628398044.git.repnop@google.com +Signed-off-by: Matthew Bobrowski +Reviewed-by: Amir Goldstein +Signed-off-by: Jan Kara +[ cel: adjusted to apply to v5.10.y ] +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify_user.c | 151 ++++++++++++++++------------- + include/linux/fanotify.h | 2 + + 2 files changed, 88 insertions(+), 65 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c +index 74b51dab2cdce..83405949a71b2 100644 +--- a/fs/notify/fanotify/fanotify_user.c ++++ b/fs/notify/fanotify/fanotify_user.c +@@ -173,7 +173,7 @@ static struct fanotify_event *get_one_event(struct fsnotify_group *group, + size_t event_size = FAN_EVENT_METADATA_LEN; + struct fanotify_event *event = NULL; + struct fsnotify_event *fsn_event; +- unsigned int fid_mode = FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS); ++ unsigned int info_mode = FAN_GROUP_FLAG(group, FANOTIFY_INFO_MODES); + + pr_debug("%s: group=%p count=%zd\n", __func__, group, count); + +@@ -183,8 +183,8 @@ static struct fanotify_event *get_one_event(struct fsnotify_group *group, + goto out; + + event = FANOTIFY_E(fsn_event); +- if (fid_mode) +- event_size += fanotify_event_info_len(fid_mode, event); ++ if (info_mode) ++ event_size += fanotify_event_info_len(info_mode, event); + + if (event_size > count) { + event = ERR_PTR(-EINVAL); +@@ -401,68 +401,17 @@ static int copy_fid_info_to_user(__kernel_fsid_t *fsid, struct fanotify_fh *fh, + return info_len; + } + +-static ssize_t copy_event_to_user(struct fsnotify_group *group, +- struct fanotify_event *event, +- char __user *buf, size_t count) ++static int copy_info_records_to_user(struct fanotify_event *event, ++ struct fanotify_info *info, ++ unsigned int info_mode, ++ char __user *buf, size_t count) + { +- struct fanotify_event_metadata metadata; +- struct path *path = fanotify_event_path(event); +- struct fanotify_info *info = fanotify_event_info(event); +- unsigned int fid_mode = FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS); +- struct file *f = NULL; +- int ret, fd = FAN_NOFD; +- int info_type = 0; +- +- pr_debug("%s: group=%p event=%p\n", __func__, group, event); +- +- metadata.event_len = FAN_EVENT_METADATA_LEN + +- fanotify_event_info_len(fid_mode, event); +- metadata.metadata_len = FAN_EVENT_METADATA_LEN; +- metadata.vers = FANOTIFY_METADATA_VERSION; +- metadata.reserved = 0; +- metadata.mask = event->mask & FANOTIFY_OUTGOING_EVENTS; +- metadata.pid = pid_vnr(event->pid); +- /* +- * For an unprivileged listener, event->pid can be used to identify the +- * events generated by the listener process itself, without disclosing +- * the pids of other processes. +- */ +- if (FAN_GROUP_FLAG(group, FANOTIFY_UNPRIV) && +- task_tgid(current) != event->pid) +- metadata.pid = 0; +- +- /* +- * For now, fid mode is required for an unprivileged listener and +- * fid mode does not report fd in events. Keep this check anyway +- * for safety in case fid mode requirement is relaxed in the future +- * to allow unprivileged listener to get events with no fd and no fid. +- */ +- if (!FAN_GROUP_FLAG(group, FANOTIFY_UNPRIV) && +- path && path->mnt && path->dentry) { +- fd = create_fd(group, path, &f); +- if (fd < 0) +- return fd; +- } +- metadata.fd = fd; ++ int ret, total_bytes = 0, info_type = 0; ++ unsigned int fid_mode = info_mode & FANOTIFY_FID_BITS; + +- ret = -EFAULT; + /* +- * Sanity check copy size in case get_one_event() and +- * event_len sizes ever get out of sync. ++ * Event info records order is as follows: dir fid + name, child fid. + */ +- if (WARN_ON_ONCE(metadata.event_len > count)) +- goto out_close_fd; +- +- if (copy_to_user(buf, &metadata, FAN_EVENT_METADATA_LEN)) +- goto out_close_fd; +- +- buf += FAN_EVENT_METADATA_LEN; +- count -= FAN_EVENT_METADATA_LEN; +- +- if (fanotify_is_perm_event(event->mask)) +- FANOTIFY_PERM(event)->fd = fd; +- +- /* Event info records order is: dir fid + name, child fid */ + if (fanotify_event_dir_fh_len(event)) { + info_type = info->name_len ? FAN_EVENT_INFO_TYPE_DFID_NAME : + FAN_EVENT_INFO_TYPE_DFID; +@@ -472,10 +421,11 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group, + fanotify_info_name(info), + info->name_len, buf, count); + if (ret < 0) +- goto out_close_fd; ++ return ret; + + buf += ret; + count -= ret; ++ total_bytes += ret; + } + + if (fanotify_event_object_fh_len(event)) { +@@ -492,8 +442,8 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group, + (event->mask & FAN_ONDIR)) { + /* + * With group flag FAN_REPORT_NAME, if name was not +- * recorded in an event on a directory, report the +- * name "." with info type DFID_NAME. ++ * recorded in an event on a directory, report the name ++ * "." with info type DFID_NAME. + */ + info_type = FAN_EVENT_INFO_TYPE_DFID_NAME; + dot = "."; +@@ -521,10 +471,81 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group, + info_type, dot, dot_len, + buf, count); + if (ret < 0) +- goto out_close_fd; ++ return ret; + + buf += ret; + count -= ret; ++ total_bytes += ret; ++ } ++ ++ return total_bytes; ++} ++ ++static ssize_t copy_event_to_user(struct fsnotify_group *group, ++ struct fanotify_event *event, ++ char __user *buf, size_t count) ++{ ++ struct fanotify_event_metadata metadata; ++ struct path *path = fanotify_event_path(event); ++ struct fanotify_info *info = fanotify_event_info(event); ++ unsigned int info_mode = FAN_GROUP_FLAG(group, FANOTIFY_INFO_MODES); ++ struct file *f = NULL; ++ int ret, fd = FAN_NOFD; ++ ++ pr_debug("%s: group=%p event=%p\n", __func__, group, event); ++ ++ metadata.event_len = FAN_EVENT_METADATA_LEN + ++ fanotify_event_info_len(info_mode, event); ++ metadata.metadata_len = FAN_EVENT_METADATA_LEN; ++ metadata.vers = FANOTIFY_METADATA_VERSION; ++ metadata.reserved = 0; ++ metadata.mask = event->mask & FANOTIFY_OUTGOING_EVENTS; ++ metadata.pid = pid_vnr(event->pid); ++ /* ++ * For an unprivileged listener, event->pid can be used to identify the ++ * events generated by the listener process itself, without disclosing ++ * the pids of other processes. ++ */ ++ if (FAN_GROUP_FLAG(group, FANOTIFY_UNPRIV) && ++ task_tgid(current) != event->pid) ++ metadata.pid = 0; ++ ++ /* ++ * For now, fid mode is required for an unprivileged listener and ++ * fid mode does not report fd in events. Keep this check anyway ++ * for safety in case fid mode requirement is relaxed in the future ++ * to allow unprivileged listener to get events with no fd and no fid. ++ */ ++ if (!FAN_GROUP_FLAG(group, FANOTIFY_UNPRIV) && ++ path && path->mnt && path->dentry) { ++ fd = create_fd(group, path, &f); ++ if (fd < 0) ++ return fd; ++ } ++ metadata.fd = fd; ++ ++ ret = -EFAULT; ++ /* ++ * Sanity check copy size in case get_one_event() and ++ * event_len sizes ever get out of sync. ++ */ ++ if (WARN_ON_ONCE(metadata.event_len > count)) ++ goto out_close_fd; ++ ++ if (copy_to_user(buf, &metadata, FAN_EVENT_METADATA_LEN)) ++ goto out_close_fd; ++ ++ buf += FAN_EVENT_METADATA_LEN; ++ count -= FAN_EVENT_METADATA_LEN; ++ ++ if (fanotify_is_perm_event(event->mask)) ++ FANOTIFY_PERM(event)->fd = fd; ++ ++ if (info_mode) { ++ ret = copy_info_records_to_user(event, info, info_mode, ++ buf, count); ++ if (ret < 0) ++ goto out_close_fd; + } + + if (f) +diff --git a/include/linux/fanotify.h b/include/linux/fanotify.h +index a16dbeced1528..10a7e26ddba6c 100644 +--- a/include/linux/fanotify.h ++++ b/include/linux/fanotify.h +@@ -27,6 +27,8 @@ extern struct ctl_table fanotify_table[]; /* for sysctl */ + + #define FANOTIFY_FID_BITS (FAN_REPORT_FID | FAN_REPORT_DFID_NAME) + ++#define FANOTIFY_INFO_MODES (FANOTIFY_FID_BITS) ++ + /* + * fanotify_init() flags that require CAP_SYS_ADMIN. + * We do not allow unprivileged groups to request permission events. +-- +2.43.0 + diff --git a/queue-5.10/fanotify-introduce-fan_mark_ignore.patch b/queue-5.10/fanotify-introduce-fan_mark_ignore.patch new file mode 100644 index 00000000000..c0e64f39a51 --- /dev/null +++ b/queue-5.10/fanotify-introduce-fan_mark_ignore.patch @@ -0,0 +1,273 @@ +From d71306654618c855836d2f6cdec612c1c6aeca29 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Jun 2022 17:42:10 +0300 +Subject: fanotify: introduce FAN_MARK_IGNORE + +From: Amir Goldstein + +[ Upstream commit e252f2ed1c8c6c3884ab5dd34e003ed21f1fe6e0 ] + +This flag is a new way to configure ignore mask which allows adding and +removing the event flags FAN_ONDIR and FAN_EVENT_ON_CHILD in ignore mask. + +The legacy FAN_MARK_IGNORED_MASK flag would always ignore events on +directories and would ignore events on children depending on whether +the FAN_EVENT_ON_CHILD flag was set in the (non ignored) mask. + +FAN_MARK_IGNORE can be used to ignore events on children without setting +FAN_EVENT_ON_CHILD in the mark's mask and will not ignore events on +directories unconditionally, only when FAN_ONDIR is set in ignore mask. + +The new behavior is non-downgradable. After calling fanotify_mark() with +FAN_MARK_IGNORE once, calling fanotify_mark() with FAN_MARK_IGNORED_MASK +on the same object will return EEXIST error. + +Setting the event flags with FAN_MARK_IGNORE on a non-dir inode mark +has no meaning and will return ENOTDIR error. + +The meaning of FAN_MARK_IGNORED_SURV_MODIFY is preserved with the new +FAN_MARK_IGNORE flag, but with a few semantic differences: + +1. FAN_MARK_IGNORED_SURV_MODIFY is required for filesystem and mount + marks and on an inode mark on a directory. Omitting this flag + will return EINVAL or EISDIR error. + +2. An ignore mask on a non-directory inode that survives modify could + never be downgraded to an ignore mask that does not survive modify. + With new FAN_MARK_IGNORE semantics we make that rule explicit - + trying to update a surviving ignore mask without the flag + FAN_MARK_IGNORED_SURV_MODIFY will return EEXIST error. + +The conveniene macro FAN_MARK_IGNORE_SURV is added for +(FAN_MARK_IGNORE | FAN_MARK_IGNORED_SURV_MODIFY), because the +common case should use short constant names. + +Link: https://lore.kernel.org/r/20220629144210.2983229-4-amir73il@gmail.com +Signed-off-by: Amir Goldstein +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify.h | 2 + + fs/notify/fanotify/fanotify_user.c | 63 +++++++++++++++++++++++++----- + include/linux/fanotify.h | 5 ++- + include/uapi/linux/fanotify.h | 8 ++++ + 4 files changed, 67 insertions(+), 11 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify.h b/fs/notify/fanotify/fanotify.h +index 80e0ec95b1131..1d9f11255c64f 100644 +--- a/fs/notify/fanotify/fanotify.h ++++ b/fs/notify/fanotify/fanotify.h +@@ -499,6 +499,8 @@ static inline unsigned int fanotify_mark_user_flags(struct fsnotify_mark *mark) + mflags |= FAN_MARK_IGNORED_SURV_MODIFY; + if (mark->flags & FSNOTIFY_MARK_FLAG_NO_IREF) + mflags |= FAN_MARK_EVICTABLE; ++ if (mark->flags & FSNOTIFY_MARK_FLAG_HAS_IGNORE_FLAGS) ++ mflags |= FAN_MARK_IGNORE; + + return mflags; + } +diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c +index 715e41b344129..72dd446606a78 100644 +--- a/fs/notify/fanotify/fanotify_user.c ++++ b/fs/notify/fanotify/fanotify_user.c +@@ -997,7 +997,7 @@ static __u32 fanotify_mark_remove_from_mask(struct fsnotify_mark *fsn_mark, + mask &= ~umask; + spin_lock(&fsn_mark->lock); + oldmask = fsnotify_calc_mask(fsn_mark); +- if (!(flags & FAN_MARK_IGNORED_MASK)) { ++ if (!(flags & FANOTIFY_MARK_IGNORE_BITS)) { + fsn_mark->mask &= ~mask; + } else { + fsn_mark->ignore_mask &= ~mask; +@@ -1073,15 +1073,24 @@ static bool fanotify_mark_update_flags(struct fsnotify_mark *fsn_mark, + unsigned int fan_flags) + { + bool want_iref = !(fan_flags & FAN_MARK_EVICTABLE); ++ unsigned int ignore = fan_flags & FANOTIFY_MARK_IGNORE_BITS; + bool recalc = false; + ++ /* ++ * When using FAN_MARK_IGNORE for the first time, mark starts using ++ * independent event flags in ignore mask. After that, trying to ++ * update the ignore mask with the old FAN_MARK_IGNORED_MASK API ++ * will result in EEXIST error. ++ */ ++ if (ignore == FAN_MARK_IGNORE) ++ fsn_mark->flags |= FSNOTIFY_MARK_FLAG_HAS_IGNORE_FLAGS; ++ + /* + * Setting FAN_MARK_IGNORED_SURV_MODIFY for the first time may lead to + * the removal of the FS_MODIFY bit in calculated mask if it was set + * because of an ignore mask that is now going to survive FS_MODIFY. + */ +- if ((fan_flags & FAN_MARK_IGNORED_MASK) && +- (fan_flags & FAN_MARK_IGNORED_SURV_MODIFY) && ++ if (ignore && (fan_flags & FAN_MARK_IGNORED_SURV_MODIFY) && + !(fsn_mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY)) { + fsn_mark->flags |= FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY; + if (!(fsn_mark->mask & FS_MODIFY)) +@@ -1108,7 +1117,7 @@ static bool fanotify_mark_add_to_mask(struct fsnotify_mark *fsn_mark, + bool recalc; + + spin_lock(&fsn_mark->lock); +- if (!(fan_flags & FAN_MARK_IGNORED_MASK)) ++ if (!(fan_flags & FANOTIFY_MARK_IGNORE_BITS)) + fsn_mark->mask |= mask; + else + fsn_mark->ignore_mask |= mask; +@@ -1185,6 +1194,24 @@ static int fanotify_may_update_existing_mark(struct fsnotify_mark *fsn_mark, + !(fsn_mark->flags & FSNOTIFY_MARK_FLAG_NO_IREF)) + return -EEXIST; + ++ /* ++ * New ignore mask semantics cannot be downgraded to old semantics. ++ */ ++ if (fan_flags & FAN_MARK_IGNORED_MASK && ++ fsn_mark->flags & FSNOTIFY_MARK_FLAG_HAS_IGNORE_FLAGS) ++ return -EEXIST; ++ ++ /* ++ * An ignore mask that survives modify could never be downgraded to not ++ * survive modify. With new FAN_MARK_IGNORE semantics we make that rule ++ * explicit and return an error when trying to update the ignore mask ++ * without the original FAN_MARK_IGNORED_SURV_MODIFY value. ++ */ ++ if (fan_flags & FAN_MARK_IGNORE && ++ !(fan_flags & FAN_MARK_IGNORED_SURV_MODIFY) && ++ fsn_mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY) ++ return -EEXIST; ++ + return 0; + } + +@@ -1219,7 +1246,8 @@ static int fanotify_add_mark(struct fsnotify_group *group, + * Error events are pre-allocated per group, only if strictly + * needed (i.e. FAN_FS_ERROR was requested). + */ +- if (!(fan_flags & FAN_MARK_IGNORED_MASK) && (mask & FAN_FS_ERROR)) { ++ if (!(fan_flags & FANOTIFY_MARK_IGNORE_BITS) && ++ (mask & FAN_FS_ERROR)) { + ret = fanotify_group_init_error_pool(group); + if (ret) + goto out; +@@ -1263,7 +1291,7 @@ static int fanotify_add_inode_mark(struct fsnotify_group *group, + * an ignore mask, unless that ignore mask is supposed to survive + * modification changes anyway. + */ +- if ((flags & FAN_MARK_IGNORED_MASK) && ++ if ((flags & FANOTIFY_MARK_IGNORE_BITS) && + !(flags & FAN_MARK_IGNORED_SURV_MODIFY) && + inode_is_open_for_write(inode)) + return 0; +@@ -1519,7 +1547,8 @@ static int fanotify_events_supported(struct fsnotify_group *group, + unsigned int mark_type = flags & FANOTIFY_MARK_TYPE_BITS; + /* Strict validation of events in non-dir inode mask with v5.17+ APIs */ + bool strict_dir_events = FAN_GROUP_FLAG(group, FAN_REPORT_TARGET_FID) || +- (mask & FAN_RENAME); ++ (mask & FAN_RENAME) || ++ (flags & FAN_MARK_IGNORE); + + /* + * Some filesystems such as 'proc' acquire unusual locks when opening +@@ -1571,7 +1600,7 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, + u32 valid_mask = FANOTIFY_EVENTS | FANOTIFY_EVENT_FLAGS; + unsigned int mark_type = flags & FANOTIFY_MARK_TYPE_BITS; + unsigned int mark_cmd = flags & FANOTIFY_MARK_CMD_BITS; +- bool ignore = flags & FAN_MARK_IGNORED_MASK; ++ unsigned int ignore = flags & FANOTIFY_MARK_IGNORE_BITS; + unsigned int obj_type, fid_mode; + u32 umask = 0; + int ret; +@@ -1620,12 +1649,19 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, + if (mask & ~valid_mask) + return -EINVAL; + ++ ++ /* We don't allow FAN_MARK_IGNORE & FAN_MARK_IGNORED_MASK together */ ++ if (ignore == (FAN_MARK_IGNORE | FAN_MARK_IGNORED_MASK)) ++ return -EINVAL; ++ + /* + * Event flags (FAN_ONDIR, FAN_EVENT_ON_CHILD) have no effect with + * FAN_MARK_IGNORED_MASK. + */ +- if (ignore) ++ if (ignore == FAN_MARK_IGNORED_MASK) { + mask &= ~FANOTIFY_EVENT_FLAGS; ++ umask = FANOTIFY_EVENT_FLAGS; ++ } + + f = fdget(fanotify_fd); + if (unlikely(!f.file)) +@@ -1729,6 +1765,13 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, + else + mnt = path.mnt; + ++ ret = mnt ? -EINVAL : -EISDIR; ++ /* FAN_MARK_IGNORE requires SURV_MODIFY for sb/mount/dir marks */ ++ if (mark_cmd == FAN_MARK_ADD && ignore == FAN_MARK_IGNORE && ++ (mnt || S_ISDIR(inode->i_mode)) && ++ !(flags & FAN_MARK_IGNORED_SURV_MODIFY)) ++ goto path_put_and_out; ++ + /* Mask out FAN_EVENT_ON_CHILD flag for sb/mount/non-dir marks */ + if (mnt || !S_ISDIR(inode->i_mode)) { + mask &= ~FAN_EVENT_ON_CHILD; +@@ -1821,7 +1864,7 @@ static int __init fanotify_user_setup(void) + + BUILD_BUG_ON(FANOTIFY_INIT_FLAGS & FANOTIFY_INTERNAL_GROUP_FLAGS); + BUILD_BUG_ON(HWEIGHT32(FANOTIFY_INIT_FLAGS) != 12); +- BUILD_BUG_ON(HWEIGHT32(FANOTIFY_MARK_FLAGS) != 10); ++ BUILD_BUG_ON(HWEIGHT32(FANOTIFY_MARK_FLAGS) != 11); + + fanotify_mark_cache = KMEM_CACHE(fsnotify_mark, + SLAB_PANIC|SLAB_ACCOUNT); +diff --git a/include/linux/fanotify.h b/include/linux/fanotify.h +index c9e185407ebcb..558844c8d2598 100644 +--- a/include/linux/fanotify.h ++++ b/include/linux/fanotify.h +@@ -64,11 +64,14 @@ extern struct ctl_table fanotify_table[]; /* for sysctl */ + #define FANOTIFY_MARK_CMD_BITS (FAN_MARK_ADD | FAN_MARK_REMOVE | \ + FAN_MARK_FLUSH) + ++#define FANOTIFY_MARK_IGNORE_BITS (FAN_MARK_IGNORED_MASK | \ ++ FAN_MARK_IGNORE) ++ + #define FANOTIFY_MARK_FLAGS (FANOTIFY_MARK_TYPE_BITS | \ + FANOTIFY_MARK_CMD_BITS | \ ++ FANOTIFY_MARK_IGNORE_BITS | \ + FAN_MARK_DONT_FOLLOW | \ + FAN_MARK_ONLYDIR | \ +- FAN_MARK_IGNORED_MASK | \ + FAN_MARK_IGNORED_SURV_MODIFY | \ + FAN_MARK_EVICTABLE) + +diff --git a/include/uapi/linux/fanotify.h b/include/uapi/linux/fanotify.h +index f1f89132d60e2..d8536d77fea1c 100644 +--- a/include/uapi/linux/fanotify.h ++++ b/include/uapi/linux/fanotify.h +@@ -83,12 +83,20 @@ + #define FAN_MARK_FLUSH 0x00000080 + /* FAN_MARK_FILESYSTEM is 0x00000100 */ + #define FAN_MARK_EVICTABLE 0x00000200 ++/* This bit is mutually exclusive with FAN_MARK_IGNORED_MASK bit */ ++#define FAN_MARK_IGNORE 0x00000400 + + /* These are NOT bitwise flags. Both bits can be used togther. */ + #define FAN_MARK_INODE 0x00000000 + #define FAN_MARK_MOUNT 0x00000010 + #define FAN_MARK_FILESYSTEM 0x00000100 + ++/* ++ * Convenience macro - FAN_MARK_IGNORE requires FAN_MARK_IGNORED_SURV_MODIFY ++ * for non-inode mark types. ++ */ ++#define FAN_MARK_IGNORE_SURV (FAN_MARK_IGNORE | FAN_MARK_IGNORED_SURV_MODIFY) ++ + /* Deprecated - do not use this in programs and do not add new flags here! */ + #define FAN_ALL_MARK_FLAGS (FAN_MARK_ADD |\ + FAN_MARK_REMOVE |\ +-- +2.43.0 + diff --git a/queue-5.10/fanotify-introduce-group-flag-fan_report_target_fid.patch b/queue-5.10/fanotify-introduce-group-flag-fan_report_target_fid.patch new file mode 100644 index 00000000000..2d02943be50 --- /dev/null +++ b/queue-5.10/fanotify-introduce-group-flag-fan_report_target_fid.patch @@ -0,0 +1,178 @@ +From 014a84fdad8bb329903556db8a51df325cf2dd1f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Nov 2021 22:15:29 +0200 +Subject: fanotify: introduce group flag FAN_REPORT_TARGET_FID + +From: Amir Goldstein + +[ Upstream commit d61fd650e9d206a71fda789f02a1ced4b19944c4 ] + +FAN_REPORT_FID is ambiguous in that it reports the fid of the child for +some events and the fid of the parent for create/delete/move events. + +The new FAN_REPORT_TARGET_FID flag is an implicit request to report +the fid of the target object of the operation (a.k.a the child inode) +also in create/delete/move events in addition to the fid of the parent +and the name of the child. + +To reduce the test matrix for uninteresting use cases, the new +FAN_REPORT_TARGET_FID flag requires both FAN_REPORT_NAME and +FAN_REPORT_FID. The convenience macro FAN_REPORT_DFID_NAME_TARGET +combines FAN_REPORT_TARGET_FID with all the required flags. + +Link: https://lore.kernel.org/r/20211129201537.1932819-4-amir73il@gmail.com +Signed-off-by: Amir Goldstein +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify.c | 48 ++++++++++++++++++++++-------- + fs/notify/fanotify/fanotify_user.c | 11 ++++++- + include/linux/fanotify.h | 2 +- + include/uapi/linux/fanotify.h | 4 +++ + 4 files changed, 51 insertions(+), 14 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c +index 652fe84cb8acd..85e542b164c8c 100644 +--- a/fs/notify/fanotify/fanotify.c ++++ b/fs/notify/fanotify/fanotify.c +@@ -458,17 +458,41 @@ static int fanotify_encode_fh(struct fanotify_fh *fh, struct inode *inode, + } + + /* +- * The inode to use as identifier when reporting fid depends on the event. +- * Report the modified directory inode on dirent modification events. +- * Report the "victim" inode otherwise. ++ * FAN_REPORT_FID is ambiguous in that it reports the fid of the child for ++ * some events and the fid of the parent for create/delete/move events. ++ * ++ * With the FAN_REPORT_TARGET_FID flag, the fid of the child is reported ++ * also in create/delete/move events in addition to the fid of the parent ++ * and the name of the child. ++ */ ++static inline bool fanotify_report_child_fid(unsigned int fid_mode, u32 mask) ++{ ++ if (mask & ALL_FSNOTIFY_DIRENT_EVENTS) ++ return (fid_mode & FAN_REPORT_TARGET_FID); ++ ++ return (fid_mode & FAN_REPORT_FID) && !(mask & FAN_ONDIR); ++} ++ ++/* ++ * The inode to use as identifier when reporting fid depends on the event ++ * and the group flags. ++ * ++ * With the group flag FAN_REPORT_TARGET_FID, always report the child fid. ++ * ++ * Without the group flag FAN_REPORT_TARGET_FID, report the modified directory ++ * fid on dirent events and the child fid otherwise. ++ * + * For example: +- * FS_ATTRIB reports the child inode even if reported on a watched parent. +- * FS_CREATE reports the modified dir inode and not the created inode. ++ * FS_ATTRIB reports the child fid even if reported on a watched parent. ++ * FS_CREATE reports the modified dir fid without FAN_REPORT_TARGET_FID. ++ * and reports the created child fid with FAN_REPORT_TARGET_FID. + */ + static struct inode *fanotify_fid_inode(u32 event_mask, const void *data, +- int data_type, struct inode *dir) ++ int data_type, struct inode *dir, ++ unsigned int fid_mode) + { +- if (event_mask & ALL_FSNOTIFY_DIRENT_EVENTS) ++ if ((event_mask & ALL_FSNOTIFY_DIRENT_EVENTS) && ++ !(fid_mode & FAN_REPORT_TARGET_FID)) + return dir; + + return fsnotify_data_inode(data, data_type); +@@ -647,10 +671,11 @@ static struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group, + { + struct fanotify_event *event = NULL; + gfp_t gfp = GFP_KERNEL_ACCOUNT; +- struct inode *id = fanotify_fid_inode(mask, data, data_type, dir); ++ unsigned int fid_mode = FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS); ++ struct inode *id = fanotify_fid_inode(mask, data, data_type, dir, ++ fid_mode); + struct inode *dirid = fanotify_dfid_inode(mask, data, data_type, dir); + const struct path *path = fsnotify_data_path(data, data_type); +- unsigned int fid_mode = FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS); + struct mem_cgroup *old_memcg; + struct inode *child = NULL; + bool name_event = false; +@@ -660,11 +685,10 @@ static struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group, + + if ((fid_mode & FAN_REPORT_DIR_FID) && dirid) { + /* +- * With both flags FAN_REPORT_DIR_FID and FAN_REPORT_FID, we +- * report the child fid for events reported on a non-dir child ++ * For certain events and group flags, report the child fid + * in addition to reporting the parent fid and maybe child name. + */ +- if ((fid_mode & FAN_REPORT_FID) && id != dirid && !ondir) ++ if (fanotify_report_child_fid(fid_mode, mask) && id != dirid) + child = id; + + id = dirid; +diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c +index 2f78999a7aa3d..6b058d652f47b 100644 +--- a/fs/notify/fanotify/fanotify_user.c ++++ b/fs/notify/fanotify/fanotify_user.c +@@ -1270,6 +1270,15 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) + if ((fid_mode & FAN_REPORT_NAME) && !(fid_mode & FAN_REPORT_DIR_FID)) + return -EINVAL; + ++ /* ++ * FAN_REPORT_TARGET_FID requires FAN_REPORT_NAME and FAN_REPORT_FID ++ * and is used as an indication to report both dir and child fid on all ++ * dirent events. ++ */ ++ if ((fid_mode & FAN_REPORT_TARGET_FID) && ++ (!(fid_mode & FAN_REPORT_NAME) || !(fid_mode & FAN_REPORT_FID))) ++ return -EINVAL; ++ + f_flags = O_RDWR | FMODE_NONOTIFY; + if (flags & FAN_CLOEXEC) + f_flags |= O_CLOEXEC; +@@ -1680,7 +1689,7 @@ static int __init fanotify_user_setup(void) + FANOTIFY_DEFAULT_MAX_USER_MARKS); + + BUILD_BUG_ON(FANOTIFY_INIT_FLAGS & FANOTIFY_INTERNAL_GROUP_FLAGS); +- BUILD_BUG_ON(HWEIGHT32(FANOTIFY_INIT_FLAGS) != 11); ++ BUILD_BUG_ON(HWEIGHT32(FANOTIFY_INIT_FLAGS) != 12); + BUILD_BUG_ON(HWEIGHT32(FANOTIFY_MARK_FLAGS) != 9); + + fanotify_mark_cache = KMEM_CACHE(fsnotify_mark, +diff --git a/include/linux/fanotify.h b/include/linux/fanotify.h +index 616af2ea20f30..376e050e6f384 100644 +--- a/include/linux/fanotify.h ++++ b/include/linux/fanotify.h +@@ -25,7 +25,7 @@ extern struct ctl_table fanotify_table[]; /* for sysctl */ + + #define FANOTIFY_CLASS_BITS (FAN_CLASS_NOTIF | FANOTIFY_PERM_CLASSES) + +-#define FANOTIFY_FID_BITS (FAN_REPORT_FID | FAN_REPORT_DFID_NAME) ++#define FANOTIFY_FID_BITS (FAN_REPORT_DFID_NAME_TARGET) + + #define FANOTIFY_INFO_MODES (FANOTIFY_FID_BITS | FAN_REPORT_PIDFD) + +diff --git a/include/uapi/linux/fanotify.h b/include/uapi/linux/fanotify.h +index bd1932c2074d5..60f73639a896a 100644 +--- a/include/uapi/linux/fanotify.h ++++ b/include/uapi/linux/fanotify.h +@@ -57,9 +57,13 @@ + #define FAN_REPORT_FID 0x00000200 /* Report unique file id */ + #define FAN_REPORT_DIR_FID 0x00000400 /* Report unique directory id */ + #define FAN_REPORT_NAME 0x00000800 /* Report events with name */ ++#define FAN_REPORT_TARGET_FID 0x00001000 /* Report dirent target id */ + + /* Convenience macro - FAN_REPORT_NAME requires FAN_REPORT_DIR_FID */ + #define FAN_REPORT_DFID_NAME (FAN_REPORT_DIR_FID | FAN_REPORT_NAME) ++/* Convenience macro - FAN_REPORT_TARGET_FID requires all other FID flags */ ++#define FAN_REPORT_DFID_NAME_TARGET (FAN_REPORT_DFID_NAME | \ ++ FAN_REPORT_FID | FAN_REPORT_TARGET_FID) + + /* Deprecated - do not use this in programs and do not add new flags here! */ + #define FAN_ALL_INIT_FLAGS (FAN_CLOEXEC | FAN_NONBLOCK | \ +-- +2.43.0 + diff --git a/queue-5.10/fanotify-limit-number-of-event-merge-attempts.patch-30929 b/queue-5.10/fanotify-limit-number-of-event-merge-attempts.patch-30929 new file mode 100644 index 00000000000..710f9935cf0 --- /dev/null +++ b/queue-5.10/fanotify-limit-number-of-event-merge-attempts.patch-30929 @@ -0,0 +1,58 @@ +From 76608fa6240eaaefbae1926e528eec908054dccd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Mar 2021 12:48:26 +0200 +Subject: fanotify: limit number of event merge attempts + +From: Amir Goldstein + +[ Upstream commit b8cd0ee8cda68a888a317991c1e918a8cba1a568 ] + +Event merges are expensive when event queue size is large, so limit the +linear search to 128 merge tests. + +In combination with 128 size hash table, there is a potential to merge +with up to 16K events in the hashed queue. + +Link: https://lore.kernel.org/r/20210304104826.3993892-6-amir73il@gmail.com +Signed-off-by: Amir Goldstein +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c +index 50b3abc062156..754e27ead8742 100644 +--- a/fs/notify/fanotify/fanotify.c ++++ b/fs/notify/fanotify/fanotify.c +@@ -148,6 +148,9 @@ static bool fanotify_should_merge(struct fanotify_event *old, + return false; + } + ++/* Limit event merges to limit CPU overhead per event */ ++#define FANOTIFY_MAX_MERGE_EVENTS 128 ++ + /* and the list better be locked by something too! */ + static int fanotify_merge(struct fsnotify_group *group, + struct fsnotify_event *event) +@@ -155,6 +158,7 @@ static int fanotify_merge(struct fsnotify_group *group, + struct fanotify_event *old, *new = FANOTIFY_E(event); + unsigned int bucket = fanotify_event_hash_bucket(group, new); + struct hlist_head *hlist = &group->fanotify_data.merge_hash[bucket]; ++ int i = 0; + + pr_debug("%s: group=%p event=%p bucket=%u\n", __func__, + group, event, bucket); +@@ -168,6 +172,8 @@ static int fanotify_merge(struct fsnotify_group *group, + return 0; + + hlist_for_each_entry(old, hlist, merge_list) { ++ if (++i > FANOTIFY_MAX_MERGE_EVENTS) ++ break; + if (fanotify_should_merge(old, new)) { + old->mask |= new->mask; + return 1; +-- +2.43.0 + diff --git a/queue-5.10/fanotify-minor-cosmetic-adjustments-to-fid-labels.patch b/queue-5.10/fanotify-minor-cosmetic-adjustments-to-fid-labels.patch new file mode 100644 index 00000000000..3a5f2709d6e --- /dev/null +++ b/queue-5.10/fanotify-minor-cosmetic-adjustments-to-fid-labels.patch @@ -0,0 +1,120 @@ +From 5973d0fd3e212585fe79c28f3367e7e0b7e829cc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 8 Aug 2021 15:25:32 +1000 +Subject: fanotify: minor cosmetic adjustments to fid labels + +From: Matthew Bobrowski + +[ Upstream commit d3424c9bac893bd06f38a20474cd622881d384ca ] + +With the idea to support additional info record types in the future +i.e. fanotify_event_info_pidfd, it's a good idea to rename some of the +labels assigned to some of the existing fid related functions, +parameters, etc which more accurately represent the intent behind +their usage. + +For example, copy_info_to_user() was defined with a generic function +label, which arguably reads as being supportive of different info +record types, however the parameter list for this function is +explicitly tailored towards the creation and copying of the +fanotify_event_info_fid records. This same point applies to the macro +defined as FANOTIFY_INFO_HDR_LEN. + +With fanotify_event_info_len(), we change the parameter label so that +the function implies that it can be extended to calculate the length +for additional info record types. + +Link: https://lore.kernel.org/r/7c3ec33f3c718dac40764305d4d494d858f59c51.1628398044.git.repnop@google.com +Signed-off-by: Matthew Bobrowski +Reviewed-by: Amir Goldstein +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify_user.c | 33 +++++++++++++++++------------- + 1 file changed, 19 insertions(+), 14 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c +index 1c439e2fdcd80..74b51dab2cdce 100644 +--- a/fs/notify/fanotify/fanotify_user.c ++++ b/fs/notify/fanotify/fanotify_user.c +@@ -104,7 +104,7 @@ struct kmem_cache *fanotify_path_event_cachep __read_mostly; + struct kmem_cache *fanotify_perm_event_cachep __read_mostly; + + #define FANOTIFY_EVENT_ALIGN 4 +-#define FANOTIFY_INFO_HDR_LEN \ ++#define FANOTIFY_FID_INFO_HDR_LEN \ + (sizeof(struct fanotify_event_info_fid) + sizeof(struct file_handle)) + + static int fanotify_fid_info_len(int fh_len, int name_len) +@@ -114,10 +114,11 @@ static int fanotify_fid_info_len(int fh_len, int name_len) + if (name_len) + info_len += name_len + 1; + +- return roundup(FANOTIFY_INFO_HDR_LEN + info_len, FANOTIFY_EVENT_ALIGN); ++ return roundup(FANOTIFY_FID_INFO_HDR_LEN + info_len, ++ FANOTIFY_EVENT_ALIGN); + } + +-static int fanotify_event_info_len(unsigned int fid_mode, ++static int fanotify_event_info_len(unsigned int info_mode, + struct fanotify_event *event) + { + struct fanotify_info *info = fanotify_event_info(event); +@@ -128,7 +129,8 @@ static int fanotify_event_info_len(unsigned int fid_mode, + + if (dir_fh_len) { + info_len += fanotify_fid_info_len(dir_fh_len, info->name_len); +- } else if ((fid_mode & FAN_REPORT_NAME) && (event->mask & FAN_ONDIR)) { ++ } else if ((info_mode & FAN_REPORT_NAME) && ++ (event->mask & FAN_ONDIR)) { + /* + * With group flag FAN_REPORT_NAME, if name was not recorded in + * event on a directory, we will report the name ".". +@@ -303,9 +305,10 @@ static int process_access_response(struct fsnotify_group *group, + return -ENOENT; + } + +-static int copy_info_to_user(__kernel_fsid_t *fsid, struct fanotify_fh *fh, +- int info_type, const char *name, size_t name_len, +- char __user *buf, size_t count) ++static int copy_fid_info_to_user(__kernel_fsid_t *fsid, struct fanotify_fh *fh, ++ int info_type, const char *name, ++ size_t name_len, ++ char __user *buf, size_t count) + { + struct fanotify_event_info_fid info = { }; + struct file_handle handle = { }; +@@ -463,10 +466,11 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group, + if (fanotify_event_dir_fh_len(event)) { + info_type = info->name_len ? FAN_EVENT_INFO_TYPE_DFID_NAME : + FAN_EVENT_INFO_TYPE_DFID; +- ret = copy_info_to_user(fanotify_event_fsid(event), +- fanotify_info_dir_fh(info), +- info_type, fanotify_info_name(info), +- info->name_len, buf, count); ++ ret = copy_fid_info_to_user(fanotify_event_fsid(event), ++ fanotify_info_dir_fh(info), ++ info_type, ++ fanotify_info_name(info), ++ info->name_len, buf, count); + if (ret < 0) + goto out_close_fd; + +@@ -512,9 +516,10 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group, + info_type = FAN_EVENT_INFO_TYPE_FID; + } + +- ret = copy_info_to_user(fanotify_event_fsid(event), +- fanotify_event_object_fh(event), +- info_type, dot, dot_len, buf, count); ++ ret = copy_fid_info_to_user(fanotify_event_fsid(event), ++ fanotify_event_object_fh(event), ++ info_type, dot, dot_len, ++ buf, count); + if (ret < 0) + goto out_close_fd; + +-- +2.43.0 + diff --git a/queue-5.10/fanotify-mix-event-info-and-pid-into-merge-key-hash.patch b/queue-5.10/fanotify-mix-event-info-and-pid-into-merge-key-hash.patch new file mode 100644 index 00000000000..93069a7fa9d --- /dev/null +++ b/queue-5.10/fanotify-mix-event-info-and-pid-into-merge-key-hash.patch @@ -0,0 +1,273 @@ +From a489b28a950ca7da5ada6fc595d61667e8deb41b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Mar 2021 12:48:24 +0200 +Subject: fanotify: mix event info and pid into merge key hash + +From: Amir Goldstein + +[ Upstream commit 7e3e5c6943994943eb76cab2d3a1806bc10b9045 ] + +Improve the merge key hash by mixing more values relevant for merge. + +For example, all FAN_CREATE name events in the same dir used to have the +same merge key based on the dir inode. With this change the created +file name is mixed into the merge key. + +The object id that was used as merge key is redundant to the event info +so it is no longer mixed into the hash. + +Permission events are not hashed, so no need to hash their info. + +Link: https://lore.kernel.org/r/20210304104826.3993892-4-amir73il@gmail.com +Signed-off-by: Amir Goldstein +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify.c | 87 ++++++++++++++++++++++++----------- + fs/notify/fanotify/fanotify.h | 5 ++ + 2 files changed, 66 insertions(+), 26 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c +index 8a2bb6954e02c..43a606f153702 100644 +--- a/fs/notify/fanotify/fanotify.c ++++ b/fs/notify/fanotify/fanotify.c +@@ -14,6 +14,7 @@ + #include + #include + #include ++#include + + #include "fanotify.h" + +@@ -22,12 +23,24 @@ static bool fanotify_path_equal(struct path *p1, struct path *p2) + return p1->mnt == p2->mnt && p1->dentry == p2->dentry; + } + ++static unsigned int fanotify_hash_path(const struct path *path) ++{ ++ return hash_ptr(path->dentry, FANOTIFY_EVENT_HASH_BITS) ^ ++ hash_ptr(path->mnt, FANOTIFY_EVENT_HASH_BITS); ++} ++ + static inline bool fanotify_fsid_equal(__kernel_fsid_t *fsid1, + __kernel_fsid_t *fsid2) + { + return fsid1->val[0] == fsid2->val[0] && fsid1->val[1] == fsid2->val[1]; + } + ++static unsigned int fanotify_hash_fsid(__kernel_fsid_t *fsid) ++{ ++ return hash_32(fsid->val[0], FANOTIFY_EVENT_HASH_BITS) ^ ++ hash_32(fsid->val[1], FANOTIFY_EVENT_HASH_BITS); ++} ++ + static bool fanotify_fh_equal(struct fanotify_fh *fh1, + struct fanotify_fh *fh2) + { +@@ -38,6 +51,16 @@ static bool fanotify_fh_equal(struct fanotify_fh *fh1, + !memcmp(fanotify_fh_buf(fh1), fanotify_fh_buf(fh2), fh1->len); + } + ++static unsigned int fanotify_hash_fh(struct fanotify_fh *fh) ++{ ++ long salt = (long)fh->type | (long)fh->len << 8; ++ ++ /* ++ * full_name_hash() works long by long, so it handles fh buf optimally. ++ */ ++ return full_name_hash((void *)salt, fanotify_fh_buf(fh), fh->len); ++} ++ + static bool fanotify_fid_event_equal(struct fanotify_fid_event *ffe1, + struct fanotify_fid_event *ffe2) + { +@@ -325,7 +348,8 @@ static int fanotify_encode_fh_len(struct inode *inode) + * Return 0 on failure to encode. + */ + static int fanotify_encode_fh(struct fanotify_fh *fh, struct inode *inode, +- unsigned int fh_len, gfp_t gfp) ++ unsigned int fh_len, unsigned int *hash, ++ gfp_t gfp) + { + int dwords, type = 0; + char *ext_buf = NULL; +@@ -368,6 +392,9 @@ static int fanotify_encode_fh(struct fanotify_fh *fh, struct inode *inode, + fh->type = type; + fh->len = fh_len; + ++ /* Mix fh into event merge key */ ++ *hash ^= fanotify_hash_fh(fh); ++ + return FANOTIFY_FH_HDR_LEN + fh_len; + + out_err: +@@ -421,6 +448,7 @@ static struct inode *fanotify_dfid_inode(u32 event_mask, const void *data, + } + + static struct fanotify_event *fanotify_alloc_path_event(const struct path *path, ++ unsigned int *hash, + gfp_t gfp) + { + struct fanotify_path_event *pevent; +@@ -431,6 +459,7 @@ static struct fanotify_event *fanotify_alloc_path_event(const struct path *path, + + pevent->fae.type = FANOTIFY_EVENT_TYPE_PATH; + pevent->path = *path; ++ *hash ^= fanotify_hash_path(path); + path_get(path); + + return &pevent->fae; +@@ -456,6 +485,7 @@ static struct fanotify_event *fanotify_alloc_perm_event(const struct path *path, + + static struct fanotify_event *fanotify_alloc_fid_event(struct inode *id, + __kernel_fsid_t *fsid, ++ unsigned int *hash, + gfp_t gfp) + { + struct fanotify_fid_event *ffe; +@@ -466,16 +496,18 @@ static struct fanotify_event *fanotify_alloc_fid_event(struct inode *id, + + ffe->fae.type = FANOTIFY_EVENT_TYPE_FID; + ffe->fsid = *fsid; ++ *hash ^= fanotify_hash_fsid(fsid); + fanotify_encode_fh(&ffe->object_fh, id, fanotify_encode_fh_len(id), +- gfp); ++ hash, gfp); + + return &ffe->fae; + } + + static struct fanotify_event *fanotify_alloc_name_event(struct inode *id, + __kernel_fsid_t *fsid, +- const struct qstr *file_name, ++ const struct qstr *name, + struct inode *child, ++ unsigned int *hash, + gfp_t gfp) + { + struct fanotify_name_event *fne; +@@ -488,24 +520,30 @@ static struct fanotify_event *fanotify_alloc_name_event(struct inode *id, + size = sizeof(*fne) + FANOTIFY_FH_HDR_LEN + dir_fh_len; + if (child_fh_len) + size += FANOTIFY_FH_HDR_LEN + child_fh_len; +- if (file_name) +- size += file_name->len + 1; ++ if (name) ++ size += name->len + 1; + fne = kmalloc(size, gfp); + if (!fne) + return NULL; + + fne->fae.type = FANOTIFY_EVENT_TYPE_FID_NAME; + fne->fsid = *fsid; ++ *hash ^= fanotify_hash_fsid(fsid); + info = &fne->info; + fanotify_info_init(info); + dfh = fanotify_info_dir_fh(info); +- info->dir_fh_totlen = fanotify_encode_fh(dfh, id, dir_fh_len, 0); ++ info->dir_fh_totlen = fanotify_encode_fh(dfh, id, dir_fh_len, hash, 0); + if (child_fh_len) { + ffh = fanotify_info_file_fh(info); +- info->file_fh_totlen = fanotify_encode_fh(ffh, child, child_fh_len, 0); ++ info->file_fh_totlen = fanotify_encode_fh(ffh, child, ++ child_fh_len, hash, 0); ++ } ++ if (name) { ++ long salt = name->len; ++ ++ fanotify_info_copy_name(info, name); ++ *hash ^= full_name_hash((void *)salt, name->name, name->len); + } +- if (file_name) +- fanotify_info_copy_name(info, file_name); + + pr_debug("%s: ino=%lu size=%u dir_fh_len=%u child_fh_len=%u name_len=%u name='%.*s'\n", + __func__, id->i_ino, size, dir_fh_len, child_fh_len, +@@ -530,6 +568,8 @@ static struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group, + struct inode *child = NULL; + bool name_event = false; + unsigned int hash = 0; ++ bool ondir = mask & FAN_ONDIR; ++ struct pid *pid; + + if ((fid_mode & FAN_REPORT_DIR_FID) && dirid) { + /* +@@ -537,8 +577,7 @@ static struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group, + * report the child fid for events reported on a non-dir child + * in addition to reporting the parent fid and maybe child name. + */ +- if ((fid_mode & FAN_REPORT_FID) && +- id != dirid && !(mask & FAN_ONDIR)) ++ if ((fid_mode & FAN_REPORT_FID) && id != dirid && !ondir) + child = id; + + id = dirid; +@@ -559,8 +598,7 @@ static struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group, + if (!(fid_mode & FAN_REPORT_NAME)) { + name_event = !!child; + file_name = NULL; +- } else if ((mask & ALL_FSNOTIFY_DIRENT_EVENTS) || +- !(mask & FAN_ONDIR)) { ++ } else if ((mask & ALL_FSNOTIFY_DIRENT_EVENTS) || !ondir) { + name_event = true; + } + } +@@ -583,28 +621,25 @@ static struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group, + event = fanotify_alloc_perm_event(path, gfp); + } else if (name_event && (file_name || child)) { + event = fanotify_alloc_name_event(id, fsid, file_name, child, +- gfp); ++ &hash, gfp); + } else if (fid_mode) { +- event = fanotify_alloc_fid_event(id, fsid, gfp); ++ event = fanotify_alloc_fid_event(id, fsid, &hash, gfp); + } else { +- event = fanotify_alloc_path_event(path, gfp); ++ event = fanotify_alloc_path_event(path, &hash, gfp); + } + + if (!event) + goto out; + +- /* +- * Use the victim inode instead of the watching inode as the id for +- * event queue, so event reported on parent is merged with event +- * reported on child when both directory and child watches exist. +- * Hash object id for queue merge. +- */ +- hash = hash_ptr(id, FANOTIFY_EVENT_HASH_BITS); +- fanotify_init_event(event, hash, mask); + if (FAN_GROUP_FLAG(group, FAN_REPORT_TID)) +- event->pid = get_pid(task_pid(current)); ++ pid = get_pid(task_pid(current)); + else +- event->pid = get_pid(task_tgid(current)); ++ pid = get_pid(task_tgid(current)); ++ ++ /* Mix event info, FAN_ONDIR flag and pid into event merge key */ ++ hash ^= hash_long((unsigned long)pid | ondir, FANOTIFY_EVENT_HASH_BITS); ++ fanotify_init_event(event, hash, mask); ++ event->pid = pid; + + out: + set_active_memcg(old_memcg); +diff --git a/fs/notify/fanotify/fanotify.h b/fs/notify/fanotify/fanotify.h +index d531f0cfa46f2..9871f76cd9c2c 100644 +--- a/fs/notify/fanotify/fanotify.h ++++ b/fs/notify/fanotify/fanotify.h +@@ -115,6 +115,11 @@ static inline void fanotify_info_init(struct fanotify_info *info) + info->name_len = 0; + } + ++static inline unsigned int fanotify_info_len(struct fanotify_info *info) ++{ ++ return info->dir_fh_totlen + info->file_fh_totlen + info->name_len; ++} ++ + static inline void fanotify_info_copy_name(struct fanotify_info *info, + const struct qstr *name) + { +-- +2.43.0 + diff --git a/queue-5.10/fanotify-pre-allocate-pool-of-error-events.patch b/queue-5.10/fanotify-pre-allocate-pool-of-error-events.patch new file mode 100644 index 00000000000..61afb626141 --- /dev/null +++ b/queue-5.10/fanotify-pre-allocate-pool-of-error-events.patch @@ -0,0 +1,158 @@ +From cd5484dec48fe72a71cedaca309246003f9b7cbd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 Oct 2021 16:27:34 -0300 +Subject: fanotify: Pre-allocate pool of error events + +From: Gabriel Krisman Bertazi + +[ Upstream commit 734a1a5eccc5f7473002b0669f788e135f1f64aa ] + +Pre-allocate slots for file system errors to have greater chances of +succeeding, since error events can happen in GFP_NOFS context. This +patch introduces a group-wide mempool of error events, shared by all +FAN_FS_ERROR marks in this group. + +Link: https://lore.kernel.org/r/20211025192746.66445-20-krisman@collabora.com +Reviewed-by: Amir Goldstein +Reviewed-by: Jan Kara +Signed-off-by: Gabriel Krisman Bertazi +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify.c | 3 +++ + fs/notify/fanotify/fanotify.h | 11 +++++++++++ + fs/notify/fanotify/fanotify_user.c | 26 +++++++++++++++++++++++++- + include/linux/fsnotify_backend.h | 2 ++ + 4 files changed, 41 insertions(+), 1 deletion(-) + +diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c +index 8f152445d75c4..01d68dfc74aa2 100644 +--- a/fs/notify/fanotify/fanotify.c ++++ b/fs/notify/fanotify/fanotify.c +@@ -819,6 +819,9 @@ static void fanotify_free_group_priv(struct fsnotify_group *group) + if (group->fanotify_data.ucounts) + dec_ucount(group->fanotify_data.ucounts, + UCOUNT_FANOTIFY_GROUPS); ++ ++ if (mempool_initialized(&group->fanotify_data.error_events_pool)) ++ mempool_exit(&group->fanotify_data.error_events_pool); + } + + static void fanotify_free_path_event(struct fanotify_event *event) +diff --git a/fs/notify/fanotify/fanotify.h b/fs/notify/fanotify/fanotify.h +index c42cf8fd7d798..a577e87fac2b4 100644 +--- a/fs/notify/fanotify/fanotify.h ++++ b/fs/notify/fanotify/fanotify.h +@@ -141,6 +141,7 @@ enum fanotify_event_type { + FANOTIFY_EVENT_TYPE_PATH, + FANOTIFY_EVENT_TYPE_PATH_PERM, + FANOTIFY_EVENT_TYPE_OVERFLOW, /* struct fanotify_event */ ++ FANOTIFY_EVENT_TYPE_FS_ERROR, /* struct fanotify_error_event */ + __FANOTIFY_EVENT_TYPE_NUM + }; + +@@ -196,6 +197,16 @@ FANOTIFY_NE(struct fanotify_event *event) + return container_of(event, struct fanotify_name_event, fae); + } + ++struct fanotify_error_event { ++ struct fanotify_event fae; ++}; ++ ++static inline struct fanotify_error_event * ++FANOTIFY_EE(struct fanotify_event *event) ++{ ++ return container_of(event, struct fanotify_error_event, fae); ++} ++ + static inline __kernel_fsid_t *fanotify_event_fsid(struct fanotify_event *event) + { + if (event->type == FANOTIFY_EVENT_TYPE_FID) +diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c +index 34bf71108f7a3..8a2b7941fc986 100644 +--- a/fs/notify/fanotify/fanotify_user.c ++++ b/fs/notify/fanotify/fanotify_user.c +@@ -30,6 +30,7 @@ + #define FANOTIFY_DEFAULT_MAX_EVENTS 16384 + #define FANOTIFY_OLD_DEFAULT_MAX_MARKS 8192 + #define FANOTIFY_DEFAULT_MAX_GROUPS 128 ++#define FANOTIFY_DEFAULT_FEE_POOL_SIZE 32 + + /* + * Legacy fanotify marks limits (8192) is per group and we introduced a tunable +@@ -1049,6 +1050,15 @@ static struct fsnotify_mark *fanotify_add_new_mark(struct fsnotify_group *group, + return ERR_PTR(ret); + } + ++static int fanotify_group_init_error_pool(struct fsnotify_group *group) ++{ ++ if (mempool_initialized(&group->fanotify_data.error_events_pool)) ++ return 0; ++ ++ return mempool_init_kmalloc_pool(&group->fanotify_data.error_events_pool, ++ FANOTIFY_DEFAULT_FEE_POOL_SIZE, ++ sizeof(struct fanotify_error_event)); ++} + + static int fanotify_add_mark(struct fsnotify_group *group, + fsnotify_connp_t *connp, unsigned int type, +@@ -1057,6 +1067,7 @@ static int fanotify_add_mark(struct fsnotify_group *group, + { + struct fsnotify_mark *fsn_mark; + __u32 added; ++ int ret = 0; + + mutex_lock(&group->mark_mutex); + fsn_mark = fsnotify_find_mark(connp, group); +@@ -1067,13 +1078,26 @@ static int fanotify_add_mark(struct fsnotify_group *group, + return PTR_ERR(fsn_mark); + } + } ++ ++ /* ++ * Error events are pre-allocated per group, only if strictly ++ * needed (i.e. FAN_FS_ERROR was requested). ++ */ ++ if (!(flags & FAN_MARK_IGNORED_MASK) && (mask & FAN_FS_ERROR)) { ++ ret = fanotify_group_init_error_pool(group); ++ if (ret) ++ goto out; ++ } ++ + added = fanotify_mark_add_to_mask(fsn_mark, mask, flags); + if (added & ~fsnotify_conn_mask(fsn_mark->connector)) + fsnotify_recalc_mask(fsn_mark->connector); ++ ++out: + mutex_unlock(&group->mark_mutex); + + fsnotify_put_mark(fsn_mark); +- return 0; ++ return ret; + } + + static int fanotify_add_vfsmount_mark(struct fsnotify_group *group, +diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h +index 00dbaafbcf953..51ef2b079bfa0 100644 +--- a/include/linux/fsnotify_backend.h ++++ b/include/linux/fsnotify_backend.h +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + + /* + * IN_* from inotfy.h lines up EXACTLY with FS_*, this is so we can easily +@@ -246,6 +247,7 @@ struct fsnotify_group { + int flags; /* flags from fanotify_init() */ + int f_flags; /* event_f_flags from fanotify_init() */ + struct ucounts *ucounts; ++ mempool_t error_events_pool; + } fanotify_data; + #endif /* CONFIG_FANOTIFY */ + }; +-- +2.43.0 + diff --git a/queue-5.10/fanotify-prepare-for-setting-event-flags-in-ignore-m.patch b/queue-5.10/fanotify-prepare-for-setting-event-flags-in-ignore-m.patch new file mode 100644 index 00000000000..dad0f82ef50 --- /dev/null +++ b/queue-5.10/fanotify-prepare-for-setting-event-flags-in-ignore-m.patch @@ -0,0 +1,399 @@ +From 4086f888b5f2d16701a60ebaefc884a818a4ea91 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Jun 2022 17:42:08 +0300 +Subject: fanotify: prepare for setting event flags in ignore mask + +From: Amir Goldstein + +[ Upstream commit 31a371e419c885e0f137ce70395356ba8639dc52 ] + +Setting flags FAN_ONDIR FAN_EVENT_ON_CHILD in ignore mask has no effect. +The FAN_EVENT_ON_CHILD flag in mask implicitly applies to ignore mask and +ignore mask is always implicitly applied to events on directories. + +Define a mark flag that replaces this legacy behavior with logic of +applying the ignore mask according to event flags in ignore mask. + +Implement the new logic to prepare for supporting an ignore mask that +ignores events on children and ignore mask that does not ignore events +on directories. + +To emphasize the change in terminology, also rename ignored_mask mark +member to ignore_mask and use accessors to get only the effective +ignored events or the ignored events and flags. + +This change in terminology finally aligns with the "ignore mask" +language in man pages and in most of the comments. + +Link: https://lore.kernel.org/r/20220629144210.2983229-2-amir73il@gmail.com +Signed-off-by: Amir Goldstein +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify.c | 19 ++++--- + fs/notify/fanotify/fanotify_user.c | 21 ++++--- + fs/notify/fdinfo.c | 6 +- + fs/notify/fsnotify.c | 21 ++++--- + include/linux/fsnotify_backend.h | 89 ++++++++++++++++++++++++++++-- + 5 files changed, 121 insertions(+), 35 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c +index 4f897e1095470..cd7d09a569fff 100644 +--- a/fs/notify/fanotify/fanotify.c ++++ b/fs/notify/fanotify/fanotify.c +@@ -295,12 +295,13 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group, + const void *data, int data_type, + struct inode *dir) + { +- __u32 marks_mask = 0, marks_ignored_mask = 0; ++ __u32 marks_mask = 0, marks_ignore_mask = 0; + __u32 test_mask, user_mask = FANOTIFY_OUTGOING_EVENTS | + FANOTIFY_EVENT_FLAGS; + const struct path *path = fsnotify_data_path(data, data_type); + unsigned int fid_mode = FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS); + struct fsnotify_mark *mark; ++ bool ondir = event_mask & FAN_ONDIR; + int type; + + pr_debug("%s: report_mask=%x mask=%x data=%p data_type=%d\n", +@@ -315,19 +316,21 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group, + return 0; + } else if (!(fid_mode & FAN_REPORT_FID)) { + /* Do we have a directory inode to report? */ +- if (!dir && !(event_mask & FS_ISDIR)) ++ if (!dir && !ondir) + return 0; + } + + fsnotify_foreach_iter_mark_type(iter_info, mark, type) { +- /* Apply ignore mask regardless of mark's ISDIR flag */ +- marks_ignored_mask |= mark->ignored_mask; ++ /* ++ * Apply ignore mask depending on event flags in ignore mask. ++ */ ++ marks_ignore_mask |= ++ fsnotify_effective_ignore_mask(mark, ondir, type); + + /* +- * If the event is on dir and this mark doesn't care about +- * events on dir, don't send it! ++ * Send the event depending on event flags in mark mask. + */ +- if (event_mask & FS_ISDIR && !(mark->mask & FS_ISDIR)) ++ if (!fsnotify_mask_applicable(mark->mask, ondir, type)) + continue; + + marks_mask |= mark->mask; +@@ -336,7 +339,7 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group, + *match_mask |= 1U << type; + } + +- test_mask = event_mask & marks_mask & ~marks_ignored_mask; ++ test_mask = event_mask & marks_mask & ~marks_ignore_mask; + + /* + * For dirent modification events (create/delete/move) that do not carry +diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c +index 990464e00aec7..0d61cb0e49075 100644 +--- a/fs/notify/fanotify/fanotify_user.c ++++ b/fs/notify/fanotify/fanotify_user.c +@@ -1000,7 +1000,7 @@ static __u32 fanotify_mark_remove_from_mask(struct fsnotify_mark *fsn_mark, + if (!(flags & FAN_MARK_IGNORED_MASK)) { + fsn_mark->mask &= ~mask; + } else { +- fsn_mark->ignored_mask &= ~mask; ++ fsn_mark->ignore_mask &= ~mask; + } + newmask = fsnotify_calc_mask(fsn_mark); + /* +@@ -1009,7 +1009,7 @@ static __u32 fanotify_mark_remove_from_mask(struct fsnotify_mark *fsn_mark, + * changes to the mask. + * Destroy mark when only umask bits remain. + */ +- *destroy = !((fsn_mark->mask | fsn_mark->ignored_mask) & ~umask); ++ *destroy = !((fsn_mark->mask | fsn_mark->ignore_mask) & ~umask); + spin_unlock(&fsn_mark->lock); + + return oldmask & ~newmask; +@@ -1078,7 +1078,7 @@ static bool fanotify_mark_update_flags(struct fsnotify_mark *fsn_mark, + /* + * Setting FAN_MARK_IGNORED_SURV_MODIFY for the first time may lead to + * the removal of the FS_MODIFY bit in calculated mask if it was set +- * because of an ignored mask that is now going to survive FS_MODIFY. ++ * because of an ignore mask that is now going to survive FS_MODIFY. + */ + if ((fan_flags & FAN_MARK_IGNORED_MASK) && + (fan_flags & FAN_MARK_IGNORED_SURV_MODIFY) && +@@ -1111,7 +1111,7 @@ static bool fanotify_mark_add_to_mask(struct fsnotify_mark *fsn_mark, + if (!(fan_flags & FAN_MARK_IGNORED_MASK)) + fsn_mark->mask |= mask; + else +- fsn_mark->ignored_mask |= mask; ++ fsn_mark->ignore_mask |= mask; + + recalc = fsnotify_calc_mask(fsn_mark) & + ~fsnotify_conn_mask(fsn_mark->connector); +@@ -1249,7 +1249,7 @@ static int fanotify_add_inode_mark(struct fsnotify_group *group, + + /* + * If some other task has this inode open for write we should not add +- * an ignored mark, unless that ignored mark is supposed to survive ++ * an ignore mask, unless that ignore mask is supposed to survive + * modification changes anyway. + */ + if ((flags & FAN_MARK_IGNORED_MASK) && +@@ -1559,7 +1559,7 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, + __kernel_fsid_t __fsid, *fsid = NULL; + u32 valid_mask = FANOTIFY_EVENTS | FANOTIFY_EVENT_FLAGS; + unsigned int mark_type = flags & FANOTIFY_MARK_TYPE_BITS; +- bool ignored = flags & FAN_MARK_IGNORED_MASK; ++ bool ignore = flags & FAN_MARK_IGNORED_MASK; + unsigned int obj_type, fid_mode; + u32 umask = 0; + int ret; +@@ -1608,8 +1608,11 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, + if (mask & ~valid_mask) + return -EINVAL; + +- /* Event flags (ONDIR, ON_CHILD) are meaningless in ignored mask */ +- if (ignored) ++ /* ++ * Event flags (FAN_ONDIR, FAN_EVENT_ON_CHILD) have no effect with ++ * FAN_MARK_IGNORED_MASK. ++ */ ++ if (ignore) + mask &= ~FANOTIFY_EVENT_FLAGS; + + f = fdget(fanotify_fd); +@@ -1723,7 +1726,7 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, + * events with parent/name info for non-directory. + */ + if ((fid_mode & FAN_REPORT_DIR_FID) && +- (flags & FAN_MARK_ADD) && !ignored) ++ (flags & FAN_MARK_ADD) && !ignore) + mask |= FAN_EVENT_ON_CHILD; + } + +diff --git a/fs/notify/fdinfo.c b/fs/notify/fdinfo.c +index 59fb40abe33d3..55081ae3a6ec0 100644 +--- a/fs/notify/fdinfo.c ++++ b/fs/notify/fdinfo.c +@@ -113,7 +113,7 @@ static void fanotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark) + return; + seq_printf(m, "fanotify ino:%lx sdev:%x mflags:%x mask:%x ignored_mask:%x ", + inode->i_ino, inode->i_sb->s_dev, +- mflags, mark->mask, mark->ignored_mask); ++ mflags, mark->mask, mark->ignore_mask); + show_mark_fhandle(m, inode); + seq_putc(m, '\n'); + iput(inode); +@@ -121,12 +121,12 @@ static void fanotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark) + struct mount *mnt = fsnotify_conn_mount(mark->connector); + + seq_printf(m, "fanotify mnt_id:%x mflags:%x mask:%x ignored_mask:%x\n", +- mnt->mnt_id, mflags, mark->mask, mark->ignored_mask); ++ mnt->mnt_id, mflags, mark->mask, mark->ignore_mask); + } else if (mark->connector->type == FSNOTIFY_OBJ_TYPE_SB) { + struct super_block *sb = fsnotify_conn_sb(mark->connector); + + seq_printf(m, "fanotify sdev:%x mflags:%x mask:%x ignored_mask:%x\n", +- sb->s_dev, mflags, mark->mask, mark->ignored_mask); ++ sb->s_dev, mflags, mark->mask, mark->ignore_mask); + } + } + +diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c +index 0b3e74935cb4f..8687562df2e37 100644 +--- a/fs/notify/fsnotify.c ++++ b/fs/notify/fsnotify.c +@@ -324,7 +324,8 @@ static int send_to_group(__u32 mask, const void *data, int data_type, + struct fsnotify_group *group = NULL; + __u32 test_mask = (mask & ALL_FSNOTIFY_EVENTS); + __u32 marks_mask = 0; +- __u32 marks_ignored_mask = 0; ++ __u32 marks_ignore_mask = 0; ++ bool is_dir = mask & FS_ISDIR; + struct fsnotify_mark *mark; + int type; + +@@ -336,7 +337,7 @@ static int send_to_group(__u32 mask, const void *data, int data_type, + fsnotify_foreach_iter_mark_type(iter_info, mark, type) { + if (!(mark->flags & + FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY)) +- mark->ignored_mask = 0; ++ mark->ignore_mask = 0; + } + } + +@@ -344,14 +345,15 @@ static int send_to_group(__u32 mask, const void *data, int data_type, + fsnotify_foreach_iter_mark_type(iter_info, mark, type) { + group = mark->group; + marks_mask |= mark->mask; +- marks_ignored_mask |= mark->ignored_mask; ++ marks_ignore_mask |= ++ fsnotify_effective_ignore_mask(mark, is_dir, type); + } + +- pr_debug("%s: group=%p mask=%x marks_mask=%x marks_ignored_mask=%x data=%p data_type=%d dir=%p cookie=%d\n", +- __func__, group, mask, marks_mask, marks_ignored_mask, ++ pr_debug("%s: group=%p mask=%x marks_mask=%x marks_ignore_mask=%x data=%p data_type=%d dir=%p cookie=%d\n", ++ __func__, group, mask, marks_mask, marks_ignore_mask, + data, data_type, dir, cookie); + +- if (!(test_mask & marks_mask & ~marks_ignored_mask)) ++ if (!(test_mask & marks_mask & ~marks_ignore_mask)) + return 0; + + if (group->ops->handle_event) { +@@ -423,7 +425,8 @@ static bool fsnotify_iter_select_report_types( + * But is *this mark* watching children? + */ + if (type == FSNOTIFY_ITER_TYPE_PARENT && +- !(mark->mask & FS_EVENT_ON_CHILD)) ++ !(mark->mask & FS_EVENT_ON_CHILD) && ++ !(fsnotify_ignore_mask(mark) & FS_EVENT_ON_CHILD)) + continue; + + fsnotify_iter_set_report_type(iter_info, type); +@@ -532,8 +535,8 @@ int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir, + + + /* +- * If this is a modify event we may need to clear some ignored masks. +- * In that case, the object with ignored masks will have the FS_MODIFY ++ * If this is a modify event we may need to clear some ignore masks. ++ * In that case, the object with ignore masks will have the FS_MODIFY + * event in its mask. + * Otherwise, return if none of the marks care about this type of event. + */ +diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h +index 9560734759fa6..d7d96c806bff2 100644 +--- a/include/linux/fsnotify_backend.h ++++ b/include/linux/fsnotify_backend.h +@@ -518,8 +518,8 @@ struct fsnotify_mark { + struct hlist_node obj_list; + /* Head of list of marks for an object [mark ref] */ + struct fsnotify_mark_connector *connector; +- /* Events types to ignore [mark->lock, group->mark_mutex] */ +- __u32 ignored_mask; ++ /* Events types and flags to ignore [mark->lock, group->mark_mutex] */ ++ __u32 ignore_mask; + /* General fsnotify mark flags */ + #define FSNOTIFY_MARK_FLAG_ALIVE 0x0001 + #define FSNOTIFY_MARK_FLAG_ATTACHED 0x0002 +@@ -529,6 +529,7 @@ struct fsnotify_mark { + /* fanotify mark flags */ + #define FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY 0x0100 + #define FSNOTIFY_MARK_FLAG_NO_IREF 0x0200 ++#define FSNOTIFY_MARK_FLAG_HAS_IGNORE_FLAGS 0x0400 + unsigned int flags; /* flags [mark->lock] */ + }; + +@@ -655,15 +656,91 @@ extern void fsnotify_remove_queued_event(struct fsnotify_group *group, + + /* functions used to manipulate the marks attached to inodes */ + +-/* Get mask for calculating object interest taking ignored mask into account */ ++/* ++ * Canonical "ignore mask" including event flags. ++ * ++ * Note the subtle semantic difference from the legacy ->ignored_mask. ++ * ->ignored_mask traditionally only meant which events should be ignored, ++ * while ->ignore_mask also includes flags regarding the type of objects on ++ * which events should be ignored. ++ */ ++static inline __u32 fsnotify_ignore_mask(struct fsnotify_mark *mark) ++{ ++ __u32 ignore_mask = mark->ignore_mask; ++ ++ /* The event flags in ignore mask take effect */ ++ if (mark->flags & FSNOTIFY_MARK_FLAG_HAS_IGNORE_FLAGS) ++ return ignore_mask; ++ ++ /* ++ * Legacy behavior: ++ * - Always ignore events on dir ++ * - Ignore events on child if parent is watching children ++ */ ++ ignore_mask |= FS_ISDIR; ++ ignore_mask &= ~FS_EVENT_ON_CHILD; ++ ignore_mask |= mark->mask & FS_EVENT_ON_CHILD; ++ ++ return ignore_mask; ++} ++ ++/* Legacy ignored_mask - only event types to ignore */ ++static inline __u32 fsnotify_ignored_events(struct fsnotify_mark *mark) ++{ ++ return mark->ignore_mask & ALL_FSNOTIFY_EVENTS; ++} ++ ++/* ++ * Check if mask (or ignore mask) should be applied depending if victim is a ++ * directory and whether it is reported to a watching parent. ++ */ ++static inline bool fsnotify_mask_applicable(__u32 mask, bool is_dir, ++ int iter_type) ++{ ++ /* Should mask be applied to a directory? */ ++ if (is_dir && !(mask & FS_ISDIR)) ++ return false; ++ ++ /* Should mask be applied to a child? */ ++ if (iter_type == FSNOTIFY_ITER_TYPE_PARENT && ++ !(mask & FS_EVENT_ON_CHILD)) ++ return false; ++ ++ return true; ++} ++ ++/* ++ * Effective ignore mask taking into account if event victim is a ++ * directory and whether it is reported to a watching parent. ++ */ ++static inline __u32 fsnotify_effective_ignore_mask(struct fsnotify_mark *mark, ++ bool is_dir, int iter_type) ++{ ++ __u32 ignore_mask = fsnotify_ignored_events(mark); ++ ++ if (!ignore_mask) ++ return 0; ++ ++ /* For non-dir and non-child, no need to consult the event flags */ ++ if (!is_dir && iter_type != FSNOTIFY_ITER_TYPE_PARENT) ++ return ignore_mask; ++ ++ ignore_mask = fsnotify_ignore_mask(mark); ++ if (!fsnotify_mask_applicable(ignore_mask, is_dir, iter_type)) ++ return 0; ++ ++ return ignore_mask & ALL_FSNOTIFY_EVENTS; ++} ++ ++/* Get mask for calculating object interest taking ignore mask into account */ + static inline __u32 fsnotify_calc_mask(struct fsnotify_mark *mark) + { + __u32 mask = mark->mask; + +- if (!mark->ignored_mask) ++ if (!fsnotify_ignored_events(mark)) + return mask; + +- /* Interest in FS_MODIFY may be needed for clearing ignored mask */ ++ /* Interest in FS_MODIFY may be needed for clearing ignore mask */ + if (!(mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY)) + mask |= FS_MODIFY; + +@@ -671,7 +748,7 @@ static inline __u32 fsnotify_calc_mask(struct fsnotify_mark *mark) + * If mark is interested in ignoring events on children, the object must + * show interest in those events for fsnotify_parent() to notice it. + */ +- return mask | (mark->ignored_mask & ALL_FSNOTIFY_EVENTS); ++ return mask | mark->ignore_mask; + } + + /* Get mask of events for a list of marks */ +-- +2.43.0 + diff --git a/queue-5.10/fanotify-record-either-old-name-new-name-or-both-for.patch b/queue-5.10/fanotify-record-either-old-name-new-name-or-both-for.patch new file mode 100644 index 00000000000..a2144dcd6e9 --- /dev/null +++ b/queue-5.10/fanotify-record-either-old-name-new-name-or-both-for.patch @@ -0,0 +1,149 @@ +From eca1cf3e628ef0bf4d14f3a8821b7554e60292e4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Nov 2021 22:15:35 +0200 +Subject: fanotify: record either old name new name or both for FAN_RENAME + +From: Amir Goldstein + +[ Upstream commit 2bfbcccde6e7a787feabad4645f628f963fe0663 ] + +We do not want to report the dirfid+name of a directory whose +inode/sb are not watched, because watcher may not have permissions +to see the directory content. + +Use an internal iter_info to indicate to fanotify_alloc_event() +which marks of this group are watching FAN_RENAME, so it can decide +if we need to record only the old parent+name, new parent+name or both. + +Link: https://lore.kernel.org/r/20211129201537.1932819-10-amir73il@gmail.com +Signed-off-by: Amir Goldstein +[JK: Modified code to pass around only mask of mark types matching +generated event] +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify.c | 59 ++++++++++++++++++++++++++--------- + 1 file changed, 44 insertions(+), 15 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c +index db81eab905442..14bc0f12cc9f3 100644 +--- a/fs/notify/fanotify/fanotify.c ++++ b/fs/notify/fanotify/fanotify.c +@@ -284,8 +284,9 @@ static int fanotify_get_response(struct fsnotify_group *group, + */ + static u32 fanotify_group_event_mask(struct fsnotify_group *group, + struct fsnotify_iter_info *iter_info, +- u32 event_mask, const void *data, +- int data_type, struct inode *dir) ++ u32 *match_mask, u32 event_mask, ++ const void *data, int data_type, ++ struct inode *dir) + { + __u32 marks_mask = 0, marks_ignored_mask = 0; + __u32 test_mask, user_mask = FANOTIFY_OUTGOING_EVENTS | +@@ -335,6 +336,9 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group, + continue; + + marks_mask |= mark->mask; ++ ++ /* Record the mark types of this group that matched the event */ ++ *match_mask |= 1U << type; + } + + test_mask = event_mask & marks_mask & ~marks_ignored_mask; +@@ -701,11 +705,11 @@ static struct fanotify_event *fanotify_alloc_error_event( + return &fee->fae; + } + +-static struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group, +- u32 mask, const void *data, +- int data_type, struct inode *dir, +- const struct qstr *file_name, +- __kernel_fsid_t *fsid) ++static struct fanotify_event *fanotify_alloc_event( ++ struct fsnotify_group *group, ++ u32 mask, const void *data, int data_type, ++ struct inode *dir, const struct qstr *file_name, ++ __kernel_fsid_t *fsid, u32 match_mask) + { + struct fanotify_event *event = NULL; + gfp_t gfp = GFP_KERNEL_ACCOUNT; +@@ -753,13 +757,36 @@ static struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group, + } + + /* +- * In the special case of FAN_RENAME event, we record both +- * old and new parent+name. ++ * In the special case of FAN_RENAME event, use the match_mask ++ * to determine if we need to report only the old parent+name, ++ * only the new parent+name or both. + * 'dirid' and 'file_name' are the old parent+name and + * 'moved' has the new parent+name. + */ +- if (mask & FAN_RENAME) +- moved = fsnotify_data_dentry(data, data_type); ++ if (mask & FAN_RENAME) { ++ bool report_old, report_new; ++ ++ if (WARN_ON_ONCE(!match_mask)) ++ return NULL; ++ ++ /* Report both old and new parent+name if sb watching */ ++ report_old = report_new = ++ match_mask & (1U << FSNOTIFY_ITER_TYPE_SB); ++ report_old |= ++ match_mask & (1U << FSNOTIFY_ITER_TYPE_INODE); ++ report_new |= ++ match_mask & (1U << FSNOTIFY_ITER_TYPE_INODE2); ++ ++ if (!report_old) { ++ /* Do not report old parent+name */ ++ dirid = NULL; ++ file_name = NULL; ++ } ++ if (report_new) { ++ /* Report new parent+name */ ++ moved = fsnotify_data_dentry(data, data_type); ++ } ++ } + } + + /* +@@ -872,6 +899,7 @@ static int fanotify_handle_event(struct fsnotify_group *group, u32 mask, + struct fanotify_event *event; + struct fsnotify_event *fsn_event; + __kernel_fsid_t fsid = {}; ++ u32 match_mask = 0; + + BUILD_BUG_ON(FAN_ACCESS != FS_ACCESS); + BUILD_BUG_ON(FAN_MODIFY != FS_MODIFY); +@@ -897,12 +925,13 @@ static int fanotify_handle_event(struct fsnotify_group *group, u32 mask, + + BUILD_BUG_ON(HWEIGHT32(ALL_FANOTIFY_EVENT_BITS) != 20); + +- mask = fanotify_group_event_mask(group, iter_info, mask, data, +- data_type, dir); ++ mask = fanotify_group_event_mask(group, iter_info, &match_mask, ++ mask, data, data_type, dir); + if (!mask) + return 0; + +- pr_debug("%s: group=%p mask=%x\n", __func__, group, mask); ++ pr_debug("%s: group=%p mask=%x report_mask=%x\n", __func__, ++ group, mask, match_mask); + + if (fanotify_is_perm_event(mask)) { + /* +@@ -921,7 +950,7 @@ static int fanotify_handle_event(struct fsnotify_group *group, u32 mask, + } + + event = fanotify_alloc_event(group, mask, data, data_type, dir, +- file_name, &fsid); ++ file_name, &fsid, match_mask); + ret = -ENOMEM; + if (unlikely(!event)) { + /* +-- +2.43.0 + diff --git a/queue-5.10/fanotify-record-old-and-new-parent-and-name-in-fan_r.patch b/queue-5.10/fanotify-record-old-and-new-parent-and-name-in-fan_r.patch new file mode 100644 index 00000000000..91e50f230ef --- /dev/null +++ b/queue-5.10/fanotify-record-old-and-new-parent-and-name-in-fan_r.patch @@ -0,0 +1,152 @@ +From 6e0f67b8b5090b361f2cd09b7bb458239236c05b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Nov 2021 22:15:34 +0200 +Subject: fanotify: record old and new parent and name in FAN_RENAME event + +From: Amir Goldstein + +[ Upstream commit 3982534ba5ce45e890b2f5ef5e7372c1accd14c7 ] + +In the special case of FAN_RENAME event, we record both the old +and new parent and name. + +Link: https://lore.kernel.org/r/20211129201537.1932819-9-amir73il@gmail.com +Signed-off-by: Amir Goldstein +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify.c | 42 +++++++++++++++++++++++++++++++---- + include/uapi/linux/fanotify.h | 2 ++ + 2 files changed, 40 insertions(+), 4 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c +index 5f184b2d6ea7c..db81eab905442 100644 +--- a/fs/notify/fanotify/fanotify.c ++++ b/fs/notify/fanotify/fanotify.c +@@ -592,21 +592,28 @@ static struct fanotify_event *fanotify_alloc_name_event(struct inode *dir, + __kernel_fsid_t *fsid, + const struct qstr *name, + struct inode *child, ++ struct dentry *moved, + unsigned int *hash, + gfp_t gfp) + { + struct fanotify_name_event *fne; + struct fanotify_info *info; + struct fanotify_fh *dfh, *ffh; ++ struct inode *dir2 = moved ? d_inode(moved->d_parent) : NULL; ++ const struct qstr *name2 = moved ? &moved->d_name : NULL; + unsigned int dir_fh_len = fanotify_encode_fh_len(dir); ++ unsigned int dir2_fh_len = fanotify_encode_fh_len(dir2); + unsigned int child_fh_len = fanotify_encode_fh_len(child); + unsigned long name_len = name ? name->len : 0; ++ unsigned long name2_len = name2 ? name2->len : 0; + unsigned int len, size; + + /* Reserve terminating null byte even for empty name */ +- size = sizeof(*fne) + name_len + 1; ++ size = sizeof(*fne) + name_len + name2_len + 2; + if (dir_fh_len) + size += FANOTIFY_FH_HDR_LEN + dir_fh_len; ++ if (dir2_fh_len) ++ size += FANOTIFY_FH_HDR_LEN + dir2_fh_len; + if (child_fh_len) + size += FANOTIFY_FH_HDR_LEN + child_fh_len; + fne = kmalloc(size, gfp); +@@ -623,6 +630,11 @@ static struct fanotify_event *fanotify_alloc_name_event(struct inode *dir, + len = fanotify_encode_fh(dfh, dir, dir_fh_len, hash, 0); + fanotify_info_set_dir_fh(info, len); + } ++ if (dir2_fh_len) { ++ dfh = fanotify_info_dir2_fh(info); ++ len = fanotify_encode_fh(dfh, dir2, dir2_fh_len, hash, 0); ++ fanotify_info_set_dir2_fh(info, len); ++ } + if (child_fh_len) { + ffh = fanotify_info_file_fh(info); + len = fanotify_encode_fh(ffh, child, child_fh_len, hash, 0); +@@ -632,11 +644,22 @@ static struct fanotify_event *fanotify_alloc_name_event(struct inode *dir, + fanotify_info_copy_name(info, name); + *hash ^= full_name_hash((void *)name_len, name->name, name_len); + } ++ if (name2_len) { ++ fanotify_info_copy_name2(info, name2); ++ *hash ^= full_name_hash((void *)name2_len, name2->name, ++ name2_len); ++ } + + pr_debug("%s: size=%u dir_fh_len=%u child_fh_len=%u name_len=%u name='%.*s'\n", + __func__, size, dir_fh_len, child_fh_len, + info->name_len, info->name_len, fanotify_info_name(info)); + ++ if (dir2_fh_len) { ++ pr_debug("%s: dir2_fh_len=%u name2_len=%u name2='%.*s'\n", ++ __func__, dir2_fh_len, info->name2_len, ++ info->name2_len, fanotify_info_name2(info)); ++ } ++ + return &fne->fae; + } + +@@ -692,6 +715,7 @@ static struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group, + struct inode *dirid = fanotify_dfid_inode(mask, data, data_type, dir); + const struct path *path = fsnotify_data_path(data, data_type); + struct mem_cgroup *old_memcg; ++ struct dentry *moved = NULL; + struct inode *child = NULL; + bool name_event = false; + unsigned int hash = 0; +@@ -727,6 +751,15 @@ static struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group, + } else if ((mask & ALL_FSNOTIFY_DIRENT_EVENTS) || !ondir) { + name_event = true; + } ++ ++ /* ++ * In the special case of FAN_RENAME event, we record both ++ * old and new parent+name. ++ * 'dirid' and 'file_name' are the old parent+name and ++ * 'moved' has the new parent+name. ++ */ ++ if (mask & FAN_RENAME) ++ moved = fsnotify_data_dentry(data, data_type); + } + + /* +@@ -748,9 +781,9 @@ static struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group, + } else if (fanotify_is_error_event(mask)) { + event = fanotify_alloc_error_event(group, fsid, data, + data_type, &hash); +- } else if (name_event && (file_name || child)) { +- event = fanotify_alloc_name_event(id, fsid, file_name, child, +- &hash, gfp); ++ } else if (name_event && (file_name || moved || child)) { ++ event = fanotify_alloc_name_event(dirid, fsid, file_name, child, ++ moved, &hash, gfp); + } else if (fid_mode) { + event = fanotify_alloc_fid_event(id, fsid, &hash, gfp); + } else { +@@ -860,6 +893,7 @@ static int fanotify_handle_event(struct fsnotify_group *group, u32 mask, + BUILD_BUG_ON(FAN_OPEN_EXEC != FS_OPEN_EXEC); + BUILD_BUG_ON(FAN_OPEN_EXEC_PERM != FS_OPEN_EXEC_PERM); + BUILD_BUG_ON(FAN_FS_ERROR != FS_ERROR); ++ BUILD_BUG_ON(FAN_RENAME != FS_RENAME); + + BUILD_BUG_ON(HWEIGHT32(ALL_FANOTIFY_EVENT_BITS) != 20); + +diff --git a/include/uapi/linux/fanotify.h b/include/uapi/linux/fanotify.h +index 60f73639a896a..9d0e2dc5767b5 100644 +--- a/include/uapi/linux/fanotify.h ++++ b/include/uapi/linux/fanotify.h +@@ -28,6 +28,8 @@ + + #define FAN_EVENT_ON_CHILD 0x08000000 /* Interested in child events */ + ++#define FAN_RENAME 0x10000000 /* File was renamed */ ++ + #define FAN_ONDIR 0x40000000 /* Event occurred against dir */ + + /* helper events */ +-- +2.43.0 + diff --git a/queue-5.10/fanotify-reduce-event-objectid-to-29-bit-hash.patch b/queue-5.10/fanotify-reduce-event-objectid-to-29-bit-hash.patch new file mode 100644 index 00000000000..9a3a30fb00b --- /dev/null +++ b/queue-5.10/fanotify-reduce-event-objectid-to-29-bit-hash.patch @@ -0,0 +1,195 @@ +From 1976b35bc185f52b94bd3b454dae202d76def54a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Mar 2021 12:48:23 +0200 +Subject: fanotify: reduce event objectid to 29-bit hash + +From: Amir Goldstein + +[ Upstream commit 8988f11abb820bacfcc53d498370bfb30f792ec4 ] + +objectid is only used by fanotify backend and it is just an optimization +for event merge before comparing all fields in event. + +Move the objectid member from common struct fsnotify_event into struct +fanotify_event and reduce it to 29-bit hash to cram it together with the +3-bit event type. + +Events of different types are never merged, so the combination of event +type and hash form a 32-bit key for fast compare of events. + +This reduces the size of events by one pointer and paves the way for +adding hashed queue support for fanotify. + +Link: https://lore.kernel.org/r/20210304104826.3993892-3-amir73il@gmail.com +Signed-off-by: Amir Goldstein +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify.c | 25 ++++++++++++------------- + fs/notify/fanotify/fanotify.h | 16 +++++++++++++--- + fs/notify/inotify/inotify_fsnotify.c | 2 +- + fs/notify/inotify/inotify_user.c | 2 +- + include/linux/fsnotify_backend.h | 5 +---- + 5 files changed, 28 insertions(+), 22 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c +index 1192c99536200..8a2bb6954e02c 100644 +--- a/fs/notify/fanotify/fanotify.c ++++ b/fs/notify/fanotify/fanotify.c +@@ -88,16 +88,12 @@ static bool fanotify_name_event_equal(struct fanotify_name_event *fne1, + return fanotify_info_equal(info1, info2); + } + +-static bool fanotify_should_merge(struct fsnotify_event *old_fsn, +- struct fsnotify_event *new_fsn) ++static bool fanotify_should_merge(struct fanotify_event *old, ++ struct fanotify_event *new) + { +- struct fanotify_event *old, *new; ++ pr_debug("%s: old=%p new=%p\n", __func__, old, new); + +- pr_debug("%s: old=%p new=%p\n", __func__, old_fsn, new_fsn); +- old = FANOTIFY_E(old_fsn); +- new = FANOTIFY_E(new_fsn); +- +- if (old_fsn->objectid != new_fsn->objectid || ++ if (old->hash != new->hash || + old->type != new->type || old->pid != new->pid) + return false; + +@@ -133,10 +129,9 @@ static bool fanotify_should_merge(struct fsnotify_event *old_fsn, + static int fanotify_merge(struct list_head *list, struct fsnotify_event *event) + { + struct fsnotify_event *test_event; +- struct fanotify_event *new; ++ struct fanotify_event *old, *new = FANOTIFY_E(event); + + pr_debug("%s: list=%p event=%p\n", __func__, list, event); +- new = FANOTIFY_E(event); + + /* + * Don't merge a permission event with any other event so that we know +@@ -147,8 +142,9 @@ static int fanotify_merge(struct list_head *list, struct fsnotify_event *event) + return 0; + + list_for_each_entry_reverse(test_event, list, list) { +- if (fanotify_should_merge(test_event, event)) { +- FANOTIFY_E(test_event)->mask |= new->mask; ++ old = FANOTIFY_E(test_event); ++ if (fanotify_should_merge(old, new)) { ++ old->mask |= new->mask; + return 1; + } + } +@@ -533,6 +529,7 @@ static struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group, + struct mem_cgroup *old_memcg; + struct inode *child = NULL; + bool name_event = false; ++ unsigned int hash = 0; + + if ((fid_mode & FAN_REPORT_DIR_FID) && dirid) { + /* +@@ -600,8 +597,10 @@ static struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group, + * Use the victim inode instead of the watching inode as the id for + * event queue, so event reported on parent is merged with event + * reported on child when both directory and child watches exist. ++ * Hash object id for queue merge. + */ +- fanotify_init_event(event, (unsigned long)id, mask); ++ hash = hash_ptr(id, FANOTIFY_EVENT_HASH_BITS); ++ fanotify_init_event(event, hash, mask); + if (FAN_GROUP_FLAG(group, FAN_REPORT_TID)) + event->pid = get_pid(task_pid(current)); + else +diff --git a/fs/notify/fanotify/fanotify.h b/fs/notify/fanotify/fanotify.h +index 896c819a17863..d531f0cfa46f2 100644 +--- a/fs/notify/fanotify/fanotify.h ++++ b/fs/notify/fanotify/fanotify.h +@@ -135,19 +135,29 @@ enum fanotify_event_type { + FANOTIFY_EVENT_TYPE_PATH, + FANOTIFY_EVENT_TYPE_PATH_PERM, + FANOTIFY_EVENT_TYPE_OVERFLOW, /* struct fanotify_event */ ++ __FANOTIFY_EVENT_TYPE_NUM + }; + ++#define FANOTIFY_EVENT_TYPE_BITS \ ++ (ilog2(__FANOTIFY_EVENT_TYPE_NUM - 1) + 1) ++#define FANOTIFY_EVENT_HASH_BITS \ ++ (32 - FANOTIFY_EVENT_TYPE_BITS) ++ + struct fanotify_event { + struct fsnotify_event fse; + u32 mask; +- enum fanotify_event_type type; ++ struct { ++ unsigned int type : FANOTIFY_EVENT_TYPE_BITS; ++ unsigned int hash : FANOTIFY_EVENT_HASH_BITS; ++ }; + struct pid *pid; + }; + + static inline void fanotify_init_event(struct fanotify_event *event, +- unsigned long id, u32 mask) ++ unsigned int hash, u32 mask) + { +- fsnotify_init_event(&event->fse, id); ++ fsnotify_init_event(&event->fse); ++ event->hash = hash; + event->mask = mask; + event->pid = NULL; + } +diff --git a/fs/notify/inotify/inotify_fsnotify.c b/fs/notify/inotify/inotify_fsnotify.c +index 66991c7fef9e2..e2b124c0081dc 100644 +--- a/fs/notify/inotify/inotify_fsnotify.c ++++ b/fs/notify/inotify/inotify_fsnotify.c +@@ -114,7 +114,7 @@ int inotify_handle_inode_event(struct fsnotify_mark *inode_mark, u32 mask, + mask &= ~IN_ISDIR; + + fsn_event = &event->fse; +- fsnotify_init_event(fsn_event, 0); ++ fsnotify_init_event(fsn_event); + event->mask = mask; + event->wd = wd; + event->sync_cookie = cookie; +diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c +index c2018983832e5..62cd91bc00b83 100644 +--- a/fs/notify/inotify/inotify_user.c ++++ b/fs/notify/inotify/inotify_user.c +@@ -641,7 +641,7 @@ static struct fsnotify_group *inotify_new_group(unsigned int max_events) + return ERR_PTR(-ENOMEM); + } + group->overflow_event = &oevent->fse; +- fsnotify_init_event(group->overflow_event, 0); ++ fsnotify_init_event(group->overflow_event); + oevent->mask = FS_Q_OVERFLOW; + oevent->wd = -1; + oevent->sync_cookie = 0; +diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h +index 7eb979bfc1413..fc98f9f88d126 100644 +--- a/include/linux/fsnotify_backend.h ++++ b/include/linux/fsnotify_backend.h +@@ -167,7 +167,6 @@ struct fsnotify_ops { + */ + struct fsnotify_event { + struct list_head list; +- unsigned long objectid; /* identifier for queue merges */ + }; + + /* +@@ -582,11 +581,9 @@ extern void fsnotify_put_mark(struct fsnotify_mark *mark); + extern void fsnotify_finish_user_wait(struct fsnotify_iter_info *iter_info); + extern bool fsnotify_prepare_user_wait(struct fsnotify_iter_info *iter_info); + +-static inline void fsnotify_init_event(struct fsnotify_event *event, +- unsigned long objectid) ++static inline void fsnotify_init_event(struct fsnotify_event *event) + { + INIT_LIST_HEAD(&event->list); +- event->objectid = objectid; + } + + #else +-- +2.43.0 + diff --git a/queue-5.10/fanotify-refine-the-validation-checks-on-non-dir-ino.patch b/queue-5.10/fanotify-refine-the-validation-checks-on-non-dir-ino.patch new file mode 100644 index 00000000000..56ed80d84e1 --- /dev/null +++ b/queue-5.10/fanotify-refine-the-validation-checks-on-non-dir-ino.patch @@ -0,0 +1,121 @@ +From ab92571e8278b2b9aea7801fc08d294ebc7db86a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Jun 2022 20:47:19 +0300 +Subject: fanotify: refine the validation checks on non-dir inode mask + +From: Amir Goldstein + +[ Upstream commit 8698e3bab4dd7968666e84e111d0bfd17c040e77 ] + +Commit ceaf69f8eadc ("fanotify: do not allow setting dirent events in +mask of non-dir") added restrictions about setting dirent events in the +mask of a non-dir inode mark, which does not make any sense. + +For backward compatibility, these restictions were added only to new +(v5.17+) APIs. + +It also does not make any sense to set the flags FAN_EVENT_ON_CHILD or +FAN_ONDIR in the mask of a non-dir inode. Add these flags to the +dir-only restriction of the new APIs as well. + +Move the check of the dir-only flags for new APIs into the helper +fanotify_events_supported(), which is only called for FAN_MARK_ADD, +because there is no need to error on an attempt to remove the dir-only +flags from non-dir inode. + +Fixes: ceaf69f8eadc ("fanotify: do not allow setting dirent events in mask of non-dir") +Link: https://lore.kernel.org/linux-fsdevel/20220627113224.kr2725conevh53u4@quack3.lan/ +Link: https://lore.kernel.org/r/20220627174719.2838175-1-amir73il@gmail.com +Signed-off-by: Amir Goldstein +Signed-off-by: Jan Kara +[ cel: adjusted to apply to v5.10.y ] +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify_user.c | 30 +++++++++++++++--------------- + include/linux/fanotify.h | 4 ++++ + 2 files changed, 19 insertions(+), 15 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c +index f4a5e9074dd42..990464e00aec7 100644 +--- a/fs/notify/fanotify/fanotify_user.c ++++ b/fs/notify/fanotify/fanotify_user.c +@@ -1501,10 +1501,14 @@ static int fanotify_test_fid(struct dentry *dentry) + return 0; + } + +-static int fanotify_events_supported(struct path *path, __u64 mask, ++static int fanotify_events_supported(struct fsnotify_group *group, ++ struct path *path, __u64 mask, + unsigned int flags) + { + unsigned int mark_type = flags & FANOTIFY_MARK_TYPE_BITS; ++ /* Strict validation of events in non-dir inode mask with v5.17+ APIs */ ++ bool strict_dir_events = FAN_GROUP_FLAG(group, FAN_REPORT_TARGET_FID) || ++ (mask & FAN_RENAME); + + /* + * Some filesystems such as 'proc' acquire unusual locks when opening +@@ -1532,6 +1536,15 @@ static int fanotify_events_supported(struct path *path, __u64 mask, + path->mnt->mnt_sb->s_flags & SB_NOUSER) + return -EINVAL; + ++ /* ++ * We shouldn't have allowed setting dirent events and the directory ++ * flags FAN_ONDIR and FAN_EVENT_ON_CHILD in mask of non-dir inode, ++ * but because we always allowed it, error only when using new APIs. ++ */ ++ if (strict_dir_events && mark_type == FAN_MARK_INODE && ++ !d_is_dir(path->dentry) && (mask & FANOTIFY_DIRONLY_EVENT_BITS)) ++ return -ENOTDIR; ++ + return 0; + } + +@@ -1678,7 +1691,7 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, + goto fput_and_out; + + if (flags & FAN_MARK_ADD) { +- ret = fanotify_events_supported(&path, mask, flags); ++ ret = fanotify_events_supported(group, &path, mask, flags); + if (ret) + goto path_put_and_out; + } +@@ -1701,19 +1714,6 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, + else + mnt = path.mnt; + +- /* +- * FAN_RENAME is not allowed on non-dir (for now). +- * We shouldn't have allowed setting any dirent events in mask of +- * non-dir, but because we always allowed it, error only if group +- * was initialized with the new flag FAN_REPORT_TARGET_FID. +- */ +- ret = -ENOTDIR; +- if (inode && !S_ISDIR(inode->i_mode) && +- ((mask & FAN_RENAME) || +- ((mask & FANOTIFY_DIRENT_EVENTS) && +- FAN_GROUP_FLAG(group, FAN_REPORT_TARGET_FID)))) +- goto path_put_and_out; +- + /* Mask out FAN_EVENT_ON_CHILD flag for sb/mount/non-dir marks */ + if (mnt || !S_ISDIR(inode->i_mode)) { + mask &= ~FAN_EVENT_ON_CHILD; +diff --git a/include/linux/fanotify.h b/include/linux/fanotify.h +index 81f45061c1b18..4f6cbe6c6e235 100644 +--- a/include/linux/fanotify.h ++++ b/include/linux/fanotify.h +@@ -113,6 +113,10 @@ extern struct ctl_table fanotify_table[]; /* for sysctl */ + FANOTIFY_PERM_EVENTS | \ + FAN_Q_OVERFLOW | FAN_ONDIR) + ++/* Events and flags relevant only for directories */ ++#define FANOTIFY_DIRONLY_EVENT_BITS (FANOTIFY_DIRENT_EVENTS | \ ++ FAN_EVENT_ON_CHILD | FAN_ONDIR) ++ + #define ALL_FANOTIFY_EVENT_BITS (FANOTIFY_OUTGOING_EVENTS | \ + FANOTIFY_EVENT_FLAGS) + +-- +2.43.0 + diff --git a/queue-5.10/fanotify-remove-obsoleted-fanotify_event_has_path.patch b/queue-5.10/fanotify-remove-obsoleted-fanotify_event_has_path.patch new file mode 100644 index 00000000000..6c888d1eefb --- /dev/null +++ b/queue-5.10/fanotify-remove-obsoleted-fanotify_event_has_path.patch @@ -0,0 +1,43 @@ +From c141893282bff4df94f2b3472a5a376e039028a6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Sep 2022 10:30:18 +0800 +Subject: fanotify: Remove obsoleted fanotify_event_has_path() + +From: Gaosheng Cui + +[ Upstream commit 7a80bf902d2bc722b4477442ee772e8574603185 ] + +All uses of fanotify_event_has_path() have +been removed since commit 9c61f3b560f5 ("fanotify: break up +fanotify_alloc_event()"), now it is useless, so remove it. + +Link: https://lore.kernel.org/r/20220926023018.1505270-1-cuigaosheng1@huawei.com +Signed-off-by: Gaosheng Cui +Signed-off-by: Jan Kara +[ cel: resolved merge conflict ] +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify.h | 6 ------ + 1 file changed, 6 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify.h b/fs/notify/fanotify/fanotify.h +index bf6d4d38afa04..57f51a9a3015d 100644 +--- a/fs/notify/fanotify/fanotify.h ++++ b/fs/notify/fanotify/fanotify.h +@@ -452,12 +452,6 @@ static inline bool fanotify_is_error_event(u32 mask) + return mask & FAN_FS_ERROR; + } + +-static inline bool fanotify_event_has_path(struct fanotify_event *event) +-{ +- return event->type == FANOTIFY_EVENT_TYPE_PATH || +- event->type == FANOTIFY_EVENT_TYPE_PATH_PERM; +-} +- + static inline const struct path *fanotify_event_path(struct fanotify_event *event) + { + if (event->type == FANOTIFY_EVENT_TYPE_PATH) +-- +2.43.0 + diff --git a/queue-5.10/fanotify-remove-variable-set-but-not-used.patch b/queue-5.10/fanotify-remove-variable-set-but-not-used.patch new file mode 100644 index 00000000000..3d3e502d257 --- /dev/null +++ b/queue-5.10/fanotify-remove-variable-set-but-not-used.patch @@ -0,0 +1,54 @@ +From f8c05a759ea552f0b9b8b41fc091f43714952e76 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 20 Jan 2022 13:57:22 +0100 +Subject: fanotify: remove variable set but not used +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Yang Li + +[ Upstream commit 217663f101a56ef77f82273818253fff082bf503 ] + +The code that uses the pointer info has been removed in 7326e382c21e +("fanotify: report old and/or new parent+name in FAN_RENAME event"). +and fanotify_event_info() doesn't change 'event', so the declaration and +assignment of info can be removed. + +Eliminate the following clang warning: +fs/notify/fanotify/fanotify_user.c:161:24: warning: variable ‘info’ set +but not used + +Reported-by: Abaci Robot +Signed-off-by: Yang Li +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify_user.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c +index 3bac2329dc35f..6679700574113 100644 +--- a/fs/notify/fanotify/fanotify_user.c ++++ b/fs/notify/fanotify/fanotify_user.c +@@ -146,7 +146,6 @@ static size_t fanotify_event_len(unsigned int info_mode, + struct fanotify_event *event) + { + size_t event_len = FAN_EVENT_METADATA_LEN; +- struct fanotify_info *info; + int fh_len; + int dot_len = 0; + +@@ -156,8 +155,6 @@ static size_t fanotify_event_len(unsigned int info_mode, + if (fanotify_is_error_event(event->mask)) + event_len += FANOTIFY_ERROR_INFO_LEN; + +- info = fanotify_event_info(event); +- + if (fanotify_event_has_any_dir_fh(event)) { + event_len += fanotify_dir_name_info_len(event); + } else if ((info_mode & FAN_REPORT_NAME) && +-- +2.43.0 + diff --git a/queue-5.10/fanotify-report-fid-info-for-file-related-file-syste.patch b/queue-5.10/fanotify-report-fid-info-for-file-related-file-syste.patch new file mode 100644 index 00000000000..2cbac9d2920 --- /dev/null +++ b/queue-5.10/fanotify-report-fid-info-for-file-related-file-syste.patch @@ -0,0 +1,134 @@ +From 74eca5c9b4651ee089d144ffd00aa131a9609f8d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 Oct 2021 16:27:41 -0300 +Subject: fanotify: Report fid info for file related file system errors + +From: Gabriel Krisman Bertazi + +[ Upstream commit 936d6a38be39177495af38497bf8da1c6128fa1b ] + +Plumb the pieces to add a FID report to error records. Since all error +event memory must be pre-allocated, we pre-allocate the maximum file +handle size possible, such that it should always fit. + +For errors that don't expose a file handle, report it with an invalid +FID. Internally we use zero-length FILEID_ROOT file handle for passing +the information (which we report as zero-length FILEID_INVALID file +handle to userspace) so we update the handle reporting code to deal with +this case correctly. + +Link: https://lore.kernel.org/r/20211025192746.66445-27-krisman@collabora.com +Link: https://lore.kernel.org/r/20211025192746.66445-25-krisman@collabora.com +Signed-off-by: Gabriel Krisman Bertazi +Reviewed-by: Amir Goldstein +Reviewed-by: Jan Kara +[Folded two patches into 2 to make series bisectable] +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify.c | 11 +++++++++++ + fs/notify/fanotify/fanotify.h | 9 +++++++++ + fs/notify/fanotify/fanotify_user.c | 8 +++++--- + 3 files changed, 25 insertions(+), 3 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c +index 45df610debbe4..465f07e70e6dc 100644 +--- a/fs/notify/fanotify/fanotify.c ++++ b/fs/notify/fanotify/fanotify.c +@@ -609,7 +609,9 @@ static struct fanotify_event *fanotify_alloc_error_event( + { + struct fs_error_report *report = + fsnotify_data_error_report(data, data_type); ++ struct inode *inode; + struct fanotify_error_event *fee; ++ int fh_len; + + if (WARN_ON_ONCE(!report)) + return NULL; +@@ -622,6 +624,15 @@ static struct fanotify_event *fanotify_alloc_error_event( + fee->err_count = 1; + fee->fsid = *fsid; + ++ inode = report->inode; ++ fh_len = fanotify_encode_fh_len(inode); ++ ++ /* Bad fh_len. Fallback to using an invalid fh. Should never happen. */ ++ if (!fh_len && inode) ++ inode = NULL; ++ ++ fanotify_encode_fh(&fee->object_fh, inode, fh_len, NULL, 0); ++ + *hash ^= fanotify_hash_fsid(fsid); + + return &fee->fae; +diff --git a/fs/notify/fanotify/fanotify.h b/fs/notify/fanotify/fanotify.h +index 80af269eebb89..edd7587adcc59 100644 +--- a/fs/notify/fanotify/fanotify.h ++++ b/fs/notify/fanotify/fanotify.h +@@ -208,6 +208,8 @@ struct fanotify_error_event { + u32 err_count; /* Suppressed errors count */ + + __kernel_fsid_t fsid; /* FSID this error refers to. */ ++ ++ FANOTIFY_INLINE_FH(object_fh, MAX_HANDLE_SZ); + }; + + static inline struct fanotify_error_event * +@@ -222,6 +224,8 @@ static inline __kernel_fsid_t *fanotify_event_fsid(struct fanotify_event *event) + return &FANOTIFY_FE(event)->fsid; + else if (event->type == FANOTIFY_EVENT_TYPE_FID_NAME) + return &FANOTIFY_NE(event)->fsid; ++ else if (event->type == FANOTIFY_EVENT_TYPE_FS_ERROR) ++ return &FANOTIFY_EE(event)->fsid; + else + return NULL; + } +@@ -233,6 +237,8 @@ static inline struct fanotify_fh *fanotify_event_object_fh( + return &FANOTIFY_FE(event)->object_fh; + else if (event->type == FANOTIFY_EVENT_TYPE_FID_NAME) + return fanotify_info_file_fh(&FANOTIFY_NE(event)->info); ++ else if (event->type == FANOTIFY_EVENT_TYPE_FS_ERROR) ++ return &FANOTIFY_EE(event)->object_fh; + else + return NULL; + } +@@ -266,6 +272,9 @@ static inline int fanotify_event_dir_fh_len(struct fanotify_event *event) + + static inline bool fanotify_event_has_object_fh(struct fanotify_event *event) + { ++ /* For error events, even zeroed fh are reported. */ ++ if (event->type == FANOTIFY_EVENT_TYPE_FS_ERROR) ++ return true; + return fanotify_event_object_fh_len(event) > 0; + } + +diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c +index 34ed30be0e4d4..0d36ac3ed7e99 100644 +--- a/fs/notify/fanotify/fanotify_user.c ++++ b/fs/notify/fanotify/fanotify_user.c +@@ -334,9 +334,6 @@ static int copy_fid_info_to_user(__kernel_fsid_t *fsid, struct fanotify_fh *fh, + pr_debug("%s: fh_len=%zu name_len=%zu, info_len=%zu, count=%zu\n", + __func__, fh_len, name_len, info_len, count); + +- if (!fh_len) +- return 0; +- + if (WARN_ON_ONCE(len < sizeof(info) || len > count)) + return -EFAULT; + +@@ -371,6 +368,11 @@ static int copy_fid_info_to_user(__kernel_fsid_t *fsid, struct fanotify_fh *fh, + + handle.handle_type = fh->type; + handle.handle_bytes = fh_len; ++ ++ /* Mangle handle_type for bad file_handle */ ++ if (!fh_len) ++ handle.handle_type = FILEID_INVALID; ++ + if (copy_to_user(buf, &handle, sizeof(handle))) + return -EFAULT; + +-- +2.43.0 + diff --git a/queue-5.10/fanotify-report-old-and-or-new-parent-name-in-fan_re.patch b/queue-5.10/fanotify-report-old-and-or-new-parent-name-in-fan_re.patch new file mode 100644 index 00000000000..1cf8f3c1314 --- /dev/null +++ b/queue-5.10/fanotify-report-old-and-or-new-parent-name-in-fan_re.patch @@ -0,0 +1,207 @@ +From 7e76f8e5f3797cd0e42643ea065cd32904049845 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Nov 2021 22:15:36 +0200 +Subject: fanotify: report old and/or new parent+name in FAN_RENAME event + +From: Amir Goldstein + +[ Upstream commit 7326e382c21e9c23c89c88369afdc90b82a14da8 ] + +In the special case of FAN_RENAME event, we report old or new or both +old and new parent+name. + +A single info record will be reported if either the old or new dir +is watched and two records will be reported if both old and new dir +(or their filesystem) are watched. + +The old and new parent+name are reported using new info record types +FAN_EVENT_INFO_TYPE_{OLD,NEW}_DFID_NAME, so if a single info record +is reported, it is clear to the application, to which dir entry the +fid+name info is referring to. + +Link: https://lore.kernel.org/r/20211129201537.1932819-11-amir73il@gmail.com +Signed-off-by: Amir Goldstein +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify.c | 7 ++++ + fs/notify/fanotify/fanotify.h | 18 +++++++++++ + fs/notify/fanotify/fanotify_user.c | 52 +++++++++++++++++++++++++++--- + include/uapi/linux/fanotify.h | 6 ++++ + 4 files changed, 78 insertions(+), 5 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c +index 14bc0f12cc9f3..0da305b6f3e2f 100644 +--- a/fs/notify/fanotify/fanotify.c ++++ b/fs/notify/fanotify/fanotify.c +@@ -153,6 +153,13 @@ static bool fanotify_should_merge(struct fanotify_event *old, + if ((old->mask & FS_ISDIR) != (new->mask & FS_ISDIR)) + return false; + ++ /* ++ * FAN_RENAME event is reported with special info record types, ++ * so we cannot merge it with other events. ++ */ ++ if ((old->mask & FAN_RENAME) != (new->mask & FAN_RENAME)) ++ return false; ++ + switch (old->type) { + case FANOTIFY_EVENT_TYPE_PATH: + return fanotify_path_equal(fanotify_event_path(old), +diff --git a/fs/notify/fanotify/fanotify.h b/fs/notify/fanotify/fanotify.h +index 8fa3bc0effd45..a3d5b751cac5b 100644 +--- a/fs/notify/fanotify/fanotify.h ++++ b/fs/notify/fanotify/fanotify.h +@@ -373,6 +373,13 @@ static inline int fanotify_event_dir_fh_len(struct fanotify_event *event) + return info ? fanotify_info_dir_fh_len(info) : 0; + } + ++static inline int fanotify_event_dir2_fh_len(struct fanotify_event *event) ++{ ++ struct fanotify_info *info = fanotify_event_info(event); ++ ++ return info ? fanotify_info_dir2_fh_len(info) : 0; ++} ++ + static inline bool fanotify_event_has_object_fh(struct fanotify_event *event) + { + /* For error events, even zeroed fh are reported. */ +@@ -386,6 +393,17 @@ static inline bool fanotify_event_has_dir_fh(struct fanotify_event *event) + return fanotify_event_dir_fh_len(event) > 0; + } + ++static inline bool fanotify_event_has_dir2_fh(struct fanotify_event *event) ++{ ++ return fanotify_event_dir2_fh_len(event) > 0; ++} ++ ++static inline bool fanotify_event_has_any_dir_fh(struct fanotify_event *event) ++{ ++ return fanotify_event_has_dir_fh(event) || ++ fanotify_event_has_dir2_fh(event); ++} ++ + struct fanotify_path_event { + struct fanotify_event fae; + struct path path; +diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c +index d69570db5efd2..e16b18fdf1a65 100644 +--- a/fs/notify/fanotify/fanotify_user.c ++++ b/fs/notify/fanotify/fanotify_user.c +@@ -124,12 +124,29 @@ static int fanotify_fid_info_len(int fh_len, int name_len) + FANOTIFY_EVENT_ALIGN); + } + ++/* FAN_RENAME may have one or two dir+name info records */ ++static int fanotify_dir_name_info_len(struct fanotify_event *event) ++{ ++ struct fanotify_info *info = fanotify_event_info(event); ++ int dir_fh_len = fanotify_event_dir_fh_len(event); ++ int dir2_fh_len = fanotify_event_dir2_fh_len(event); ++ int info_len = 0; ++ ++ if (dir_fh_len) ++ info_len += fanotify_fid_info_len(dir_fh_len, ++ info->name_len); ++ if (dir2_fh_len) ++ info_len += fanotify_fid_info_len(dir2_fh_len, ++ info->name2_len); ++ ++ return info_len; ++} ++ + static size_t fanotify_event_len(unsigned int info_mode, + struct fanotify_event *event) + { + size_t event_len = FAN_EVENT_METADATA_LEN; + struct fanotify_info *info; +- int dir_fh_len; + int fh_len; + int dot_len = 0; + +@@ -141,9 +158,8 @@ static size_t fanotify_event_len(unsigned int info_mode, + + info = fanotify_event_info(event); + +- if (fanotify_event_has_dir_fh(event)) { +- dir_fh_len = fanotify_event_dir_fh_len(event); +- event_len += fanotify_fid_info_len(dir_fh_len, info->name_len); ++ if (fanotify_event_has_any_dir_fh(event)) { ++ event_len += fanotify_dir_name_info_len(event); + } else if ((info_mode & FAN_REPORT_NAME) && + (event->mask & FAN_ONDIR)) { + /* +@@ -374,6 +390,8 @@ static int copy_fid_info_to_user(__kernel_fsid_t *fsid, struct fanotify_fh *fh, + return -EFAULT; + break; + case FAN_EVENT_INFO_TYPE_DFID_NAME: ++ case FAN_EVENT_INFO_TYPE_OLD_DFID_NAME: ++ case FAN_EVENT_INFO_TYPE_NEW_DFID_NAME: + if (WARN_ON_ONCE(!name || !name_len)) + return -EFAULT; + break; +@@ -473,11 +491,19 @@ static int copy_info_records_to_user(struct fanotify_event *event, + unsigned int pidfd_mode = info_mode & FAN_REPORT_PIDFD; + + /* +- * Event info records order is as follows: dir fid + name, child fid. ++ * Event info records order is as follows: ++ * 1. dir fid + name ++ * 2. (optional) new dir fid + new name ++ * 3. (optional) child fid + */ + if (fanotify_event_has_dir_fh(event)) { + info_type = info->name_len ? FAN_EVENT_INFO_TYPE_DFID_NAME : + FAN_EVENT_INFO_TYPE_DFID; ++ ++ /* FAN_RENAME uses special info types */ ++ if (event->mask & FAN_RENAME) ++ info_type = FAN_EVENT_INFO_TYPE_OLD_DFID_NAME; ++ + ret = copy_fid_info_to_user(fanotify_event_fsid(event), + fanotify_info_dir_fh(info), + info_type, +@@ -491,6 +517,22 @@ static int copy_info_records_to_user(struct fanotify_event *event, + total_bytes += ret; + } + ++ /* New dir fid+name may be reported in addition to old dir fid+name */ ++ if (fanotify_event_has_dir2_fh(event)) { ++ info_type = FAN_EVENT_INFO_TYPE_NEW_DFID_NAME; ++ ret = copy_fid_info_to_user(fanotify_event_fsid(event), ++ fanotify_info_dir2_fh(info), ++ info_type, ++ fanotify_info_name2(info), ++ info->name2_len, buf, count); ++ if (ret < 0) ++ return ret; ++ ++ buf += ret; ++ count -= ret; ++ total_bytes += ret; ++ } ++ + if (fanotify_event_has_object_fh(event)) { + const char *dot = NULL; + int dot_len = 0; +diff --git a/include/uapi/linux/fanotify.h b/include/uapi/linux/fanotify.h +index 9d0e2dc5767b5..e8ac38cc2fd6d 100644 +--- a/include/uapi/linux/fanotify.h ++++ b/include/uapi/linux/fanotify.h +@@ -134,6 +134,12 @@ struct fanotify_event_metadata { + #define FAN_EVENT_INFO_TYPE_PIDFD 4 + #define FAN_EVENT_INFO_TYPE_ERROR 5 + ++/* Special info types for FAN_RENAME */ ++#define FAN_EVENT_INFO_TYPE_OLD_DFID_NAME 10 ++/* Reserved for FAN_EVENT_INFO_TYPE_OLD_DFID 11 */ ++#define FAN_EVENT_INFO_TYPE_NEW_DFID_NAME 12 ++/* Reserved for FAN_EVENT_INFO_TYPE_NEW_DFID 13 */ ++ + /* Variable length info record following event metadata */ + struct fanotify_event_info_header { + __u8 info_type; +-- +2.43.0 + diff --git a/queue-5.10/fanotify-require-fid_mode-for-any-non-fd-event.patch b/queue-5.10/fanotify-require-fid_mode-for-any-non-fd-event.patch new file mode 100644 index 00000000000..570a5d408a9 --- /dev/null +++ b/queue-5.10/fanotify-require-fid_mode-for-any-non-fd-event.patch @@ -0,0 +1,69 @@ +From 17a920326f6144f2502d6525121b89a404e8903e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 Oct 2021 16:27:31 -0300 +Subject: fanotify: Require fid_mode for any non-fd event + +From: Gabriel Krisman Bertazi + +[ Upstream commit 4fe595cf1c80e7a5af4d00c4da29def64aff57a2 ] + +Like inode events, FAN_FS_ERROR will require fid mode. Therefore, +convert the verification during fanotify_mark(2) to require fid for any +non-fd event. This means fid_mode will not only be required for inode +events, but for any event that doesn't provide a descriptor. + +Link: https://lore.kernel.org/r/20211025192746.66445-17-krisman@collabora.com +Suggested-by: Amir Goldstein +Reviewed-by: Jan Kara +Reviewed-by: Amir Goldstein +Signed-off-by: Gabriel Krisman Bertazi +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify_user.c | 12 ++++++------ + include/linux/fanotify.h | 3 +++ + 2 files changed, 9 insertions(+), 6 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c +index 6dd6a2e05f55d..34bf71108f7a3 100644 +--- a/fs/notify/fanotify/fanotify_user.c ++++ b/fs/notify/fanotify/fanotify_user.c +@@ -1471,14 +1471,14 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, + goto fput_and_out; + + /* +- * Events with data type inode do not carry enough information to report +- * event->fd, so we do not allow setting a mask for inode events unless +- * group supports reporting fid. +- * inode events are not supported on a mount mark, because they do not +- * carry enough information (i.e. path) to be filtered by mount point. ++ * Events that do not carry enough information to report ++ * event->fd require a group that supports reporting fid. Those ++ * events are not supported on a mount mark, because they do not ++ * carry enough information (i.e. path) to be filtered by mount ++ * point. + */ + fid_mode = FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS); +- if (mask & FANOTIFY_INODE_EVENTS && ++ if (mask & ~(FANOTIFY_FD_EVENTS|FANOTIFY_EVENT_FLAGS) && + (!fid_mode || mark_type == FAN_MARK_MOUNT)) + goto fput_and_out; + +diff --git a/include/linux/fanotify.h b/include/linux/fanotify.h +index eec3b7c408115..52d464802d99f 100644 +--- a/include/linux/fanotify.h ++++ b/include/linux/fanotify.h +@@ -84,6 +84,9 @@ extern struct ctl_table fanotify_table[]; /* for sysctl */ + */ + #define FANOTIFY_DIRENT_EVENTS (FAN_MOVE | FAN_CREATE | FAN_DELETE) + ++/* Events that can be reported with event->fd */ ++#define FANOTIFY_FD_EVENTS (FANOTIFY_PATH_EVENTS | FANOTIFY_PERM_EVENTS) ++ + /* Events that can only be reported with data type FSNOTIFY_EVENT_INODE */ + #define FANOTIFY_INODE_EVENTS (FANOTIFY_DIRENT_EVENTS | \ + FAN_ATTRIB | FAN_MOVE_SELF | FAN_DELETE_SELF) +-- +2.43.0 + diff --git a/queue-5.10/fanotify-reserve-uapi-bits-for-fan_fs_error.patch b/queue-5.10/fanotify-reserve-uapi-bits-for-fan_fs_error.patch new file mode 100644 index 00000000000..c31219d6553 --- /dev/null +++ b/queue-5.10/fanotify-reserve-uapi-bits-for-fan_fs_error.patch @@ -0,0 +1,52 @@ +From 5f1f3fbfe806597959f1b380cfeb8c52a5e72937 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 Oct 2021 16:27:33 -0300 +Subject: fanotify: Reserve UAPI bits for FAN_FS_ERROR + +From: Gabriel Krisman Bertazi + +[ Upstream commit 8d11a4f43ef4679be0908026907a7613b33d7127 ] + +FAN_FS_ERROR allows reporting of event type FS_ERROR to userspace, which +is a mechanism to report file system wide problems via fanotify. This +commit preallocate userspace visible bits to match the FS_ERROR event. + +Link: https://lore.kernel.org/r/20211025192746.66445-19-krisman@collabora.com +Reviewed-by: Jan Kara +Reviewed-by: Amir Goldstein +Signed-off-by: Gabriel Krisman Bertazi +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify.c | 1 + + include/uapi/linux/fanotify.h | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c +index c64d61b673caf..8f152445d75c4 100644 +--- a/fs/notify/fanotify/fanotify.c ++++ b/fs/notify/fanotify/fanotify.c +@@ -752,6 +752,7 @@ static int fanotify_handle_event(struct fsnotify_group *group, u32 mask, + BUILD_BUG_ON(FAN_ONDIR != FS_ISDIR); + BUILD_BUG_ON(FAN_OPEN_EXEC != FS_OPEN_EXEC); + BUILD_BUG_ON(FAN_OPEN_EXEC_PERM != FS_OPEN_EXEC_PERM); ++ BUILD_BUG_ON(FAN_FS_ERROR != FS_ERROR); + + BUILD_BUG_ON(HWEIGHT32(ALL_FANOTIFY_EVENT_BITS) != 19); + +diff --git a/include/uapi/linux/fanotify.h b/include/uapi/linux/fanotify.h +index 64553df9d7350..2990731ddc8bc 100644 +--- a/include/uapi/linux/fanotify.h ++++ b/include/uapi/linux/fanotify.h +@@ -20,6 +20,7 @@ + #define FAN_OPEN_EXEC 0x00001000 /* File was opened for exec */ + + #define FAN_Q_OVERFLOW 0x00004000 /* Event queued overflowed */ ++#define FAN_FS_ERROR 0x00008000 /* Filesystem error */ + + #define FAN_OPEN_PERM 0x00010000 /* File open in perm check */ + #define FAN_ACCESS_PERM 0x00020000 /* File accessed in perm check */ +-- +2.43.0 + diff --git a/queue-5.10/fanotify-split-fsid-check-from-other-fid-mode-checks.patch b/queue-5.10/fanotify-split-fsid-check-from-other-fid-mode-checks.patch new file mode 100644 index 00000000000..68e54fccf89 --- /dev/null +++ b/queue-5.10/fanotify-split-fsid-check-from-other-fid-mode-checks.patch @@ -0,0 +1,104 @@ +From 0f5e491541fd0c09f2ae199629f0cc97d4fcee6f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 Oct 2021 16:27:21 -0300 +Subject: fanotify: Split fsid check from other fid mode checks + +From: Gabriel Krisman Bertazi + +[ Upstream commit 8299212cbdb01a5867e230e961f82e5c02a6de34 ] + +FAN_FS_ERROR will require fsid, but not necessarily require the +filesystem to expose a file handle. Split those checks into different +functions, so they can be used separately when setting up an event. + +While there, update a comment about tmpfs having 0 fsid, which is no +longer true. + +Link: https://lore.kernel.org/r/20211025192746.66445-7-krisman@collabora.com +Reviewed-by: Amir Goldstein +Reviewed-by: Jan Kara +Signed-off-by: Gabriel Krisman Bertazi +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify_user.c | 27 ++++++++++++++++++--------- + 1 file changed, 18 insertions(+), 9 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c +index 846e2a661526c..6dd6a2e05f55d 100644 +--- a/fs/notify/fanotify/fanotify_user.c ++++ b/fs/notify/fanotify/fanotify_user.c +@@ -1295,16 +1295,15 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) + return fd; + } + +-/* Check if filesystem can encode a unique fid */ +-static int fanotify_test_fid(struct path *path, __kernel_fsid_t *fsid) ++static int fanotify_test_fsid(struct dentry *dentry, __kernel_fsid_t *fsid) + { + __kernel_fsid_t root_fsid; + int err; + + /* +- * Make sure path is not in filesystem with zero fsid (e.g. tmpfs). ++ * Make sure dentry is not of a filesystem with zero fsid (e.g. fuse). + */ +- err = vfs_get_fsid(path->dentry, fsid); ++ err = vfs_get_fsid(dentry, fsid); + if (err) + return err; + +@@ -1312,10 +1311,10 @@ static int fanotify_test_fid(struct path *path, __kernel_fsid_t *fsid) + return -ENODEV; + + /* +- * Make sure path is not inside a filesystem subvolume (e.g. btrfs) ++ * Make sure dentry is not of a filesystem subvolume (e.g. btrfs) + * which uses a different fsid than sb root. + */ +- err = vfs_get_fsid(path->dentry->d_sb->s_root, &root_fsid); ++ err = vfs_get_fsid(dentry->d_sb->s_root, &root_fsid); + if (err) + return err; + +@@ -1323,6 +1322,12 @@ static int fanotify_test_fid(struct path *path, __kernel_fsid_t *fsid) + root_fsid.val[1] != fsid->val[1]) + return -EXDEV; + ++ return 0; ++} ++ ++/* Check if filesystem can encode a unique fid */ ++static int fanotify_test_fid(struct dentry *dentry) ++{ + /* + * We need to make sure that the file system supports at least + * encoding a file handle so user can use name_to_handle_at() to +@@ -1330,8 +1335,8 @@ static int fanotify_test_fid(struct path *path, __kernel_fsid_t *fsid) + * objects. However, name_to_handle_at() requires that the + * filesystem also supports decoding file handles. + */ +- if (!path->dentry->d_sb->s_export_op || +- !path->dentry->d_sb->s_export_op->fh_to_dentry) ++ if (!dentry->d_sb->s_export_op || ++ !dentry->d_sb->s_export_op->fh_to_dentry) + return -EOPNOTSUPP; + + return 0; +@@ -1500,7 +1505,11 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, + } + + if (fid_mode) { +- ret = fanotify_test_fid(&path, &__fsid); ++ ret = fanotify_test_fsid(path.dentry, &__fsid); ++ if (ret) ++ goto path_put_and_out; ++ ++ ret = fanotify_test_fid(path.dentry); + if (ret) + goto path_put_and_out; + +-- +2.43.0 + diff --git a/queue-5.10/fanotify-support-enqueueing-of-error-events.patch b/queue-5.10/fanotify-support-enqueueing-of-error-events.patch new file mode 100644 index 00000000000..f26880856a8 --- /dev/null +++ b/queue-5.10/fanotify-support-enqueueing-of-error-events.patch @@ -0,0 +1,123 @@ +From 04f432b73026ab19f0a3762f2ae059c7721b0493 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 Oct 2021 16:27:35 -0300 +Subject: fanotify: Support enqueueing of error events + +From: Gabriel Krisman Bertazi + +[ Upstream commit 83e9acbe13dc1b767f91b5c1350f7a65689b26f6 ] + +Once an error event is triggered, enqueue it in the notification group, +similarly to what is done for other events. FAN_FS_ERROR is not +handled specially, since the memory is now handled by a preallocated +mempool. + +For now, make the event unhashed. A future patch implements merging of +this kind of event. + +Link: https://lore.kernel.org/r/20211025192746.66445-21-krisman@collabora.com +Reviewed-by: Jan Kara +Reviewed-by: Amir Goldstein +Signed-off-by: Gabriel Krisman Bertazi +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify.c | 35 +++++++++++++++++++++++++++++++++++ + fs/notify/fanotify/fanotify.h | 6 ++++++ + 2 files changed, 41 insertions(+) + +diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c +index 01d68dfc74aa2..1f195c95dfcd0 100644 +--- a/fs/notify/fanotify/fanotify.c ++++ b/fs/notify/fanotify/fanotify.c +@@ -574,6 +574,27 @@ static struct fanotify_event *fanotify_alloc_name_event(struct inode *id, + return &fne->fae; + } + ++static struct fanotify_event *fanotify_alloc_error_event( ++ struct fsnotify_group *group, ++ __kernel_fsid_t *fsid, ++ const void *data, int data_type) ++{ ++ struct fs_error_report *report = ++ fsnotify_data_error_report(data, data_type); ++ struct fanotify_error_event *fee; ++ ++ if (WARN_ON_ONCE(!report)) ++ return NULL; ++ ++ fee = mempool_alloc(&group->fanotify_data.error_events_pool, GFP_NOFS); ++ if (!fee) ++ return NULL; ++ ++ fee->fae.type = FANOTIFY_EVENT_TYPE_FS_ERROR; ++ ++ return &fee->fae; ++} ++ + static struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group, + u32 mask, const void *data, + int data_type, struct inode *dir, +@@ -641,6 +662,9 @@ static struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group, + + if (fanotify_is_perm_event(mask)) { + event = fanotify_alloc_perm_event(path, gfp); ++ } else if (fanotify_is_error_event(mask)) { ++ event = fanotify_alloc_error_event(group, fsid, data, ++ data_type); + } else if (name_event && (file_name || child)) { + event = fanotify_alloc_name_event(id, fsid, file_name, child, + &hash, gfp); +@@ -850,6 +874,14 @@ static void fanotify_free_name_event(struct fanotify_event *event) + kfree(FANOTIFY_NE(event)); + } + ++static void fanotify_free_error_event(struct fsnotify_group *group, ++ struct fanotify_event *event) ++{ ++ struct fanotify_error_event *fee = FANOTIFY_EE(event); ++ ++ mempool_free(fee, &group->fanotify_data.error_events_pool); ++} ++ + static void fanotify_free_event(struct fsnotify_group *group, + struct fsnotify_event *fsn_event) + { +@@ -873,6 +905,9 @@ static void fanotify_free_event(struct fsnotify_group *group, + case FANOTIFY_EVENT_TYPE_OVERFLOW: + kfree(event); + break; ++ case FANOTIFY_EVENT_TYPE_FS_ERROR: ++ fanotify_free_error_event(group, event); ++ break; + default: + WARN_ON_ONCE(1); + } +diff --git a/fs/notify/fanotify/fanotify.h b/fs/notify/fanotify/fanotify.h +index a577e87fac2b4..ebef952481fa0 100644 +--- a/fs/notify/fanotify/fanotify.h ++++ b/fs/notify/fanotify/fanotify.h +@@ -298,6 +298,11 @@ static inline struct fanotify_event *FANOTIFY_E(struct fsnotify_event *fse) + return container_of(fse, struct fanotify_event, fse); + } + ++static inline bool fanotify_is_error_event(u32 mask) ++{ ++ return mask & FAN_FS_ERROR; ++} ++ + static inline bool fanotify_event_has_path(struct fanotify_event *event) + { + return event->type == FANOTIFY_EVENT_TYPE_PATH || +@@ -327,6 +332,7 @@ static inline struct path *fanotify_event_path(struct fanotify_event *event) + static inline bool fanotify_is_hashed_event(u32 mask) + { + return !(fanotify_is_perm_event(mask) || ++ fanotify_is_error_event(mask) || + fsnotify_is_overflow_event(mask)); + } + +-- +2.43.0 + diff --git a/queue-5.10/fanotify-support-limited-functionality-for-unprivile.patch b/queue-5.10/fanotify-support-limited-functionality-for-unprivile.patch new file mode 100644 index 00000000000..f6567cfe657 --- /dev/null +++ b/queue-5.10/fanotify-support-limited-functionality-for-unprivile.patch @@ -0,0 +1,161 @@ +From 8820101c07d8c7d211a8bb2082969a1104b14710 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Mar 2021 13:29:21 +0200 +Subject: fanotify: support limited functionality for unprivileged users + +From: Amir Goldstein + +[ Upstream commit 7cea2a3c505e87a9d6afc78be4a7f7be636a73a7 ] + +Add limited support for unprivileged fanotify groups. +An unprivileged users is not allowed to get an open file descriptor in +the event nor the process pid of another process. An unprivileged user +cannot request permission events, cannot set mount/filesystem marks and +cannot request unlimited queue/marks. + +This enables the limited functionality similar to inotify when watching a +set of files and directories for OPEN/ACCESS/MODIFY/CLOSE events, without +requiring SYS_CAP_ADMIN privileges. + +The FAN_REPORT_DFID_NAME init flag, provide a method for an unprivileged +listener watching a set of directories (with FAN_EVENT_ON_CHILD) to monitor +all changes inside those directories. + +This typically requires that the listener keeps a map of watched directory +fid to dirfd (O_PATH), where fid is obtained with name_to_handle_at() +before starting to watch for changes. + +When getting an event, the reported fid of the parent should be resolved +to dirfd and fstatsat(2) with dirfd and name should be used to query the +state of the filesystem entry. + +Link: https://lore.kernel.org/r/20210304112921.3996419-3-amir73il@gmail.com +Signed-off-by: Amir Goldstein +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify_user.c | 29 ++++++++++++++++++++++++-- + fs/notify/fdinfo.c | 3 ++- + include/linux/fanotify.h | 33 +++++++++++++++++++++++++----- + 3 files changed, 57 insertions(+), 8 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c +index 74b4da6354e1c..842cccb4f7499 100644 +--- a/fs/notify/fanotify/fanotify_user.c ++++ b/fs/notify/fanotify/fanotify_user.c +@@ -419,6 +419,14 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group, + metadata.reserved = 0; + metadata.mask = event->mask & FANOTIFY_OUTGOING_EVENTS; + metadata.pid = pid_vnr(event->pid); ++ /* ++ * For an unprivileged listener, event->pid can be used to identify the ++ * events generated by the listener process itself, without disclosing ++ * the pids of other processes. ++ */ ++ if (!capable(CAP_SYS_ADMIN) && ++ task_tgid(current) != event->pid) ++ metadata.pid = 0; + + if (path && path->mnt && path->dentry) { + fd = create_fd(group, path, &f); +@@ -1036,8 +1044,16 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) + pr_debug("%s: flags=%x event_f_flags=%x\n", + __func__, flags, event_f_flags); + +- if (!capable(CAP_SYS_ADMIN)) +- return -EPERM; ++ if (!capable(CAP_SYS_ADMIN)) { ++ /* ++ * An unprivileged user can setup an fanotify group with ++ * limited functionality - an unprivileged group is limited to ++ * notification events with file handles and it cannot use ++ * unlimited queue/marks. ++ */ ++ if ((flags & FANOTIFY_ADMIN_INIT_FLAGS) || !fid_mode) ++ return -EPERM; ++ } + + #ifdef CONFIG_AUDITSYSCALL + if (flags & ~(FANOTIFY_INIT_FLAGS | FAN_ENABLE_AUDIT)) +@@ -1306,6 +1322,15 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, + goto fput_and_out; + group = f.file->private_data; + ++ /* ++ * An unprivileged user is not allowed to watch a mount point nor ++ * a filesystem. ++ */ ++ ret = -EPERM; ++ if (!capable(CAP_SYS_ADMIN) && ++ mark_type != FAN_MARK_INODE) ++ goto fput_and_out; ++ + /* + * group->priority == FS_PRIO_0 == FAN_CLASS_NOTIF. These are not + * allowed to set permissions events. +diff --git a/fs/notify/fdinfo.c b/fs/notify/fdinfo.c +index 765b50aeadd28..85b112bd88511 100644 +--- a/fs/notify/fdinfo.c ++++ b/fs/notify/fdinfo.c +@@ -137,7 +137,8 @@ void fanotify_show_fdinfo(struct seq_file *m, struct file *f) + struct fsnotify_group *group = f->private_data; + + seq_printf(m, "fanotify flags:%x event-flags:%x\n", +- group->fanotify_data.flags, group->fanotify_data.f_flags); ++ group->fanotify_data.flags, ++ group->fanotify_data.f_flags); + + show_fdinfo(m, f, fanotify_fdinfo); + } +diff --git a/include/linux/fanotify.h b/include/linux/fanotify.h +index 031a97d8369ae..bad41bcb25dfb 100644 +--- a/include/linux/fanotify.h ++++ b/include/linux/fanotify.h +@@ -18,15 +18,38 @@ extern struct ctl_table fanotify_table[]; /* for sysctl */ + * these constant, the programs may break if re-compiled with new uapi headers + * and then run on an old kernel. + */ +-#define FANOTIFY_CLASS_BITS (FAN_CLASS_NOTIF | FAN_CLASS_CONTENT | \ ++ ++/* Group classes where permission events are allowed */ ++#define FANOTIFY_PERM_CLASSES (FAN_CLASS_CONTENT | \ + FAN_CLASS_PRE_CONTENT) + ++#define FANOTIFY_CLASS_BITS (FAN_CLASS_NOTIF | FANOTIFY_PERM_CLASSES) ++ + #define FANOTIFY_FID_BITS (FAN_REPORT_FID | FAN_REPORT_DFID_NAME) + +-#define FANOTIFY_INIT_FLAGS (FANOTIFY_CLASS_BITS | FANOTIFY_FID_BITS | \ +- FAN_REPORT_TID | \ +- FAN_CLOEXEC | FAN_NONBLOCK | \ +- FAN_UNLIMITED_QUEUE | FAN_UNLIMITED_MARKS) ++/* ++ * fanotify_init() flags that require CAP_SYS_ADMIN. ++ * We do not allow unprivileged groups to request permission events. ++ * We do not allow unprivileged groups to get other process pid in events. ++ * We do not allow unprivileged groups to use unlimited resources. ++ */ ++#define FANOTIFY_ADMIN_INIT_FLAGS (FANOTIFY_PERM_CLASSES | \ ++ FAN_REPORT_TID | \ ++ FAN_UNLIMITED_QUEUE | \ ++ FAN_UNLIMITED_MARKS) ++ ++/* ++ * fanotify_init() flags that are allowed for user without CAP_SYS_ADMIN. ++ * FAN_CLASS_NOTIF is the only class we allow for unprivileged group. ++ * We do not allow unprivileged groups to get file descriptors in events, ++ * so one of the flags for reporting file handles is required. ++ */ ++#define FANOTIFY_USER_INIT_FLAGS (FAN_CLASS_NOTIF | \ ++ FANOTIFY_FID_BITS | \ ++ FAN_CLOEXEC | FAN_NONBLOCK) ++ ++#define FANOTIFY_INIT_FLAGS (FANOTIFY_ADMIN_INIT_FLAGS | \ ++ FANOTIFY_USER_INIT_FLAGS) + + #define FANOTIFY_MARK_TYPE_BITS (FAN_MARK_INODE | FAN_MARK_MOUNT | \ + FAN_MARK_FILESYSTEM) +-- +2.43.0 + diff --git a/queue-5.10/fanotify-support-merging-of-error-events.patch b/queue-5.10/fanotify-support-merging-of-error-events.patch new file mode 100644 index 00000000000..ff704f324e1 --- /dev/null +++ b/queue-5.10/fanotify-support-merging-of-error-events.patch @@ -0,0 +1,123 @@ +From 391a57c91a9015d6a4f46aa3c77ed46c73c54265 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 Oct 2021 16:27:36 -0300 +Subject: fanotify: Support merging of error events + +From: Gabriel Krisman Bertazi + +[ Upstream commit 8a6ae64132fd27a944faed7bc38484827609eb76 ] + +Error events (FAN_FS_ERROR) against the same file system can be merged +by simply iterating the error count. The hash is taken from the fsid, +without considering the FH. This means that only the first error object +is reported. + +Link: https://lore.kernel.org/r/20211025192746.66445-22-krisman@collabora.com +Reviewed-by: Amir Goldstein +Reviewed-by: Jan Kara +Signed-off-by: Gabriel Krisman Bertazi +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify.c | 26 ++++++++++++++++++++++++-- + fs/notify/fanotify/fanotify.h | 4 +++- + 2 files changed, 27 insertions(+), 3 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c +index 1f195c95dfcd0..cedcb15468043 100644 +--- a/fs/notify/fanotify/fanotify.c ++++ b/fs/notify/fanotify/fanotify.c +@@ -111,6 +111,16 @@ static bool fanotify_name_event_equal(struct fanotify_name_event *fne1, + return fanotify_info_equal(info1, info2); + } + ++static bool fanotify_error_event_equal(struct fanotify_error_event *fee1, ++ struct fanotify_error_event *fee2) ++{ ++ /* Error events against the same file system are always merged. */ ++ if (!fanotify_fsid_equal(&fee1->fsid, &fee2->fsid)) ++ return false; ++ ++ return true; ++} ++ + static bool fanotify_should_merge(struct fanotify_event *old, + struct fanotify_event *new) + { +@@ -141,6 +151,9 @@ static bool fanotify_should_merge(struct fanotify_event *old, + case FANOTIFY_EVENT_TYPE_FID_NAME: + return fanotify_name_event_equal(FANOTIFY_NE(old), + FANOTIFY_NE(new)); ++ case FANOTIFY_EVENT_TYPE_FS_ERROR: ++ return fanotify_error_event_equal(FANOTIFY_EE(old), ++ FANOTIFY_EE(new)); + default: + WARN_ON_ONCE(1); + } +@@ -176,6 +189,10 @@ static int fanotify_merge(struct fsnotify_group *group, + break; + if (fanotify_should_merge(old, new)) { + old->mask |= new->mask; ++ ++ if (fanotify_is_error_event(old->mask)) ++ FANOTIFY_EE(old)->err_count++; ++ + return 1; + } + } +@@ -577,7 +594,8 @@ static struct fanotify_event *fanotify_alloc_name_event(struct inode *id, + static struct fanotify_event *fanotify_alloc_error_event( + struct fsnotify_group *group, + __kernel_fsid_t *fsid, +- const void *data, int data_type) ++ const void *data, int data_type, ++ unsigned int *hash) + { + struct fs_error_report *report = + fsnotify_data_error_report(data, data_type); +@@ -591,6 +609,10 @@ static struct fanotify_event *fanotify_alloc_error_event( + return NULL; + + fee->fae.type = FANOTIFY_EVENT_TYPE_FS_ERROR; ++ fee->err_count = 1; ++ fee->fsid = *fsid; ++ ++ *hash ^= fanotify_hash_fsid(fsid); + + return &fee->fae; + } +@@ -664,7 +686,7 @@ static struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group, + event = fanotify_alloc_perm_event(path, gfp); + } else if (fanotify_is_error_event(mask)) { + event = fanotify_alloc_error_event(group, fsid, data, +- data_type); ++ data_type, &hash); + } else if (name_event && (file_name || child)) { + event = fanotify_alloc_name_event(id, fsid, file_name, child, + &hash, gfp); +diff --git a/fs/notify/fanotify/fanotify.h b/fs/notify/fanotify/fanotify.h +index ebef952481fa0..2b032b79d5b06 100644 +--- a/fs/notify/fanotify/fanotify.h ++++ b/fs/notify/fanotify/fanotify.h +@@ -199,6 +199,9 @@ FANOTIFY_NE(struct fanotify_event *event) + + struct fanotify_error_event { + struct fanotify_event fae; ++ u32 err_count; /* Suppressed errors count */ ++ ++ __kernel_fsid_t fsid; /* FSID this error refers to. */ + }; + + static inline struct fanotify_error_event * +@@ -332,7 +335,6 @@ static inline struct path *fanotify_event_path(struct fanotify_event *event) + static inline bool fanotify_is_hashed_event(u32 mask) + { + return !(fanotify_is_perm_event(mask) || +- fanotify_is_error_event(mask) || + fsnotify_is_overflow_event(mask)); + } + +-- +2.43.0 + diff --git a/queue-5.10/fanotify-support-null-inode-event-in-fanotify_dfid_i.patch b/queue-5.10/fanotify-support-null-inode-event-in-fanotify_dfid_i.patch new file mode 100644 index 00000000000..f75d735f718 --- /dev/null +++ b/queue-5.10/fanotify-support-null-inode-event-in-fanotify_dfid_i.patch @@ -0,0 +1,41 @@ +From bc844e528cb21b270bd6ec834a4504658ac4415c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 Oct 2021 16:27:28 -0300 +Subject: fanotify: Support null inode event in fanotify_dfid_inode + +From: Gabriel Krisman Bertazi + +[ Upstream commit 12f47bf0f0990933d95d021d13d31bda010648fd ] + +FAN_FS_ERROR doesn't support DFID, but this function is still called for +every event. The problem is that it is not capable of handling null +inodes, which now can happen in case of superblock error events. For +this case, just returning dir will be enough. + +Link: https://lore.kernel.org/r/20211025192746.66445-14-krisman@collabora.com +Reviewed-by: Amir Goldstein +Reviewed-by: Jan Kara +Signed-off-by: Gabriel Krisman Bertazi +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c +index c620b4f6fe123..397ee623ff1e8 100644 +--- a/fs/notify/fanotify/fanotify.c ++++ b/fs/notify/fanotify/fanotify.c +@@ -452,7 +452,7 @@ static struct inode *fanotify_dfid_inode(u32 event_mask, const void *data, + if (event_mask & ALL_FSNOTIFY_DIRENT_EVENTS) + return dir; + +- if (S_ISDIR(inode->i_mode)) ++ if (inode && S_ISDIR(inode->i_mode)) + return inode; + + return dir; +-- +2.43.0 + diff --git a/queue-5.10/fanotify-support-secondary-dir-fh-and-name-in-fanoti.patch b/queue-5.10/fanotify-support-secondary-dir-fh-and-name-in-fanoti.patch new file mode 100644 index 00000000000..1bd2b426a36 --- /dev/null +++ b/queue-5.10/fanotify-support-secondary-dir-fh-and-name-in-fanoti.patch @@ -0,0 +1,248 @@ +From bfa4c11a10f11994313f27ae33240a4c61805462 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Nov 2021 22:15:33 +0200 +Subject: fanotify: support secondary dir fh and name in fanotify_info + +From: Amir Goldstein + +[ Upstream commit 3cf984e950c1c3f41d407ed31db33beb996be132 ] + +Allow storing a secondary dir fh and name tupple in fanotify_info. +This will be used to store the new parent and name information in +FAN_RENAME event. + +Link: https://lore.kernel.org/r/20211129201537.1932819-8-amir73il@gmail.com +Signed-off-by: Amir Goldstein +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify.c | 20 ++++++-- + fs/notify/fanotify/fanotify.h | 79 +++++++++++++++++++++++++++--- + fs/notify/fanotify/fanotify_user.c | 3 +- + 3 files changed, 88 insertions(+), 14 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c +index 2b13c79cebc62..5f184b2d6ea7c 100644 +--- a/fs/notify/fanotify/fanotify.c ++++ b/fs/notify/fanotify/fanotify.c +@@ -76,8 +76,10 @@ static bool fanotify_info_equal(struct fanotify_info *info1, + struct fanotify_info *info2) + { + if (info1->dir_fh_totlen != info2->dir_fh_totlen || ++ info1->dir2_fh_totlen != info2->dir2_fh_totlen || + info1->file_fh_totlen != info2->file_fh_totlen || +- info1->name_len != info2->name_len) ++ info1->name_len != info2->name_len || ++ info1->name2_len != info2->name2_len) + return false; + + if (info1->dir_fh_totlen && +@@ -85,14 +87,24 @@ static bool fanotify_info_equal(struct fanotify_info *info1, + fanotify_info_dir_fh(info2))) + return false; + ++ if (info1->dir2_fh_totlen && ++ !fanotify_fh_equal(fanotify_info_dir2_fh(info1), ++ fanotify_info_dir2_fh(info2))) ++ return false; ++ + if (info1->file_fh_totlen && + !fanotify_fh_equal(fanotify_info_file_fh(info1), + fanotify_info_file_fh(info2))) + return false; + +- return !info1->name_len || +- !memcmp(fanotify_info_name(info1), fanotify_info_name(info2), +- info1->name_len); ++ if (info1->name_len && ++ memcmp(fanotify_info_name(info1), fanotify_info_name(info2), ++ info1->name_len)) ++ return false; ++ ++ return !info1->name2_len || ++ !memcmp(fanotify_info_name2(info1), fanotify_info_name2(info2), ++ info1->name2_len); + } + + static bool fanotify_name_event_equal(struct fanotify_name_event *fne1, +diff --git a/fs/notify/fanotify/fanotify.h b/fs/notify/fanotify/fanotify.h +index 7ac6f9f1e4148..8fa3bc0effd45 100644 +--- a/fs/notify/fanotify/fanotify.h ++++ b/fs/notify/fanotify/fanotify.h +@@ -40,31 +40,45 @@ struct fanotify_fh { + struct fanotify_info { + /* size of dir_fh/file_fh including fanotify_fh hdr size */ + u8 dir_fh_totlen; ++ u8 dir2_fh_totlen; + u8 file_fh_totlen; + u8 name_len; +- u8 pad; ++ u8 name2_len; ++ u8 pad[3]; + unsigned char buf[]; + /* + * (struct fanotify_fh) dir_fh starts at buf[0] +- * (optional) file_fh starts at buf[dir_fh_totlen] +- * name starts at buf[dir_fh_totlen + file_fh_totlen] ++ * (optional) dir2_fh starts at buf[dir_fh_totlen] ++ * (optional) file_fh starts at buf[dir_fh_totlen + dir2_fh_totlen] ++ * name starts at buf[dir_fh_totlen + dir2_fh_totlen + file_fh_totlen] ++ * ... + */ + #define FANOTIFY_DIR_FH_SIZE(info) ((info)->dir_fh_totlen) ++#define FANOTIFY_DIR2_FH_SIZE(info) ((info)->dir2_fh_totlen) + #define FANOTIFY_FILE_FH_SIZE(info) ((info)->file_fh_totlen) + #define FANOTIFY_NAME_SIZE(info) ((info)->name_len + 1) ++#define FANOTIFY_NAME2_SIZE(info) ((info)->name2_len + 1) + + #define FANOTIFY_DIR_FH_OFFSET(info) 0 +-#define FANOTIFY_FILE_FH_OFFSET(info) \ ++#define FANOTIFY_DIR2_FH_OFFSET(info) \ + (FANOTIFY_DIR_FH_OFFSET(info) + FANOTIFY_DIR_FH_SIZE(info)) ++#define FANOTIFY_FILE_FH_OFFSET(info) \ ++ (FANOTIFY_DIR2_FH_OFFSET(info) + FANOTIFY_DIR2_FH_SIZE(info)) + #define FANOTIFY_NAME_OFFSET(info) \ + (FANOTIFY_FILE_FH_OFFSET(info) + FANOTIFY_FILE_FH_SIZE(info)) ++#define FANOTIFY_NAME2_OFFSET(info) \ ++ (FANOTIFY_NAME_OFFSET(info) + FANOTIFY_NAME_SIZE(info)) + + #define FANOTIFY_DIR_FH_BUF(info) \ + ((info)->buf + FANOTIFY_DIR_FH_OFFSET(info)) ++#define FANOTIFY_DIR2_FH_BUF(info) \ ++ ((info)->buf + FANOTIFY_DIR2_FH_OFFSET(info)) + #define FANOTIFY_FILE_FH_BUF(info) \ + ((info)->buf + FANOTIFY_FILE_FH_OFFSET(info)) + #define FANOTIFY_NAME_BUF(info) \ + ((info)->buf + FANOTIFY_NAME_OFFSET(info)) ++#define FANOTIFY_NAME2_BUF(info) \ ++ ((info)->buf + FANOTIFY_NAME2_OFFSET(info)) + } __aligned(4); + + static inline bool fanotify_fh_has_ext_buf(struct fanotify_fh *fh) +@@ -106,6 +120,20 @@ static inline struct fanotify_fh *fanotify_info_dir_fh(struct fanotify_info *inf + return (struct fanotify_fh *)FANOTIFY_DIR_FH_BUF(info); + } + ++static inline int fanotify_info_dir2_fh_len(struct fanotify_info *info) ++{ ++ if (!info->dir2_fh_totlen || ++ WARN_ON_ONCE(info->dir2_fh_totlen < FANOTIFY_FH_HDR_LEN)) ++ return 0; ++ ++ return info->dir2_fh_totlen - FANOTIFY_FH_HDR_LEN; ++} ++ ++static inline struct fanotify_fh *fanotify_info_dir2_fh(struct fanotify_info *info) ++{ ++ return (struct fanotify_fh *)FANOTIFY_DIR2_FH_BUF(info); ++} ++ + static inline int fanotify_info_file_fh_len(struct fanotify_info *info) + { + if (!info->file_fh_totlen || +@@ -128,31 +156,55 @@ static inline char *fanotify_info_name(struct fanotify_info *info) + return FANOTIFY_NAME_BUF(info); + } + ++static inline char *fanotify_info_name2(struct fanotify_info *info) ++{ ++ if (!info->name2_len) ++ return NULL; ++ ++ return FANOTIFY_NAME2_BUF(info); ++} ++ + static inline void fanotify_info_init(struct fanotify_info *info) + { + BUILD_BUG_ON(FANOTIFY_FH_HDR_LEN + MAX_HANDLE_SZ > U8_MAX); + BUILD_BUG_ON(NAME_MAX > U8_MAX); + + info->dir_fh_totlen = 0; ++ info->dir2_fh_totlen = 0; + info->file_fh_totlen = 0; + info->name_len = 0; ++ info->name2_len = 0; + } + + /* These set/copy helpers MUST be called by order */ + static inline void fanotify_info_set_dir_fh(struct fanotify_info *info, + unsigned int totlen) + { +- if (WARN_ON_ONCE(info->file_fh_totlen > 0) || +- WARN_ON_ONCE(info->name_len > 0)) ++ if (WARN_ON_ONCE(info->dir2_fh_totlen > 0) || ++ WARN_ON_ONCE(info->file_fh_totlen > 0) || ++ WARN_ON_ONCE(info->name_len > 0) || ++ WARN_ON_ONCE(info->name2_len > 0)) + return; + + info->dir_fh_totlen = totlen; + } + ++static inline void fanotify_info_set_dir2_fh(struct fanotify_info *info, ++ unsigned int totlen) ++{ ++ if (WARN_ON_ONCE(info->file_fh_totlen > 0) || ++ WARN_ON_ONCE(info->name_len > 0) || ++ WARN_ON_ONCE(info->name2_len > 0)) ++ return; ++ ++ info->dir2_fh_totlen = totlen; ++} ++ + static inline void fanotify_info_set_file_fh(struct fanotify_info *info, + unsigned int totlen) + { +- if (WARN_ON_ONCE(info->name_len > 0)) ++ if (WARN_ON_ONCE(info->name_len > 0) || ++ WARN_ON_ONCE(info->name2_len > 0)) + return; + + info->file_fh_totlen = totlen; +@@ -161,13 +213,24 @@ static inline void fanotify_info_set_file_fh(struct fanotify_info *info, + static inline void fanotify_info_copy_name(struct fanotify_info *info, + const struct qstr *name) + { +- if (WARN_ON_ONCE(name->len > NAME_MAX)) ++ if (WARN_ON_ONCE(name->len > NAME_MAX) || ++ WARN_ON_ONCE(info->name2_len > 0)) + return; + + info->name_len = name->len; + strcpy(fanotify_info_name(info), name->name); + } + ++static inline void fanotify_info_copy_name2(struct fanotify_info *info, ++ const struct qstr *name) ++{ ++ if (WARN_ON_ONCE(name->len > NAME_MAX)) ++ return; ++ ++ info->name2_len = name->len; ++ strcpy(fanotify_info_name2(info), name->name); ++} ++ + /* + * Common structure for fanotify events. Concrete structs are allocated in + * fanotify_handle_event() and freed when the information is retrieved by +diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c +index 6b058d652f47b..d69570db5efd2 100644 +--- a/fs/notify/fanotify/fanotify_user.c ++++ b/fs/notify/fanotify/fanotify_user.c +@@ -327,11 +327,10 @@ static int process_access_response(struct fsnotify_group *group, + static size_t copy_error_info_to_user(struct fanotify_event *event, + char __user *buf, int count) + { +- struct fanotify_event_info_error info; ++ struct fanotify_event_info_error info = { }; + struct fanotify_error_event *fee = FANOTIFY_EE(event); + + info.hdr.info_type = FAN_EVENT_INFO_TYPE_ERROR; +- info.hdr.pad = 0; + info.hdr.len = FANOTIFY_ERROR_INFO_LEN; + + if (WARN_ON(count < info.hdr.len)) +-- +2.43.0 + diff --git a/queue-5.10/fanotify-use-fsnotify-group-lock-helpers.patch b/queue-5.10/fanotify-use-fsnotify-group-lock-helpers.patch new file mode 100644 index 00000000000..4012a7badfa --- /dev/null +++ b/queue-5.10/fanotify-use-fsnotify-group-lock-helpers.patch @@ -0,0 +1,113 @@ +From 0b9983c80190586543aa6d38f1e7b75afebb9f25 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 Apr 2022 15:03:26 +0300 +Subject: fanotify: use fsnotify group lock helpers + +From: Amir Goldstein + +[ Upstream commit e79719a2ca5c61912c0493bc1367db52759cf6fd ] + +Direct reclaim from fanotify mark allocation context may try to evict +inodes with evictable marks of the same group and hit this deadlock: + +[<0>] fsnotify_destroy_mark+0x1f/0x3a +[<0>] fsnotify_destroy_marks+0x71/0xd9 +[<0>] __destroy_inode+0x24/0x7e +[<0>] destroy_inode+0x2c/0x67 +[<0>] dispose_list+0x49/0x68 +[<0>] prune_icache_sb+0x5b/0x79 +[<0>] super_cache_scan+0x11c/0x16f +[<0>] shrink_slab.constprop.0+0x23e/0x40f +[<0>] shrink_node+0x218/0x3e7 +[<0>] do_try_to_free_pages+0x12a/0x2d2 +[<0>] try_to_free_pages+0x166/0x242 +[<0>] __alloc_pages_slowpath.constprop.0+0x30c/0x903 +[<0>] __alloc_pages+0xeb/0x1c7 +[<0>] cache_grow_begin+0x6f/0x31e +[<0>] fallback_alloc+0xe0/0x12d +[<0>] ____cache_alloc_node+0x15a/0x17e +[<0>] kmem_cache_alloc_trace+0xa1/0x143 +[<0>] fanotify_add_mark+0xd5/0x2b2 +[<0>] do_fanotify_mark+0x566/0x5eb +[<0>] __x64_sys_fanotify_mark+0x21/0x24 +[<0>] do_syscall_64+0x6d/0x80 +[<0>] entry_SYSCALL_64_after_hwframe+0x44/0xae + +Set the FSNOTIFY_GROUP_NOFS flag to prevent going into direct reclaim +from allocations under fanotify group lock and use the safe group lock +helpers. + +Link: https://lore.kernel.org/r/20220422120327.3459282-16-amir73il@gmail.com +Suggested-by: Jan Kara +Link: https://lore.kernel.org/r/20220321112310.vpr7oxro2xkz5llh@quack3.lan/ +Signed-off-by: Amir Goldstein +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify_user.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c +index ab7a13686b49d..ad520a2796181 100644 +--- a/fs/notify/fanotify/fanotify_user.c ++++ b/fs/notify/fanotify/fanotify_user.c +@@ -1023,10 +1023,10 @@ static int fanotify_remove_mark(struct fsnotify_group *group, + __u32 removed; + int destroy_mark; + +- mutex_lock(&group->mark_mutex); ++ fsnotify_group_lock(group); + fsn_mark = fsnotify_find_mark(connp, group); + if (!fsn_mark) { +- mutex_unlock(&group->mark_mutex); ++ fsnotify_group_unlock(group); + return -ENOENT; + } + +@@ -1036,7 +1036,7 @@ static int fanotify_remove_mark(struct fsnotify_group *group, + fsnotify_recalc_mask(fsn_mark->connector); + if (destroy_mark) + fsnotify_detach_mark(fsn_mark); +- mutex_unlock(&group->mark_mutex); ++ fsnotify_group_unlock(group); + if (destroy_mark) + fsnotify_free_mark(fsn_mark); + +@@ -1184,13 +1184,13 @@ static int fanotify_add_mark(struct fsnotify_group *group, + bool recalc; + int ret = 0; + +- mutex_lock(&group->mark_mutex); ++ fsnotify_group_lock(group); + fsn_mark = fsnotify_find_mark(connp, group); + if (!fsn_mark) { + fsn_mark = fanotify_add_new_mark(group, connp, obj_type, + fan_flags, fsid); + if (IS_ERR(fsn_mark)) { +- mutex_unlock(&group->mark_mutex); ++ fsnotify_group_unlock(group); + return PTR_ERR(fsn_mark); + } + } +@@ -1219,7 +1219,7 @@ static int fanotify_add_mark(struct fsnotify_group *group, + fsnotify_recalc_mask(fsn_mark->connector); + + out: +- mutex_unlock(&group->mark_mutex); ++ fsnotify_group_unlock(group); + + fsnotify_put_mark(fsn_mark); + return ret; +@@ -1373,7 +1373,7 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) + + /* fsnotify_alloc_group takes a ref. Dropped in fanotify_release */ + group = fsnotify_alloc_group(&fanotify_fsnotify_ops, +- FSNOTIFY_GROUP_USER); ++ FSNOTIFY_GROUP_USER | FSNOTIFY_GROUP_NOFS); + if (IS_ERR(group)) { + return PTR_ERR(group); + } +-- +2.43.0 + diff --git a/queue-5.10/fanotify-use-helpers-to-parcel-fanotify_info-buffer.patch b/queue-5.10/fanotify-use-helpers-to-parcel-fanotify_info-buffer.patch new file mode 100644 index 00000000000..d760a29bf58 --- /dev/null +++ b/queue-5.10/fanotify-use-helpers-to-parcel-fanotify_info-buffer.patch @@ -0,0 +1,130 @@ +From 2067855ce9afffbaaa3b5e3c7b1060324ae8bdf3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Nov 2021 22:15:32 +0200 +Subject: fanotify: use helpers to parcel fanotify_info buffer + +From: Amir Goldstein + +[ Upstream commit 1a9515ac9e55e68d733bab81bd408463ab1e25b1 ] + +fanotify_info buffer is parceled into variable sized records, so the +records must be written in order: dir_fh, file_fh, name. + +Use helpers to assert that order and make fanotify_alloc_name_event() +a bit more generic to allow empty dir_fh record and to allow expanding +to more records (i.e. name2) soon. + +Link: https://lore.kernel.org/r/20211129201537.1932819-7-amir73il@gmail.com +Signed-off-by: Amir Goldstein +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify.c | 35 +++++++++++++++++++---------------- + fs/notify/fanotify/fanotify.h | 20 ++++++++++++++++++++ + 2 files changed, 39 insertions(+), 16 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c +index ffad224be0149..2b13c79cebc62 100644 +--- a/fs/notify/fanotify/fanotify.c ++++ b/fs/notify/fanotify/fanotify.c +@@ -576,7 +576,7 @@ static struct fanotify_event *fanotify_alloc_fid_event(struct inode *id, + return &ffe->fae; + } + +-static struct fanotify_event *fanotify_alloc_name_event(struct inode *id, ++static struct fanotify_event *fanotify_alloc_name_event(struct inode *dir, + __kernel_fsid_t *fsid, + const struct qstr *name, + struct inode *child, +@@ -586,15 +586,17 @@ static struct fanotify_event *fanotify_alloc_name_event(struct inode *id, + struct fanotify_name_event *fne; + struct fanotify_info *info; + struct fanotify_fh *dfh, *ffh; +- unsigned int dir_fh_len = fanotify_encode_fh_len(id); ++ unsigned int dir_fh_len = fanotify_encode_fh_len(dir); + unsigned int child_fh_len = fanotify_encode_fh_len(child); +- unsigned int size; ++ unsigned long name_len = name ? name->len : 0; ++ unsigned int len, size; + +- size = sizeof(*fne) + FANOTIFY_FH_HDR_LEN + dir_fh_len; ++ /* Reserve terminating null byte even for empty name */ ++ size = sizeof(*fne) + name_len + 1; ++ if (dir_fh_len) ++ size += FANOTIFY_FH_HDR_LEN + dir_fh_len; + if (child_fh_len) + size += FANOTIFY_FH_HDR_LEN + child_fh_len; +- if (name) +- size += name->len + 1; + fne = kmalloc(size, gfp); + if (!fne) + return NULL; +@@ -604,22 +606,23 @@ static struct fanotify_event *fanotify_alloc_name_event(struct inode *id, + *hash ^= fanotify_hash_fsid(fsid); + info = &fne->info; + fanotify_info_init(info); +- dfh = fanotify_info_dir_fh(info); +- info->dir_fh_totlen = fanotify_encode_fh(dfh, id, dir_fh_len, hash, 0); ++ if (dir_fh_len) { ++ dfh = fanotify_info_dir_fh(info); ++ len = fanotify_encode_fh(dfh, dir, dir_fh_len, hash, 0); ++ fanotify_info_set_dir_fh(info, len); ++ } + if (child_fh_len) { + ffh = fanotify_info_file_fh(info); +- info->file_fh_totlen = fanotify_encode_fh(ffh, child, +- child_fh_len, hash, 0); ++ len = fanotify_encode_fh(ffh, child, child_fh_len, hash, 0); ++ fanotify_info_set_file_fh(info, len); + } +- if (name) { +- long salt = name->len; +- ++ if (name_len) { + fanotify_info_copy_name(info, name); +- *hash ^= full_name_hash((void *)salt, name->name, name->len); ++ *hash ^= full_name_hash((void *)name_len, name->name, name_len); + } + +- pr_debug("%s: ino=%lu size=%u dir_fh_len=%u child_fh_len=%u name_len=%u name='%.*s'\n", +- __func__, id->i_ino, size, dir_fh_len, child_fh_len, ++ pr_debug("%s: size=%u dir_fh_len=%u child_fh_len=%u name_len=%u name='%.*s'\n", ++ __func__, size, dir_fh_len, child_fh_len, + info->name_len, info->name_len, fanotify_info_name(info)); + + return &fne->fae; +diff --git a/fs/notify/fanotify/fanotify.h b/fs/notify/fanotify/fanotify.h +index dd23ba659e76b..7ac6f9f1e4148 100644 +--- a/fs/notify/fanotify/fanotify.h ++++ b/fs/notify/fanotify/fanotify.h +@@ -138,6 +138,26 @@ static inline void fanotify_info_init(struct fanotify_info *info) + info->name_len = 0; + } + ++/* These set/copy helpers MUST be called by order */ ++static inline void fanotify_info_set_dir_fh(struct fanotify_info *info, ++ unsigned int totlen) ++{ ++ if (WARN_ON_ONCE(info->file_fh_totlen > 0) || ++ WARN_ON_ONCE(info->name_len > 0)) ++ return; ++ ++ info->dir_fh_totlen = totlen; ++} ++ ++static inline void fanotify_info_set_file_fh(struct fanotify_info *info, ++ unsigned int totlen) ++{ ++ if (WARN_ON_ONCE(info->name_len > 0)) ++ return; ++ ++ info->file_fh_totlen = totlen; ++} ++ + static inline void fanotify_info_copy_name(struct fanotify_info *info, + const struct qstr *name) + { +-- +2.43.0 + diff --git a/queue-5.10/fanotify-use-macros-to-get-the-offset-to-fanotify_in.patch b/queue-5.10/fanotify-use-macros-to-get-the-offset-to-fanotify_in.patch new file mode 100644 index 00000000000..68093e2cf14 --- /dev/null +++ b/queue-5.10/fanotify-use-macros-to-get-the-offset-to-fanotify_in.patch @@ -0,0 +1,126 @@ +From 49dc429db4b4128740c1681a65471a80537d0a5c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Nov 2021 22:15:31 +0200 +Subject: fanotify: use macros to get the offset to fanotify_info buffer + +From: Amir Goldstein + +[ Upstream commit 2d9374f095136206a02eb0b6cd9ef94632c1e9f7 ] + +The fanotify_info buffer contains up to two file handles and a name. +Use macros to simplify the code that access the different items within +the buffer. + +Add assertions to verify that stored fh len and name len do not overflow +the u8 stored value in fanotify_info header. + +Remove the unused fanotify_info_len() helper. + +Link: https://lore.kernel.org/r/20211129201537.1932819-6-amir73il@gmail.com +Signed-off-by: Amir Goldstein +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify.c | 2 +- + fs/notify/fanotify/fanotify.h | 41 +++++++++++++++++++++++++---------- + 2 files changed, 31 insertions(+), 12 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c +index 85e542b164c8c..ffad224be0149 100644 +--- a/fs/notify/fanotify/fanotify.c ++++ b/fs/notify/fanotify/fanotify.c +@@ -411,7 +411,7 @@ static int fanotify_encode_fh(struct fanotify_fh *fh, struct inode *inode, + * be zero in that case if encoding fh len failed. + */ + err = -ENOENT; +- if (fh_len < 4 || WARN_ON_ONCE(fh_len % 4)) ++ if (fh_len < 4 || WARN_ON_ONCE(fh_len % 4) || fh_len > MAX_HANDLE_SZ) + goto out_err; + + /* No external buffer in a variable size allocated fh */ +diff --git a/fs/notify/fanotify/fanotify.h b/fs/notify/fanotify/fanotify.h +index d25f500bf7e79..dd23ba659e76b 100644 +--- a/fs/notify/fanotify/fanotify.h ++++ b/fs/notify/fanotify/fanotify.h +@@ -49,6 +49,22 @@ struct fanotify_info { + * (optional) file_fh starts at buf[dir_fh_totlen] + * name starts at buf[dir_fh_totlen + file_fh_totlen] + */ ++#define FANOTIFY_DIR_FH_SIZE(info) ((info)->dir_fh_totlen) ++#define FANOTIFY_FILE_FH_SIZE(info) ((info)->file_fh_totlen) ++#define FANOTIFY_NAME_SIZE(info) ((info)->name_len + 1) ++ ++#define FANOTIFY_DIR_FH_OFFSET(info) 0 ++#define FANOTIFY_FILE_FH_OFFSET(info) \ ++ (FANOTIFY_DIR_FH_OFFSET(info) + FANOTIFY_DIR_FH_SIZE(info)) ++#define FANOTIFY_NAME_OFFSET(info) \ ++ (FANOTIFY_FILE_FH_OFFSET(info) + FANOTIFY_FILE_FH_SIZE(info)) ++ ++#define FANOTIFY_DIR_FH_BUF(info) \ ++ ((info)->buf + FANOTIFY_DIR_FH_OFFSET(info)) ++#define FANOTIFY_FILE_FH_BUF(info) \ ++ ((info)->buf + FANOTIFY_FILE_FH_OFFSET(info)) ++#define FANOTIFY_NAME_BUF(info) \ ++ ((info)->buf + FANOTIFY_NAME_OFFSET(info)) + } __aligned(4); + + static inline bool fanotify_fh_has_ext_buf(struct fanotify_fh *fh) +@@ -87,7 +103,7 @@ static inline struct fanotify_fh *fanotify_info_dir_fh(struct fanotify_info *inf + { + BUILD_BUG_ON(offsetof(struct fanotify_info, buf) % 4); + +- return (struct fanotify_fh *)info->buf; ++ return (struct fanotify_fh *)FANOTIFY_DIR_FH_BUF(info); + } + + static inline int fanotify_info_file_fh_len(struct fanotify_info *info) +@@ -101,32 +117,35 @@ static inline int fanotify_info_file_fh_len(struct fanotify_info *info) + + static inline struct fanotify_fh *fanotify_info_file_fh(struct fanotify_info *info) + { +- return (struct fanotify_fh *)(info->buf + info->dir_fh_totlen); ++ return (struct fanotify_fh *)FANOTIFY_FILE_FH_BUF(info); + } + +-static inline const char *fanotify_info_name(struct fanotify_info *info) ++static inline char *fanotify_info_name(struct fanotify_info *info) + { +- return info->buf + info->dir_fh_totlen + info->file_fh_totlen; ++ if (!info->name_len) ++ return NULL; ++ ++ return FANOTIFY_NAME_BUF(info); + } + + static inline void fanotify_info_init(struct fanotify_info *info) + { ++ BUILD_BUG_ON(FANOTIFY_FH_HDR_LEN + MAX_HANDLE_SZ > U8_MAX); ++ BUILD_BUG_ON(NAME_MAX > U8_MAX); ++ + info->dir_fh_totlen = 0; + info->file_fh_totlen = 0; + info->name_len = 0; + } + +-static inline unsigned int fanotify_info_len(struct fanotify_info *info) +-{ +- return info->dir_fh_totlen + info->file_fh_totlen + info->name_len; +-} +- + static inline void fanotify_info_copy_name(struct fanotify_info *info, + const struct qstr *name) + { ++ if (WARN_ON_ONCE(name->len > NAME_MAX)) ++ return; ++ + info->name_len = name->len; +- strcpy(info->buf + info->dir_fh_totlen + info->file_fh_totlen, +- name->name); ++ strcpy(fanotify_info_name(info), name->name); + } + + /* +-- +2.43.0 + diff --git a/queue-5.10/fanotify-warn_on-against-too-large-file-handles.patch b/queue-5.10/fanotify-warn_on-against-too-large-file-handles.patch new file mode 100644 index 00000000000..15cdf2f78c3 --- /dev/null +++ b/queue-5.10/fanotify-warn_on-against-too-large-file-handles.patch @@ -0,0 +1,56 @@ +From 125e8a5a7b76b37d8bfd92185238fc6d8ca67256 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 Oct 2021 16:27:40 -0300 +Subject: fanotify: WARN_ON against too large file handles + +From: Gabriel Krisman Bertazi + +[ Upstream commit 572c28f27a269f88e2d8d7b6b1507f114d637337 ] + +struct fanotify_error_event, at least, is preallocated and isn't able to +to handle arbitrarily large file handles. Future-proof the code by +complaining loudly if a handle larger than MAX_HANDLE_SZ is ever found. + +Link: https://lore.kernel.org/r/20211025192746.66445-26-krisman@collabora.com +Reviewed-by: Amir Goldstein +Reviewed-by: Jan Kara +Signed-off-by: Gabriel Krisman Bertazi +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify.c | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c +index cedcb15468043..45df610debbe4 100644 +--- a/fs/notify/fanotify/fanotify.c ++++ b/fs/notify/fanotify/fanotify.c +@@ -360,13 +360,23 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group, + static int fanotify_encode_fh_len(struct inode *inode) + { + int dwords = 0; ++ int fh_len; + + if (!inode) + return 0; + + exportfs_encode_inode_fh(inode, NULL, &dwords, NULL); ++ fh_len = dwords << 2; + +- return dwords << 2; ++ /* ++ * struct fanotify_error_event might be preallocated and is ++ * limited to MAX_HANDLE_SZ. This should never happen, but ++ * safeguard by forcing an invalid file handle. ++ */ ++ if (WARN_ON_ONCE(fh_len > MAX_HANDLE_SZ)) ++ return 0; ++ ++ return fh_len; + } + + /* +-- +2.43.0 + diff --git a/queue-5.10/fanotify-wire-up-fan_rename-event.patch b/queue-5.10/fanotify-wire-up-fan_rename-event.patch new file mode 100644 index 00000000000..da7c473efad --- /dev/null +++ b/queue-5.10/fanotify-wire-up-fan_rename-event.patch @@ -0,0 +1,82 @@ +From 837d3efd5bc1d45a0bad68dd04f47aefddcd5da7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Nov 2021 22:15:37 +0200 +Subject: fanotify: wire up FAN_RENAME event + +From: Amir Goldstein + +[ Upstream commit 8cc3b1ccd930fe6971e1527f0c4f1bdc8cb56026 ] + +FAN_RENAME is the successor of FAN_MOVED_FROM and FAN_MOVED_TO +and can be used to get the old and new parent+name information in +a single event. + +FAN_MOVED_FROM and FAN_MOVED_TO are still supported for backward +compatibility, but it makes little sense to use them together with +FAN_RENAME in the same group. + +FAN_RENAME uses special info type records to report the old and +new parent+name, so reporting only old and new parent id is less +useful and was not implemented. +Therefore, FAN_REANAME requires a group with flag FAN_REPORT_NAME. + +Link: https://lore.kernel.org/r/20211129201537.1932819-12-amir73il@gmail.com +Signed-off-by: Amir Goldstein +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify.c | 2 +- + fs/notify/fanotify/fanotify_user.c | 8 ++++++++ + include/linux/fanotify.h | 3 ++- + 3 files changed, 11 insertions(+), 2 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c +index 0da305b6f3e2f..985e995d2a398 100644 +--- a/fs/notify/fanotify/fanotify.c ++++ b/fs/notify/fanotify/fanotify.c +@@ -930,7 +930,7 @@ static int fanotify_handle_event(struct fsnotify_group *group, u32 mask, + BUILD_BUG_ON(FAN_FS_ERROR != FS_ERROR); + BUILD_BUG_ON(FAN_RENAME != FS_RENAME); + +- BUILD_BUG_ON(HWEIGHT32(ALL_FANOTIFY_EVENT_BITS) != 20); ++ BUILD_BUG_ON(HWEIGHT32(ALL_FANOTIFY_EVENT_BITS) != 21); + + mask = fanotify_group_event_mask(group, iter_info, &match_mask, + mask, data, data_type, dir); +diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c +index e16b18fdf1a65..3bac2329dc35f 100644 +--- a/fs/notify/fanotify/fanotify_user.c ++++ b/fs/notify/fanotify/fanotify_user.c +@@ -1599,6 +1599,14 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, + (!fid_mode || mark_type == FAN_MARK_MOUNT)) + goto fput_and_out; + ++ /* ++ * FAN_RENAME uses special info type records to report the old and ++ * new parent+name. Reporting only old and new parent id is less ++ * useful and was not implemented. ++ */ ++ if (mask & FAN_RENAME && !(fid_mode & FAN_REPORT_NAME)) ++ goto fput_and_out; ++ + if (flags & FAN_MARK_FLUSH) { + ret = 0; + if (mark_type == FAN_MARK_MOUNT) +diff --git a/include/linux/fanotify.h b/include/linux/fanotify.h +index 376e050e6f384..3afdf339d53c9 100644 +--- a/include/linux/fanotify.h ++++ b/include/linux/fanotify.h +@@ -82,7 +82,8 @@ extern struct ctl_table fanotify_table[]; /* for sysctl */ + * Directory entry modification events - reported only to directory + * where entry is modified and not to a watching parent. + */ +-#define FANOTIFY_DIRENT_EVENTS (FAN_MOVE | FAN_CREATE | FAN_DELETE) ++#define FANOTIFY_DIRENT_EVENTS (FAN_MOVE | FAN_CREATE | FAN_DELETE | \ ++ FAN_RENAME) + + /* Events that can be reported with event->fd */ + #define FANOTIFY_FD_EVENTS (FANOTIFY_PATH_EVENTS | FANOTIFY_PERM_EVENTS) +-- +2.43.0 + diff --git a/queue-5.10/fanotify-wrap-object_fh-inline-space-in-a-creator-ma.patch b/queue-5.10/fanotify-wrap-object_fh-inline-space-in-a-creator-ma.patch new file mode 100644 index 00000000000..d8a71a0c638 --- /dev/null +++ b/queue-5.10/fanotify-wrap-object_fh-inline-space-in-a-creator-ma.patch @@ -0,0 +1,54 @@ +From 2ac220253abee9b1f68d26466f5a6219e4c25b3f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 Oct 2021 16:27:37 -0300 +Subject: fanotify: Wrap object_fh inline space in a creator macro + +From: Gabriel Krisman Bertazi + +[ Upstream commit 2c5069433a3adc01ff9c5673567961bb7f138074 ] + +fanotify_error_event would duplicate this sequence of declarations that +already exist elsewhere with a slight different size. Create a helper +macro to avoid code duplication. + +Link: https://lore.kernel.org/r/20211025192746.66445-23-krisman@collabora.com +Suggested-by: Jan Kara +Reviewed-by: Amir Goldstein +Reviewed-by: Jan Kara +Signed-off-by: Gabriel Krisman Bertazi +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify.h | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify.h b/fs/notify/fanotify/fanotify.h +index 2b032b79d5b06..3510d06654ed0 100644 +--- a/fs/notify/fanotify/fanotify.h ++++ b/fs/notify/fanotify/fanotify.h +@@ -171,12 +171,18 @@ static inline void fanotify_init_event(struct fanotify_event *event, + event->pid = NULL; + } + ++#define FANOTIFY_INLINE_FH(name, size) \ ++struct { \ ++ struct fanotify_fh (name); \ ++ /* Space for object_fh.buf[] - access with fanotify_fh_buf() */ \ ++ unsigned char _inline_fh_buf[(size)]; \ ++} ++ + struct fanotify_fid_event { + struct fanotify_event fae; + __kernel_fsid_t fsid; +- struct fanotify_fh object_fh; +- /* Reserve space in object_fh.buf[] - access with fanotify_fh_buf() */ +- unsigned char _inline_fh_buf[FANOTIFY_INLINE_FH_LEN]; ++ ++ FANOTIFY_INLINE_FH(object_fh, FANOTIFY_INLINE_FH_LEN); + }; + + static inline struct fanotify_fid_event * +-- +2.43.0 + diff --git a/queue-5.10/fanotify_user-use-upper_32_bits-to-verify-mask.patch b/queue-5.10/fanotify_user-use-upper_32_bits-to-verify-mask.patch new file mode 100644 index 00000000000..157ddb7d2f4 --- /dev/null +++ b/queue-5.10/fanotify_user-use-upper_32_bits-to-verify-mask.patch @@ -0,0 +1,40 @@ +From 5a09f4182243bad5dd4cedad43e1fe55e66ded7e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 25 Mar 2021 09:37:43 +0100 +Subject: fanotify_user: use upper_32_bits() to verify mask + +From: Christian Brauner + +[ Upstream commit 22d483b99863202e3631ff66fa0f3c2302c0f96f ] + +I don't see an obvious reason why the upper 32 bit check needs to be +open-coded this way. Switch to upper_32_bits() which is more idiomatic and +should conceptually be the same check. + +Cc: Amir Goldstein +Cc: Jan Kara +Link: https://lore.kernel.org/r/20210325083742.2334933-1-brauner@kernel.org +Signed-off-by: Christian Brauner +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify_user.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c +index 842cccb4f7499..98289ace66fac 100644 +--- a/fs/notify/fanotify/fanotify_user.c ++++ b/fs/notify/fanotify/fanotify_user.c +@@ -1268,7 +1268,7 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask, + __func__, fanotify_fd, flags, dfd, pathname, mask); + + /* we only use the lower 32 bits as of right now. */ +- if (mask & ((__u64)0xffffffff << 32)) ++ if (upper_32_bits(mask)) + return -EINVAL; + + if (flags & ~FANOTIFY_MARK_FLAGS) +-- +2.43.0 + diff --git a/queue-5.10/file-factor-files_lookup_fd_locked-out-of-fcheck_fil.patch b/queue-5.10/file-factor-files_lookup_fd_locked-out-of-fcheck_fil.patch new file mode 100644 index 00000000000..84f3473e443 --- /dev/null +++ b/queue-5.10/file-factor-files_lookup_fd_locked-out-of-fcheck_fil.patch @@ -0,0 +1,122 @@ +From c33f7df863623f9e08f90dbaf8fd116a957fa688 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Nov 2020 17:14:25 -0600 +Subject: file: Factor files_lookup_fd_locked out of fcheck_files + +From: Eric W. Biederman + +[ Upstream commit 120ce2b0cd52abe73e8b16c23461eb14df5a87d8 ] + +To make it easy to tell where files->file_lock protection is being +used when looking up a file create files_lookup_fd_locked. Only allow +this function to be called with the file_lock held. + +Update the callers of fcheck and fcheck_files that are called with the +files->file_lock held to call files_lookup_fd_locked instead. + +Hopefully this makes it easier to quickly understand what is going on. + +The need for better names became apparent in the last round of +discussion of this set of changes[1]. + +[1] https://lkml.kernel.org/r/CAHk-=wj8BQbgJFLa+J0e=iT-1qpmCRTbPAJ8gd6MJQ=kbRPqyQ@mail.gmail.com +Link: https://lkml.kernel.org/r/20201120231441.29911-8-ebiederm@xmission.com +Signed-off-by: Eric W. Biederman +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/file.c | 2 +- + fs/locks.c | 14 ++++++++------ + fs/proc/fd.c | 2 +- + include/linux/fdtable.h | 7 +++++++ + 4 files changed, 17 insertions(+), 8 deletions(-) + +diff --git a/fs/file.c b/fs/file.c +index eb1e2b7220ac6..6a6b03ce4ad69 100644 +--- a/fs/file.c ++++ b/fs/file.c +@@ -1158,7 +1158,7 @@ static int ksys_dup3(unsigned int oldfd, unsigned int newfd, int flags) + + spin_lock(&files->file_lock); + err = expand_files(files, newfd); +- file = fcheck(oldfd); ++ file = files_lookup_fd_locked(files, oldfd); + if (unlikely(!file)) + goto Ebadf; + if (unlikely(err < 0)) { +diff --git a/fs/locks.c b/fs/locks.c +index cbb5701ce9f37..873f97504bddf 100644 +--- a/fs/locks.c ++++ b/fs/locks.c +@@ -2536,14 +2536,15 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd, + */ + if (!error && file_lock->fl_type != F_UNLCK && + !(file_lock->fl_flags & FL_OFDLCK)) { ++ struct files_struct *files = current->files; + /* + * We need that spin_lock here - it prevents reordering between + * update of i_flctx->flc_posix and check for it done in + * close(). rcu_read_lock() wouldn't do. + */ +- spin_lock(¤t->files->file_lock); +- f = fcheck(fd); +- spin_unlock(¤t->files->file_lock); ++ spin_lock(&files->file_lock); ++ f = files_lookup_fd_locked(files, fd); ++ spin_unlock(&files->file_lock); + if (f != filp) { + file_lock->fl_type = F_UNLCK; + error = do_lock_file_wait(filp, cmd, file_lock); +@@ -2667,14 +2668,15 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd, + */ + if (!error && file_lock->fl_type != F_UNLCK && + !(file_lock->fl_flags & FL_OFDLCK)) { ++ struct files_struct *files = current->files; + /* + * We need that spin_lock here - it prevents reordering between + * update of i_flctx->flc_posix and check for it done in + * close(). rcu_read_lock() wouldn't do. + */ +- spin_lock(¤t->files->file_lock); +- f = fcheck(fd); +- spin_unlock(¤t->files->file_lock); ++ spin_lock(&files->file_lock); ++ f = files_lookup_fd_locked(files, fd); ++ spin_unlock(&files->file_lock); + if (f != filp) { + file_lock->fl_type = F_UNLCK; + error = do_lock_file_wait(filp, cmd, file_lock); +diff --git a/fs/proc/fd.c b/fs/proc/fd.c +index d58960f6ee524..2cca9bca3b3a3 100644 +--- a/fs/proc/fd.c ++++ b/fs/proc/fd.c +@@ -35,7 +35,7 @@ static int seq_show(struct seq_file *m, void *v) + unsigned int fd = proc_fd(m->private); + + spin_lock(&files->file_lock); +- file = fcheck_files(files, fd); ++ file = files_lookup_fd_locked(files, fd); + if (file) { + struct fdtable *fdt = files_fdtable(files); + +diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h +index 10e75b4c30a43..87be704268d26 100644 +--- a/include/linux/fdtable.h ++++ b/include/linux/fdtable.h +@@ -91,6 +91,13 @@ static inline struct file *files_lookup_fd_raw(struct files_struct *files, unsig + return NULL; + } + ++static inline struct file *files_lookup_fd_locked(struct files_struct *files, unsigned int fd) ++{ ++ RCU_LOCKDEP_WARN(!lockdep_is_held(&files->file_lock), ++ "suspicious rcu_dereference_check() usage"); ++ return files_lookup_fd_raw(files, fd); ++} ++ + static inline struct file *fcheck_files(struct files_struct *files, unsigned int fd) + { + RCU_LOCKDEP_WARN(!rcu_read_lock_held() && +-- +2.43.0 + diff --git a/queue-5.10/file-implement-task_lookup_fd_rcu.patch b/queue-5.10/file-implement-task_lookup_fd_rcu.patch new file mode 100644 index 00000000000..45d2a425785 --- /dev/null +++ b/queue-5.10/file-implement-task_lookup_fd_rcu.patch @@ -0,0 +1,65 @@ +From 3f3708f566736fa1cfa783187da901a6cbcde952 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Nov 2020 17:14:28 -0600 +Subject: file: Implement task_lookup_fd_rcu + +From: Eric W. Biederman + +[ Upstream commit 3a879fb38082125cc0d8aa89b70c7f3a7cdf584b ] + +As a companion to lookup_fd_rcu implement task_lookup_fd_rcu for +querying an arbitrary process about a specific file. + +Acked-by: Christian Brauner +v1: https://lkml.kernel.org/r/20200818103713.aw46m7vprsy4vlve@wittgenstein +Link: https://lkml.kernel.org/r/20201120231441.29911-11-ebiederm@xmission.com +Signed-off-by: Eric W. Biederman +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/file.c | 15 +++++++++++++++ + include/linux/fdtable.h | 2 ++ + 2 files changed, 17 insertions(+) + +diff --git a/fs/file.c b/fs/file.c +index 6149f75a18a66..60a3ccba728cd 100644 +--- a/fs/file.c ++++ b/fs/file.c +@@ -911,6 +911,21 @@ struct file *fget_task(struct task_struct *task, unsigned int fd) + return file; + } + ++struct file *task_lookup_fd_rcu(struct task_struct *task, unsigned int fd) ++{ ++ /* Must be called with rcu_read_lock held */ ++ struct files_struct *files; ++ struct file *file = NULL; ++ ++ task_lock(task); ++ files = task->files; ++ if (files) ++ file = files_lookup_fd_rcu(files, fd); ++ task_unlock(task); ++ ++ return file; ++} ++ + /* + * Lightweight file lookup - no refcnt increment if fd table isn't shared. + * +diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h +index 695306cc5337a..a88f68f740677 100644 +--- a/include/linux/fdtable.h ++++ b/include/linux/fdtable.h +@@ -110,6 +110,8 @@ static inline struct file *lookup_fd_rcu(unsigned int fd) + return files_lookup_fd_rcu(current->files, fd); + } + ++struct file *task_lookup_fd_rcu(struct task_struct *task, unsigned int fd); ++ + struct task_struct; + + struct files_struct *get_files_struct(struct task_struct *); +-- +2.43.0 + diff --git a/queue-5.10/file-implement-task_lookup_next_fd_rcu.patch b/queue-5.10/file-implement-task_lookup_next_fd_rcu.patch new file mode 100644 index 00000000000..50847d47743 --- /dev/null +++ b/queue-5.10/file-implement-task_lookup_next_fd_rcu.patch @@ -0,0 +1,89 @@ +From ab786a84301ccd4708199bd45f66c5660301e09e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Nov 2020 17:14:31 -0600 +Subject: file: Implement task_lookup_next_fd_rcu + +From: Eric W. Biederman + +[ Upstream commit e9a53aeb5e0a838f10fcea74235664e7ad5e6e1a ] + +As a companion to fget_task and task_lookup_fd_rcu implement +task_lookup_next_fd_rcu that will return the struct file for the first +file descriptor number that is equal or greater than the fd argument +value, or NULL if there is no such struct file. + +This allows file descriptors of foreign processes to be iterated +through safely, without needed to increment the count on files_struct. + +Some concern[1] has been expressed that this function takes the task_lock +for each iteration and thus for each file descriptor. This place +where this function will be called in a commonly used code path is for +listing /proc//fd. I did some small benchmarks and did not see +any measurable performance differences. For ordinary users ls is +likely to stat each of the directory entries and tid_fd_mode called +from tid_fd_revalidae has always taken the task lock for each file +descriptor. So this does not look like it will be a big change in +practice. + +At some point is will probably be worth changing put_files_struct to +free files_struct after an rcu grace period so that task_lock won't be +needed at all. + +[1] https://lkml.kernel.org/r/20200817220425.9389-10-ebiederm@xmission.com +v1: https://lkml.kernel.org/r/20200817220425.9389-9-ebiederm@xmission.com +Link: https://lkml.kernel.org/r/20201120231441.29911-14-ebiederm@xmission.com +Signed-off-by: Eric W. Biederman +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/file.c | 21 +++++++++++++++++++++ + include/linux/fdtable.h | 1 + + 2 files changed, 22 insertions(+) + +diff --git a/fs/file.c b/fs/file.c +index 60a3ccba728cd..9fa49e6298fba 100644 +--- a/fs/file.c ++++ b/fs/file.c +@@ -926,6 +926,27 @@ struct file *task_lookup_fd_rcu(struct task_struct *task, unsigned int fd) + return file; + } + ++struct file *task_lookup_next_fd_rcu(struct task_struct *task, unsigned int *ret_fd) ++{ ++ /* Must be called with rcu_read_lock held */ ++ struct files_struct *files; ++ unsigned int fd = *ret_fd; ++ struct file *file = NULL; ++ ++ task_lock(task); ++ files = task->files; ++ if (files) { ++ for (; fd < files_fdtable(files)->max_fds; fd++) { ++ file = files_lookup_fd_rcu(files, fd); ++ if (file) ++ break; ++ } ++ } ++ task_unlock(task); ++ *ret_fd = fd; ++ return file; ++} ++ + /* + * Lightweight file lookup - no refcnt increment if fd table isn't shared. + * +diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h +index a88f68f740677..b0c6a959c6a00 100644 +--- a/include/linux/fdtable.h ++++ b/include/linux/fdtable.h +@@ -111,6 +111,7 @@ static inline struct file *lookup_fd_rcu(unsigned int fd) + } + + struct file *task_lookup_fd_rcu(struct task_struct *task, unsigned int fd); ++struct file *task_lookup_next_fd_rcu(struct task_struct *task, unsigned int *fd); + + struct task_struct; + +-- +2.43.0 + diff --git a/queue-5.10/file-in-f_dupfd-read-rlimit_nofile-once.patch b/queue-5.10/file-in-f_dupfd-read-rlimit_nofile-once.patch new file mode 100644 index 00000000000..b4ed15a1b92 --- /dev/null +++ b/queue-5.10/file-in-f_dupfd-read-rlimit_nofile-once.patch @@ -0,0 +1,60 @@ +From e8a8458ab206395b87d4c15d952abff7786cb84a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Nov 2020 17:14:36 -0600 +Subject: file: In f_dupfd read RLIMIT_NOFILE once. + +From: Eric W. Biederman + +Simplify the code, and remove the chance of races by reading +RLIMIT_NOFILE only once in f_dupfd. + +Pass the read value of RLIMIT_NOFILE into alloc_fd which is the other +location the rlimit was read in f_dupfd. As f_dupfd is the only +caller of alloc_fd this changing alloc_fd is trivially safe. + +Further this causes alloc_fd to take all of the same arguments as +__alloc_fd except for the files_struct argument. + +Acked-by: Christian Brauner +v1: https://lkml.kernel.org/r/20200817220425.9389-15-ebiederm@xmission.com +Link: https://lkml.kernel.org/r/20201120231441.29911-19-ebiederm@xmission.com +Signed-off-by: Eric W. Biederman +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/file.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/fs/file.c b/fs/file.c +index a80deabe7f7dc..9e2b171b92520 100644 +--- a/fs/file.c ++++ b/fs/file.c +@@ -567,9 +567,9 @@ int __alloc_fd(struct files_struct *files, + return error; + } + +-static int alloc_fd(unsigned start, unsigned flags) ++static int alloc_fd(unsigned start, unsigned end, unsigned flags) + { +- return __alloc_fd(current->files, start, rlimit(RLIMIT_NOFILE), flags); ++ return __alloc_fd(current->files, start, end, flags); + } + + int __get_unused_fd_flags(unsigned flags, unsigned long nofile) +@@ -1235,10 +1235,11 @@ SYSCALL_DEFINE1(dup, unsigned int, fildes) + + int f_dupfd(unsigned int from, struct file *file, unsigned flags) + { ++ unsigned long nofile = rlimit(RLIMIT_NOFILE); + int err; +- if (from >= rlimit(RLIMIT_NOFILE)) ++ if (from >= nofile) + return -EINVAL; +- err = alloc_fd(from, flags); ++ err = alloc_fd(from, nofile, flags); + if (err >= 0) { + get_file(file); + fd_install(err, file); +-- +2.43.0 + diff --git a/queue-5.10/file-merge-__alloc_fd-into-alloc_fd.patch b/queue-5.10/file-merge-__alloc_fd-into-alloc_fd.patch new file mode 100644 index 00000000000..5f73fae9540 --- /dev/null +++ b/queue-5.10/file-merge-__alloc_fd-into-alloc_fd.patch @@ -0,0 +1,77 @@ +From 8e0a0480ded04b7da413b74db4e0bd621e7aa916 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Nov 2020 17:14:37 -0600 +Subject: file: Merge __alloc_fd into alloc_fd + +From: Eric W. Biederman + +[ Upstream commit aa384d10f3d06d4b85597ff5df41551262220e16 ] + +The function __alloc_fd was added to support binder[1]. With binder +fixed[2] there are no more users. + +As alloc_fd just calls __alloc_fd with "files=current->files", +merge them together by transforming the files parameter into a +local variable initialized to current->files. + +[1] dcfadfa4ec5a ("new helper: __alloc_fd()") +[2] 44d8047f1d87 ("binder: use standard functions to allocate fds") +Acked-by: Christian Brauner +v1: https://lkml.kernel.org/r/20200817220425.9389-16-ebiederm@xmission.com +Link: https://lkml.kernel.org/r/20201120231441.29911-20-ebiederm@xmission.com +Signed-off-by: Eric W. Biederman +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/file.c | 11 +++-------- + include/linux/fdtable.h | 2 -- + 2 files changed, 3 insertions(+), 10 deletions(-) + +diff --git a/fs/file.c b/fs/file.c +index 9e2b171b92520..48d0306e42ccc 100644 +--- a/fs/file.c ++++ b/fs/file.c +@@ -509,9 +509,9 @@ static unsigned int find_next_fd(struct fdtable *fdt, unsigned int start) + /* + * allocate a file descriptor, mark it busy. + */ +-int __alloc_fd(struct files_struct *files, +- unsigned start, unsigned end, unsigned flags) ++static int alloc_fd(unsigned start, unsigned end, unsigned flags) + { ++ struct files_struct *files = current->files; + unsigned int fd; + int error; + struct fdtable *fdt; +@@ -567,14 +567,9 @@ int __alloc_fd(struct files_struct *files, + return error; + } + +-static int alloc_fd(unsigned start, unsigned end, unsigned flags) +-{ +- return __alloc_fd(current->files, start, end, flags); +-} +- + int __get_unused_fd_flags(unsigned flags, unsigned long nofile) + { +- return __alloc_fd(current->files, 0, nofile, flags); ++ return alloc_fd(0, nofile, flags); + } + + int get_unused_fd_flags(unsigned flags) +diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h +index 6e8743a4c9d31..d26b884fcc5cc 100644 +--- a/include/linux/fdtable.h ++++ b/include/linux/fdtable.h +@@ -124,8 +124,6 @@ int iterate_fd(struct files_struct *, unsigned, + int (*)(const void *, struct file *, unsigned), + const void *); + +-extern int __alloc_fd(struct files_struct *files, +- unsigned start, unsigned end, unsigned flags); + extern int __close_fd(struct files_struct *files, + unsigned int fd); + extern int __close_range(unsigned int fd, unsigned int max_fd, unsigned int flags); +-- +2.43.0 + diff --git a/queue-5.10/file-merge-__fd_install-into-fd_install.patch b/queue-5.10/file-merge-__fd_install-into-fd_install.patch new file mode 100644 index 00000000000..5a6d162aab8 --- /dev/null +++ b/queue-5.10/file-merge-__fd_install-into-fd_install.patch @@ -0,0 +1,105 @@ +From e662bd2f8594d4f9e04ff4e275951604b1d651e1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Nov 2020 17:14:35 -0600 +Subject: file: Merge __fd_install into fd_install + +From: Eric W. Biederman + +[ Upstream commit d74ba04d919ebe30bf47406819c18c6b50003d92 ] + +The function __fd_install was added to support binder[1]. With binder +fixed[2] there are no more users. + +As fd_install just calls __fd_install with "files=current->files", +merge them together by transforming the files parameter into a +local variable initialized to current->files. + +[1] f869e8a7f753 ("expose a low-level variant of fd_install() for binder") +[2] 44d8047f1d87 ("binder: use standard functions to allocate fds") +Acked-by: Christian Brauner +v1: https://lkml.kernel.org/r/20200817220425.9389-14-ebiederm@xmission.com +Link: https://lkml.kernel.org/r/20201120231441.29911-18-ebiederm@xmission.com +Signed-off-by: Eric W. Biederman +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/file.c | 25 ++++++------------------- + include/linux/fdtable.h | 2 -- + 2 files changed, 6 insertions(+), 21 deletions(-) + +diff --git a/fs/file.c b/fs/file.c +index 9fa49e6298fba..a80deabe7f7dc 100644 +--- a/fs/file.c ++++ b/fs/file.c +@@ -175,7 +175,7 @@ static int expand_fdtable(struct files_struct *files, unsigned int nr) + spin_unlock(&files->file_lock); + new_fdt = alloc_fdtable(nr); + +- /* make sure all __fd_install() have seen resize_in_progress ++ /* make sure all fd_install() have seen resize_in_progress + * or have finished their rcu_read_lock_sched() section. + */ + if (atomic_read(&files->count) > 1) +@@ -198,7 +198,7 @@ static int expand_fdtable(struct files_struct *files, unsigned int nr) + rcu_assign_pointer(files->fdt, new_fdt); + if (cur_fdt != &files->fdtab) + call_rcu(&cur_fdt->rcu, free_fdtable_rcu); +- /* coupled with smp_rmb() in __fd_install() */ ++ /* coupled with smp_rmb() in fd_install() */ + smp_wmb(); + return 1; + } +@@ -613,17 +613,13 @@ EXPORT_SYMBOL(put_unused_fd); + * It should never happen - if we allow dup2() do it, _really_ bad things + * will follow. + * +- * NOTE: __fd_install() variant is really, really low-level; don't +- * use it unless you are forced to by truly lousy API shoved down +- * your throat. 'files' *MUST* be either current->files or obtained +- * by get_files_struct(current) done by whoever had given it to you, +- * or really bad things will happen. Normally you want to use +- * fd_install() instead. ++ * This consumes the "file" refcount, so callers should treat it ++ * as if they had called fput(file). + */ + +-void __fd_install(struct files_struct *files, unsigned int fd, +- struct file *file) ++void fd_install(unsigned int fd, struct file *file) + { ++ struct files_struct *files = current->files; + struct fdtable *fdt; + + rcu_read_lock_sched(); +@@ -645,15 +641,6 @@ void __fd_install(struct files_struct *files, unsigned int fd, + rcu_read_unlock_sched(); + } + +-/* +- * This consumes the "file" refcount, so callers should treat it +- * as if they had called fput(file). +- */ +-void fd_install(unsigned int fd, struct file *file) +-{ +- __fd_install(current->files, fd, file); +-} +- + EXPORT_SYMBOL(fd_install); + + static struct file *pick_file(struct files_struct *files, unsigned fd) +diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h +index b0c6a959c6a00..6e8743a4c9d31 100644 +--- a/include/linux/fdtable.h ++++ b/include/linux/fdtable.h +@@ -126,8 +126,6 @@ int iterate_fd(struct files_struct *, unsigned, + + extern int __alloc_fd(struct files_struct *files, + unsigned start, unsigned end, unsigned flags); +-extern void __fd_install(struct files_struct *files, +- unsigned int fd, struct file *file); + extern int __close_fd(struct files_struct *files, + unsigned int fd); + extern int __close_range(unsigned int fd, unsigned int max_fd, unsigned int flags); +-- +2.43.0 + diff --git a/queue-5.10/file-rename-__close_fd-to-close_fd-and-remove-the-fi.patch b/queue-5.10/file-rename-__close_fd-to-close_fd-and-remove-the-fi.patch new file mode 100644 index 00000000000..5eb66eff3c1 --- /dev/null +++ b/queue-5.10/file-rename-__close_fd-to-close_fd-and-remove-the-fi.patch @@ -0,0 +1,127 @@ +From abf02278a25c4f3829b481b22ff5bdd79c414769 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Nov 2020 17:14:38 -0600 +Subject: file: Rename __close_fd to close_fd and remove the files parameter + +From: Eric W. Biederman + +[ Upstream commit 8760c909f54a82aaa6e76da19afe798a0c77c3c3 ] + +The function __close_fd was added to support binder[1]. Now that +binder has been fixed to no longer need __close_fd[2] all calls +to __close_fd pass current->files. + +Therefore transform the files parameter into a local variable +initialized to current->files, and rename __close_fd to close_fd to +reflect this change, and keep it in sync with the similar changes to +__alloc_fd, and __fd_install. + +This removes the need for callers to care about the extra care that +needs to be take if anything except current->files is passed, by +limiting the callers to only operation on current->files. + +[1] 483ce1d4b8c3 ("take descriptor-related part of close() to file.c") +[2] 44d8047f1d87 ("binder: use standard functions to allocate fds") +Acked-by: Christian Brauner +v1: https://lkml.kernel.org/r/20200817220425.9389-17-ebiederm@xmission.com +Link: https://lkml.kernel.org/r/20201120231441.29911-21-ebiederm@xmission.com +Signed-off-by: Eric W. Biederman +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/file.c | 10 ++++------ + fs/open.c | 2 +- + include/linux/fdtable.h | 3 +-- + include/linux/syscalls.h | 6 +++--- + 4 files changed, 9 insertions(+), 12 deletions(-) + +diff --git a/fs/file.c b/fs/file.c +index 48d0306e42ccc..fdb84a64724b7 100644 +--- a/fs/file.c ++++ b/fs/file.c +@@ -659,11 +659,9 @@ static struct file *pick_file(struct files_struct *files, unsigned fd) + return file; + } + +-/* +- * The same warnings as for __alloc_fd()/__fd_install() apply here... +- */ +-int __close_fd(struct files_struct *files, unsigned fd) ++int close_fd(unsigned fd) + { ++ struct files_struct *files = current->files; + struct file *file; + + file = pick_file(files, fd); +@@ -672,7 +670,7 @@ int __close_fd(struct files_struct *files, unsigned fd) + + return filp_close(file, files); + } +-EXPORT_SYMBOL(__close_fd); /* for ksys_close() */ ++EXPORT_SYMBOL(close_fd); /* for ksys_close() */ + + /** + * __close_range() - Close all file descriptors in a given range. +@@ -1087,7 +1085,7 @@ int replace_fd(unsigned fd, struct file *file, unsigned flags) + struct files_struct *files = current->files; + + if (!file) +- return __close_fd(files, fd); ++ return close_fd(fd); + + if (fd >= rlimit(RLIMIT_NOFILE)) + return -EBADF; +diff --git a/fs/open.c b/fs/open.c +index 83f62cf1432c8..48933cbb75391 100644 +--- a/fs/open.c ++++ b/fs/open.c +@@ -1310,7 +1310,7 @@ EXPORT_SYMBOL(filp_close); + */ + SYSCALL_DEFINE1(close, unsigned int, fd) + { +- int retval = __close_fd(current->files, fd); ++ int retval = close_fd(fd); + + /* can't restart close syscall because file table entry was cleared */ + if (unlikely(retval == -ERESTARTSYS || +diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h +index d26b884fcc5cc..4ed3589f9294e 100644 +--- a/include/linux/fdtable.h ++++ b/include/linux/fdtable.h +@@ -124,8 +124,7 @@ int iterate_fd(struct files_struct *, unsigned, + int (*)(const void *, struct file *, unsigned), + const void *); + +-extern int __close_fd(struct files_struct *files, +- unsigned int fd); ++extern int close_fd(unsigned int fd); + extern int __close_range(unsigned int fd, unsigned int max_fd, unsigned int flags); + extern int close_fd_get_file(unsigned int fd, struct file **res); + extern int unshare_fd(unsigned long unshare_flags, unsigned int max_fds, +diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h +index 17a24e1180dad..0bc3dd86f9e50 100644 +--- a/include/linux/syscalls.h ++++ b/include/linux/syscalls.h +@@ -1320,16 +1320,16 @@ static inline long ksys_ftruncate(unsigned int fd, loff_t length) + return do_sys_ftruncate(fd, length, 1); + } + +-extern int __close_fd(struct files_struct *files, unsigned int fd); ++extern int close_fd(unsigned int fd); + + /* + * In contrast to sys_close(), this stub does not check whether the syscall + * should or should not be restarted, but returns the raw error codes from +- * __close_fd(). ++ * close_fd(). + */ + static inline int ksys_close(unsigned int fd) + { +- return __close_fd(current->files, fd); ++ return close_fd(fd); + } + + extern long do_sys_truncate(const char __user *pathname, loff_t length); +-- +2.43.0 + diff --git a/queue-5.10/file-rename-__fcheck_files-to-files_lookup_fd_raw.patch b/queue-5.10/file-rename-__fcheck_files-to-files_lookup_fd_raw.patch new file mode 100644 index 00000000000..5030e528a79 --- /dev/null +++ b/queue-5.10/file-rename-__fcheck_files-to-files_lookup_fd_raw.patch @@ -0,0 +1,89 @@ +From 8dafd13fcc568d3becd6291a6503b5a7a006dae9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 10 Dec 2020 12:39:54 -0600 +Subject: file: Rename __fcheck_files to files_lookup_fd_raw + +From: Eric W. Biederman + +[ Upstream commit bebf684bf330915e6c96313ad7db89a5480fc9c2 ] + +The function fcheck despite it's comment is poorly named +as it has no callers that only check it's return value. +All of fcheck's callers use the returned file descriptor. +The same is true for fcheck_files and __fcheck_files. + +A new less confusing name is needed. In addition the names +of these functions are confusing as they do not report +the kind of locks that are needed to be held when these +functions are called making error prone to use them. + +To remedy this I am making the base functio name lookup_fd +and will and prefixes and sufficies to indicate the rest +of the context. + +Name the function (previously called __fcheck_files) that proceeds +from a struct files_struct, looks up the struct file of a file +descriptor, and requires it's callers to verify all of the appropriate +locks are held files_lookup_fd_raw. + +The need for better names became apparent in the last round of +discussion of this set of changes[1]. + +[1] https://lkml.kernel.org/r/CAHk-=wj8BQbgJFLa+J0e=iT-1qpmCRTbPAJ8gd6MJQ=kbRPqyQ@mail.gmail.com +Link: https://lkml.kernel.org/r/20201120231441.29911-7-ebiederm@xmission.com +Signed-off-by: Eric W. Biederman +[ cel: adjusted to apply to v5.10.y ] +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/file.c | 4 ++-- + include/linux/fdtable.h | 4 ++-- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/fs/file.c b/fs/file.c +index fea693acc065e..eb1e2b7220ac6 100644 +--- a/fs/file.c ++++ b/fs/file.c +@@ -866,7 +866,7 @@ static struct file *__fget_files(struct files_struct *files, unsigned int fd, + file = NULL; + else if (!get_file_rcu_many(file, refs)) + goto loop; +- else if (__fcheck_files(files, fd) != file) { ++ else if (files_lookup_fd_raw(files, fd) != file) { + fput_many(file, refs); + goto loop; + } +@@ -933,7 +933,7 @@ static unsigned long __fget_light(unsigned int fd, fmode_t mask) + struct file *file; + + if (atomic_read(&files->count) == 1) { +- file = __fcheck_files(files, fd); ++ file = files_lookup_fd_raw(files, fd); + if (!file || unlikely(file->f_mode & mask)) + return 0; + return (unsigned long)file; +diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h +index c0ca6fb3f0f95..10e75b4c30a43 100644 +--- a/include/linux/fdtable.h ++++ b/include/linux/fdtable.h +@@ -80,7 +80,7 @@ struct dentry; + /* + * The caller must ensure that fd table isn't shared or hold rcu or file lock + */ +-static inline struct file *__fcheck_files(struct files_struct *files, unsigned int fd) ++static inline struct file *files_lookup_fd_raw(struct files_struct *files, unsigned int fd) + { + struct fdtable *fdt = rcu_dereference_raw(files->fdt); + +@@ -96,7 +96,7 @@ static inline struct file *fcheck_files(struct files_struct *files, unsigned int + RCU_LOCKDEP_WARN(!rcu_read_lock_held() && + !lockdep_is_held(&files->file_lock), + "suspicious rcu_dereference_check() usage"); +- return __fcheck_files(files, fd); ++ return files_lookup_fd_raw(files, fd); + } + + /* +-- +2.43.0 + diff --git a/queue-5.10/file-rename-fcheck-lookup_fd_rcu.patch b/queue-5.10/file-rename-fcheck-lookup_fd_rcu.patch new file mode 100644 index 00000000000..93ab6b305f4 --- /dev/null +++ b/queue-5.10/file-rename-fcheck-lookup_fd_rcu.patch @@ -0,0 +1,107 @@ +From f9313dfc75a70fbce10206182f0b11a610dee433 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Nov 2020 17:14:27 -0600 +Subject: file: Rename fcheck lookup_fd_rcu + +From: Eric W. Biederman + +[ Upstream commit 460b4f812a9d473d4b39d87d37844f9fc30a9eb3 ] + +Also remove the confusing comment about checking if a fd exists. I +could not find one instance in the entire kernel that still matches +the description or the reason for the name fcheck. + +The need for better names became apparent in the last round of +discussion of this set of changes[1]. + +[1] https://lkml.kernel.org/r/CAHk-=wj8BQbgJFLa+J0e=iT-1qpmCRTbPAJ8gd6MJQ=kbRPqyQ@mail.gmail.com +Link: https://lkml.kernel.org/r/20201120231441.29911-10-ebiederm@xmission.com +Signed-off-by: Eric W. Biederman +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + Documentation/filesystems/files.rst | 6 +++--- + arch/powerpc/platforms/cell/spufs/coredump.c | 2 +- + fs/notify/dnotify/dnotify.c | 2 +- + include/linux/fdtable.h | 8 ++++---- + 4 files changed, 9 insertions(+), 9 deletions(-) + +diff --git a/Documentation/filesystems/files.rst b/Documentation/filesystems/files.rst +index ea75acdb632c0..bcf84459917f5 100644 +--- a/Documentation/filesystems/files.rst ++++ b/Documentation/filesystems/files.rst +@@ -62,7 +62,7 @@ the fdtable structure - + be held. + + 4. To look up the file structure given an fd, a reader +- must use either fcheck() or files_lookup_fd_rcu() APIs. These ++ must use either lookup_fd_rcu() or files_lookup_fd_rcu() APIs. These + take care of barrier requirements due to lock-free lookup. + + An example:: +@@ -70,7 +70,7 @@ the fdtable structure - + struct file *file; + + rcu_read_lock(); +- file = fcheck(fd); ++ file = lookup_fd_rcu(fd); + if (file) { + ... + } +@@ -104,7 +104,7 @@ the fdtable structure - + lock-free, they must be installed using rcu_assign_pointer() + API. If they are looked up lock-free, rcu_dereference() + must be used. However it is advisable to use files_fdtable() +- and fcheck()/files_lookup_fd_rcu() which take care of these issues. ++ and lookup_fd_rcu()/files_lookup_fd_rcu() which take care of these issues. + + 7. While updating, the fdtable pointer must be looked up while + holding files->file_lock. If ->file_lock is dropped, then +diff --git a/arch/powerpc/platforms/cell/spufs/coredump.c b/arch/powerpc/platforms/cell/spufs/coredump.c +index 026c181a98c5d..60b5583e9eafc 100644 +--- a/arch/powerpc/platforms/cell/spufs/coredump.c ++++ b/arch/powerpc/platforms/cell/spufs/coredump.c +@@ -74,7 +74,7 @@ static struct spu_context *coredump_next_context(int *fd) + *fd = n - 1; + + rcu_read_lock(); +- file = fcheck(*fd); ++ file = lookup_fd_rcu(*fd); + ctx = SPUFS_I(file_inode(file))->i_ctx; + get_spu_context(ctx); + rcu_read_unlock(); +diff --git a/fs/notify/dnotify/dnotify.c b/fs/notify/dnotify/dnotify.c +index e45ca6ecba959..e85e13c50d6d4 100644 +--- a/fs/notify/dnotify/dnotify.c ++++ b/fs/notify/dnotify/dnotify.c +@@ -327,7 +327,7 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg) + } + + rcu_read_lock(); +- f = fcheck(fd); ++ f = lookup_fd_rcu(fd); + rcu_read_unlock(); + + /* if (f != filp) means that we lost a race and another task/thread +diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h +index a45fa2ef723f5..695306cc5337a 100644 +--- a/include/linux/fdtable.h ++++ b/include/linux/fdtable.h +@@ -105,10 +105,10 @@ static inline struct file *files_lookup_fd_rcu(struct files_struct *files, unsig + return files_lookup_fd_raw(files, fd); + } + +-/* +- * Check whether the specified fd has an open file. +- */ +-#define fcheck(fd) files_lookup_fd_rcu(current->files, fd) ++static inline struct file *lookup_fd_rcu(unsigned int fd) ++{ ++ return files_lookup_fd_rcu(current->files, fd); ++} + + struct task_struct; + +-- +2.43.0 + diff --git a/queue-5.10/file-replace-fcheck_files-with-files_lookup_fd_rcu.patch b/queue-5.10/file-replace-fcheck_files-with-files_lookup_fd_rcu.patch new file mode 100644 index 00000000000..c4b67582378 --- /dev/null +++ b/queue-5.10/file-replace-fcheck_files-with-files_lookup_fd_rcu.patch @@ -0,0 +1,168 @@ +From 9bc605844b97347e57107bedbe7a832833270813 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Nov 2020 17:14:26 -0600 +Subject: file: Replace fcheck_files with files_lookup_fd_rcu + +From: Eric W. Biederman + +[ Upstream commit f36c2943274199cb8aef32ac96531ffb7c4b43d0 ] + +This change renames fcheck_files to files_lookup_fd_rcu. All of the +remaining callers take the rcu_read_lock before calling this function +so the _rcu suffix is appropriate. This change also tightens up the +debug check to verify that all callers hold the rcu_read_lock. + +All callers that used to call files_check with the files->file_lock +held have now been changed to call files_lookup_fd_locked. + +This change of name has helped remind me of which locks and which +guarantees are in place helping me to catch bugs later in the +patchset. + +The need for better names became apparent in the last round of +discussion of this set of changes[1]. + +[1] https://lkml.kernel.org/r/CAHk-=wj8BQbgJFLa+J0e=iT-1qpmCRTbPAJ8gd6MJQ=kbRPqyQ@mail.gmail.com +Link: https://lkml.kernel.org/r/20201120231441.29911-9-ebiederm@xmission.com +Signed-off-by: Eric W. Biederman +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + Documentation/filesystems/files.rst | 6 +++--- + fs/file.c | 4 ++-- + fs/proc/fd.c | 4 ++-- + include/linux/fdtable.h | 7 +++---- + kernel/bpf/task_iter.c | 2 +- + kernel/kcmp.c | 2 +- + 6 files changed, 12 insertions(+), 13 deletions(-) + +diff --git a/Documentation/filesystems/files.rst b/Documentation/filesystems/files.rst +index cbf8e57376bf6..ea75acdb632c0 100644 +--- a/Documentation/filesystems/files.rst ++++ b/Documentation/filesystems/files.rst +@@ -62,7 +62,7 @@ the fdtable structure - + be held. + + 4. To look up the file structure given an fd, a reader +- must use either fcheck() or fcheck_files() APIs. These ++ must use either fcheck() or files_lookup_fd_rcu() APIs. These + take care of barrier requirements due to lock-free lookup. + + An example:: +@@ -84,7 +84,7 @@ the fdtable structure - + on ->f_count:: + + rcu_read_lock(); +- file = fcheck_files(files, fd); ++ file = files_lookup_fd_rcu(files, fd); + if (file) { + if (atomic_long_inc_not_zero(&file->f_count)) + *fput_needed = 1; +@@ -104,7 +104,7 @@ the fdtable structure - + lock-free, they must be installed using rcu_assign_pointer() + API. If they are looked up lock-free, rcu_dereference() + must be used. However it is advisable to use files_fdtable() +- and fcheck()/fcheck_files() which take care of these issues. ++ and fcheck()/files_lookup_fd_rcu() which take care of these issues. + + 7. While updating, the fdtable pointer must be looked up while + holding files->file_lock. If ->file_lock is dropped, then +diff --git a/fs/file.c b/fs/file.c +index 6a6b03ce4ad69..6149f75a18a66 100644 +--- a/fs/file.c ++++ b/fs/file.c +@@ -856,7 +856,7 @@ static struct file *__fget_files(struct files_struct *files, unsigned int fd, + + rcu_read_lock(); + loop: +- file = fcheck_files(files, fd); ++ file = files_lookup_fd_rcu(files, fd); + if (file) { + /* File object ref couldn't be taken. + * dup2() atomicity guarantee is the reason +@@ -1187,7 +1187,7 @@ SYSCALL_DEFINE2(dup2, unsigned int, oldfd, unsigned int, newfd) + int retval = oldfd; + + rcu_read_lock(); +- if (!fcheck_files(files, oldfd)) ++ if (!files_lookup_fd_rcu(files, oldfd)) + retval = -EBADF; + rcu_read_unlock(); + return retval; +diff --git a/fs/proc/fd.c b/fs/proc/fd.c +index 2cca9bca3b3a3..3dec44d7c5c5c 100644 +--- a/fs/proc/fd.c ++++ b/fs/proc/fd.c +@@ -90,7 +90,7 @@ static bool tid_fd_mode(struct task_struct *task, unsigned fd, fmode_t *mode) + return false; + + rcu_read_lock(); +- file = fcheck_files(files, fd); ++ file = files_lookup_fd_rcu(files, fd); + if (file) + *mode = file->f_mode; + rcu_read_unlock(); +@@ -243,7 +243,7 @@ static int proc_readfd_common(struct file *file, struct dir_context *ctx, + char name[10 + 1]; + unsigned int len; + +- f = fcheck_files(files, fd); ++ f = files_lookup_fd_rcu(files, fd); + if (!f) + continue; + data.mode = f->f_mode; +diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h +index 87be704268d26..a45fa2ef723f5 100644 +--- a/include/linux/fdtable.h ++++ b/include/linux/fdtable.h +@@ -98,10 +98,9 @@ static inline struct file *files_lookup_fd_locked(struct files_struct *files, un + return files_lookup_fd_raw(files, fd); + } + +-static inline struct file *fcheck_files(struct files_struct *files, unsigned int fd) ++static inline struct file *files_lookup_fd_rcu(struct files_struct *files, unsigned int fd) + { +- RCU_LOCKDEP_WARN(!rcu_read_lock_held() && +- !lockdep_is_held(&files->file_lock), ++ RCU_LOCKDEP_WARN(!rcu_read_lock_held(), + "suspicious rcu_dereference_check() usage"); + return files_lookup_fd_raw(files, fd); + } +@@ -109,7 +108,7 @@ static inline struct file *fcheck_files(struct files_struct *files, unsigned int + /* + * Check whether the specified fd has an open file. + */ +-#define fcheck(fd) fcheck_files(current->files, fd) ++#define fcheck(fd) files_lookup_fd_rcu(current->files, fd) + + struct task_struct; + +diff --git a/kernel/bpf/task_iter.c b/kernel/bpf/task_iter.c +index f3d3a562a802a..762b4d7c37795 100644 +--- a/kernel/bpf/task_iter.c ++++ b/kernel/bpf/task_iter.c +@@ -185,7 +185,7 @@ task_file_seq_get_next(struct bpf_iter_seq_task_file_info *info) + for (; curr_fd < max_fds; curr_fd++) { + struct file *f; + +- f = fcheck_files(curr_files, curr_fd); ++ f = files_lookup_fd_rcu(curr_files, curr_fd); + if (!f) + continue; + if (!get_file_rcu(f)) +diff --git a/kernel/kcmp.c b/kernel/kcmp.c +index bd6f9edf98fd3..5b2435e030472 100644 +--- a/kernel/kcmp.c ++++ b/kernel/kcmp.c +@@ -67,7 +67,7 @@ get_file_raw_ptr(struct task_struct *task, unsigned int idx) + rcu_read_lock(); + + if (task->files) +- file = fcheck_files(task->files, idx); ++ file = files_lookup_fd_rcu(task->files, idx); + + rcu_read_unlock(); + task_unlock(task); +-- +2.43.0 + diff --git a/queue-5.10/file-replace-ksys_close-with-close_fd.patch b/queue-5.10/file-replace-ksys_close-with-close_fd.patch new file mode 100644 index 00000000000..996a5d65565 --- /dev/null +++ b/queue-5.10/file-replace-ksys_close-with-close_fd.patch @@ -0,0 +1,74 @@ +From 8cd670c5a346a92e1e984c2e972154a37da0c909 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Nov 2020 17:14:39 -0600 +Subject: file: Replace ksys_close with close_fd + +From: Eric W. Biederman + +[ Upstream commit 1572bfdf21d4d50e51941498ffe0b56c2289f783 ] + +Now that ksys_close is exactly identical to close_fd replace +the one caller of ksys_close with close_fd. + +[1] https://lkml.kernel.org/r/20200818112020.GA17080@infradead.org +Suggested-by: Christoph Hellwig +Link: https://lkml.kernel.org/r/20201120231441.29911-22-ebiederm@xmission.com +Signed-off-by: Eric W. Biederman +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/autofs/dev-ioctl.c | 5 +++-- + include/linux/syscalls.h | 12 ------------ + 2 files changed, 3 insertions(+), 14 deletions(-) + +diff --git a/fs/autofs/dev-ioctl.c b/fs/autofs/dev-ioctl.c +index 322b7dfb4ea01..5bf781ea6d676 100644 +--- a/fs/autofs/dev-ioctl.c ++++ b/fs/autofs/dev-ioctl.c +@@ -4,9 +4,10 @@ + * Copyright 2008 Ian Kent + */ + ++#include + #include + #include +-#include ++#include + #include + #include + +@@ -289,7 +290,7 @@ static int autofs_dev_ioctl_closemount(struct file *fp, + struct autofs_sb_info *sbi, + struct autofs_dev_ioctl *param) + { +- return ksys_close(param->ioctlfd); ++ return close_fd(param->ioctlfd); + } + + /* +diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h +index 0bc3dd86f9e50..1ea422b1a9f1c 100644 +--- a/include/linux/syscalls.h ++++ b/include/linux/syscalls.h +@@ -1320,18 +1320,6 @@ static inline long ksys_ftruncate(unsigned int fd, loff_t length) + return do_sys_ftruncate(fd, length, 1); + } + +-extern int close_fd(unsigned int fd); +- +-/* +- * In contrast to sys_close(), this stub does not check whether the syscall +- * should or should not be restarted, but returns the raw error codes from +- * close_fd(). +- */ +-static inline int ksys_close(unsigned int fd) +-{ +- return close_fd(fd); +-} +- + extern long do_sys_truncate(const char __user *pathname, loff_t length); + + static inline long ksys_truncate(const char __user *pathname, loff_t length) +-- +2.43.0 + diff --git a/queue-5.10/filelock-add-a-new-locks_inode_context-accessor-func.patch b/queue-5.10/filelock-add-a-new-locks_inode_context-accessor-func.patch new file mode 100644 index 00000000000..f708f4e82bf --- /dev/null +++ b/queue-5.10/filelock-add-a-new-locks_inode_context-accessor-func.patch @@ -0,0 +1,174 @@ +From 364559e599a3a838dde92d4a07098cfe752f1eca Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 16 Nov 2022 09:02:30 -0500 +Subject: filelock: add a new locks_inode_context accessor function + +From: Jeff Layton + +[ Upstream commit 401a8b8fd5acd51582b15238d72a8d0edd580e9f ] + +There are a number of places in the kernel that are accessing the +inode->i_flctx field without smp_load_acquire. This is required to +ensure that the caller doesn't see a partially-initialized structure. + +Add a new accessor function for it to make this clear and convert all of +the relevant accesses in locks.c to use it. Also, convert +locks_free_lock_context to use the helper as well instead of just doing +a "bare" assignment. + +Reviewed-by: Christoph Hellwig +Signed-off-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/locks.c | 24 ++++++++++++------------ + include/linux/fs.h | 14 ++++++++++++++ + 2 files changed, 26 insertions(+), 12 deletions(-) + +diff --git a/fs/locks.c b/fs/locks.c +index 13a3ba97b73d1..b0753c8871fb2 100644 +--- a/fs/locks.c ++++ b/fs/locks.c +@@ -251,7 +251,7 @@ locks_get_lock_context(struct inode *inode, int type) + struct file_lock_context *ctx; + + /* paired with cmpxchg() below */ +- ctx = smp_load_acquire(&inode->i_flctx); ++ ctx = locks_inode_context(inode); + if (likely(ctx) || type == F_UNLCK) + goto out; + +@@ -270,7 +270,7 @@ locks_get_lock_context(struct inode *inode, int type) + */ + if (cmpxchg(&inode->i_flctx, NULL, ctx)) { + kmem_cache_free(flctx_cache, ctx); +- ctx = smp_load_acquire(&inode->i_flctx); ++ ctx = locks_inode_context(inode); + } + out: + trace_locks_get_lock_context(inode, type, ctx); +@@ -323,7 +323,7 @@ locks_check_ctx_file_list(struct file *filp, struct list_head *list, + void + locks_free_lock_context(struct inode *inode) + { +- struct file_lock_context *ctx = inode->i_flctx; ++ struct file_lock_context *ctx = locks_inode_context(inode); + + if (unlikely(ctx)) { + locks_check_ctx_lists(inode); +@@ -985,7 +985,7 @@ posix_test_lock(struct file *filp, struct file_lock *fl) + void *owner; + void (*func)(void); + +- ctx = smp_load_acquire(&inode->i_flctx); ++ ctx = locks_inode_context(inode); + if (!ctx || list_empty_careful(&ctx->flc_posix)) { + fl->fl_type = F_UNLCK; + return; +@@ -1674,7 +1674,7 @@ int __break_lease(struct inode *inode, unsigned int mode, unsigned int type) + new_fl->fl_flags = type; + + /* typically we will check that ctx is non-NULL before calling */ +- ctx = smp_load_acquire(&inode->i_flctx); ++ ctx = locks_inode_context(inode); + if (!ctx) { + WARN_ON_ONCE(1); + goto free_lock; +@@ -1779,7 +1779,7 @@ void lease_get_mtime(struct inode *inode, struct timespec64 *time) + struct file_lock_context *ctx; + struct file_lock *fl; + +- ctx = smp_load_acquire(&inode->i_flctx); ++ ctx = locks_inode_context(inode); + if (ctx && !list_empty_careful(&ctx->flc_lease)) { + spin_lock(&ctx->flc_lock); + fl = list_first_entry_or_null(&ctx->flc_lease, +@@ -1825,7 +1825,7 @@ int fcntl_getlease(struct file *filp) + int type = F_UNLCK; + LIST_HEAD(dispose); + +- ctx = smp_load_acquire(&inode->i_flctx); ++ ctx = locks_inode_context(inode); + if (ctx && !list_empty_careful(&ctx->flc_lease)) { + percpu_down_read(&file_rwsem); + spin_lock(&ctx->flc_lock); +@@ -2014,7 +2014,7 @@ static int generic_delete_lease(struct file *filp, void *owner) + struct file_lock_context *ctx; + LIST_HEAD(dispose); + +- ctx = smp_load_acquire(&inode->i_flctx); ++ ctx = locks_inode_context(inode); + if (!ctx) { + trace_generic_delete_lease(inode, NULL); + return error; +@@ -2765,7 +2765,7 @@ void locks_remove_posix(struct file *filp, fl_owner_t owner) + * posix_lock_file(). Another process could be setting a lock on this + * file at the same time, but we wouldn't remove that lock anyway. + */ +- ctx = smp_load_acquire(&inode->i_flctx); ++ ctx = locks_inode_context(inode); + if (!ctx || list_empty(&ctx->flc_posix)) + return; + +@@ -2838,7 +2838,7 @@ void locks_remove_file(struct file *filp) + { + struct file_lock_context *ctx; + +- ctx = smp_load_acquire(&locks_inode(filp)->i_flctx); ++ ctx = locks_inode_context(locks_inode(filp)); + if (!ctx) + return; + +@@ -2885,7 +2885,7 @@ bool vfs_inode_has_locks(struct inode *inode) + struct file_lock_context *ctx; + bool ret; + +- ctx = smp_load_acquire(&inode->i_flctx); ++ ctx = locks_inode_context(inode); + if (!ctx) + return false; + +@@ -3030,7 +3030,7 @@ void show_fd_locks(struct seq_file *f, + struct file_lock_context *ctx; + int id = 0; + +- ctx = smp_load_acquire(&inode->i_flctx); ++ ctx = locks_inode_context(inode); + if (!ctx) + return; + +diff --git a/include/linux/fs.h b/include/linux/fs.h +index 7e7098bf2c57e..6a26ef54ac25d 100644 +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -1168,6 +1168,13 @@ extern void show_fd_locks(struct seq_file *f, + struct file *filp, struct files_struct *files); + extern bool locks_owner_has_blockers(struct file_lock_context *flctx, + fl_owner_t owner); ++ ++static inline struct file_lock_context * ++locks_inode_context(const struct inode *inode) ++{ ++ return smp_load_acquire(&inode->i_flctx); ++} ++ + #else /* !CONFIG_FILE_LOCKING */ + static inline int fcntl_getlk(struct file *file, unsigned int cmd, + struct flock __user *user) +@@ -1313,6 +1320,13 @@ static inline bool locks_owner_has_blockers(struct file_lock_context *flctx, + { + return false; + } ++ ++static inline struct file_lock_context * ++locks_inode_context(const struct inode *inode) ++{ ++ return NULL; ++} ++ + #endif /* !CONFIG_FILE_LOCKING */ + + static inline struct inode *file_inode(const struct file *f) +-- +2.43.0 + diff --git a/queue-5.10/fs-add-file-and-path-permissions-helpers.patch b/queue-5.10/fs-add-file-and-path-permissions-helpers.patch new file mode 100644 index 00000000000..d10a908313b --- /dev/null +++ b/queue-5.10/fs-add-file-and-path-permissions-helpers.patch @@ -0,0 +1,256 @@ +From 21f3967455d95b6e829ff038626cc1b52dd959e5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 Jan 2021 14:19:22 +0100 +Subject: fs: add file and path permissions helpers + +From: Christian Brauner + +[ Upstream commit 02f92b3868a1b34ab98464e76b0e4e060474ba10 ] + +Add two simple helpers to check permissions on a file and path +respectively and convert over some callers. It simplifies quite a few +codepaths and also reduces the churn in later patches quite a bit. +Christoph also correctly points out that this makes codepaths (e.g. +ioctls) way easier to follow that would otherwise have to do more +complex argument passing than necessary. + +Link: https://lore.kernel.org/r/20210121131959.646623-4-christian.brauner@ubuntu.com +Cc: David Howells +Cc: Al Viro +Cc: linux-fsdevel@vger.kernel.org +Suggested-by: Christoph Hellwig +Reviewed-by: Christoph Hellwig +Reviewed-by: James Morris +Signed-off-by: Christian Brauner +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/init.c | 6 +++--- + fs/notify/fanotify/fanotify_user.c | 2 +- + fs/notify/inotify/inotify_user.c | 2 +- + fs/open.c | 6 +++--- + fs/udf/file.c | 2 +- + fs/verity/enable.c | 2 +- + include/linux/fs.h | 8 ++++++++ + kernel/bpf/inode.c | 2 +- + kernel/sys.c | 2 +- + mm/madvise.c | 2 +- + mm/memcontrol.c | 2 +- + mm/mincore.c | 2 +- + net/unix/af_unix.c | 2 +- + 13 files changed, 24 insertions(+), 16 deletions(-) + +diff --git a/fs/init.c b/fs/init.c +index e9c320a48cf15..02723bea84990 100644 +--- a/fs/init.c ++++ b/fs/init.c +@@ -49,7 +49,7 @@ int __init init_chdir(const char *filename) + error = kern_path(filename, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path); + if (error) + return error; +- error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR); ++ error = path_permission(&path, MAY_EXEC | MAY_CHDIR); + if (!error) + set_fs_pwd(current->fs, &path); + path_put(&path); +@@ -64,7 +64,7 @@ int __init init_chroot(const char *filename) + error = kern_path(filename, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path); + if (error) + return error; +- error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR); ++ error = path_permission(&path, MAY_EXEC | MAY_CHDIR); + if (error) + goto dput_and_out; + error = -EPERM; +@@ -118,7 +118,7 @@ int __init init_eaccess(const char *filename) + error = kern_path(filename, LOOKUP_FOLLOW, &path); + if (error) + return error; +- error = inode_permission(d_inode(path.dentry), MAY_ACCESS); ++ error = path_permission(&path, MAY_ACCESS); + path_put(&path); + return error; + } +diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c +index 3e905b2e1b9c3..829ead2792dfb 100644 +--- a/fs/notify/fanotify/fanotify_user.c ++++ b/fs/notify/fanotify/fanotify_user.c +@@ -702,7 +702,7 @@ static int fanotify_find_path(int dfd, const char __user *filename, + } + + /* you can only watch an inode if you have read permissions on it */ +- ret = inode_permission(path->dentry->d_inode, MAY_READ); ++ ret = path_permission(path, MAY_READ); + if (ret) { + path_put(path); + goto out; +diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c +index ad8fb4bca6dc1..82fc0cf86a7c3 100644 +--- a/fs/notify/inotify/inotify_user.c ++++ b/fs/notify/inotify/inotify_user.c +@@ -352,7 +352,7 @@ static int inotify_find_inode(const char __user *dirname, struct path *path, + if (error) + return error; + /* you can only watch an inode if you have read permissions on it */ +- error = inode_permission(path->dentry->d_inode, MAY_READ); ++ error = path_permission(path, MAY_READ); + if (error) { + path_put(path); + return error; +diff --git a/fs/open.c b/fs/open.c +index 48933cbb75391..9f56ebacfbefe 100644 +--- a/fs/open.c ++++ b/fs/open.c +@@ -492,7 +492,7 @@ SYSCALL_DEFINE1(chdir, const char __user *, filename) + if (error) + goto out; + +- error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR); ++ error = path_permission(&path, MAY_EXEC | MAY_CHDIR); + if (error) + goto dput_and_out; + +@@ -521,7 +521,7 @@ SYSCALL_DEFINE1(fchdir, unsigned int, fd) + if (!d_can_lookup(f.file->f_path.dentry)) + goto out_putf; + +- error = inode_permission(file_inode(f.file), MAY_EXEC | MAY_CHDIR); ++ error = file_permission(f.file, MAY_EXEC | MAY_CHDIR); + if (!error) + set_fs_pwd(current->fs, &f.file->f_path); + out_putf: +@@ -540,7 +540,7 @@ SYSCALL_DEFINE1(chroot, const char __user *, filename) + if (error) + goto out; + +- error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR); ++ error = path_permission(&path, MAY_EXEC | MAY_CHDIR); + if (error) + goto dput_and_out; + +diff --git a/fs/udf/file.c b/fs/udf/file.c +index e283a62701b83..25f7c915f22b7 100644 +--- a/fs/udf/file.c ++++ b/fs/udf/file.c +@@ -181,7 +181,7 @@ long udf_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) + long old_block, new_block; + int result; + +- if (inode_permission(inode, MAY_READ) != 0) { ++ if (file_permission(filp, MAY_READ) != 0) { + udf_debug("no permission to access inode %lu\n", inode->i_ino); + return -EPERM; + } +diff --git a/fs/verity/enable.c b/fs/verity/enable.c +index 5ceae66e1ae02..29becb66d0d88 100644 +--- a/fs/verity/enable.c ++++ b/fs/verity/enable.c +@@ -369,7 +369,7 @@ int fsverity_ioctl_enable(struct file *filp, const void __user *uarg) + * has verity enabled, and to stabilize the data being hashed. + */ + +- err = inode_permission(inode, MAY_WRITE); ++ err = file_permission(filp, MAY_WRITE); + if (err) + return err; + +diff --git a/include/linux/fs.h b/include/linux/fs.h +index 6de70634e5471..0974e8160f50c 100644 +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -2824,6 +2824,14 @@ static inline int bmap(struct inode *inode, sector_t *block) + extern int notify_change(struct dentry *, struct iattr *, struct inode **); + extern int inode_permission(struct inode *, int); + extern int generic_permission(struct inode *, int); ++static inline int file_permission(struct file *file, int mask) ++{ ++ return inode_permission(file_inode(file), mask); ++} ++static inline int path_permission(const struct path *path, int mask) ++{ ++ return inode_permission(d_inode(path->dentry), mask); ++} + extern int __check_sticky(struct inode *dir, struct inode *inode); + + static inline bool execute_ok(struct inode *inode) +diff --git a/kernel/bpf/inode.c b/kernel/bpf/inode.c +index 6b14b4c4068cc..5966013bc788b 100644 +--- a/kernel/bpf/inode.c ++++ b/kernel/bpf/inode.c +@@ -507,7 +507,7 @@ static void *bpf_obj_do_get(const char __user *pathname, + return ERR_PTR(ret); + + inode = d_backing_inode(path.dentry); +- ret = inode_permission(inode, ACC_MODE(flags)); ++ ret = path_permission(&path, ACC_MODE(flags)); + if (ret) + goto out; + +diff --git a/kernel/sys.c b/kernel/sys.c +index efc213ae4c5ad..7a2cfb57fa9e7 100644 +--- a/kernel/sys.c ++++ b/kernel/sys.c +@@ -1873,7 +1873,7 @@ static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd) + if (!S_ISREG(inode->i_mode) || path_noexec(&exe.file->f_path)) + goto exit; + +- err = inode_permission(inode, MAY_EXEC); ++ err = file_permission(exe.file, MAY_EXEC); + if (err) + goto exit; + +diff --git a/mm/madvise.c b/mm/madvise.c +index f71fc88f0b331..a63aa04ec7fa3 100644 +--- a/mm/madvise.c ++++ b/mm/madvise.c +@@ -543,7 +543,7 @@ static inline bool can_do_pageout(struct vm_area_struct *vma) + * opens a side channel. + */ + return inode_owner_or_capable(file_inode(vma->vm_file)) || +- inode_permission(file_inode(vma->vm_file), MAY_WRITE) == 0; ++ file_permission(vma->vm_file, MAY_WRITE) == 0; + } + + static long madvise_pageout(struct vm_area_struct *vma, +diff --git a/mm/memcontrol.c b/mm/memcontrol.c +index ddc8ed096deca..186ae9dba0fd5 100644 +--- a/mm/memcontrol.c ++++ b/mm/memcontrol.c +@@ -4918,7 +4918,7 @@ static ssize_t memcg_write_event_control(struct kernfs_open_file *of, + + /* the process need read permission on control file */ + /* AV: shouldn't we check that it's been opened for read instead? */ +- ret = inode_permission(file_inode(cfile.file), MAY_READ); ++ ret = file_permission(cfile.file, MAY_READ); + if (ret < 0) + goto out_put_cfile; + +diff --git a/mm/mincore.c b/mm/mincore.c +index 02db1a834021b..7bdb4673f776a 100644 +--- a/mm/mincore.c ++++ b/mm/mincore.c +@@ -167,7 +167,7 @@ static inline bool can_do_mincore(struct vm_area_struct *vma) + * mappings, which opens a side channel. + */ + return inode_owner_or_capable(file_inode(vma->vm_file)) || +- inode_permission(file_inode(vma->vm_file), MAY_WRITE) == 0; ++ file_permission(vma->vm_file, MAY_WRITE) == 0; + } + + static const struct mm_walk_ops mincore_walk_ops = { +diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c +index 3ab726a668e8a..405bf3e6eb796 100644 +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -959,7 +959,7 @@ static struct sock *unix_find_other(struct net *net, + if (err) + goto fail; + inode = d_backing_inode(path.dentry); +- err = inode_permission(inode, MAY_WRITE); ++ err = path_permission(&path, MAY_WRITE); + if (err) + goto put_fail; + +-- +2.43.0 + diff --git a/queue-5.10/fs-inotify-fix-typo-in-inotify-comment.patch b/queue-5.10/fs-inotify-fix-typo-in-inotify-comment.patch new file mode 100644 index 00000000000..a6dec8f3ea3 --- /dev/null +++ b/queue-5.10/fs-inotify-fix-typo-in-inotify-comment.patch @@ -0,0 +1,36 @@ +From 67405511a280986611269a54b683285ac3d84c8d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 May 2022 15:59:59 +0100 +Subject: fs: inotify: Fix typo in inotify comment + +From: Oliver Ford + +[ Upstream commit c05787b4c2f80a3bebcb9cdbf255d4fa5c1e24e1 ] + +Correct spelling in comment. + +Signed-off-by: Oliver Ford +Signed-off-by: Jan Kara +Link: https://lore.kernel.org/r/20220518145959.41-1-ojford@gmail.com +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/inotify/inotify_user.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c +index 3d5d536f8fd63..7360d16ce46d7 100644 +--- a/fs/notify/inotify/inotify_user.c ++++ b/fs/notify/inotify/inotify_user.c +@@ -123,7 +123,7 @@ static inline u32 inotify_mask_to_arg(__u32 mask) + IN_Q_OVERFLOW); + } + +-/* intofiy userspace file descriptor functions */ ++/* inotify userspace file descriptor functions */ + static __poll_t inotify_poll(struct file *file, poll_table *wait) + { + struct fsnotify_group *group = file->private_data; +-- +2.43.0 + diff --git a/queue-5.10/fs-lock-add-2-callbacks-to-lock_manager_operations-t.patch b/queue-5.10/fs-lock-add-2-callbacks-to-lock_manager_operations-t.patch new file mode 100644 index 00000000000..4a5240b0510 --- /dev/null +++ b/queue-5.10/fs-lock-add-2-callbacks-to-lock_manager_operations-t.patch @@ -0,0 +1,167 @@ +From ae9b5cab5ee64abd01aabf81f49b4abb694b19af Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 May 2022 14:19:25 -0700 +Subject: fs/lock: add 2 callbacks to lock_manager_operations to resolve + conflict + +From: Dai Ngo + +[ Upstream commit 2443da2259e97688f93d64d17ab69b15f466078a ] + +Add 2 new callbacks, lm_lock_expirable and lm_expire_lock, to +lock_manager_operations to allow the lock manager to take appropriate +action to resolve the lock conflict if possible. + +A new field, lm_mod_owner, is also added to lock_manager_operations. +The lm_mod_owner is used by the fs/lock code to make sure the lock +manager module such as nfsd, is not freed while lock conflict is being +resolved. + +lm_lock_expirable checks and returns true to indicate that the lock +conflict can be resolved else return false. This callback must be +called with the flc_lock held so it can not block. + +lm_expire_lock is called to resolve the lock conflict if the returned +value from lm_lock_expirable is true. This callback is called without +the flc_lock held since it's allowed to block. Upon returning from +this callback, the lock conflict should be resolved and the caller is +expected to restart the conflict check from the beginnning of the list. + +Lock manager, such as NFSv4 courteous server, uses this callback to +resolve conflict by destroying lock owner, or the NFSv4 courtesy client +(client that has expired but allowed to maintains its states) that owns +the lock. + +Reviewed-by: J. Bruce Fields +Signed-off-by: Dai Ngo +Signed-off-by: Chuck Lever +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + Documentation/filesystems/locking.rst | 4 ++++ + fs/locks.c | 33 ++++++++++++++++++++++++--- + include/linux/fs.h | 3 +++ + 3 files changed, 37 insertions(+), 3 deletions(-) + +diff --git a/Documentation/filesystems/locking.rst b/Documentation/filesystems/locking.rst +index 07e57f7629202..23a0d24168bc5 100644 +--- a/Documentation/filesystems/locking.rst ++++ b/Documentation/filesystems/locking.rst +@@ -433,6 +433,8 @@ prototypes:: + void (*lm_break)(struct file_lock *); /* break_lease callback */ + int (*lm_change)(struct file_lock **, int); + bool (*lm_breaker_owns_lease)(struct file_lock *); ++ bool (*lm_lock_expirable)(struct file_lock *); ++ void (*lm_expire_lock)(void); + + locking rules: + +@@ -444,6 +446,8 @@ lm_grant: no no no + lm_break: yes no no + lm_change yes no no + lm_breaker_owns_lease: yes no no ++lm_lock_expirable yes no no ++lm_expire_lock no no yes + ====================== ============= ================= ========= + + buffer_head +diff --git a/fs/locks.c b/fs/locks.c +index 118df2812f8aa..13a3ba97b73d1 100644 +--- a/fs/locks.c ++++ b/fs/locks.c +@@ -982,6 +982,8 @@ posix_test_lock(struct file *filp, struct file_lock *fl) + struct file_lock *cfl; + struct file_lock_context *ctx; + struct inode *inode = locks_inode(filp); ++ void *owner; ++ void (*func)(void); + + ctx = smp_load_acquire(&inode->i_flctx); + if (!ctx || list_empty_careful(&ctx->flc_posix)) { +@@ -989,12 +991,23 @@ posix_test_lock(struct file *filp, struct file_lock *fl) + return; + } + ++retry: + spin_lock(&ctx->flc_lock); + list_for_each_entry(cfl, &ctx->flc_posix, fl_list) { +- if (posix_locks_conflict(fl, cfl)) { +- locks_copy_conflock(fl, cfl); +- goto out; ++ if (!posix_locks_conflict(fl, cfl)) ++ continue; ++ if (cfl->fl_lmops && cfl->fl_lmops->lm_lock_expirable ++ && (*cfl->fl_lmops->lm_lock_expirable)(cfl)) { ++ owner = cfl->fl_lmops->lm_mod_owner; ++ func = cfl->fl_lmops->lm_expire_lock; ++ __module_get(owner); ++ spin_unlock(&ctx->flc_lock); ++ (*func)(); ++ module_put(owner); ++ goto retry; + } ++ locks_copy_conflock(fl, cfl); ++ goto out; + } + fl->fl_type = F_UNLCK; + out: +@@ -1168,6 +1181,8 @@ static int posix_lock_inode(struct inode *inode, struct file_lock *request, + int error; + bool added = false; + LIST_HEAD(dispose); ++ void *owner; ++ void (*func)(void); + + ctx = locks_get_lock_context(inode, request->fl_type); + if (!ctx) +@@ -1186,6 +1201,7 @@ static int posix_lock_inode(struct inode *inode, struct file_lock *request, + new_fl2 = locks_alloc_lock(); + } + ++retry: + percpu_down_read(&file_rwsem); + spin_lock(&ctx->flc_lock); + /* +@@ -1197,6 +1213,17 @@ static int posix_lock_inode(struct inode *inode, struct file_lock *request, + list_for_each_entry(fl, &ctx->flc_posix, fl_list) { + if (!posix_locks_conflict(request, fl)) + continue; ++ if (fl->fl_lmops && fl->fl_lmops->lm_lock_expirable ++ && (*fl->fl_lmops->lm_lock_expirable)(fl)) { ++ owner = fl->fl_lmops->lm_mod_owner; ++ func = fl->fl_lmops->lm_expire_lock; ++ __module_get(owner); ++ spin_unlock(&ctx->flc_lock); ++ percpu_up_read(&file_rwsem); ++ (*func)(); ++ module_put(owner); ++ goto retry; ++ } + if (conflock) + locks_copy_conflock(conflock, fl); + error = -EAGAIN; +diff --git a/include/linux/fs.h b/include/linux/fs.h +index 17dc1ee8c6cb2..3e9105b3cc767 100644 +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -1017,6 +1017,7 @@ struct file_lock_operations { + }; + + struct lock_manager_operations { ++ void *lm_mod_owner; + fl_owner_t (*lm_get_owner)(fl_owner_t); + void (*lm_put_owner)(fl_owner_t); + void (*lm_notify)(struct file_lock *); /* unblock callback */ +@@ -1025,6 +1026,8 @@ struct lock_manager_operations { + int (*lm_change)(struct file_lock *, int, struct list_head *); + void (*lm_setup)(struct file_lock *, void **); + bool (*lm_breaker_owns_lease)(struct file_lock *); ++ bool (*lm_lock_expirable)(struct file_lock *cfl); ++ void (*lm_expire_lock)(void); + }; + + struct lock_manager { +-- +2.43.0 + diff --git a/queue-5.10/fs-lock-add-helper-locks_owner_has_blockers-to-check.patch b/queue-5.10/fs-lock-add-helper-locks_owner_has_blockers-to-check.patch new file mode 100644 index 00000000000..1e4ae17bf27 --- /dev/null +++ b/queue-5.10/fs-lock-add-helper-locks_owner_has_blockers-to-check.patch @@ -0,0 +1,90 @@ +From 656ab4cf3b6d6c56f156211c9b69e0b3ffe1dd83 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 May 2022 14:19:24 -0700 +Subject: fs/lock: add helper locks_owner_has_blockers to check for blockers + +From: Dai Ngo + +[ Upstream commit 591502c5cb325b1c6ec59ab161927d606b918aa0 ] + +Add helper locks_owner_has_blockers to check if there is any blockers +for a given lockowner. + +Reviewed-by: J. Bruce Fields +Signed-off-by: Dai Ngo +Signed-off-by: Chuck Lever +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/locks.c | 28 ++++++++++++++++++++++++++++ + include/linux/fs.h | 7 +++++++ + 2 files changed, 35 insertions(+) + +diff --git a/fs/locks.c b/fs/locks.c +index 101867933e4d3..118df2812f8aa 100644 +--- a/fs/locks.c ++++ b/fs/locks.c +@@ -376,6 +376,34 @@ void locks_release_private(struct file_lock *fl) + } + EXPORT_SYMBOL_GPL(locks_release_private); + ++/** ++ * locks_owner_has_blockers - Check for blocking lock requests ++ * @flctx: file lock context ++ * @owner: lock owner ++ * ++ * Return values: ++ * %true: @owner has at least one blocker ++ * %false: @owner has no blockers ++ */ ++bool locks_owner_has_blockers(struct file_lock_context *flctx, ++ fl_owner_t owner) ++{ ++ struct file_lock *fl; ++ ++ spin_lock(&flctx->flc_lock); ++ list_for_each_entry(fl, &flctx->flc_posix, fl_list) { ++ if (fl->fl_owner != owner) ++ continue; ++ if (!list_empty(&fl->fl_blocked_requests)) { ++ spin_unlock(&flctx->flc_lock); ++ return true; ++ } ++ } ++ spin_unlock(&flctx->flc_lock); ++ return false; ++} ++EXPORT_SYMBOL_GPL(locks_owner_has_blockers); ++ + /* Free a lock which is not in use. */ + void locks_free_lock(struct file_lock *fl) + { +diff --git a/include/linux/fs.h b/include/linux/fs.h +index c0459446e1440..17dc1ee8c6cb2 100644 +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -1163,6 +1163,8 @@ extern void lease_unregister_notifier(struct notifier_block *); + struct files_struct; + extern void show_fd_locks(struct seq_file *f, + struct file *filp, struct files_struct *files); ++extern bool locks_owner_has_blockers(struct file_lock_context *flctx, ++ fl_owner_t owner); + #else /* !CONFIG_FILE_LOCKING */ + static inline int fcntl_getlk(struct file *file, unsigned int cmd, + struct flock __user *user) +@@ -1303,6 +1305,11 @@ static inline int lease_modify(struct file_lock *fl, int arg, + struct files_struct; + static inline void show_fd_locks(struct seq_file *f, + struct file *filp, struct files_struct *files) {} ++static inline bool locks_owner_has_blockers(struct file_lock_context *flctx, ++ fl_owner_t owner) ++{ ++ return false; ++} + #endif /* !CONFIG_FILE_LOCKING */ + + static inline struct inode *file_inode(const struct file *f) +-- +2.43.0 + diff --git a/queue-5.10/fs-lock-documentation-cleanup.-replace-inode-i_lock-.patch b/queue-5.10/fs-lock-documentation-cleanup.-replace-inode-i_lock-.patch new file mode 100644 index 00000000000..91d81f77241 --- /dev/null +++ b/queue-5.10/fs-lock-documentation-cleanup.-replace-inode-i_lock-.patch @@ -0,0 +1,46 @@ +From 630c8bc86219ffc16caf17f0369572a2ddd921eb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 12 Feb 2022 10:12:52 -0800 +Subject: fs/lock: documentation cleanup. Replace inode->i_lock with flc_lock. + +From: Dai Ngo + +[ Upstream commit 9d6647762b9c6b555bc83d97d7c93be6057a990f ] + +Update lock usage of lock_manager_operations' functions to reflect +the changes in commit 6109c85037e5 ("locks: add a dedicated spinlock +to protect i_flctx lists"). + +Signed-off-by: Dai Ngo +Signed-off-by: Chuck Lever +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + Documentation/filesystems/locking.rst | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/Documentation/filesystems/locking.rst b/Documentation/filesystems/locking.rst +index fbd695d66905f..07e57f7629202 100644 +--- a/Documentation/filesystems/locking.rst ++++ b/Documentation/filesystems/locking.rst +@@ -437,13 +437,13 @@ prototypes:: + locking rules: + + ====================== ============= ================= ========= +-ops inode->i_lock blocked_lock_lock may block ++ops flc_lock blocked_lock_lock may block + ====================== ============= ================= ========= +-lm_notify: yes yes no ++lm_notify: no yes no + lm_grant: no no no + lm_break: yes no no + lm_change yes no no +-lm_breaker_owns_lease: no no no ++lm_breaker_owns_lease: yes no no + ====================== ============= ================= ========= + + buffer_head +-- +2.43.0 + diff --git a/queue-5.10/fs-lockd-convert-comma-to-semicolon.patch b/queue-5.10/fs-lockd-convert-comma-to-semicolon.patch new file mode 100644 index 00000000000..12784bb46c6 --- /dev/null +++ b/queue-5.10/fs-lockd-convert-comma-to-semicolon.patch @@ -0,0 +1,35 @@ +From 0ba88c6763cdde4c4943007a455ad529eca963bd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 11 Dec 2020 16:41:58 +0800 +Subject: fs/lockd: convert comma to semicolon + +From: Zheng Yongjun + +[ Upstream commit 3316fb80a0b4c1fef03a3eb1a7f0651e2133c429 ] + +Replace a comma between expression statements by a semicolon. + +Signed-off-by: Zheng Yongjun +Signed-off-by: Trond Myklebust +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/host.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/lockd/host.c b/fs/lockd/host.c +index 771c289f6df7f..f802223e71abe 100644 +--- a/fs/lockd/host.c ++++ b/fs/lockd/host.c +@@ -163,7 +163,7 @@ static struct nlm_host *nlm_alloc_host(struct nlm_lookup_host_info *ni, + host->h_nsmhandle = nsm; + host->h_addrbuf = nsm->sm_addrbuf; + host->net = ni->net; +- host->h_cred = get_cred(ni->cred), ++ host->h_cred = get_cred(ni->cred); + strlcpy(host->nodename, utsname()->nodename, sizeof(host->nodename)); + + out: +-- +2.43.0 + diff --git a/queue-5.10/fs-notify-constify-path.patch b/queue-5.10/fs-notify-constify-path.patch new file mode 100644 index 00000000000..a6ac7f0acb2 --- /dev/null +++ b/queue-5.10/fs-notify-constify-path.patch @@ -0,0 +1,80 @@ +From f9ae680c96711af599ec36bd71cd9f2bfed10296 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Aug 2022 12:57:38 -0400 +Subject: fs/notify: constify path + +From: Al Viro + +[ Upstream commit d5bf88895f24686641c39420ee6df716dc1d95d8 ] + +Reviewed-by: Matthew Bobrowski +Reviewed-by: Christian Brauner (Microsoft) +Signed-off-by: Al Viro +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify.c | 2 +- + fs/notify/fanotify/fanotify.h | 2 +- + fs/notify/fanotify/fanotify_user.c | 6 +++--- + 3 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c +index cd7d09a569fff..a2a15bc4df280 100644 +--- a/fs/notify/fanotify/fanotify.c ++++ b/fs/notify/fanotify/fanotify.c +@@ -18,7 +18,7 @@ + + #include "fanotify.h" + +-static bool fanotify_path_equal(struct path *p1, struct path *p2) ++static bool fanotify_path_equal(const struct path *p1, const struct path *p2) + { + return p1->mnt == p2->mnt && p1->dentry == p2->dentry; + } +diff --git a/fs/notify/fanotify/fanotify.h b/fs/notify/fanotify/fanotify.h +index 1d9f11255c64f..bf6d4d38afa04 100644 +--- a/fs/notify/fanotify/fanotify.h ++++ b/fs/notify/fanotify/fanotify.h +@@ -458,7 +458,7 @@ static inline bool fanotify_event_has_path(struct fanotify_event *event) + event->type == FANOTIFY_EVENT_TYPE_PATH_PERM; + } + +-static inline struct path *fanotify_event_path(struct fanotify_event *event) ++static inline const struct path *fanotify_event_path(struct fanotify_event *event) + { + if (event->type == FANOTIFY_EVENT_TYPE_PATH) + return &FANOTIFY_PE(event)->path; +diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c +index 72dd446606a78..5302313f28bed 100644 +--- a/fs/notify/fanotify/fanotify_user.c ++++ b/fs/notify/fanotify/fanotify_user.c +@@ -237,7 +237,7 @@ static struct fanotify_event *get_one_event(struct fsnotify_group *group, + return event; + } + +-static int create_fd(struct fsnotify_group *group, struct path *path, ++static int create_fd(struct fsnotify_group *group, const struct path *path, + struct file **file) + { + int client_fd; +@@ -607,7 +607,7 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group, + char __user *buf, size_t count) + { + struct fanotify_event_metadata metadata; +- struct path *path = fanotify_event_path(event); ++ const struct path *path = fanotify_event_path(event); + struct fanotify_info *info = fanotify_event_info(event); + unsigned int info_mode = FAN_GROUP_FLAG(group, FANOTIFY_INFO_MODES); + unsigned int pidfd_mode = info_mode & FAN_REPORT_PIDFD; +@@ -1541,7 +1541,7 @@ static int fanotify_test_fid(struct dentry *dentry) + } + + static int fanotify_events_supported(struct fsnotify_group *group, +- struct path *path, __u64 mask, ++ const struct path *path, __u64 mask, + unsigned int flags) + { + unsigned int mark_type = flags & FANOTIFY_MARK_TYPE_BITS; +-- +2.43.0 + diff --git a/queue-5.10/fsnotify-add-helper-to-detect-overflow_event.patch b/queue-5.10/fsnotify-add-helper-to-detect-overflow_event.patch new file mode 100644 index 00000000000..900dd4195e6 --- /dev/null +++ b/queue-5.10/fsnotify-add-helper-to-detect-overflow_event.patch @@ -0,0 +1,58 @@ +From 123127f76271dc64ec3f3de92a2d234371993134 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 Oct 2021 16:27:23 -0300 +Subject: fsnotify: Add helper to detect overflow_event + +From: Gabriel Krisman Bertazi + +[ Upstream commit 808967a0a4d2f4ce6a2005c5692fffbecaf018c1 ] + +Similarly to fanotify_is_perm_event and friends, provide a helper +predicate to say whether a mask is of an overflow event. + +Link: https://lore.kernel.org/r/20211025192746.66445-9-krisman@collabora.com +Suggested-by: Amir Goldstein +Reviewed-by: Amir Goldstein +Reviewed-by: Jan Kara +Signed-off-by: Gabriel Krisman Bertazi +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify.h | 3 ++- + include/linux/fsnotify_backend.h | 5 +++++ + 2 files changed, 7 insertions(+), 1 deletion(-) + +diff --git a/fs/notify/fanotify/fanotify.h b/fs/notify/fanotify/fanotify.h +index 4a5e555dc3d25..c42cf8fd7d798 100644 +--- a/fs/notify/fanotify/fanotify.h ++++ b/fs/notify/fanotify/fanotify.h +@@ -315,7 +315,8 @@ static inline struct path *fanotify_event_path(struct fanotify_event *event) + */ + static inline bool fanotify_is_hashed_event(u32 mask) + { +- return !fanotify_is_perm_event(mask) && !(mask & FS_Q_OVERFLOW); ++ return !(fanotify_is_perm_event(mask) || ++ fsnotify_is_overflow_event(mask)); + } + + static inline unsigned int fanotify_event_hash_bucket( +diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h +index a2db821e8a8f2..749bc85e1d1c4 100644 +--- a/include/linux/fsnotify_backend.h ++++ b/include/linux/fsnotify_backend.h +@@ -510,6 +510,11 @@ static inline void fsnotify_queue_overflow(struct fsnotify_group *group) + fsnotify_add_event(group, group->overflow_event, NULL, NULL); + } + ++static inline bool fsnotify_is_overflow_event(u32 mask) ++{ ++ return mask & FS_Q_OVERFLOW; ++} ++ + static inline bool fsnotify_notify_queue_is_empty(struct fsnotify_group *group) + { + assert_spin_locked(&group->notification_lock); +-- +2.43.0 + diff --git a/queue-5.10/fsnotify-add-wrapper-around-fsnotify_add_event.patch b/queue-5.10/fsnotify-add-wrapper-around-fsnotify_add_event.patch new file mode 100644 index 00000000000..c0b44bf3fed --- /dev/null +++ b/queue-5.10/fsnotify-add-wrapper-around-fsnotify_add_event.patch @@ -0,0 +1,120 @@ +From 84ae2043b9d5d90c39f0b7b13ebe137c36a9a603 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 Oct 2021 16:27:24 -0300 +Subject: fsnotify: Add wrapper around fsnotify_add_event + +From: Gabriel Krisman Bertazi + +[ Upstream commit 1ad03c3a326a86e259389592117252c851873395 ] + +fsnotify_add_event is growing in number of parameters, which in most +case are just passed a NULL pointer. So, split out a new +fsnotify_insert_event function to clean things up for users who don't +need an insert hook. + +Link: https://lore.kernel.org/r/20211025192746.66445-10-krisman@collabora.com +Suggested-by: Amir Goldstein +Reviewed-by: Amir Goldstein +Reviewed-by: Jan Kara +Signed-off-by: Gabriel Krisman Bertazi +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify.c | 4 ++-- + fs/notify/inotify/inotify_fsnotify.c | 2 +- + fs/notify/notification.c | 12 ++++++------ + include/linux/fsnotify_backend.h | 23 ++++++++++++++++------- + 4 files changed, 25 insertions(+), 16 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c +index 310246f8d3f19..f82e20228999c 100644 +--- a/fs/notify/fanotify/fanotify.c ++++ b/fs/notify/fanotify/fanotify.c +@@ -781,8 +781,8 @@ static int fanotify_handle_event(struct fsnotify_group *group, u32 mask, + } + + fsn_event = &event->fse; +- ret = fsnotify_add_event(group, fsn_event, fanotify_merge, +- fanotify_insert_event); ++ ret = fsnotify_insert_event(group, fsn_event, fanotify_merge, ++ fanotify_insert_event); + if (ret) { + /* Permission events shouldn't be merged */ + BUG_ON(ret == 1 && mask & FANOTIFY_PERM_EVENTS); +diff --git a/fs/notify/inotify/inotify_fsnotify.c b/fs/notify/inotify/inotify_fsnotify.c +index b0530f75b274a..be3eb1cebdcce 100644 +--- a/fs/notify/inotify/inotify_fsnotify.c ++++ b/fs/notify/inotify/inotify_fsnotify.c +@@ -123,7 +123,7 @@ int inotify_handle_inode_event(struct fsnotify_mark *inode_mark, u32 mask, + if (len) + strcpy(event->name, name->name); + +- ret = fsnotify_add_event(group, fsn_event, inotify_merge, NULL); ++ ret = fsnotify_add_event(group, fsn_event, inotify_merge); + if (ret) { + /* Our event wasn't used in the end. Free it. */ + fsnotify_destroy_event(group, fsn_event); +diff --git a/fs/notify/notification.c b/fs/notify/notification.c +index 32f45543b9c64..44bb10f507153 100644 +--- a/fs/notify/notification.c ++++ b/fs/notify/notification.c +@@ -78,12 +78,12 @@ void fsnotify_destroy_event(struct fsnotify_group *group, + * 2 if the event was not queued - either the queue of events has overflown + * or the group is shutting down. + */ +-int fsnotify_add_event(struct fsnotify_group *group, +- struct fsnotify_event *event, +- int (*merge)(struct fsnotify_group *, +- struct fsnotify_event *), +- void (*insert)(struct fsnotify_group *, +- struct fsnotify_event *)) ++int fsnotify_insert_event(struct fsnotify_group *group, ++ struct fsnotify_event *event, ++ int (*merge)(struct fsnotify_group *, ++ struct fsnotify_event *), ++ void (*insert)(struct fsnotify_group *, ++ struct fsnotify_event *)) + { + int ret = 0; + struct list_head *list = &group->notification_list; +diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h +index 749bc85e1d1c4..b323d0c4b9671 100644 +--- a/include/linux/fsnotify_backend.h ++++ b/include/linux/fsnotify_backend.h +@@ -498,16 +498,25 @@ extern int fsnotify_fasync(int fd, struct file *file, int on); + extern void fsnotify_destroy_event(struct fsnotify_group *group, + struct fsnotify_event *event); + /* attach the event to the group notification queue */ +-extern int fsnotify_add_event(struct fsnotify_group *group, +- struct fsnotify_event *event, +- int (*merge)(struct fsnotify_group *, +- struct fsnotify_event *), +- void (*insert)(struct fsnotify_group *, +- struct fsnotify_event *)); ++extern int fsnotify_insert_event(struct fsnotify_group *group, ++ struct fsnotify_event *event, ++ int (*merge)(struct fsnotify_group *, ++ struct fsnotify_event *), ++ void (*insert)(struct fsnotify_group *, ++ struct fsnotify_event *)); ++ ++static inline int fsnotify_add_event(struct fsnotify_group *group, ++ struct fsnotify_event *event, ++ int (*merge)(struct fsnotify_group *, ++ struct fsnotify_event *)) ++{ ++ return fsnotify_insert_event(group, event, merge, NULL); ++} ++ + /* Queue overflow event to a notification group */ + static inline void fsnotify_queue_overflow(struct fsnotify_group *group) + { +- fsnotify_add_event(group, group->overflow_event, NULL, NULL); ++ fsnotify_add_event(group, group->overflow_event, NULL); + } + + static inline bool fsnotify_is_overflow_event(u32 mask) +-- +2.43.0 + diff --git a/queue-5.10/fsnotify-allow-adding-an-inode-mark-without-pinning-.patch b/queue-5.10/fsnotify-allow-adding-an-inode-mark-without-pinning-.patch new file mode 100644 index 00000000000..773cc22152d --- /dev/null +++ b/queue-5.10/fsnotify-allow-adding-an-inode-mark-without-pinning-.patch @@ -0,0 +1,217 @@ +From 345137d3735026896cbaa4c57204b949253c215f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 Apr 2022 15:03:22 +0300 +Subject: fsnotify: allow adding an inode mark without pinning inode + +From: Amir Goldstein + +[ Upstream commit c3638b5b13740fa31762d414bbce8b7a694e582a ] + +fsnotify_add_mark() and variants implicitly take a reference on inode +when attaching a mark to an inode. + +Make that behavior opt-out with the mark flag FSNOTIFY_MARK_FLAG_NO_IREF. + +Instead of taking the inode reference when attaching connector to inode +and dropping the inode reference when detaching connector from inode, +take the inode reference on attach of the first mark that wants to hold +an inode reference and drop the inode reference on detach of the last +mark that wants to hold an inode reference. + +Backends can "upgrade" an existing mark to take an inode reference, but +cannot "downgrade" a mark with inode reference to release the refernce. + +This leaves the choice to the backend whether or not to pin the inode +when adding an inode mark. + +This is intended to be used when adding a mark with ignored mask that is +used for optimization in cases where group can afford getting unneeded +events and reinstate the mark with ignored mask when inode is accessed +again after being evicted. + +Link: https://lore.kernel.org/r/20220422120327.3459282-12-amir73il@gmail.com +Signed-off-by: Amir Goldstein +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/mark.c | 76 +++++++++++++++++++++++--------- + include/linux/fsnotify_backend.h | 2 + + 2 files changed, 58 insertions(+), 20 deletions(-) + +diff --git a/fs/notify/mark.c b/fs/notify/mark.c +index 982ca2f20ff5d..c74ef947447d6 100644 +--- a/fs/notify/mark.c ++++ b/fs/notify/mark.c +@@ -116,20 +116,64 @@ __u32 fsnotify_conn_mask(struct fsnotify_mark_connector *conn) + return *fsnotify_conn_mask_p(conn); + } + +-static void __fsnotify_recalc_mask(struct fsnotify_mark_connector *conn) ++static void fsnotify_get_inode_ref(struct inode *inode) ++{ ++ ihold(inode); ++ atomic_long_inc(&inode->i_sb->s_fsnotify_connectors); ++} ++ ++/* ++ * Grab or drop inode reference for the connector if needed. ++ * ++ * When it's time to drop the reference, we only clear the HAS_IREF flag and ++ * return the inode object. fsnotify_drop_object() will be resonsible for doing ++ * iput() outside of spinlocks. This happens when last mark that wanted iref is ++ * detached. ++ */ ++static struct inode *fsnotify_update_iref(struct fsnotify_mark_connector *conn, ++ bool want_iref) ++{ ++ bool has_iref = conn->flags & FSNOTIFY_CONN_FLAG_HAS_IREF; ++ struct inode *inode = NULL; ++ ++ if (conn->type != FSNOTIFY_OBJ_TYPE_INODE || ++ want_iref == has_iref) ++ return NULL; ++ ++ if (want_iref) { ++ /* Pin inode if any mark wants inode refcount held */ ++ fsnotify_get_inode_ref(fsnotify_conn_inode(conn)); ++ conn->flags |= FSNOTIFY_CONN_FLAG_HAS_IREF; ++ } else { ++ /* Unpin inode after detach of last mark that wanted iref */ ++ inode = fsnotify_conn_inode(conn); ++ conn->flags &= ~FSNOTIFY_CONN_FLAG_HAS_IREF; ++ } ++ ++ return inode; ++} ++ ++static void *__fsnotify_recalc_mask(struct fsnotify_mark_connector *conn) + { + u32 new_mask = 0; ++ bool want_iref = false; + struct fsnotify_mark *mark; + + assert_spin_locked(&conn->lock); + /* We can get detached connector here when inode is getting unlinked. */ + if (!fsnotify_valid_obj_type(conn->type)) +- return; ++ return NULL; + hlist_for_each_entry(mark, &conn->list, obj_list) { +- if (mark->flags & FSNOTIFY_MARK_FLAG_ATTACHED) +- new_mask |= fsnotify_calc_mask(mark); ++ if (!(mark->flags & FSNOTIFY_MARK_FLAG_ATTACHED)) ++ continue; ++ new_mask |= fsnotify_calc_mask(mark); ++ if (conn->type == FSNOTIFY_OBJ_TYPE_INODE && ++ !(mark->flags & FSNOTIFY_MARK_FLAG_NO_IREF)) ++ want_iref = true; + } + *fsnotify_conn_mask_p(conn) = new_mask; ++ ++ return fsnotify_update_iref(conn, want_iref); + } + + /* +@@ -169,12 +213,6 @@ static void fsnotify_connector_destroy_workfn(struct work_struct *work) + } + } + +-static void fsnotify_get_inode_ref(struct inode *inode) +-{ +- ihold(inode); +- atomic_long_inc(&inode->i_sb->s_fsnotify_connectors); +-} +- + static void fsnotify_put_inode_ref(struct inode *inode) + { + struct super_block *sb = inode->i_sb; +@@ -213,6 +251,10 @@ static void *fsnotify_detach_connector_from_object( + if (conn->type == FSNOTIFY_OBJ_TYPE_INODE) { + inode = fsnotify_conn_inode(conn); + inode->i_fsnotify_mask = 0; ++ ++ /* Unpin inode when detaching from connector */ ++ if (!(conn->flags & FSNOTIFY_CONN_FLAG_HAS_IREF)) ++ inode = NULL; + } else if (conn->type == FSNOTIFY_OBJ_TYPE_VFSMOUNT) { + fsnotify_conn_mount(conn)->mnt_fsnotify_mask = 0; + } else if (conn->type == FSNOTIFY_OBJ_TYPE_SB) { +@@ -274,7 +316,8 @@ void fsnotify_put_mark(struct fsnotify_mark *mark) + objp = fsnotify_detach_connector_from_object(conn, &type); + free_conn = true; + } else { +- __fsnotify_recalc_mask(conn); ++ objp = __fsnotify_recalc_mask(conn); ++ type = conn->type; + } + WRITE_ONCE(mark->connector, NULL); + spin_unlock(&conn->lock); +@@ -497,7 +540,6 @@ static int fsnotify_attach_connector_to_object(fsnotify_connp_t *connp, + unsigned int obj_type, + __kernel_fsid_t *fsid) + { +- struct inode *inode = NULL; + struct fsnotify_mark_connector *conn; + + conn = kmem_cache_alloc(fsnotify_mark_connector_cachep, GFP_KERNEL); +@@ -505,6 +547,7 @@ static int fsnotify_attach_connector_to_object(fsnotify_connp_t *connp, + return -ENOMEM; + spin_lock_init(&conn->lock); + INIT_HLIST_HEAD(&conn->list); ++ conn->flags = 0; + conn->type = obj_type; + conn->obj = connp; + /* Cache fsid of filesystem containing the object */ +@@ -515,10 +558,6 @@ static int fsnotify_attach_connector_to_object(fsnotify_connp_t *connp, + conn->fsid.val[0] = conn->fsid.val[1] = 0; + conn->flags = 0; + } +- if (conn->type == FSNOTIFY_OBJ_TYPE_INODE) { +- inode = fsnotify_conn_inode(conn); +- fsnotify_get_inode_ref(inode); +- } + fsnotify_get_sb_connectors(conn); + + /* +@@ -527,8 +566,6 @@ static int fsnotify_attach_connector_to_object(fsnotify_connp_t *connp, + */ + if (cmpxchg(connp, NULL, conn)) { + /* Someone else created list structure for us */ +- if (inode) +- fsnotify_put_inode_ref(inode); + fsnotify_put_sb_connectors(conn); + kmem_cache_free(fsnotify_mark_connector_cachep, conn); + } +@@ -690,8 +727,7 @@ int fsnotify_add_mark_locked(struct fsnotify_mark *mark, + if (ret) + goto err; + +- if (mark->mask || mark->ignored_mask) +- fsnotify_recalc_mask(mark->connector); ++ fsnotify_recalc_mask(mark->connector); + + return ret; + err: +diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h +index d62111e832440..9a1a9e78f69f5 100644 +--- a/include/linux/fsnotify_backend.h ++++ b/include/linux/fsnotify_backend.h +@@ -456,6 +456,7 @@ struct fsnotify_mark_connector { + spinlock_t lock; + unsigned short type; /* Type of object [lock] */ + #define FSNOTIFY_CONN_FLAG_HAS_FSID 0x01 ++#define FSNOTIFY_CONN_FLAG_HAS_IREF 0x02 + unsigned short flags; /* flags [lock] */ + __kernel_fsid_t fsid; /* fsid of filesystem containing object */ + union { +@@ -510,6 +511,7 @@ struct fsnotify_mark { + #define FSNOTIFY_MARK_FLAG_IN_ONESHOT 0x0020 + /* fanotify mark flags */ + #define FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY 0x0100 ++#define FSNOTIFY_MARK_FLAG_NO_IREF 0x0200 + unsigned int flags; /* flags [mark->lock] */ + }; + +-- +2.43.0 + diff --git a/queue-5.10/fsnotify-allow-fsnotify_-peek-remove-_first_event-wi.patch b/queue-5.10/fsnotify-allow-fsnotify_-peek-remove-_first_event-wi.patch new file mode 100644 index 00000000000..6c121be6b91 --- /dev/null +++ b/queue-5.10/fsnotify-allow-fsnotify_-peek-remove-_first_event-wi.patch @@ -0,0 +1,207 @@ +From d519c5aa107e3e3ba276e5670603fd7f74de71d6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Mar 2021 12:48:22 +0200 +Subject: fsnotify: allow fsnotify_{peek,remove}_first_event with empty queue + +From: Amir Goldstein + +[ Upstream commit 6f73171e192366ff7c98af9fb50615ef9615f8a7 ] + +Current code has an assumtion that fsnotify_notify_queue_is_empty() is +called to verify that queue is not empty before trying to peek or remove +an event from queue. + +Remove this assumption by moving the fsnotify_notify_queue_is_empty() +into the functions, allow them to return NULL value and check return +value by all callers. + +This is a prep patch for multi event queues. + +Link: https://lore.kernel.org/r/20210304104826.3993892-2-amir73il@gmail.com +Signed-off-by: Amir Goldstein +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify_user.c | 26 +++++++++++------- + fs/notify/inotify/inotify_user.c | 5 ++-- + fs/notify/notification.c | 42 ++++++++++++++---------------- + include/linux/fsnotify_backend.h | 8 +++++- + 4 files changed, 44 insertions(+), 37 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c +index 829ead2792dfb..30651e8d1a6d5 100644 +--- a/fs/notify/fanotify/fanotify_user.c ++++ b/fs/notify/fanotify/fanotify_user.c +@@ -100,24 +100,30 @@ static struct fanotify_event *get_one_event(struct fsnotify_group *group, + { + size_t event_size = FAN_EVENT_METADATA_LEN; + struct fanotify_event *event = NULL; ++ struct fsnotify_event *fsn_event; + unsigned int fid_mode = FAN_GROUP_FLAG(group, FANOTIFY_FID_BITS); + + pr_debug("%s: group=%p count=%zd\n", __func__, group, count); + + spin_lock(&group->notification_lock); +- if (fsnotify_notify_queue_is_empty(group)) ++ fsn_event = fsnotify_peek_first_event(group); ++ if (!fsn_event) + goto out; + +- if (fid_mode) { +- event_size += fanotify_event_info_len(fid_mode, +- FANOTIFY_E(fsnotify_peek_first_event(group))); +- } ++ event = FANOTIFY_E(fsn_event); ++ if (fid_mode) ++ event_size += fanotify_event_info_len(fid_mode, event); + + if (event_size > count) { + event = ERR_PTR(-EINVAL); + goto out; + } +- event = FANOTIFY_E(fsnotify_remove_first_event(group)); ++ ++ /* ++ * Held the notification_lock the whole time, so this is the ++ * same event we peeked above. ++ */ ++ fsnotify_remove_first_event(group); + if (fanotify_is_perm_event(event->mask)) + FANOTIFY_PERM(event)->state = FAN_EVENT_REPORTED; + out: +@@ -573,6 +579,7 @@ static ssize_t fanotify_write(struct file *file, const char __user *buf, size_t + static int fanotify_release(struct inode *ignored, struct file *file) + { + struct fsnotify_group *group = file->private_data; ++ struct fsnotify_event *fsn_event; + + /* + * Stop new events from arriving in the notification queue. since +@@ -601,13 +608,12 @@ static int fanotify_release(struct inode *ignored, struct file *file) + * dequeue them and set the response. They will be freed once the + * response is consumed and fanotify_get_response() returns. + */ +- while (!fsnotify_notify_queue_is_empty(group)) { +- struct fanotify_event *event; ++ while ((fsn_event = fsnotify_remove_first_event(group))) { ++ struct fanotify_event *event = FANOTIFY_E(fsn_event); + +- event = FANOTIFY_E(fsnotify_remove_first_event(group)); + if (!(event->mask & FANOTIFY_PERM_EVENTS)) { + spin_unlock(&group->notification_lock); +- fsnotify_destroy_event(group, &event->fse); ++ fsnotify_destroy_event(group, fsn_event); + } else { + finish_permission_event(group, FANOTIFY_PERM(event), + FAN_ALLOW); +diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c +index 82fc0cf86a7c3..c2018983832e5 100644 +--- a/fs/notify/inotify/inotify_user.c ++++ b/fs/notify/inotify/inotify_user.c +@@ -146,10 +146,9 @@ static struct fsnotify_event *get_one_event(struct fsnotify_group *group, + size_t event_size = sizeof(struct inotify_event); + struct fsnotify_event *event; + +- if (fsnotify_notify_queue_is_empty(group)) +- return NULL; +- + event = fsnotify_peek_first_event(group); ++ if (!event) ++ return NULL; + + pr_debug("%s: group=%p event=%p\n", __func__, group, event); + +diff --git a/fs/notify/notification.c b/fs/notify/notification.c +index 75d79d6d3ef09..001cfe7d2e4e7 100644 +--- a/fs/notify/notification.c ++++ b/fs/notify/notification.c +@@ -47,13 +47,6 @@ u32 fsnotify_get_cookie(void) + } + EXPORT_SYMBOL_GPL(fsnotify_get_cookie); + +-/* return true if the notify queue is empty, false otherwise */ +-bool fsnotify_notify_queue_is_empty(struct fsnotify_group *group) +-{ +- assert_spin_locked(&group->notification_lock); +- return list_empty(&group->notification_list) ? true : false; +-} +- + void fsnotify_destroy_event(struct fsnotify_group *group, + struct fsnotify_event *event) + { +@@ -141,33 +134,36 @@ void fsnotify_remove_queued_event(struct fsnotify_group *group, + } + + /* +- * Remove and return the first event from the notification list. It is the +- * responsibility of the caller to destroy the obtained event ++ * Return the first event on the notification list without removing it. ++ * Returns NULL if the list is empty. + */ +-struct fsnotify_event *fsnotify_remove_first_event(struct fsnotify_group *group) ++struct fsnotify_event *fsnotify_peek_first_event(struct fsnotify_group *group) + { +- struct fsnotify_event *event; +- + assert_spin_locked(&group->notification_lock); + +- pr_debug("%s: group=%p\n", __func__, group); ++ if (fsnotify_notify_queue_is_empty(group)) ++ return NULL; + +- event = list_first_entry(&group->notification_list, +- struct fsnotify_event, list); +- fsnotify_remove_queued_event(group, event); +- return event; ++ return list_first_entry(&group->notification_list, ++ struct fsnotify_event, list); + } + + /* +- * This will not remove the event, that must be done with +- * fsnotify_remove_first_event() ++ * Remove and return the first event from the notification list. It is the ++ * responsibility of the caller to destroy the obtained event + */ +-struct fsnotify_event *fsnotify_peek_first_event(struct fsnotify_group *group) ++struct fsnotify_event *fsnotify_remove_first_event(struct fsnotify_group *group) + { +- assert_spin_locked(&group->notification_lock); ++ struct fsnotify_event *event = fsnotify_peek_first_event(group); + +- return list_first_entry(&group->notification_list, +- struct fsnotify_event, list); ++ if (!event) ++ return NULL; ++ ++ pr_debug("%s: group=%p event=%p\n", __func__, group, event); ++ ++ fsnotify_remove_queued_event(group, event); ++ ++ return event; + } + + /* +diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h +index e5409b83e7313..7eb979bfc1413 100644 +--- a/include/linux/fsnotify_backend.h ++++ b/include/linux/fsnotify_backend.h +@@ -495,7 +495,13 @@ static inline void fsnotify_queue_overflow(struct fsnotify_group *group) + fsnotify_add_event(group, group->overflow_event, NULL); + } + +-/* true if the group notification queue is empty */ ++static inline bool fsnotify_notify_queue_is_empty(struct fsnotify_group *group) ++{ ++ assert_spin_locked(&group->notification_lock); ++ ++ return list_empty(&group->notification_list); ++} ++ + extern bool fsnotify_notify_queue_is_empty(struct fsnotify_group *group); + /* return, but do not dequeue the first event on the notification queue */ + extern struct fsnotify_event *fsnotify_peek_first_event(struct fsnotify_group *group); +-- +2.43.0 + diff --git a/queue-5.10/fsnotify-clarify-contract-for-create-event-hooks.patch b/queue-5.10/fsnotify-clarify-contract-for-create-event-hooks.patch new file mode 100644 index 00000000000..e4cd5ed4db8 --- /dev/null +++ b/queue-5.10/fsnotify-clarify-contract-for-create-event-hooks.patch @@ -0,0 +1,114 @@ +From b833efdaa3a8ba98263aa45932b1ef92baf7f5a3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 Oct 2021 16:27:18 -0300 +Subject: fsnotify: clarify contract for create event hooks + +From: Amir Goldstein + +[ Upstream commit dabe729dddca550446e9cc118c96d1f91703345b ] + +Clarify argument names and contract for fsnotify_create() and +fsnotify_mkdir() to reflect the anomaly of kernfs, which leaves dentries +negavite after mkdir/create. + +Remove the WARN_ON(!inode) in audit code that were added by the Fixes +commit under the wrong assumption that dentries cannot be negative after +mkdir/create. + +Fixes: aa93bdc5500c ("fsnotify: use helpers to access data by data_type") +Link: https://lore.kernel.org/linux-fsdevel/87mtp5yz0q.fsf@collabora.com/ +Link: https://lore.kernel.org/r/20211025192746.66445-4-krisman@collabora.com +Reviewed-by: Jan Kara +Reported-by: Gabriel Krisman Bertazi +Signed-off-by: Amir Goldstein +Signed-off-by: Gabriel Krisman Bertazi +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + include/linux/fsnotify.h | 22 ++++++++++++++++------ + kernel/audit_fsnotify.c | 3 +-- + kernel/audit_watch.c | 3 +-- + 3 files changed, 18 insertions(+), 10 deletions(-) + +diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h +index e969a23f70631..addca4ea56ad9 100644 +--- a/include/linux/fsnotify.h ++++ b/include/linux/fsnotify.h +@@ -192,16 +192,22 @@ static inline void fsnotify_inoderemove(struct inode *inode) + + /* + * fsnotify_create - 'name' was linked in ++ * ++ * Caller must make sure that dentry->d_name is stable. ++ * Note: some filesystems (e.g. kernfs) leave @dentry negative and instantiate ++ * ->d_inode later + */ +-static inline void fsnotify_create(struct inode *inode, struct dentry *dentry) ++static inline void fsnotify_create(struct inode *dir, struct dentry *dentry) + { +- audit_inode_child(inode, dentry, AUDIT_TYPE_CHILD_CREATE); ++ audit_inode_child(dir, dentry, AUDIT_TYPE_CHILD_CREATE); + +- fsnotify_dirent(inode, dentry, FS_CREATE); ++ fsnotify_dirent(dir, dentry, FS_CREATE); + } + + /* + * fsnotify_link - new hardlink in 'inode' directory ++ * ++ * Caller must make sure that new_dentry->d_name is stable. + * Note: We have to pass also the linked inode ptr as some filesystems leave + * new_dentry->d_inode NULL and instantiate inode pointer later + */ +@@ -267,12 +273,16 @@ static inline void fsnotify_unlink(struct inode *dir, struct dentry *dentry) + + /* + * fsnotify_mkdir - directory 'name' was created ++ * ++ * Caller must make sure that dentry->d_name is stable. ++ * Note: some filesystems (e.g. kernfs) leave @dentry negative and instantiate ++ * ->d_inode later + */ +-static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry) ++static inline void fsnotify_mkdir(struct inode *dir, struct dentry *dentry) + { +- audit_inode_child(inode, dentry, AUDIT_TYPE_CHILD_CREATE); ++ audit_inode_child(dir, dentry, AUDIT_TYPE_CHILD_CREATE); + +- fsnotify_dirent(inode, dentry, FS_CREATE | FS_ISDIR); ++ fsnotify_dirent(dir, dentry, FS_CREATE | FS_ISDIR); + } + + /* +diff --git a/kernel/audit_fsnotify.c b/kernel/audit_fsnotify.c +index b2ebacd2f3097..76a5925b4e18d 100644 +--- a/kernel/audit_fsnotify.c ++++ b/kernel/audit_fsnotify.c +@@ -161,8 +161,7 @@ static int audit_mark_handle_event(struct fsnotify_mark *inode_mark, u32 mask, + + audit_mark = container_of(inode_mark, struct audit_fsnotify_mark, mark); + +- if (WARN_ON_ONCE(inode_mark->group != audit_fsnotify_group) || +- WARN_ON_ONCE(!inode)) ++ if (WARN_ON_ONCE(inode_mark->group != audit_fsnotify_group)) + return 0; + + if (mask & (FS_CREATE|FS_MOVED_TO|FS_DELETE|FS_MOVED_FROM)) { +diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c +index edbeffee64b8e..fd7b30a2d9a4b 100644 +--- a/kernel/audit_watch.c ++++ b/kernel/audit_watch.c +@@ -472,8 +472,7 @@ static int audit_watch_handle_event(struct fsnotify_mark *inode_mark, u32 mask, + + parent = container_of(inode_mark, struct audit_parent, mark); + +- if (WARN_ON_ONCE(inode_mark->group != audit_watch_group) || +- WARN_ON_ONCE(!inode)) ++ if (WARN_ON_ONCE(inode_mark->group != audit_watch_group)) + return 0; + + if (mask & (FS_CREATE|FS_MOVED_TO) && inode) +-- +2.43.0 + diff --git a/queue-5.10/fsnotify-clarify-object-type-argument.patch b/queue-5.10/fsnotify-clarify-object-type-argument.patch new file mode 100644 index 00000000000..a0009bf0663 --- /dev/null +++ b/queue-5.10/fsnotify-clarify-object-type-argument.patch @@ -0,0 +1,275 @@ +From 80ccf49e241eeedf434f8bb1c093ba83309e3ef2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Nov 2021 22:15:27 +0200 +Subject: fsnotify: clarify object type argument + +From: Amir Goldstein + +[ Upstream commit ad69cd9972e79aba103ba5365de0acd35770c265 ] + +In preparation for separating object type from iterator type, rename +some 'type' arguments in functions to 'obj_type' and remove the unused +interface to clear marks by object type mask. + +Link: https://lore.kernel.org/r/20211129201537.1932819-2-amir73il@gmail.com +Signed-off-by: Amir Goldstein +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify_user.c | 8 ++++---- + fs/notify/group.c | 2 +- + fs/notify/mark.c | 27 +++++++++++++++------------ + include/linux/fsnotify_backend.h | 28 ++++++++++++---------------- + 4 files changed, 32 insertions(+), 33 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c +index e6860c55b3dcb..2f78999a7aa3d 100644 +--- a/fs/notify/fanotify/fanotify_user.c ++++ b/fs/notify/fanotify/fanotify_user.c +@@ -1052,7 +1052,7 @@ static __u32 fanotify_mark_add_to_mask(struct fsnotify_mark *fsn_mark, + + static struct fsnotify_mark *fanotify_add_new_mark(struct fsnotify_group *group, + fsnotify_connp_t *connp, +- unsigned int type, ++ unsigned int obj_type, + __kernel_fsid_t *fsid) + { + struct ucounts *ucounts = group->fanotify_data.ucounts; +@@ -1075,7 +1075,7 @@ static struct fsnotify_mark *fanotify_add_new_mark(struct fsnotify_group *group, + } + + fsnotify_init_mark(mark, group); +- ret = fsnotify_add_mark_locked(mark, connp, type, 0, fsid); ++ ret = fsnotify_add_mark_locked(mark, connp, obj_type, 0, fsid); + if (ret) { + fsnotify_put_mark(mark); + goto out_dec_ucounts; +@@ -1100,7 +1100,7 @@ static int fanotify_group_init_error_pool(struct fsnotify_group *group) + } + + static int fanotify_add_mark(struct fsnotify_group *group, +- fsnotify_connp_t *connp, unsigned int type, ++ fsnotify_connp_t *connp, unsigned int obj_type, + __u32 mask, unsigned int flags, + __kernel_fsid_t *fsid) + { +@@ -1111,7 +1111,7 @@ static int fanotify_add_mark(struct fsnotify_group *group, + mutex_lock(&group->mark_mutex); + fsn_mark = fsnotify_find_mark(connp, group); + if (!fsn_mark) { +- fsn_mark = fanotify_add_new_mark(group, connp, type, fsid); ++ fsn_mark = fanotify_add_new_mark(group, connp, obj_type, fsid); + if (IS_ERR(fsn_mark)) { + mutex_unlock(&group->mark_mutex); + return PTR_ERR(fsn_mark); +diff --git a/fs/notify/group.c b/fs/notify/group.c +index 6a297efc47887..b7d4d64f87c29 100644 +--- a/fs/notify/group.c ++++ b/fs/notify/group.c +@@ -58,7 +58,7 @@ void fsnotify_destroy_group(struct fsnotify_group *group) + fsnotify_group_stop_queueing(group); + + /* Clear all marks for this group and queue them for destruction */ +- fsnotify_clear_marks_by_group(group, FSNOTIFY_OBJ_ALL_TYPES_MASK); ++ fsnotify_clear_marks_by_group(group, FSNOTIFY_OBJ_TYPE_ANY); + + /* + * Some marks can still be pinned when waiting for response from +diff --git a/fs/notify/mark.c b/fs/notify/mark.c +index bea106fac0901..7c0946e16918a 100644 +--- a/fs/notify/mark.c ++++ b/fs/notify/mark.c +@@ -496,7 +496,7 @@ int fsnotify_compare_groups(struct fsnotify_group *a, struct fsnotify_group *b) + } + + static int fsnotify_attach_connector_to_object(fsnotify_connp_t *connp, +- unsigned int type, ++ unsigned int obj_type, + __kernel_fsid_t *fsid) + { + struct inode *inode = NULL; +@@ -507,7 +507,7 @@ static int fsnotify_attach_connector_to_object(fsnotify_connp_t *connp, + return -ENOMEM; + spin_lock_init(&conn->lock); + INIT_HLIST_HEAD(&conn->list); +- conn->type = type; ++ conn->type = obj_type; + conn->obj = connp; + /* Cache fsid of filesystem containing the object */ + if (fsid) { +@@ -572,7 +572,8 @@ static struct fsnotify_mark_connector *fsnotify_grab_connector( + * priority, highest number first, and then by the group's location in memory. + */ + static int fsnotify_add_mark_list(struct fsnotify_mark *mark, +- fsnotify_connp_t *connp, unsigned int type, ++ fsnotify_connp_t *connp, ++ unsigned int obj_type, + int allow_dups, __kernel_fsid_t *fsid) + { + struct fsnotify_mark *lmark, *last = NULL; +@@ -580,7 +581,7 @@ static int fsnotify_add_mark_list(struct fsnotify_mark *mark, + int cmp; + int err = 0; + +- if (WARN_ON(!fsnotify_valid_obj_type(type))) ++ if (WARN_ON(!fsnotify_valid_obj_type(obj_type))) + return -EINVAL; + + /* Backend is expected to check for zero fsid (e.g. tmpfs) */ +@@ -592,7 +593,8 @@ static int fsnotify_add_mark_list(struct fsnotify_mark *mark, + conn = fsnotify_grab_connector(connp); + if (!conn) { + spin_unlock(&mark->lock); +- err = fsnotify_attach_connector_to_object(connp, type, fsid); ++ err = fsnotify_attach_connector_to_object(connp, obj_type, ++ fsid); + if (err) + return err; + goto restart; +@@ -665,7 +667,7 @@ static int fsnotify_add_mark_list(struct fsnotify_mark *mark, + * event types should be delivered to which group. + */ + int fsnotify_add_mark_locked(struct fsnotify_mark *mark, +- fsnotify_connp_t *connp, unsigned int type, ++ fsnotify_connp_t *connp, unsigned int obj_type, + int allow_dups, __kernel_fsid_t *fsid) + { + struct fsnotify_group *group = mark->group; +@@ -686,7 +688,7 @@ int fsnotify_add_mark_locked(struct fsnotify_mark *mark, + fsnotify_get_mark(mark); /* for g_list */ + spin_unlock(&mark->lock); + +- ret = fsnotify_add_mark_list(mark, connp, type, allow_dups, fsid); ++ ret = fsnotify_add_mark_list(mark, connp, obj_type, allow_dups, fsid); + if (ret) + goto err; + +@@ -706,13 +708,14 @@ int fsnotify_add_mark_locked(struct fsnotify_mark *mark, + } + + int fsnotify_add_mark(struct fsnotify_mark *mark, fsnotify_connp_t *connp, +- unsigned int type, int allow_dups, __kernel_fsid_t *fsid) ++ unsigned int obj_type, int allow_dups, ++ __kernel_fsid_t *fsid) + { + int ret; + struct fsnotify_group *group = mark->group; + + mutex_lock(&group->mark_mutex); +- ret = fsnotify_add_mark_locked(mark, connp, type, allow_dups, fsid); ++ ret = fsnotify_add_mark_locked(mark, connp, obj_type, allow_dups, fsid); + mutex_unlock(&group->mark_mutex); + return ret; + } +@@ -747,14 +750,14 @@ EXPORT_SYMBOL_GPL(fsnotify_find_mark); + + /* Clear any marks in a group with given type mask */ + void fsnotify_clear_marks_by_group(struct fsnotify_group *group, +- unsigned int type_mask) ++ unsigned int obj_type) + { + struct fsnotify_mark *lmark, *mark; + LIST_HEAD(to_free); + struct list_head *head = &to_free; + + /* Skip selection step if we want to clear all marks. */ +- if (type_mask == FSNOTIFY_OBJ_ALL_TYPES_MASK) { ++ if (obj_type == FSNOTIFY_OBJ_TYPE_ANY) { + head = &group->marks_list; + goto clear; + } +@@ -769,7 +772,7 @@ void fsnotify_clear_marks_by_group(struct fsnotify_group *group, + */ + mutex_lock(&group->mark_mutex); + list_for_each_entry_safe(mark, lmark, &group->marks_list, g_list) { +- if ((1U << mark->connector->type) & type_mask) ++ if (mark->connector->type == obj_type) + list_move(&mark->g_list, &to_free); + } + mutex_unlock(&group->mark_mutex); +diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h +index 51ef2b079bfa0..b9c84b1dbcc8f 100644 +--- a/include/linux/fsnotify_backend.h ++++ b/include/linux/fsnotify_backend.h +@@ -338,6 +338,7 @@ static inline struct fs_error_report *fsnotify_data_error_report( + } + + enum fsnotify_obj_type { ++ FSNOTIFY_OBJ_TYPE_ANY = -1, + FSNOTIFY_OBJ_TYPE_INODE, + FSNOTIFY_OBJ_TYPE_PARENT, + FSNOTIFY_OBJ_TYPE_VFSMOUNT, +@@ -346,15 +347,9 @@ enum fsnotify_obj_type { + FSNOTIFY_OBJ_TYPE_DETACHED = FSNOTIFY_OBJ_TYPE_COUNT + }; + +-#define FSNOTIFY_OBJ_TYPE_INODE_FL (1U << FSNOTIFY_OBJ_TYPE_INODE) +-#define FSNOTIFY_OBJ_TYPE_PARENT_FL (1U << FSNOTIFY_OBJ_TYPE_PARENT) +-#define FSNOTIFY_OBJ_TYPE_VFSMOUNT_FL (1U << FSNOTIFY_OBJ_TYPE_VFSMOUNT) +-#define FSNOTIFY_OBJ_TYPE_SB_FL (1U << FSNOTIFY_OBJ_TYPE_SB) +-#define FSNOTIFY_OBJ_ALL_TYPES_MASK ((1U << FSNOTIFY_OBJ_TYPE_COUNT) - 1) +- +-static inline bool fsnotify_valid_obj_type(unsigned int type) ++static inline bool fsnotify_valid_obj_type(unsigned int obj_type) + { +- return (type < FSNOTIFY_OBJ_TYPE_COUNT); ++ return (obj_type < FSNOTIFY_OBJ_TYPE_COUNT); + } + + struct fsnotify_iter_info { +@@ -387,7 +382,7 @@ static inline void fsnotify_iter_set_report_type_mark( + static inline struct fsnotify_mark *fsnotify_iter_##name##_mark( \ + struct fsnotify_iter_info *iter_info) \ + { \ +- return (iter_info->report_mask & FSNOTIFY_OBJ_TYPE_##NAME##_FL) ? \ ++ return (iter_info->report_mask & (1U << FSNOTIFY_OBJ_TYPE_##NAME)) ? \ + iter_info->marks[FSNOTIFY_OBJ_TYPE_##NAME] : NULL; \ + } + +@@ -604,11 +599,11 @@ extern int fsnotify_get_conn_fsid(const struct fsnotify_mark_connector *conn, + __kernel_fsid_t *fsid); + /* attach the mark to the object */ + extern int fsnotify_add_mark(struct fsnotify_mark *mark, +- fsnotify_connp_t *connp, unsigned int type, ++ fsnotify_connp_t *connp, unsigned int obj_type, + int allow_dups, __kernel_fsid_t *fsid); + extern int fsnotify_add_mark_locked(struct fsnotify_mark *mark, + fsnotify_connp_t *connp, +- unsigned int type, int allow_dups, ++ unsigned int obj_type, int allow_dups, + __kernel_fsid_t *fsid); + + /* attach the mark to the inode */ +@@ -637,22 +632,23 @@ extern void fsnotify_detach_mark(struct fsnotify_mark *mark); + extern void fsnotify_free_mark(struct fsnotify_mark *mark); + /* Wait until all marks queued for destruction are destroyed */ + extern void fsnotify_wait_marks_destroyed(void); +-/* run all the marks in a group, and clear all of the marks attached to given object type */ +-extern void fsnotify_clear_marks_by_group(struct fsnotify_group *group, unsigned int type); ++/* Clear all of the marks of a group attached to a given object type */ ++extern void fsnotify_clear_marks_by_group(struct fsnotify_group *group, ++ unsigned int obj_type); + /* run all the marks in a group, and clear all of the vfsmount marks */ + static inline void fsnotify_clear_vfsmount_marks_by_group(struct fsnotify_group *group) + { +- fsnotify_clear_marks_by_group(group, FSNOTIFY_OBJ_TYPE_VFSMOUNT_FL); ++ fsnotify_clear_marks_by_group(group, FSNOTIFY_OBJ_TYPE_VFSMOUNT); + } + /* run all the marks in a group, and clear all of the inode marks */ + static inline void fsnotify_clear_inode_marks_by_group(struct fsnotify_group *group) + { +- fsnotify_clear_marks_by_group(group, FSNOTIFY_OBJ_TYPE_INODE_FL); ++ fsnotify_clear_marks_by_group(group, FSNOTIFY_OBJ_TYPE_INODE); + } + /* run all the marks in a group, and clear all of the sn marks */ + static inline void fsnotify_clear_sb_marks_by_group(struct fsnotify_group *group) + { +- fsnotify_clear_marks_by_group(group, FSNOTIFY_OBJ_TYPE_SB_FL); ++ fsnotify_clear_marks_by_group(group, FSNOTIFY_OBJ_TYPE_SB); + } + extern void fsnotify_get_mark(struct fsnotify_mark *mark); + extern void fsnotify_put_mark(struct fsnotify_mark *mark); +-- +2.43.0 + diff --git a/queue-5.10/fsnotify-consistent-behavior-for-parent-not-watching.patch b/queue-5.10/fsnotify-consistent-behavior-for-parent-not-watching.patch new file mode 100644 index 00000000000..378ab5b53cd --- /dev/null +++ b/queue-5.10/fsnotify-consistent-behavior-for-parent-not-watching.patch @@ -0,0 +1,131 @@ +From 9bec16f06801a38121a1fa5b45b013a0ac7686cd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 May 2022 22:02:13 +0300 +Subject: fsnotify: consistent behavior for parent not watching children + +From: Amir Goldstein + +[ Upstream commit e730558adffb88a52e562db089e969ee9510184a ] + +The logic for handling events on child in groups that have a mark on +the parent inode, but without FS_EVENT_ON_CHILD flag in the mask is +duplicated in several places and inconsistent. + +Move the logic into the preparation of mark type iterator, so that the +parent mark type will be excluded from all mark type iterations in that +case. + +This results in several subtle changes of behavior, hopefully all +desired changes of behavior, for example: + +- Group A has a mount mark with FS_MODIFY in mask +- Group A has a mark with ignore mask that does not survive FS_MODIFY + and does not watch children on directory D. +- Group B has a mark with FS_MODIFY in mask that does watch children + on directory D. +- FS_MODIFY event on file D/foo should not clear the ignore mask of + group A, but before this change it does + +And if group A ignore mask was set to survive FS_MODIFY: +- FS_MODIFY event on file D/foo should be reported to group A on account + of the mount mark, but before this change it is wrongly ignored + +Fixes: 2f02fd3fa13e ("fanotify: fix ignore mask logic for events on child and on dir") +Reported-by: Jan Kara +Link: https://lore.kernel.org/linux-fsdevel/20220314113337.j7slrb5srxukztje@quack3.lan/ +Signed-off-by: Amir Goldstein +Signed-off-by: Jan Kara +Link: https://lore.kernel.org/r/20220511190213.831646-3-amir73il@gmail.com +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify.c | 10 +--------- + fs/notify/fsnotify.c | 34 +++++++++++++++++++--------------- + 2 files changed, 20 insertions(+), 24 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c +index 263d303d8f8f1..4f897e1095470 100644 +--- a/fs/notify/fanotify/fanotify.c ++++ b/fs/notify/fanotify/fanotify.c +@@ -320,7 +320,7 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group, + } + + fsnotify_foreach_iter_mark_type(iter_info, mark, type) { +- /* Apply ignore mask regardless of ISDIR and ON_CHILD flags */ ++ /* Apply ignore mask regardless of mark's ISDIR flag */ + marks_ignored_mask |= mark->ignored_mask; + + /* +@@ -330,14 +330,6 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group, + if (event_mask & FS_ISDIR && !(mark->mask & FS_ISDIR)) + continue; + +- /* +- * If the event is on a child and this mark is on a parent not +- * watching children, don't send it! +- */ +- if (type == FSNOTIFY_ITER_TYPE_PARENT && +- !(mark->mask & FS_EVENT_ON_CHILD)) +- continue; +- + marks_mask |= mark->mask; + + /* Record the mark types of this group that matched the event */ +diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c +index 35740a64ee453..0b3e74935cb4f 100644 +--- a/fs/notify/fsnotify.c ++++ b/fs/notify/fsnotify.c +@@ -290,22 +290,15 @@ static int fsnotify_handle_event(struct fsnotify_group *group, __u32 mask, + } + + if (parent_mark) { +- /* +- * parent_mark indicates that the parent inode is watching +- * children and interested in this event, which is an event +- * possible on child. But is *this mark* watching children and +- * interested in this event? +- */ +- if (parent_mark->mask & FS_EVENT_ON_CHILD) { +- ret = fsnotify_handle_inode_event(group, parent_mark, mask, +- data, data_type, dir, name, 0); +- if (ret) +- return ret; +- } +- if (!inode_mark) +- return 0; ++ ret = fsnotify_handle_inode_event(group, parent_mark, mask, ++ data, data_type, dir, name, 0); ++ if (ret) ++ return ret; + } + ++ if (!inode_mark) ++ return 0; ++ + if (mask & FS_EVENT_ON_CHILD) { + /* + * Some events can be sent on both parent dir and child marks +@@ -422,8 +415,19 @@ static bool fsnotify_iter_select_report_types( + iter_info->report_mask = 0; + fsnotify_foreach_iter_type(type) { + mark = iter_info->marks[type]; +- if (mark && mark->group == iter_info->current_group) ++ if (mark && mark->group == iter_info->current_group) { ++ /* ++ * FSNOTIFY_ITER_TYPE_PARENT indicates that this inode ++ * is watching children and interested in this event, ++ * which is an event possible on child. ++ * But is *this mark* watching children? ++ */ ++ if (type == FSNOTIFY_ITER_TYPE_PARENT && ++ !(mark->mask & FS_EVENT_ON_CHILD)) ++ continue; ++ + fsnotify_iter_set_report_type(iter_info, type); ++ } + } + + return true; +-- +2.43.0 + diff --git a/queue-5.10/fsnotify-count-all-objects-with-attached-connectors.patch b/queue-5.10/fsnotify-count-all-objects-with-attached-connectors.patch new file mode 100644 index 00000000000..87d13414a06 --- /dev/null +++ b/queue-5.10/fsnotify-count-all-objects-with-attached-connectors.patch @@ -0,0 +1,155 @@ +From 8603ceadb6e3247a658fd2041168f5450d479222 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Aug 2021 18:12:19 +0300 +Subject: fsnotify: count all objects with attached connectors + +From: Amir Goldstein + +[ Upstream commit ec44610fe2b86daef70f3f53f47d2a2542d7094f ] + +Rename s_fsnotify_inode_refs to s_fsnotify_connectors and count all +objects with attached connectors, not only inodes with attached +connectors. + +This will be used to optimize fsnotify() calls on sb without any +type of marks. + +Link: https://lore.kernel.org/r/20210810151220.285179-4-amir73il@gmail.com +Signed-off-by: Amir Goldstein +Reviewed-by: Matthew Bobrowski +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fsnotify.c | 6 +++--- + fs/notify/fsnotify.h | 15 +++++++++++++++ + fs/notify/mark.c | 24 +++++++++++++++++++++--- + include/linux/fs.h | 7 +++++-- + 4 files changed, 44 insertions(+), 8 deletions(-) + +diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c +index 30d422b8c0fc7..963e6ce75b961 100644 +--- a/fs/notify/fsnotify.c ++++ b/fs/notify/fsnotify.c +@@ -87,15 +87,15 @@ static void fsnotify_unmount_inodes(struct super_block *sb) + + if (iput_inode) + iput(iput_inode); +- /* Wait for outstanding inode references from connectors */ +- wait_var_event(&sb->s_fsnotify_inode_refs, +- !atomic_long_read(&sb->s_fsnotify_inode_refs)); + } + + void fsnotify_sb_delete(struct super_block *sb) + { + fsnotify_unmount_inodes(sb); + fsnotify_clear_marks_by_sb(sb); ++ /* Wait for outstanding object references from connectors */ ++ wait_var_event(&sb->s_fsnotify_connectors, ++ !atomic_long_read(&sb->s_fsnotify_connectors)); + } + + /* +diff --git a/fs/notify/fsnotify.h b/fs/notify/fsnotify.h +index ff2063ec6b0f3..87d8a50ee8038 100644 +--- a/fs/notify/fsnotify.h ++++ b/fs/notify/fsnotify.h +@@ -27,6 +27,21 @@ static inline struct super_block *fsnotify_conn_sb( + return container_of(conn->obj, struct super_block, s_fsnotify_marks); + } + ++static inline struct super_block *fsnotify_connector_sb( ++ struct fsnotify_mark_connector *conn) ++{ ++ switch (conn->type) { ++ case FSNOTIFY_OBJ_TYPE_INODE: ++ return fsnotify_conn_inode(conn)->i_sb; ++ case FSNOTIFY_OBJ_TYPE_VFSMOUNT: ++ return fsnotify_conn_mount(conn)->mnt.mnt_sb; ++ case FSNOTIFY_OBJ_TYPE_SB: ++ return fsnotify_conn_sb(conn); ++ default: ++ return NULL; ++ } ++} ++ + /* destroy all events sitting in this groups notification queue */ + extern void fsnotify_flush_notify(struct fsnotify_group *group); + +diff --git a/fs/notify/mark.c b/fs/notify/mark.c +index f6d1ad3ecca2a..796946eb0c2e2 100644 +--- a/fs/notify/mark.c ++++ b/fs/notify/mark.c +@@ -172,7 +172,7 @@ static void fsnotify_connector_destroy_workfn(struct work_struct *work) + static void fsnotify_get_inode_ref(struct inode *inode) + { + ihold(inode); +- atomic_long_inc(&inode->i_sb->s_fsnotify_inode_refs); ++ atomic_long_inc(&inode->i_sb->s_fsnotify_connectors); + } + + static void fsnotify_put_inode_ref(struct inode *inode) +@@ -180,8 +180,24 @@ static void fsnotify_put_inode_ref(struct inode *inode) + struct super_block *sb = inode->i_sb; + + iput(inode); +- if (atomic_long_dec_and_test(&sb->s_fsnotify_inode_refs)) +- wake_up_var(&sb->s_fsnotify_inode_refs); ++ if (atomic_long_dec_and_test(&sb->s_fsnotify_connectors)) ++ wake_up_var(&sb->s_fsnotify_connectors); ++} ++ ++static void fsnotify_get_sb_connectors(struct fsnotify_mark_connector *conn) ++{ ++ struct super_block *sb = fsnotify_connector_sb(conn); ++ ++ if (sb) ++ atomic_long_inc(&sb->s_fsnotify_connectors); ++} ++ ++static void fsnotify_put_sb_connectors(struct fsnotify_mark_connector *conn) ++{ ++ struct super_block *sb = fsnotify_connector_sb(conn); ++ ++ if (sb && atomic_long_dec_and_test(&sb->s_fsnotify_connectors)) ++ wake_up_var(&sb->s_fsnotify_connectors); + } + + static void *fsnotify_detach_connector_from_object( +@@ -203,6 +219,7 @@ static void *fsnotify_detach_connector_from_object( + fsnotify_conn_sb(conn)->s_fsnotify_mask = 0; + } + ++ fsnotify_put_sb_connectors(conn); + rcu_assign_pointer(*(conn->obj), NULL); + conn->obj = NULL; + conn->type = FSNOTIFY_OBJ_TYPE_DETACHED; +@@ -504,6 +521,7 @@ static int fsnotify_attach_connector_to_object(fsnotify_connp_t *connp, + inode = fsnotify_conn_inode(conn); + fsnotify_get_inode_ref(inode); + } ++ fsnotify_get_sb_connectors(conn); + + /* + * cmpxchg() provides the barrier so that readers of *connp can see +diff --git a/include/linux/fs.h b/include/linux/fs.h +index cc3b6ddf58223..a9ac60d3be1d6 100644 +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -1512,8 +1512,11 @@ struct super_block { + /* Number of inodes with nlink == 0 but still referenced */ + atomic_long_t s_remove_count; + +- /* Pending fsnotify inode refs */ +- atomic_long_t s_fsnotify_inode_refs; ++ /* ++ * Number of inode/mount/sb objects that are being watched, note that ++ * inodes objects are currently double-accounted. ++ */ ++ atomic_long_t s_fsnotify_connectors; + + /* Being remounted read-only */ + int s_readonly_remount; +-- +2.43.0 + diff --git a/queue-5.10/fsnotify-count-s_fsnotify_inode_refs-for-attached-co.patch b/queue-5.10/fsnotify-count-s_fsnotify_inode_refs-for-attached-co.patch new file mode 100644 index 00000000000..5bc9eb93cc3 --- /dev/null +++ b/queue-5.10/fsnotify-count-s_fsnotify_inode_refs-for-attached-co.patch @@ -0,0 +1,100 @@ +From 7aa0e01dffa843ebb1e01bc5f990242bae452686 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Aug 2021 18:12:18 +0300 +Subject: fsnotify: count s_fsnotify_inode_refs for attached connectors + +From: Amir Goldstein + +[ Upstream commit 11fa333b58ba1518e7c69fafb6513a0117f8fe33 ] + +Instead of incrementing s_fsnotify_inode_refs when detaching connector +from inode, increment it earlier when attaching connector to inode. +Next patch is going to use s_fsnotify_inode_refs to count all objects +with attached connectors. + +Link: https://lore.kernel.org/r/20210810151220.285179-3-amir73il@gmail.com +Reviewed-by: Matthew Bobrowski +Signed-off-by: Amir Goldstein +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/mark.c | 29 ++++++++++++++++++----------- + 1 file changed, 18 insertions(+), 11 deletions(-) + +diff --git a/fs/notify/mark.c b/fs/notify/mark.c +index 3c8fc77d3f072..f6d1ad3ecca2a 100644 +--- a/fs/notify/mark.c ++++ b/fs/notify/mark.c +@@ -169,6 +169,21 @@ static void fsnotify_connector_destroy_workfn(struct work_struct *work) + } + } + ++static void fsnotify_get_inode_ref(struct inode *inode) ++{ ++ ihold(inode); ++ atomic_long_inc(&inode->i_sb->s_fsnotify_inode_refs); ++} ++ ++static void fsnotify_put_inode_ref(struct inode *inode) ++{ ++ struct super_block *sb = inode->i_sb; ++ ++ iput(inode); ++ if (atomic_long_dec_and_test(&sb->s_fsnotify_inode_refs)) ++ wake_up_var(&sb->s_fsnotify_inode_refs); ++} ++ + static void *fsnotify_detach_connector_from_object( + struct fsnotify_mark_connector *conn, + unsigned int *type) +@@ -182,7 +197,6 @@ static void *fsnotify_detach_connector_from_object( + if (conn->type == FSNOTIFY_OBJ_TYPE_INODE) { + inode = fsnotify_conn_inode(conn); + inode->i_fsnotify_mask = 0; +- atomic_long_inc(&inode->i_sb->s_fsnotify_inode_refs); + } else if (conn->type == FSNOTIFY_OBJ_TYPE_VFSMOUNT) { + fsnotify_conn_mount(conn)->mnt_fsnotify_mask = 0; + } else if (conn->type == FSNOTIFY_OBJ_TYPE_SB) { +@@ -209,19 +223,12 @@ static void fsnotify_final_mark_destroy(struct fsnotify_mark *mark) + /* Drop object reference originally held by a connector */ + static void fsnotify_drop_object(unsigned int type, void *objp) + { +- struct inode *inode; +- struct super_block *sb; +- + if (!objp) + return; + /* Currently only inode references are passed to be dropped */ + if (WARN_ON_ONCE(type != FSNOTIFY_OBJ_TYPE_INODE)) + return; +- inode = objp; +- sb = inode->i_sb; +- iput(inode); +- if (atomic_long_dec_and_test(&sb->s_fsnotify_inode_refs)) +- wake_up_var(&sb->s_fsnotify_inode_refs); ++ fsnotify_put_inode_ref(objp); + } + + void fsnotify_put_mark(struct fsnotify_mark *mark) +@@ -495,7 +502,7 @@ static int fsnotify_attach_connector_to_object(fsnotify_connp_t *connp, + } + if (conn->type == FSNOTIFY_OBJ_TYPE_INODE) { + inode = fsnotify_conn_inode(conn); +- ihold(inode); ++ fsnotify_get_inode_ref(inode); + } + + /* +@@ -505,7 +512,7 @@ static int fsnotify_attach_connector_to_object(fsnotify_connp_t *connp, + if (cmpxchg(connp, NULL, conn)) { + /* Someone else created list structure for us */ + if (inode) +- iput(inode); ++ fsnotify_put_inode_ref(inode); + kmem_cache_free(fsnotify_mark_connector_cachep, conn); + } + +-- +2.43.0 + diff --git a/queue-5.10/fsnotify-create-helpers-for-group-mark_mutex-lock.patch b/queue-5.10/fsnotify-create-helpers-for-group-mark_mutex-lock.patch new file mode 100644 index 00000000000..400c6e82c50 --- /dev/null +++ b/queue-5.10/fsnotify-create-helpers-for-group-mark_mutex-lock.patch @@ -0,0 +1,221 @@ +From 12622be35283390204f76b145104cdf5170684f7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 Apr 2022 15:03:17 +0300 +Subject: fsnotify: create helpers for group mark_mutex lock + +From: Amir Goldstein + +[ Upstream commit 43b245a788e2d8f1bb742668a9bdace02fcb3e96 ] + +Create helpers to take and release the group mark_mutex lock. + +Define a flag FSNOTIFY_GROUP_NOFS in fsnotify_group that determines +if the mark_mutex lock is fs reclaim safe or not. If not safe, the +lock helpers take the lock and disable direct fs reclaim. + +In that case we annotate the mutex with a different lockdep class to +express to lockdep that an allocation of mark of an fs reclaim safe group +may take the group lock of another "NOFS" group to evict inodes. + +For now, converted only the callers in common code and no backend +defines the NOFS flag. It is intended to be set by fanotify for +evictable marks support. + +Link: https://lore.kernel.org/r/20220422120327.3459282-7-amir73il@gmail.com +Suggested-by: Jan Kara +Link: https://lore.kernel.org/r/20220321112310.vpr7oxro2xkz5llh@quack3.lan/ +Signed-off-by: Amir Goldstein +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fdinfo.c | 4 ++-- + fs/notify/group.c | 11 +++++++++++ + fs/notify/mark.c | 24 +++++++++++------------- + include/linux/fsnotify_backend.h | 28 ++++++++++++++++++++++++++++ + 4 files changed, 52 insertions(+), 15 deletions(-) + +diff --git a/fs/notify/fdinfo.c b/fs/notify/fdinfo.c +index 3451708fd035c..1f34c5c29fdbd 100644 +--- a/fs/notify/fdinfo.c ++++ b/fs/notify/fdinfo.c +@@ -28,13 +28,13 @@ static void show_fdinfo(struct seq_file *m, struct file *f, + struct fsnotify_group *group = f->private_data; + struct fsnotify_mark *mark; + +- mutex_lock(&group->mark_mutex); ++ fsnotify_group_lock(group); + list_for_each_entry(mark, &group->marks_list, g_list) { + show(m, mark); + if (seq_has_overflowed(m)) + break; + } +- mutex_unlock(&group->mark_mutex); ++ fsnotify_group_unlock(group); + } + + #if defined(CONFIG_EXPORTFS) +diff --git a/fs/notify/group.c b/fs/notify/group.c +index 18446b7b0d495..1de6631a3925e 100644 +--- a/fs/notify/group.c ++++ b/fs/notify/group.c +@@ -115,6 +115,7 @@ static struct fsnotify_group *__fsnotify_alloc_group( + const struct fsnotify_ops *ops, + int flags, gfp_t gfp) + { ++ static struct lock_class_key nofs_marks_lock; + struct fsnotify_group *group; + + group = kzalloc(sizeof(struct fsnotify_group), gfp); +@@ -135,6 +136,16 @@ static struct fsnotify_group *__fsnotify_alloc_group( + + group->ops = ops; + group->flags = flags; ++ /* ++ * For most backends, eviction of inode with a mark is not expected, ++ * because marks hold a refcount on the inode against eviction. ++ * ++ * Use a different lockdep class for groups that support evictable ++ * inode marks, because with evictable marks, mark_mutex is NOT ++ * fs-reclaim safe - the mutex is taken when evicting inodes. ++ */ ++ if (flags & FSNOTIFY_GROUP_NOFS) ++ lockdep_set_class(&group->mark_mutex, &nofs_marks_lock); + + return group; + } +diff --git a/fs/notify/mark.c b/fs/notify/mark.c +index 1fb246ea61752..982ca2f20ff5d 100644 +--- a/fs/notify/mark.c ++++ b/fs/notify/mark.c +@@ -398,9 +398,7 @@ void fsnotify_finish_user_wait(struct fsnotify_iter_info *iter_info) + */ + void fsnotify_detach_mark(struct fsnotify_mark *mark) + { +- struct fsnotify_group *group = mark->group; +- +- WARN_ON_ONCE(!mutex_is_locked(&group->mark_mutex)); ++ fsnotify_group_assert_locked(mark->group); + WARN_ON_ONCE(!srcu_read_lock_held(&fsnotify_mark_srcu) && + refcount_read(&mark->refcnt) < 1 + + !!(mark->flags & FSNOTIFY_MARK_FLAG_ATTACHED)); +@@ -452,9 +450,9 @@ void fsnotify_free_mark(struct fsnotify_mark *mark) + void fsnotify_destroy_mark(struct fsnotify_mark *mark, + struct fsnotify_group *group) + { +- mutex_lock(&group->mark_mutex); ++ fsnotify_group_lock(group); + fsnotify_detach_mark(mark); +- mutex_unlock(&group->mark_mutex); ++ fsnotify_group_unlock(group); + fsnotify_free_mark(mark); + } + EXPORT_SYMBOL_GPL(fsnotify_destroy_mark); +@@ -673,7 +671,7 @@ int fsnotify_add_mark_locked(struct fsnotify_mark *mark, + struct fsnotify_group *group = mark->group; + int ret = 0; + +- BUG_ON(!mutex_is_locked(&group->mark_mutex)); ++ fsnotify_group_assert_locked(group); + + /* + * LOCKING ORDER!!!! +@@ -714,9 +712,9 @@ int fsnotify_add_mark(struct fsnotify_mark *mark, fsnotify_connp_t *connp, + int ret; + struct fsnotify_group *group = mark->group; + +- mutex_lock(&group->mark_mutex); ++ fsnotify_group_lock(group); + ret = fsnotify_add_mark_locked(mark, connp, obj_type, add_flags, fsid); +- mutex_unlock(&group->mark_mutex); ++ fsnotify_group_unlock(group); + return ret; + } + EXPORT_SYMBOL_GPL(fsnotify_add_mark); +@@ -770,24 +768,24 @@ void fsnotify_clear_marks_by_group(struct fsnotify_group *group, + * move marks to free to to_free list in one go and then free marks in + * to_free list one by one. + */ +- mutex_lock(&group->mark_mutex); ++ fsnotify_group_lock(group); + list_for_each_entry_safe(mark, lmark, &group->marks_list, g_list) { + if (mark->connector->type == obj_type) + list_move(&mark->g_list, &to_free); + } +- mutex_unlock(&group->mark_mutex); ++ fsnotify_group_unlock(group); + + clear: + while (1) { +- mutex_lock(&group->mark_mutex); ++ fsnotify_group_lock(group); + if (list_empty(head)) { +- mutex_unlock(&group->mark_mutex); ++ fsnotify_group_unlock(group); + break; + } + mark = list_first_entry(head, struct fsnotify_mark, g_list); + fsnotify_get_mark(mark); + fsnotify_detach_mark(mark); +- mutex_unlock(&group->mark_mutex); ++ fsnotify_group_unlock(group); + fsnotify_free_mark(mark); + fsnotify_put_mark(mark); + } +diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h +index dd440e6ff5285..d62111e832440 100644 +--- a/include/linux/fsnotify_backend.h ++++ b/include/linux/fsnotify_backend.h +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + + /* + * IN_* from inotfy.h lines up EXACTLY with FS_*, this is so we can easily +@@ -212,7 +213,9 @@ struct fsnotify_group { + + #define FSNOTIFY_GROUP_USER 0x01 /* user allocated group */ + #define FSNOTIFY_GROUP_DUPS 0x02 /* allow multiple marks per object */ ++#define FSNOTIFY_GROUP_NOFS 0x04 /* group lock is not direct reclaim safe */ + int flags; ++ unsigned int owner_flags; /* stored flags of mark_mutex owner */ + + /* stores all fastpath marks assoc with this group so they can be cleaned on unregister */ + struct mutex mark_mutex; /* protect marks_list */ +@@ -254,6 +257,31 @@ struct fsnotify_group { + }; + }; + ++/* ++ * These helpers are used to prevent deadlock when reclaiming inodes with ++ * evictable marks of the same group that is allocating a new mark. ++ */ ++static inline void fsnotify_group_lock(struct fsnotify_group *group) ++{ ++ mutex_lock(&group->mark_mutex); ++ if (group->flags & FSNOTIFY_GROUP_NOFS) ++ group->owner_flags = memalloc_nofs_save(); ++} ++ ++static inline void fsnotify_group_unlock(struct fsnotify_group *group) ++{ ++ if (group->flags & FSNOTIFY_GROUP_NOFS) ++ memalloc_nofs_restore(group->owner_flags); ++ mutex_unlock(&group->mark_mutex); ++} ++ ++static inline void fsnotify_group_assert_locked(struct fsnotify_group *group) ++{ ++ WARN_ON_ONCE(!mutex_is_locked(&group->mark_mutex)); ++ if (group->flags & FSNOTIFY_GROUP_NOFS) ++ WARN_ON_ONCE(!(current->flags & PF_MEMALLOC_NOFS)); ++} ++ + /* When calling fsnotify tell it if the data is a path or inode */ + enum fsnotify_data_type { + FSNOTIFY_EVENT_NONE, +-- +2.43.0 + diff --git a/queue-5.10/fsnotify-don-t-insert-unmergeable-events-in-hashtabl.patch b/queue-5.10/fsnotify-don-t-insert-unmergeable-events-in-hashtabl.patch new file mode 100644 index 00000000000..d5b22736813 --- /dev/null +++ b/queue-5.10/fsnotify-don-t-insert-unmergeable-events-in-hashtabl.patch @@ -0,0 +1,54 @@ +From 9af138dcae9dfcff669a825af0aeaf1c176f2640 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 Oct 2021 16:27:19 -0300 +Subject: fsnotify: Don't insert unmergeable events in hashtable + +From: Gabriel Krisman Bertazi + +[ Upstream commit cc53b55f697fe5aa98bdbfdfe67c6401da242155 ] + +Some events, like the overflow event, are not mergeable, so they are not +hashed. But, when failing inside fsnotify_add_event for lack of space, +fsnotify_add_event() still calls the insert hook, which adds the +overflow event to the merge list. Add a check to prevent any kind of +unmergeable event to be inserted in the hashtable. + +Fixes: 94e00d28a680 ("fsnotify: use hash table for faster events merge") +Link: https://lore.kernel.org/r/20211025192746.66445-5-krisman@collabora.com +Reviewed-by: Amir Goldstein +Reviewed-by: Jan Kara +Signed-off-by: Gabriel Krisman Bertazi +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c +index 057abd2cf8875..310246f8d3f19 100644 +--- a/fs/notify/fanotify/fanotify.c ++++ b/fs/notify/fanotify/fanotify.c +@@ -702,6 +702,9 @@ static void fanotify_insert_event(struct fsnotify_group *group, + + assert_spin_locked(&group->notification_lock); + ++ if (!fanotify_is_hashed_event(event->mask)) ++ return; ++ + pr_debug("%s: group=%p event=%p bucket=%u\n", __func__, + group, event, bucket); + +@@ -779,8 +782,7 @@ static int fanotify_handle_event(struct fsnotify_group *group, u32 mask, + + fsn_event = &event->fse; + ret = fsnotify_add_event(group, fsn_event, fanotify_merge, +- fanotify_is_hashed_event(mask) ? +- fanotify_insert_event : NULL); ++ fanotify_insert_event); + if (ret) { + /* Permission events shouldn't be merged */ + BUG_ON(ret == 1 && mask & FANOTIFY_PERM_EVENTS); +-- +2.43.0 + diff --git a/queue-5.10/fsnotify-fix-comment-typo.patch b/queue-5.10/fsnotify-fix-comment-typo.patch new file mode 100644 index 00000000000..a25a1293236 --- /dev/null +++ b/queue-5.10/fsnotify-fix-comment-typo.patch @@ -0,0 +1,36 @@ +From 6902b5fc9a14e87587c4eabc1d56dd6a0cf548f9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 23 Jul 2022 03:46:39 +0800 +Subject: fsnotify: Fix comment typo + +From: Xin Gao + +[ Upstream commit feee1ce45a5666bbdb08c5bb2f5f394047b1915b ] + +The double `if' is duplicated in line 104, remove one. + +Signed-off-by: Xin Gao +Signed-off-by: Jan Kara +Link: https://lore.kernel.org/r/20220722194639.18545-1-gaoxin@cdjrlc.com +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fsnotify.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c +index 8687562df2e37..7974e91ffe134 100644 +--- a/fs/notify/fsnotify.c ++++ b/fs/notify/fsnotify.c +@@ -100,7 +100,7 @@ void fsnotify_sb_delete(struct super_block *sb) + * Given an inode, first check if we care what happens to our children. Inotify + * and dnotify both tell their parents about events. If we care about any event + * on a child we run all of our children and set a dentry flag saying that the +- * parent cares. Thus when an event happens on a child it can quickly tell if ++ * parent cares. Thus when an event happens on a child it can quickly tell + * if there is a need to find a parent and send the event to the parent. + */ + void __fsnotify_update_child_dentry_flags(struct inode *inode) +-- +2.43.0 + diff --git a/queue-5.10/fsnotify-fix-merge-with-parent-s-ignored-mask.patch b/queue-5.10/fsnotify-fix-merge-with-parent-s-ignored-mask.patch new file mode 100644 index 00000000000..508864309ab --- /dev/null +++ b/queue-5.10/fsnotify-fix-merge-with-parent-s-ignored-mask.patch @@ -0,0 +1,144 @@ +From 2826427dd1e1e7a4bd75ed4e2bf9d55e747e1270 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 23 Feb 2022 17:14:37 +0200 +Subject: fsnotify: fix merge with parent's ignored mask + +From: Amir Goldstein + +[ Upstream commit 4f0b903ded728c505850daf2914bfc08841f0ae6 ] + +fsnotify_parent() does not consider the parent's mark at all unless +the parent inode shows interest in events on children and in the +specific event. + +So unless parent added an event to both its mark mask and ignored mask, +the event will not be ignored. + +Fix this by declaring the interest of an object in an event when the +event is in either a mark mask or ignored mask. + +Link: https://lore.kernel.org/r/20220223151438.790268-2-amir73il@gmail.com +Signed-off-by: Amir Goldstein +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify_user.c | 17 +++++++++-------- + fs/notify/mark.c | 4 ++-- + include/linux/fsnotify_backend.h | 15 +++++++++++++++ + 3 files changed, 26 insertions(+), 10 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c +index 6679700574113..12fb209e60419 100644 +--- a/fs/notify/fanotify/fanotify_user.c ++++ b/fs/notify/fanotify/fanotify_user.c +@@ -991,17 +991,18 @@ static __u32 fanotify_mark_remove_from_mask(struct fsnotify_mark *fsn_mark, + __u32 mask, unsigned int flags, + __u32 umask, int *destroy) + { +- __u32 oldmask = 0; ++ __u32 oldmask, newmask; + + /* umask bits cannot be removed by user */ + mask &= ~umask; + spin_lock(&fsn_mark->lock); ++ oldmask = fsnotify_calc_mask(fsn_mark); + if (!(flags & FAN_MARK_IGNORED_MASK)) { +- oldmask = fsn_mark->mask; + fsn_mark->mask &= ~mask; + } else { + fsn_mark->ignored_mask &= ~mask; + } ++ newmask = fsnotify_calc_mask(fsn_mark); + /* + * We need to keep the mark around even if remaining mask cannot + * result in any events (e.g. mask == FAN_ONDIR) to support incremenal +@@ -1011,7 +1012,7 @@ static __u32 fanotify_mark_remove_from_mask(struct fsnotify_mark *fsn_mark, + *destroy = !((fsn_mark->mask | fsn_mark->ignored_mask) & ~umask); + spin_unlock(&fsn_mark->lock); + +- return mask & oldmask; ++ return oldmask & ~newmask; + } + + static int fanotify_remove_mark(struct fsnotify_group *group, +@@ -1069,23 +1070,23 @@ static int fanotify_remove_inode_mark(struct fsnotify_group *group, + } + + static __u32 fanotify_mark_add_to_mask(struct fsnotify_mark *fsn_mark, +- __u32 mask, +- unsigned int flags) ++ __u32 mask, unsigned int flags) + { +- __u32 oldmask = -1; ++ __u32 oldmask, newmask; + + spin_lock(&fsn_mark->lock); ++ oldmask = fsnotify_calc_mask(fsn_mark); + if (!(flags & FAN_MARK_IGNORED_MASK)) { +- oldmask = fsn_mark->mask; + fsn_mark->mask |= mask; + } else { + fsn_mark->ignored_mask |= mask; + if (flags & FAN_MARK_IGNORED_SURV_MODIFY) + fsn_mark->flags |= FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY; + } ++ newmask = fsnotify_calc_mask(fsn_mark); + spin_unlock(&fsn_mark->lock); + +- return mask & ~oldmask; ++ return newmask & ~oldmask; + } + + static struct fsnotify_mark *fanotify_add_new_mark(struct fsnotify_group *group, +diff --git a/fs/notify/mark.c b/fs/notify/mark.c +index b42629d2fc1c6..c86982be2d505 100644 +--- a/fs/notify/mark.c ++++ b/fs/notify/mark.c +@@ -127,7 +127,7 @@ static void __fsnotify_recalc_mask(struct fsnotify_mark_connector *conn) + return; + hlist_for_each_entry(mark, &conn->list, obj_list) { + if (mark->flags & FSNOTIFY_MARK_FLAG_ATTACHED) +- new_mask |= mark->mask; ++ new_mask |= fsnotify_calc_mask(mark); + } + *fsnotify_conn_mask_p(conn) = new_mask; + } +@@ -692,7 +692,7 @@ int fsnotify_add_mark_locked(struct fsnotify_mark *mark, + if (ret) + goto err; + +- if (mark->mask) ++ if (mark->mask || mark->ignored_mask) + fsnotify_recalc_mask(mark->connector); + + return ret; +diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h +index 790c31844db5d..5f9c960049b07 100644 +--- a/include/linux/fsnotify_backend.h ++++ b/include/linux/fsnotify_backend.h +@@ -601,6 +601,21 @@ extern void fsnotify_remove_queued_event(struct fsnotify_group *group, + + /* functions used to manipulate the marks attached to inodes */ + ++/* Get mask for calculating object interest taking ignored mask into account */ ++static inline __u32 fsnotify_calc_mask(struct fsnotify_mark *mark) ++{ ++ __u32 mask = mark->mask; ++ ++ if (!mark->ignored_mask) ++ return mask; ++ ++ /* ++ * If mark is interested in ignoring events on children, the object must ++ * show interest in those events for fsnotify_parent() to notice it. ++ */ ++ return mask | (mark->ignored_mask & ALL_FSNOTIFY_EVENTS); ++} ++ + /* Get mask of events for a list of marks */ + extern __u32 fsnotify_conn_mask(struct fsnotify_mark_connector *conn); + /* Calculate mask of events for a list of marks */ +-- +2.43.0 + diff --git a/queue-5.10/fsnotify-fix-sb_connectors-leak.patch b/queue-5.10/fsnotify-fix-sb_connectors-leak.patch new file mode 100644 index 00000000000..42b26503244 --- /dev/null +++ b/queue-5.10/fsnotify-fix-sb_connectors-leak.patch @@ -0,0 +1,44 @@ +From 2809833b1d3549beffc675c72385db7ec16cb0a6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 9 Sep 2021 14:56:34 +0300 +Subject: fsnotify: fix sb_connectors leak + +From: Amir Goldstein + +[ Upstream commit 4396a73115fc8739083536162e2228c0c0c3ed1a ] + +Fix a leak in s_fsnotify_connectors counter in case of a race between +concurrent add of new fsnotify mark to an object. + +The task that lost the race fails to drop the counter before freeing +the unused connector. + +Following umount() hangs in fsnotify_sb_delete()/wait_var_event(), +because s_fsnotify_connectors never drops to zero. + +Fixes: ec44610fe2b8 ("fsnotify: count all objects with attached connectors") +Reported-by: Murphy Zhou +Link: https://lore.kernel.org/linux-fsdevel/20210907063338.ycaw6wvhzrfsfdlp@xzhoux.usersys.redhat.com/ +Signed-off-by: Amir Goldstein +Signed-off-by: Linus Torvalds +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/mark.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/notify/mark.c b/fs/notify/mark.c +index 796946eb0c2e2..bea106fac0901 100644 +--- a/fs/notify/mark.c ++++ b/fs/notify/mark.c +@@ -531,6 +531,7 @@ static int fsnotify_attach_connector_to_object(fsnotify_connp_t *connp, + /* Someone else created list structure for us */ + if (inode) + fsnotify_put_inode_ref(inode); ++ fsnotify_put_sb_connectors(conn); + kmem_cache_free(fsnotify_mark_connector_cachep, conn); + } + +-- +2.43.0 + diff --git a/queue-5.10/fsnotify-generate-fs_rename-event-with-rich-informat.patch b/queue-5.10/fsnotify-generate-fs_rename-event-with-rich-informat.patch new file mode 100644 index 00000000000..3c5c516d0a3 --- /dev/null +++ b/queue-5.10/fsnotify-generate-fs_rename-event-with-rich-informat.patch @@ -0,0 +1,226 @@ +From 9d2e1b17218ab25e6363ac0d2801cb5cf021a29a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Nov 2021 22:15:30 +0200 +Subject: fsnotify: generate FS_RENAME event with rich information + +From: Amir Goldstein + +[ Upstream commit e54183fa7047c15819bc155f4c58501d9a9a3489 ] + +The dnotify FS_DN_RENAME event is used to request notification about +a move within the same parent directory and was always coupled with +the FS_MOVED_FROM event. + +Rename the FS_DN_RENAME event flag to FS_RENAME, decouple it from +FS_MOVED_FROM and report it with the moved dentry instead of the moved +inode, so it has the information about both old and new parent and name. + +Generate the FS_RENAME event regardless of same parent dir and apply +the "same parent" rule in the generic fsnotify_handle_event() helper +that is used to call backends with ->handle_inode_event() method +(i.e. dnotify). The ->handle_inode_event() method is not rich enough to +report both old and new parent and name anyway. + +The enriched event is reported to fanotify over the ->handle_event() +method with the old and new dir inode marks in marks array slots for +ITER_TYPE_INODE and a new iter type slot ITER_TYPE_INODE2. + +The enriched event will be used for reporting old and new parent+name to +fanotify groups with FAN_RENAME events. + +Link: https://lore.kernel.org/r/20211129201537.1932819-5-amir73il@gmail.com +Signed-off-by: Amir Goldstein +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/dnotify/dnotify.c | 2 +- + fs/notify/fsnotify.c | 37 +++++++++++++++++++++++++------- + include/linux/dnotify.h | 2 +- + include/linux/fsnotify.h | 9 +++++--- + include/linux/fsnotify_backend.h | 7 +++--- + 5 files changed, 41 insertions(+), 16 deletions(-) + +diff --git a/fs/notify/dnotify/dnotify.c b/fs/notify/dnotify/dnotify.c +index e85e13c50d6d4..d5ebebb034ffe 100644 +--- a/fs/notify/dnotify/dnotify.c ++++ b/fs/notify/dnotify/dnotify.c +@@ -196,7 +196,7 @@ static __u32 convert_arg(unsigned long arg) + if (arg & DN_ATTRIB) + new_mask |= FS_ATTRIB; + if (arg & DN_RENAME) +- new_mask |= FS_DN_RENAME; ++ new_mask |= FS_RENAME; + if (arg & DN_CREATE) + new_mask |= (FS_CREATE | FS_MOVED_TO); + +diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c +index 0c94457c625e2..ab81a0776ece5 100644 +--- a/fs/notify/fsnotify.c ++++ b/fs/notify/fsnotify.c +@@ -279,6 +279,18 @@ static int fsnotify_handle_event(struct fsnotify_group *group, __u32 mask, + WARN_ON_ONCE(fsnotify_iter_vfsmount_mark(iter_info))) + return 0; + ++ /* ++ * For FS_RENAME, 'dir' is old dir and 'data' is new dentry. ++ * The only ->handle_inode_event() backend that supports FS_RENAME is ++ * dnotify, where it means file was renamed within same parent. ++ */ ++ if (mask & FS_RENAME) { ++ struct dentry *moved = fsnotify_data_dentry(data, data_type); ++ ++ if (dir != moved->d_parent->d_inode) ++ return 0; ++ } ++ + if (parent_mark) { + /* + * parent_mark indicates that the parent inode is watching +@@ -469,7 +481,9 @@ int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir, + struct super_block *sb = fsnotify_data_sb(data, data_type); + struct fsnotify_iter_info iter_info = {}; + struct mount *mnt = NULL; +- struct inode *parent = NULL; ++ struct inode *inode2 = NULL; ++ struct dentry *moved; ++ int inode2_type; + int ret = 0; + __u32 test_mask, marks_mask; + +@@ -479,12 +493,19 @@ int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir, + if (!inode) { + /* Dirent event - report on TYPE_INODE to dir */ + inode = dir; ++ /* For FS_RENAME, inode is old_dir and inode2 is new_dir */ ++ if (mask & FS_RENAME) { ++ moved = fsnotify_data_dentry(data, data_type); ++ inode2 = moved->d_parent->d_inode; ++ inode2_type = FSNOTIFY_ITER_TYPE_INODE2; ++ } + } else if (mask & FS_EVENT_ON_CHILD) { + /* + * Event on child - report on TYPE_PARENT to dir if it is + * watching children and on TYPE_INODE to child. + */ +- parent = dir; ++ inode2 = dir; ++ inode2_type = FSNOTIFY_ITER_TYPE_PARENT; + } + + /* +@@ -497,7 +518,7 @@ int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir, + if (!sb->s_fsnotify_marks && + (!mnt || !mnt->mnt_fsnotify_marks) && + (!inode || !inode->i_fsnotify_marks) && +- (!parent || !parent->i_fsnotify_marks)) ++ (!inode2 || !inode2->i_fsnotify_marks)) + return 0; + + marks_mask = sb->s_fsnotify_mask; +@@ -505,8 +526,8 @@ int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir, + marks_mask |= mnt->mnt_fsnotify_mask; + if (inode) + marks_mask |= inode->i_fsnotify_mask; +- if (parent) +- marks_mask |= parent->i_fsnotify_mask; ++ if (inode2) ++ marks_mask |= inode2->i_fsnotify_mask; + + + /* +@@ -529,9 +550,9 @@ int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir, + iter_info.marks[FSNOTIFY_ITER_TYPE_INODE] = + fsnotify_first_mark(&inode->i_fsnotify_marks); + } +- if (parent) { +- iter_info.marks[FSNOTIFY_ITER_TYPE_PARENT] = +- fsnotify_first_mark(&parent->i_fsnotify_marks); ++ if (inode2) { ++ iter_info.marks[inode2_type] = ++ fsnotify_first_mark(&inode2->i_fsnotify_marks); + } + + /* +diff --git a/include/linux/dnotify.h b/include/linux/dnotify.h +index 0aad774beaec4..b87c3b85a166c 100644 +--- a/include/linux/dnotify.h ++++ b/include/linux/dnotify.h +@@ -26,7 +26,7 @@ struct dnotify_struct { + FS_MODIFY | FS_MODIFY_CHILD |\ + FS_ACCESS | FS_ACCESS_CHILD |\ + FS_ATTRIB | FS_ATTRIB_CHILD |\ +- FS_CREATE | FS_DN_RENAME |\ ++ FS_CREATE | FS_RENAME |\ + FS_MOVED_FROM | FS_MOVED_TO) + + extern int dir_notify_enable; +diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h +index bec1e23ecf787..bb8467cd11ae2 100644 +--- a/include/linux/fsnotify.h ++++ b/include/linux/fsnotify.h +@@ -144,16 +144,19 @@ static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir, + u32 fs_cookie = fsnotify_get_cookie(); + __u32 old_dir_mask = FS_MOVED_FROM; + __u32 new_dir_mask = FS_MOVED_TO; ++ __u32 rename_mask = FS_RENAME; + const struct qstr *new_name = &moved->d_name; + +- if (old_dir == new_dir) +- old_dir_mask |= FS_DN_RENAME; +- + if (isdir) { + old_dir_mask |= FS_ISDIR; + new_dir_mask |= FS_ISDIR; ++ rename_mask |= FS_ISDIR; + } + ++ /* Event with information about both old and new parent+name */ ++ fsnotify_name(rename_mask, moved, FSNOTIFY_EVENT_DENTRY, ++ old_dir, old_name, 0); ++ + fsnotify_name(old_dir_mask, source, FSNOTIFY_EVENT_INODE, + old_dir, old_name, fs_cookie); + fsnotify_name(new_dir_mask, source, FSNOTIFY_EVENT_INODE, +diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h +index 73739fee1710f..790c31844db5d 100644 +--- a/include/linux/fsnotify_backend.h ++++ b/include/linux/fsnotify_backend.h +@@ -63,7 +63,7 @@ + */ + #define FS_EVENT_ON_CHILD 0x08000000 + +-#define FS_DN_RENAME 0x10000000 /* file renamed */ ++#define FS_RENAME 0x10000000 /* File was renamed */ + #define FS_DN_MULTISHOT 0x20000000 /* dnotify multishot */ + #define FS_ISDIR 0x40000000 /* event occurred against dir */ + #define FS_IN_ONESHOT 0x80000000 /* only send event once */ +@@ -76,7 +76,7 @@ + * The watching parent may get an FS_ATTRIB|FS_EVENT_ON_CHILD event + * when a directory entry inside a child subdir changes. + */ +-#define ALL_FSNOTIFY_DIRENT_EVENTS (FS_CREATE | FS_DELETE | FS_MOVE) ++#define ALL_FSNOTIFY_DIRENT_EVENTS (FS_CREATE | FS_DELETE | FS_MOVE | FS_RENAME) + + #define ALL_FSNOTIFY_PERM_EVENTS (FS_OPEN_PERM | FS_ACCESS_PERM | \ + FS_OPEN_EXEC_PERM) +@@ -101,7 +101,7 @@ + /* Events that can be reported to backends */ + #define ALL_FSNOTIFY_EVENTS (ALL_FSNOTIFY_DIRENT_EVENTS | \ + FS_EVENTS_POSS_ON_CHILD | \ +- FS_DELETE_SELF | FS_MOVE_SELF | FS_DN_RENAME | \ ++ FS_DELETE_SELF | FS_MOVE_SELF | \ + FS_UNMOUNT | FS_Q_OVERFLOW | FS_IN_IGNORED | \ + FS_ERROR) + +@@ -349,6 +349,7 @@ enum fsnotify_iter_type { + FSNOTIFY_ITER_TYPE_VFSMOUNT, + FSNOTIFY_ITER_TYPE_SB, + FSNOTIFY_ITER_TYPE_PARENT, ++ FSNOTIFY_ITER_TYPE_INODE2, + FSNOTIFY_ITER_TYPE_COUNT + }; + +-- +2.43.0 + diff --git a/queue-5.10/fsnotify-introduce-mark-type-iterator.patch b/queue-5.10/fsnotify-introduce-mark-type-iterator.patch new file mode 100644 index 00000000000..22cfcf9f718 --- /dev/null +++ b/queue-5.10/fsnotify-introduce-mark-type-iterator.patch @@ -0,0 +1,243 @@ +From a336820c708ccbd138e722dfcffa2bcae513b481 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 May 2022 22:02:12 +0300 +Subject: fsnotify: introduce mark type iterator + +From: Amir Goldstein + +[ Upstream commit 14362a2541797cf9df0e86fb12dcd7950baf566e ] + +fsnotify_foreach_iter_mark_type() is used to reduce boilerplate code +of iterating all marks of a specific group interested in an event +by consulting the iterator report_mask. + +Use an open coded version of that iterator in fsnotify_iter_next() +that collects all marks of the current iteration group without +consulting the iterator report_mask. + +At the moment, the two iterator variants are the same, but this +decoupling will allow us to exclude some of the group's marks from +reporting the event, for example for event on child and inode marks +on parent did not request to watch events on children. + +Fixes: 2f02fd3fa13e ("fanotify: fix ignore mask logic for events on child and on dir") +Reported-by: Jan Kara +Signed-off-by: Amir Goldstein +Signed-off-by: Jan Kara +Link: https://lore.kernel.org/r/20220511190213.831646-2-amir73il@gmail.com +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify.c | 14 +++------ + fs/notify/fsnotify.c | 53 ++++++++++++++++---------------- + include/linux/fsnotify_backend.h | 31 ++++++++++++++----- + 3 files changed, 54 insertions(+), 44 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c +index 985e995d2a398..263d303d8f8f1 100644 +--- a/fs/notify/fanotify/fanotify.c ++++ b/fs/notify/fanotify/fanotify.c +@@ -319,11 +319,7 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group, + return 0; + } + +- fsnotify_foreach_iter_type(type) { +- if (!fsnotify_iter_should_report_type(iter_info, type)) +- continue; +- mark = iter_info->marks[type]; +- ++ fsnotify_foreach_iter_mark_type(iter_info, mark, type) { + /* Apply ignore mask regardless of ISDIR and ON_CHILD flags */ + marks_ignored_mask |= mark->ignored_mask; + +@@ -849,16 +845,14 @@ static struct fanotify_event *fanotify_alloc_event( + */ + static __kernel_fsid_t fanotify_get_fsid(struct fsnotify_iter_info *iter_info) + { ++ struct fsnotify_mark *mark; + int type; + __kernel_fsid_t fsid = {}; + +- fsnotify_foreach_iter_type(type) { ++ fsnotify_foreach_iter_mark_type(iter_info, mark, type) { + struct fsnotify_mark_connector *conn; + +- if (!fsnotify_iter_should_report_type(iter_info, type)) +- continue; +- +- conn = READ_ONCE(iter_info->marks[type]->connector); ++ conn = READ_ONCE(mark->connector); + /* Mark is just getting destroyed or created? */ + if (!conn) + continue; +diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c +index 6eee19d15e8cd..35740a64ee453 100644 +--- a/fs/notify/fsnotify.c ++++ b/fs/notify/fsnotify.c +@@ -335,31 +335,23 @@ static int send_to_group(__u32 mask, const void *data, int data_type, + struct fsnotify_mark *mark; + int type; + +- if (WARN_ON(!iter_info->report_mask)) ++ if (!iter_info->report_mask) + return 0; + + /* clear ignored on inode modification */ + if (mask & FS_MODIFY) { +- fsnotify_foreach_iter_type(type) { +- if (!fsnotify_iter_should_report_type(iter_info, type)) +- continue; +- mark = iter_info->marks[type]; +- if (mark && +- !(mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY)) ++ fsnotify_foreach_iter_mark_type(iter_info, mark, type) { ++ if (!(mark->flags & ++ FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY)) + mark->ignored_mask = 0; + } + } + +- fsnotify_foreach_iter_type(type) { +- if (!fsnotify_iter_should_report_type(iter_info, type)) +- continue; +- mark = iter_info->marks[type]; +- /* does the object mark tell us to do something? */ +- if (mark) { +- group = mark->group; +- marks_mask |= mark->mask; +- marks_ignored_mask |= mark->ignored_mask; +- } ++ /* Are any of the group marks interested in this event? */ ++ fsnotify_foreach_iter_mark_type(iter_info, mark, type) { ++ group = mark->group; ++ marks_mask |= mark->mask; ++ marks_ignored_mask |= mark->ignored_mask; + } + + pr_debug("%s: group=%p mask=%x marks_mask=%x marks_ignored_mask=%x data=%p data_type=%d dir=%p cookie=%d\n", +@@ -403,11 +395,11 @@ static struct fsnotify_mark *fsnotify_next_mark(struct fsnotify_mark *mark) + + /* + * iter_info is a multi head priority queue of marks. +- * Pick a subset of marks from queue heads, all with the +- * same group and set the report_mask for selected subset. +- * Returns the report_mask of the selected subset. ++ * Pick a subset of marks from queue heads, all with the same group ++ * and set the report_mask to a subset of the selected marks. ++ * Returns false if there are no more groups to iterate. + */ +-static unsigned int fsnotify_iter_select_report_types( ++static bool fsnotify_iter_select_report_types( + struct fsnotify_iter_info *iter_info) + { + struct fsnotify_group *max_prio_group = NULL; +@@ -423,30 +415,37 @@ static unsigned int fsnotify_iter_select_report_types( + } + + if (!max_prio_group) +- return 0; ++ return false; + + /* Set the report mask for marks from same group as max prio group */ ++ iter_info->current_group = max_prio_group; + iter_info->report_mask = 0; + fsnotify_foreach_iter_type(type) { + mark = iter_info->marks[type]; +- if (mark && +- fsnotify_compare_groups(max_prio_group, mark->group) == 0) ++ if (mark && mark->group == iter_info->current_group) + fsnotify_iter_set_report_type(iter_info, type); + } + +- return iter_info->report_mask; ++ return true; + } + + /* +- * Pop from iter_info multi head queue, the marks that were iterated in the ++ * Pop from iter_info multi head queue, the marks that belong to the group of + * current iteration step. + */ + static void fsnotify_iter_next(struct fsnotify_iter_info *iter_info) + { ++ struct fsnotify_mark *mark; + int type; + ++ /* ++ * We cannot use fsnotify_foreach_iter_mark_type() here because we ++ * may need to advance a mark of type X that belongs to current_group ++ * but was not selected for reporting. ++ */ + fsnotify_foreach_iter_type(type) { +- if (fsnotify_iter_should_report_type(iter_info, type)) ++ mark = iter_info->marks[type]; ++ if (mark && mark->group == iter_info->current_group) + iter_info->marks[type] = + fsnotify_next_mark(iter_info->marks[type]); + } +diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h +index 9a1a9e78f69f5..9560734759fa6 100644 +--- a/include/linux/fsnotify_backend.h ++++ b/include/linux/fsnotify_backend.h +@@ -399,6 +399,7 @@ static inline bool fsnotify_valid_obj_type(unsigned int obj_type) + + struct fsnotify_iter_info { + struct fsnotify_mark *marks[FSNOTIFY_ITER_TYPE_COUNT]; ++ struct fsnotify_group *current_group; + unsigned int report_mask; + int srcu_idx; + }; +@@ -415,20 +416,31 @@ static inline void fsnotify_iter_set_report_type( + iter_info->report_mask |= (1U << iter_type); + } + +-static inline void fsnotify_iter_set_report_type_mark( +- struct fsnotify_iter_info *iter_info, int iter_type, +- struct fsnotify_mark *mark) ++static inline struct fsnotify_mark *fsnotify_iter_mark( ++ struct fsnotify_iter_info *iter_info, int iter_type) + { +- iter_info->marks[iter_type] = mark; +- iter_info->report_mask |= (1U << iter_type); ++ if (fsnotify_iter_should_report_type(iter_info, iter_type)) ++ return iter_info->marks[iter_type]; ++ return NULL; ++} ++ ++static inline int fsnotify_iter_step(struct fsnotify_iter_info *iter, int type, ++ struct fsnotify_mark **markp) ++{ ++ while (type < FSNOTIFY_ITER_TYPE_COUNT) { ++ *markp = fsnotify_iter_mark(iter, type); ++ if (*markp) ++ break; ++ type++; ++ } ++ return type; + } + + #define FSNOTIFY_ITER_FUNCS(name, NAME) \ + static inline struct fsnotify_mark *fsnotify_iter_##name##_mark( \ + struct fsnotify_iter_info *iter_info) \ + { \ +- return (iter_info->report_mask & (1U << FSNOTIFY_ITER_TYPE_##NAME)) ? \ +- iter_info->marks[FSNOTIFY_ITER_TYPE_##NAME] : NULL; \ ++ return fsnotify_iter_mark(iter_info, FSNOTIFY_ITER_TYPE_##NAME); \ + } + + FSNOTIFY_ITER_FUNCS(inode, INODE) +@@ -438,6 +450,11 @@ FSNOTIFY_ITER_FUNCS(sb, SB) + + #define fsnotify_foreach_iter_type(type) \ + for (type = 0; type < FSNOTIFY_ITER_TYPE_COUNT; type++) ++#define fsnotify_foreach_iter_mark_type(iter, mark, type) \ ++ for (type = 0; \ ++ type = fsnotify_iter_step(iter, type, &mark), \ ++ type < FSNOTIFY_ITER_TYPE_COUNT; \ ++ type++) + + /* + * fsnotify_connp_t is what we embed in objects which connector can be attached +-- +2.43.0 + diff --git a/queue-5.10/fsnotify-make-allow_dups-a-property-of-the-group.patch b/queue-5.10/fsnotify-make-allow_dups-a-property-of-the-group.patch new file mode 100644 index 00000000000..301f32015f8 --- /dev/null +++ b/queue-5.10/fsnotify-make-allow_dups-a-property-of-the-group.patch @@ -0,0 +1,156 @@ +From 373eb4aeac2540ae9ec4ad0e65cd1a75ec6750b2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 Apr 2022 15:03:16 +0300 +Subject: fsnotify: make allow_dups a property of the group + +From: Amir Goldstein + +[ Upstream commit f3010343d9e119da35ee864b3a28993bb5c78ed7 ] + +Instead of passing the allow_dups argument to fsnotify_add_mark() +as an argument, define the group flag FSNOTIFY_GROUP_DUPS to express +the allow_dups behavior and set this behavior at group creation time +for all calls of fsnotify_add_mark(). + +Rename the allow_dups argument to generic add_flags argument for future +use. + +Link: https://lore.kernel.org/r/20220422120327.3459282-6-amir73il@gmail.com +Suggested-by: Jan Kara +Signed-off-by: Amir Goldstein +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/mark.c | 12 ++++++------ + include/linux/fsnotify_backend.h | 13 +++++++------ + kernel/audit_fsnotify.c | 4 ++-- + 3 files changed, 15 insertions(+), 14 deletions(-) + +diff --git a/fs/notify/mark.c b/fs/notify/mark.c +index c86982be2d505..1fb246ea61752 100644 +--- a/fs/notify/mark.c ++++ b/fs/notify/mark.c +@@ -574,7 +574,7 @@ static struct fsnotify_mark_connector *fsnotify_grab_connector( + static int fsnotify_add_mark_list(struct fsnotify_mark *mark, + fsnotify_connp_t *connp, + unsigned int obj_type, +- int allow_dups, __kernel_fsid_t *fsid) ++ int add_flags, __kernel_fsid_t *fsid) + { + struct fsnotify_mark *lmark, *last = NULL; + struct fsnotify_mark_connector *conn; +@@ -633,7 +633,7 @@ static int fsnotify_add_mark_list(struct fsnotify_mark *mark, + + if ((lmark->group == mark->group) && + (lmark->flags & FSNOTIFY_MARK_FLAG_ATTACHED) && +- !allow_dups) { ++ !(mark->group->flags & FSNOTIFY_GROUP_DUPS)) { + err = -EEXIST; + goto out_err; + } +@@ -668,7 +668,7 @@ static int fsnotify_add_mark_list(struct fsnotify_mark *mark, + */ + int fsnotify_add_mark_locked(struct fsnotify_mark *mark, + fsnotify_connp_t *connp, unsigned int obj_type, +- int allow_dups, __kernel_fsid_t *fsid) ++ int add_flags, __kernel_fsid_t *fsid) + { + struct fsnotify_group *group = mark->group; + int ret = 0; +@@ -688,7 +688,7 @@ int fsnotify_add_mark_locked(struct fsnotify_mark *mark, + fsnotify_get_mark(mark); /* for g_list */ + spin_unlock(&mark->lock); + +- ret = fsnotify_add_mark_list(mark, connp, obj_type, allow_dups, fsid); ++ ret = fsnotify_add_mark_list(mark, connp, obj_type, add_flags, fsid); + if (ret) + goto err; + +@@ -708,14 +708,14 @@ int fsnotify_add_mark_locked(struct fsnotify_mark *mark, + } + + int fsnotify_add_mark(struct fsnotify_mark *mark, fsnotify_connp_t *connp, +- unsigned int obj_type, int allow_dups, ++ unsigned int obj_type, int add_flags, + __kernel_fsid_t *fsid) + { + int ret; + struct fsnotify_group *group = mark->group; + + mutex_lock(&group->mark_mutex); +- ret = fsnotify_add_mark_locked(mark, connp, obj_type, allow_dups, fsid); ++ ret = fsnotify_add_mark_locked(mark, connp, obj_type, add_flags, fsid); + mutex_unlock(&group->mark_mutex); + return ret; + } +diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h +index f0bf557af0091..dd440e6ff5285 100644 +--- a/include/linux/fsnotify_backend.h ++++ b/include/linux/fsnotify_backend.h +@@ -211,6 +211,7 @@ struct fsnotify_group { + bool shutdown; /* group is being shut down, don't queue more events */ + + #define FSNOTIFY_GROUP_USER 0x01 /* user allocated group */ ++#define FSNOTIFY_GROUP_DUPS 0x02 /* allow multiple marks per object */ + int flags; + + /* stores all fastpath marks assoc with this group so they can be cleaned on unregister */ +@@ -641,26 +642,26 @@ extern int fsnotify_get_conn_fsid(const struct fsnotify_mark_connector *conn, + /* attach the mark to the object */ + extern int fsnotify_add_mark(struct fsnotify_mark *mark, + fsnotify_connp_t *connp, unsigned int obj_type, +- int allow_dups, __kernel_fsid_t *fsid); ++ int add_flags, __kernel_fsid_t *fsid); + extern int fsnotify_add_mark_locked(struct fsnotify_mark *mark, + fsnotify_connp_t *connp, +- unsigned int obj_type, int allow_dups, ++ unsigned int obj_type, int add_flags, + __kernel_fsid_t *fsid); + + /* attach the mark to the inode */ + static inline int fsnotify_add_inode_mark(struct fsnotify_mark *mark, + struct inode *inode, +- int allow_dups) ++ int add_flags) + { + return fsnotify_add_mark(mark, &inode->i_fsnotify_marks, +- FSNOTIFY_OBJ_TYPE_INODE, allow_dups, NULL); ++ FSNOTIFY_OBJ_TYPE_INODE, add_flags, NULL); + } + static inline int fsnotify_add_inode_mark_locked(struct fsnotify_mark *mark, + struct inode *inode, +- int allow_dups) ++ int add_flags) + { + return fsnotify_add_mark_locked(mark, &inode->i_fsnotify_marks, +- FSNOTIFY_OBJ_TYPE_INODE, allow_dups, ++ FSNOTIFY_OBJ_TYPE_INODE, add_flags, + NULL); + } + +diff --git a/kernel/audit_fsnotify.c b/kernel/audit_fsnotify.c +index 31f43b1475404..691f90dd09d25 100644 +--- a/kernel/audit_fsnotify.c ++++ b/kernel/audit_fsnotify.c +@@ -100,7 +100,7 @@ struct audit_fsnotify_mark *audit_alloc_mark(struct audit_krule *krule, char *pa + audit_update_mark(audit_mark, dentry->d_inode); + audit_mark->rule = krule; + +- ret = fsnotify_add_inode_mark(&audit_mark->mark, inode, true); ++ ret = fsnotify_add_inode_mark(&audit_mark->mark, inode, 0); + if (ret < 0) { + audit_mark->path = NULL; + fsnotify_put_mark(&audit_mark->mark); +@@ -183,7 +183,7 @@ static const struct fsnotify_ops audit_mark_fsnotify_ops = { + static int __init audit_fsnotify_init(void) + { + audit_fsnotify_group = fsnotify_alloc_group(&audit_mark_fsnotify_ops, +- 0); ++ FSNOTIFY_GROUP_DUPS); + if (IS_ERR(audit_fsnotify_group)) { + audit_fsnotify_group = NULL; + audit_panic("cannot create audit fsnotify group"); +-- +2.43.0 + diff --git a/queue-5.10/fsnotify-optimize-fs_modify-events-with-no-ignored-m.patch b/queue-5.10/fsnotify-optimize-fs_modify-events-with-no-ignored-m.patch new file mode 100644 index 00000000000..b16b07ec685 --- /dev/null +++ b/queue-5.10/fsnotify-optimize-fs_modify-events-with-no-ignored-m.patch @@ -0,0 +1,154 @@ +From e901bc3c152f1667701c5c6b8e9b40fb564f5e65 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 23 Feb 2022 17:14:38 +0200 +Subject: fsnotify: optimize FS_MODIFY events with no ignored masks + +From: Amir Goldstein + +[ Upstream commit 04e317ba72d07901b03399b3d1525e83424df5b3 ] + +fsnotify() treats FS_MODIFY events specially - it does not skip them +even if the FS_MODIFY event does not apear in the object's fsnotify +mask. This is because send_to_group() checks if FS_MODIFY needs to +clear ignored mask of marks. + +The common case is that an object does not have any mark with ignored +mask and in particular, that it does not have a mark with ignored mask +and without the FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY flag. + +Set FS_MODIFY in object's fsnotify mask during fsnotify_recalc_mask() +if object has a mark with an ignored mask and without the +FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY flag and remove the special +treatment of FS_MODIFY in fsnotify(), so that FS_MODIFY events could +be optimized in the common case. + +Call fsnotify_recalc_mask() from fanotify after adding or removing an +ignored mask from a mark without FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY +or when adding the FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY flag to a mark +with ignored mask (the flag cannot be removed by fanotify uapi). + +Performance results for doing 10000000 write(2)s to tmpfs: + + vanilla patched +without notification mark 25.486+-1.054 24.965+-0.244 +with notification mark 30.111+-0.139 26.891+-1.355 + +So we can see the overhead of notification subsystem has been +drastically reduced. + +Link: https://lore.kernel.org/r/20220223151438.790268-3-amir73il@gmail.com +Suggested-by: Jan Kara +Signed-off-by: Amir Goldstein +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify_user.c | 32 +++++++++++++++++++++++------- + fs/notify/fsnotify.c | 8 +++++--- + include/linux/fsnotify_backend.h | 4 ++++ + 3 files changed, 34 insertions(+), 10 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c +index 12fb209e60419..64abec874d8e3 100644 +--- a/fs/notify/fanotify/fanotify_user.c ++++ b/fs/notify/fanotify/fanotify_user.c +@@ -1069,8 +1069,28 @@ static int fanotify_remove_inode_mark(struct fsnotify_group *group, + flags, umask); + } + ++static void fanotify_mark_add_ignored_mask(struct fsnotify_mark *fsn_mark, ++ __u32 mask, unsigned int flags, ++ __u32 *removed) ++{ ++ fsn_mark->ignored_mask |= mask; ++ ++ /* ++ * Setting FAN_MARK_IGNORED_SURV_MODIFY for the first time may lead to ++ * the removal of the FS_MODIFY bit in calculated mask if it was set ++ * because of an ignored mask that is now going to survive FS_MODIFY. ++ */ ++ if ((flags & FAN_MARK_IGNORED_SURV_MODIFY) && ++ !(fsn_mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY)) { ++ fsn_mark->flags |= FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY; ++ if (!(fsn_mark->mask & FS_MODIFY)) ++ *removed = FS_MODIFY; ++ } ++} ++ + static __u32 fanotify_mark_add_to_mask(struct fsnotify_mark *fsn_mark, +- __u32 mask, unsigned int flags) ++ __u32 mask, unsigned int flags, ++ __u32 *removed) + { + __u32 oldmask, newmask; + +@@ -1079,9 +1099,7 @@ static __u32 fanotify_mark_add_to_mask(struct fsnotify_mark *fsn_mark, + if (!(flags & FAN_MARK_IGNORED_MASK)) { + fsn_mark->mask |= mask; + } else { +- fsn_mark->ignored_mask |= mask; +- if (flags & FAN_MARK_IGNORED_SURV_MODIFY) +- fsn_mark->flags |= FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY; ++ fanotify_mark_add_ignored_mask(fsn_mark, mask, flags, removed); + } + newmask = fsnotify_calc_mask(fsn_mark); + spin_unlock(&fsn_mark->lock); +@@ -1144,7 +1162,7 @@ static int fanotify_add_mark(struct fsnotify_group *group, + __kernel_fsid_t *fsid) + { + struct fsnotify_mark *fsn_mark; +- __u32 added; ++ __u32 added, removed = 0; + int ret = 0; + + mutex_lock(&group->mark_mutex); +@@ -1167,8 +1185,8 @@ static int fanotify_add_mark(struct fsnotify_group *group, + goto out; + } + +- added = fanotify_mark_add_to_mask(fsn_mark, mask, flags); +- if (added & ~fsnotify_conn_mask(fsn_mark->connector)) ++ added = fanotify_mark_add_to_mask(fsn_mark, mask, flags, &removed); ++ if (removed || (added & ~fsnotify_conn_mask(fsn_mark->connector))) + fsnotify_recalc_mask(fsn_mark->connector); + + out: +diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c +index ab81a0776ece5..494f653efbc6e 100644 +--- a/fs/notify/fsnotify.c ++++ b/fs/notify/fsnotify.c +@@ -531,11 +531,13 @@ int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir, + + + /* +- * if this is a modify event we may need to clear the ignored masks +- * otherwise return if none of the marks care about this type of event. ++ * If this is a modify event we may need to clear some ignored masks. ++ * In that case, the object with ignored masks will have the FS_MODIFY ++ * event in its mask. ++ * Otherwise, return if none of the marks care about this type of event. + */ + test_mask = (mask & ALL_FSNOTIFY_EVENTS); +- if (!(mask & FS_MODIFY) && !(test_mask & marks_mask)) ++ if (!(test_mask & marks_mask)) + return 0; + + iter_info.srcu_idx = srcu_read_lock(&fsnotify_mark_srcu); +diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h +index 5f9c960049b07..0805b74cae441 100644 +--- a/include/linux/fsnotify_backend.h ++++ b/include/linux/fsnotify_backend.h +@@ -609,6 +609,10 @@ static inline __u32 fsnotify_calc_mask(struct fsnotify_mark *mark) + if (!mark->ignored_mask) + return mask; + ++ /* Interest in FS_MODIFY may be needed for clearing ignored mask */ ++ if (!(mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY)) ++ mask |= FS_MODIFY; ++ + /* + * If mark is interested in ignoring events on children, the object must + * show interest in those events for fsnotify_parent() to notice it. +-- +2.43.0 + diff --git a/queue-5.10/fsnotify-optimize-the-case-of-no-marks-of-any-type.patch b/queue-5.10/fsnotify-optimize-the-case-of-no-marks-of-any-type.patch new file mode 100644 index 00000000000..c73a8291b4b --- /dev/null +++ b/queue-5.10/fsnotify-optimize-the-case-of-no-marks-of-any-type.patch @@ -0,0 +1,61 @@ +From 7d7b19fa04780d3f60cb78e1e255e3e3f03ccb83 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Aug 2021 18:12:20 +0300 +Subject: fsnotify: optimize the case of no marks of any type + +From: Amir Goldstein + +[ Upstream commit e43de7f0862b8598cd1ef440e3b4701cd107ea40 ] + +Add a simple check in the inline helpers to avoid calling fsnotify() +and __fsnotify_parent() in case there are no marks of any type +(inode/sb/mount) for an inode's sb, so there can be no objects +of any type interested in the event. + +Link: https://lore.kernel.org/r/20210810151220.285179-5-amir73il@gmail.com +Reviewed-by: Matthew Bobrowski +Signed-off-by: Amir Goldstein +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + include/linux/fsnotify.h | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h +index 79add91eaa04e..a9477c14fad5c 100644 +--- a/include/linux/fsnotify.h ++++ b/include/linux/fsnotify.h +@@ -30,6 +30,9 @@ static inline void fsnotify_name(struct inode *dir, __u32 mask, + struct inode *child, + const struct qstr *name, u32 cookie) + { ++ if (atomic_long_read(&dir->i_sb->s_fsnotify_connectors) == 0) ++ return; ++ + fsnotify(mask, child, FSNOTIFY_EVENT_INODE, dir, name, NULL, cookie); + } + +@@ -41,6 +44,9 @@ static inline void fsnotify_dirent(struct inode *dir, struct dentry *dentry, + + static inline void fsnotify_inode(struct inode *inode, __u32 mask) + { ++ if (atomic_long_read(&inode->i_sb->s_fsnotify_connectors) == 0) ++ return; ++ + if (S_ISDIR(inode->i_mode)) + mask |= FS_ISDIR; + +@@ -53,6 +59,9 @@ static inline int fsnotify_parent(struct dentry *dentry, __u32 mask, + { + struct inode *inode = d_inode(dentry); + ++ if (atomic_long_read(&inode->i_sb->s_fsnotify_connectors) == 0) ++ return 0; ++ + if (S_ISDIR(inode->i_mode)) { + mask |= FS_ISDIR; + +-- +2.43.0 + diff --git a/queue-5.10/fsnotify-pass-data_type-to-fsnotify_name.patch b/queue-5.10/fsnotify-pass-data_type-to-fsnotify_name.patch new file mode 100644 index 00000000000..5ef313e1545 --- /dev/null +++ b/queue-5.10/fsnotify-pass-data_type-to-fsnotify_name.patch @@ -0,0 +1,91 @@ +From e213eac7711065bcc48d67703797036759efe687 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 Oct 2021 16:27:16 -0300 +Subject: fsnotify: pass data_type to fsnotify_name() + +From: Amir Goldstein + +[ Upstream commit 9baf93d68bcc3d0a6042283b82603c076e25e4f5 ] + +Align the arguments of fsnotify_name() to those of fsnotify(). + +Link: https://lore.kernel.org/r/20211025192746.66445-2-krisman@collabora.com +Reviewed-by: Jan Kara +Signed-off-by: Amir Goldstein +Signed-off-by: Gabriel Krisman Bertazi +Signed-off-by: Jan Kara +[ cel: adjust fsnotify_delete as well, a37d9a17f099 is already applied ] +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + include/linux/fsnotify.h | 25 +++++++++++++++---------- + 1 file changed, 15 insertions(+), 10 deletions(-) + +diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h +index a9477c14fad5c..211463715e29d 100644 +--- a/include/linux/fsnotify.h ++++ b/include/linux/fsnotify.h +@@ -26,20 +26,21 @@ + * FS_EVENT_ON_CHILD mask on the parent inode and will not be reported if only + * the child is interested and not the parent. + */ +-static inline void fsnotify_name(struct inode *dir, __u32 mask, +- struct inode *child, +- const struct qstr *name, u32 cookie) ++static inline int fsnotify_name(__u32 mask, const void *data, int data_type, ++ struct inode *dir, const struct qstr *name, ++ u32 cookie) + { + if (atomic_long_read(&dir->i_sb->s_fsnotify_connectors) == 0) +- return; ++ return 0; + +- fsnotify(mask, child, FSNOTIFY_EVENT_INODE, dir, name, NULL, cookie); ++ return fsnotify(mask, data, data_type, dir, name, NULL, cookie); + } + + static inline void fsnotify_dirent(struct inode *dir, struct dentry *dentry, + __u32 mask) + { +- fsnotify_name(dir, mask, d_inode(dentry), &dentry->d_name, 0); ++ fsnotify_name(mask, d_inode(dentry), FSNOTIFY_EVENT_INODE, ++ dir, &dentry->d_name, 0); + } + + static inline void fsnotify_inode(struct inode *inode, __u32 mask) +@@ -154,8 +155,10 @@ static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir, + new_dir_mask |= FS_ISDIR; + } + +- fsnotify_name(old_dir, old_dir_mask, source, old_name, fs_cookie); +- fsnotify_name(new_dir, new_dir_mask, source, new_name, fs_cookie); ++ fsnotify_name(old_dir_mask, source, FSNOTIFY_EVENT_INODE, ++ old_dir, old_name, fs_cookie); ++ fsnotify_name(new_dir_mask, source, FSNOTIFY_EVENT_INODE, ++ new_dir, new_name, fs_cookie); + + if (target) + fsnotify_link_count(target); +@@ -209,7 +212,8 @@ static inline void fsnotify_link(struct inode *dir, struct inode *inode, + fsnotify_link_count(inode); + audit_inode_child(dir, new_dentry, AUDIT_TYPE_CHILD_CREATE); + +- fsnotify_name(dir, FS_CREATE, inode, &new_dentry->d_name, 0); ++ fsnotify_name(FS_CREATE, inode, FSNOTIFY_EVENT_INODE, ++ dir, &new_dentry->d_name, 0); + } + + /* +@@ -228,7 +232,8 @@ static inline void fsnotify_delete(struct inode *dir, struct inode *inode, + if (S_ISDIR(inode->i_mode)) + mask |= FS_ISDIR; + +- fsnotify_name(dir, mask, inode, &dentry->d_name, 0); ++ fsnotify_name(mask, inode, FSNOTIFY_EVENT_INODE, dir, &dentry->d_name, ++ 0); + } + + /** +-- +2.43.0 + diff --git a/queue-5.10/fsnotify-pass-dentry-instead-of-inode-data.patch b/queue-5.10/fsnotify-pass-dentry-instead-of-inode-data.patch new file mode 100644 index 00000000000..175d33ab01e --- /dev/null +++ b/queue-5.10/fsnotify-pass-dentry-instead-of-inode-data.patch @@ -0,0 +1,98 @@ +From 2170c279ed8354ea8b1033b6b1ae3fc06b744c0d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 Oct 2021 16:27:17 -0300 +Subject: fsnotify: pass dentry instead of inode data + +From: Amir Goldstein + +[ Upstream commit fd5a3ff49a19aa69e2bc1e26e98037c2d778e61a ] + +Define a new data type to pass for event - FSNOTIFY_EVENT_DENTRY. +Use it to pass the dentry instead of it's ->d_inode where available. + +This is needed in preparation to the refactor to retrieve the super +block from the data field. In some cases (i.e. mkdir in kernfs), the +data inode comes from a negative dentry, such that no super block +information would be available. By receiving the dentry itself, instead +of the inode, fsnotify can derive the super block even on these cases. + +Link: https://lore.kernel.org/r/20211025192746.66445-3-krisman@collabora.com +Reviewed-by: Jan Kara +Signed-off-by: Amir Goldstein +[Expand explanation in commit message] +Signed-off-by: Gabriel Krisman Bertazi +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + include/linux/fsnotify.h | 5 ++--- + include/linux/fsnotify_backend.h | 16 ++++++++++++++++ + 2 files changed, 18 insertions(+), 3 deletions(-) + +diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h +index 211463715e29d..e969a23f70631 100644 +--- a/include/linux/fsnotify.h ++++ b/include/linux/fsnotify.h +@@ -39,8 +39,7 @@ static inline int fsnotify_name(__u32 mask, const void *data, int data_type, + static inline void fsnotify_dirent(struct inode *dir, struct dentry *dentry, + __u32 mask) + { +- fsnotify_name(mask, d_inode(dentry), FSNOTIFY_EVENT_INODE, +- dir, &dentry->d_name, 0); ++ fsnotify_name(mask, dentry, FSNOTIFY_EVENT_DENTRY, dir, &dentry->d_name, 0); + } + + static inline void fsnotify_inode(struct inode *inode, __u32 mask) +@@ -87,7 +86,7 @@ static inline int fsnotify_parent(struct dentry *dentry, __u32 mask, + */ + static inline void fsnotify_dentry(struct dentry *dentry, __u32 mask) + { +- fsnotify_parent(dentry, mask, d_inode(dentry), FSNOTIFY_EVENT_INODE); ++ fsnotify_parent(dentry, mask, dentry, FSNOTIFY_EVENT_DENTRY); + } + + static inline int fsnotify_file(struct file *file, __u32 mask) +diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h +index 1ce66748a2d29..a2db821e8a8f2 100644 +--- a/include/linux/fsnotify_backend.h ++++ b/include/linux/fsnotify_backend.h +@@ -248,6 +248,7 @@ enum fsnotify_data_type { + FSNOTIFY_EVENT_NONE, + FSNOTIFY_EVENT_PATH, + FSNOTIFY_EVENT_INODE, ++ FSNOTIFY_EVENT_DENTRY, + }; + + static inline struct inode *fsnotify_data_inode(const void *data, int data_type) +@@ -255,6 +256,8 @@ static inline struct inode *fsnotify_data_inode(const void *data, int data_type) + switch (data_type) { + case FSNOTIFY_EVENT_INODE: + return (struct inode *)data; ++ case FSNOTIFY_EVENT_DENTRY: ++ return d_inode(data); + case FSNOTIFY_EVENT_PATH: + return d_inode(((const struct path *)data)->dentry); + default: +@@ -262,6 +265,19 @@ static inline struct inode *fsnotify_data_inode(const void *data, int data_type) + } + } + ++static inline struct dentry *fsnotify_data_dentry(const void *data, int data_type) ++{ ++ switch (data_type) { ++ case FSNOTIFY_EVENT_DENTRY: ++ /* Non const is needed for dget() */ ++ return (struct dentry *)data; ++ case FSNOTIFY_EVENT_PATH: ++ return ((const struct path *)data)->dentry; ++ default: ++ return NULL; ++ } ++} ++ + static inline const struct path *fsnotify_data_path(const void *data, + int data_type) + { +-- +2.43.0 + diff --git a/queue-5.10/fsnotify-pass-flags-argument-to-fsnotify_alloc_group.patch b/queue-5.10/fsnotify-pass-flags-argument-to-fsnotify_alloc_group.patch new file mode 100644 index 00000000000..f510cfcba07 --- /dev/null +++ b/queue-5.10/fsnotify-pass-flags-argument-to-fsnotify_alloc_group.patch @@ -0,0 +1,207 @@ +From 90c35e8ebf66a14d51f1145c40d8c05977f63cec Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 Apr 2022 15:03:15 +0300 +Subject: fsnotify: pass flags argument to fsnotify_alloc_group() + +From: Amir Goldstein + +[ Upstream commit 867a448d587e7fa845bceaf4ee1c632448f2a9fa ] + +Add flags argument to fsnotify_alloc_group(), define and use the flag +FSNOTIFY_GROUP_USER in inotify and fanotify instead of the helper +fsnotify_alloc_user_group() to indicate user allocation. + +Although the flag FSNOTIFY_GROUP_USER is currently not used after group +allocation, we store the flags argument in the group struct for future +use of other group flags. + +Link: https://lore.kernel.org/r/20220422120327.3459282-5-amir73il@gmail.com +Signed-off-by: Amir Goldstein +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 3 ++- + fs/notify/dnotify/dnotify.c | 2 +- + fs/notify/fanotify/fanotify_user.c | 3 ++- + fs/notify/group.c | 21 +++++++++------------ + fs/notify/inotify/inotify_user.c | 3 ++- + include/linux/fsnotify_backend.h | 8 ++++++-- + kernel/audit_fsnotify.c | 3 ++- + kernel/audit_tree.c | 2 +- + kernel/audit_watch.c | 2 +- + 9 files changed, 26 insertions(+), 21 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index 8f7ed5dbb0031..7ae2b6611fb29 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -677,7 +677,8 @@ nfsd_file_cache_init(void) + goto out_shrinker; + } + +- nfsd_file_fsnotify_group = fsnotify_alloc_group(&nfsd_file_fsnotify_ops); ++ nfsd_file_fsnotify_group = fsnotify_alloc_group(&nfsd_file_fsnotify_ops, ++ 0); + if (IS_ERR(nfsd_file_fsnotify_group)) { + pr_err("nfsd: unable to create fsnotify group: %ld\n", + PTR_ERR(nfsd_file_fsnotify_group)); +diff --git a/fs/notify/dnotify/dnotify.c b/fs/notify/dnotify/dnotify.c +index d5ebebb034ffe..6c586802c50e6 100644 +--- a/fs/notify/dnotify/dnotify.c ++++ b/fs/notify/dnotify/dnotify.c +@@ -383,7 +383,7 @@ static int __init dnotify_init(void) + SLAB_PANIC|SLAB_ACCOUNT); + dnotify_mark_cache = KMEM_CACHE(dnotify_mark, SLAB_PANIC|SLAB_ACCOUNT); + +- dnotify_group = fsnotify_alloc_group(&dnotify_fsnotify_ops); ++ dnotify_group = fsnotify_alloc_group(&dnotify_fsnotify_ops, 0); + if (IS_ERR(dnotify_group)) + panic("unable to allocate fsnotify group for dnotify\n"); + return 0; +diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c +index 921ee7b08580d..731bd7f64e018 100644 +--- a/fs/notify/fanotify/fanotify_user.c ++++ b/fs/notify/fanotify/fanotify_user.c +@@ -1343,7 +1343,8 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) + f_flags |= O_NONBLOCK; + + /* fsnotify_alloc_group takes a ref. Dropped in fanotify_release */ +- group = fsnotify_alloc_user_group(&fanotify_fsnotify_ops); ++ group = fsnotify_alloc_group(&fanotify_fsnotify_ops, ++ FSNOTIFY_GROUP_USER); + if (IS_ERR(group)) { + return PTR_ERR(group); + } +diff --git a/fs/notify/group.c b/fs/notify/group.c +index b7d4d64f87c29..18446b7b0d495 100644 +--- a/fs/notify/group.c ++++ b/fs/notify/group.c +@@ -112,7 +112,8 @@ void fsnotify_put_group(struct fsnotify_group *group) + EXPORT_SYMBOL_GPL(fsnotify_put_group); + + static struct fsnotify_group *__fsnotify_alloc_group( +- const struct fsnotify_ops *ops, gfp_t gfp) ++ const struct fsnotify_ops *ops, ++ int flags, gfp_t gfp) + { + struct fsnotify_group *group; + +@@ -133,6 +134,7 @@ static struct fsnotify_group *__fsnotify_alloc_group( + INIT_LIST_HEAD(&group->marks_list); + + group->ops = ops; ++ group->flags = flags; + + return group; + } +@@ -140,20 +142,15 @@ static struct fsnotify_group *__fsnotify_alloc_group( + /* + * Create a new fsnotify_group and hold a reference for the group returned. + */ +-struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops) ++struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops, ++ int flags) + { +- return __fsnotify_alloc_group(ops, GFP_KERNEL); +-} +-EXPORT_SYMBOL_GPL(fsnotify_alloc_group); ++ gfp_t gfp = (flags & FSNOTIFY_GROUP_USER) ? GFP_KERNEL_ACCOUNT : ++ GFP_KERNEL; + +-/* +- * Create a new fsnotify_group and hold a reference for the group returned. +- */ +-struct fsnotify_group *fsnotify_alloc_user_group(const struct fsnotify_ops *ops) +-{ +- return __fsnotify_alloc_group(ops, GFP_KERNEL_ACCOUNT); ++ return __fsnotify_alloc_group(ops, flags, gfp); + } +-EXPORT_SYMBOL_GPL(fsnotify_alloc_user_group); ++EXPORT_SYMBOL_GPL(fsnotify_alloc_group); + + int fsnotify_fasync(int fd, struct file *file, int on) + { +diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c +index 861147e574581..9e1cf8392385a 100644 +--- a/fs/notify/inotify/inotify_user.c ++++ b/fs/notify/inotify/inotify_user.c +@@ -643,7 +643,8 @@ static struct fsnotify_group *inotify_new_group(unsigned int max_events) + struct fsnotify_group *group; + struct inotify_event_info *oevent; + +- group = fsnotify_alloc_user_group(&inotify_fsnotify_ops); ++ group = fsnotify_alloc_group(&inotify_fsnotify_ops, ++ FSNOTIFY_GROUP_USER); + if (IS_ERR(group)) + return group; + +diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h +index b1c72edd97845..f0bf557af0091 100644 +--- a/include/linux/fsnotify_backend.h ++++ b/include/linux/fsnotify_backend.h +@@ -210,6 +210,9 @@ struct fsnotify_group { + unsigned int priority; + bool shutdown; /* group is being shut down, don't queue more events */ + ++#define FSNOTIFY_GROUP_USER 0x01 /* user allocated group */ ++ int flags; ++ + /* stores all fastpath marks assoc with this group so they can be cleaned on unregister */ + struct mutex mark_mutex; /* protect marks_list */ + atomic_t user_waits; /* Number of tasks waiting for user +@@ -543,8 +546,9 @@ static inline void fsnotify_update_flags(struct dentry *dentry) + /* called from fsnotify listeners, such as fanotify or dnotify */ + + /* create a new group */ +-extern struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops); +-extern struct fsnotify_group *fsnotify_alloc_user_group(const struct fsnotify_ops *ops); ++extern struct fsnotify_group *fsnotify_alloc_group( ++ const struct fsnotify_ops *ops, ++ int flags); + /* get reference to a group */ + extern void fsnotify_get_group(struct fsnotify_group *group); + /* drop reference on a group from fsnotify_alloc_group */ +diff --git a/kernel/audit_fsnotify.c b/kernel/audit_fsnotify.c +index 76a5925b4e18d..31f43b1475404 100644 +--- a/kernel/audit_fsnotify.c ++++ b/kernel/audit_fsnotify.c +@@ -182,7 +182,8 @@ static const struct fsnotify_ops audit_mark_fsnotify_ops = { + + static int __init audit_fsnotify_init(void) + { +- audit_fsnotify_group = fsnotify_alloc_group(&audit_mark_fsnotify_ops); ++ audit_fsnotify_group = fsnotify_alloc_group(&audit_mark_fsnotify_ops, ++ 0); + if (IS_ERR(audit_fsnotify_group)) { + audit_fsnotify_group = NULL; + audit_panic("cannot create audit fsnotify group"); +diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c +index 39241207ec044..0c35879bbf7c3 100644 +--- a/kernel/audit_tree.c ++++ b/kernel/audit_tree.c +@@ -1077,7 +1077,7 @@ static int __init audit_tree_init(void) + + audit_tree_mark_cachep = KMEM_CACHE(audit_tree_mark, SLAB_PANIC); + +- audit_tree_group = fsnotify_alloc_group(&audit_tree_ops); ++ audit_tree_group = fsnotify_alloc_group(&audit_tree_ops, 0); + if (IS_ERR(audit_tree_group)) + audit_panic("cannot initialize fsnotify group for rectree watches"); + +diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c +index fd7b30a2d9a4b..5cf22fe301493 100644 +--- a/kernel/audit_watch.c ++++ b/kernel/audit_watch.c +@@ -492,7 +492,7 @@ static const struct fsnotify_ops audit_watch_fsnotify_ops = { + + static int __init audit_watch_init(void) + { +- audit_watch_group = fsnotify_alloc_group(&audit_watch_fsnotify_ops); ++ audit_watch_group = fsnotify_alloc_group(&audit_watch_fsnotify_ops, 0); + if (IS_ERR(audit_watch_group)) { + audit_watch_group = NULL; + audit_panic("cannot create audit fsnotify group"); +-- +2.43.0 + diff --git a/queue-5.10/fsnotify-pass-group-argument-to-free_event.patch b/queue-5.10/fsnotify-pass-group-argument-to-free_event.patch new file mode 100644 index 00000000000..95ab24e00ec --- /dev/null +++ b/queue-5.10/fsnotify-pass-group-argument-to-free_event.patch @@ -0,0 +1,98 @@ +From 16b3de404109609dea2c127faa12b7b9724f4948 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 Oct 2021 16:27:27 -0300 +Subject: fsnotify: Pass group argument to free_event + +From: Gabriel Krisman Bertazi + +[ Upstream commit 330ae77d2a5b0af32c0f29e139bf28ec8591de59 ] + +For group-wide mempool backed events, like FS_ERROR, the free_event +callback will need to reference the group's mempool to free the memory. +Wire that argument into the current callers. + +Link: https://lore.kernel.org/r/20211025192746.66445-13-krisman@collabora.com +Reviewed-by: Jan Kara +Reviewed-by: Amir Goldstein +Signed-off-by: Gabriel Krisman Bertazi +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify.c | 3 ++- + fs/notify/group.c | 2 +- + fs/notify/inotify/inotify_fsnotify.c | 3 ++- + fs/notify/notification.c | 2 +- + include/linux/fsnotify_backend.h | 2 +- + 5 files changed, 7 insertions(+), 5 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c +index f82e20228999c..c620b4f6fe123 100644 +--- a/fs/notify/fanotify/fanotify.c ++++ b/fs/notify/fanotify/fanotify.c +@@ -835,7 +835,8 @@ static void fanotify_free_name_event(struct fanotify_event *event) + kfree(FANOTIFY_NE(event)); + } + +-static void fanotify_free_event(struct fsnotify_event *fsn_event) ++static void fanotify_free_event(struct fsnotify_group *group, ++ struct fsnotify_event *fsn_event) + { + struct fanotify_event *event; + +diff --git a/fs/notify/group.c b/fs/notify/group.c +index fb89c351295d6..6a297efc47887 100644 +--- a/fs/notify/group.c ++++ b/fs/notify/group.c +@@ -88,7 +88,7 @@ void fsnotify_destroy_group(struct fsnotify_group *group) + * that deliberately ignores overflow events. + */ + if (group->overflow_event) +- group->ops->free_event(group->overflow_event); ++ group->ops->free_event(group, group->overflow_event); + + fsnotify_put_group(group); + } +diff --git a/fs/notify/inotify/inotify_fsnotify.c b/fs/notify/inotify/inotify_fsnotify.c +index be3eb1cebdcce..8279827836399 100644 +--- a/fs/notify/inotify/inotify_fsnotify.c ++++ b/fs/notify/inotify/inotify_fsnotify.c +@@ -184,7 +184,8 @@ static void inotify_free_group_priv(struct fsnotify_group *group) + dec_inotify_instances(group->inotify_data.ucounts); + } + +-static void inotify_free_event(struct fsnotify_event *fsn_event) ++static void inotify_free_event(struct fsnotify_group *group, ++ struct fsnotify_event *fsn_event) + { + kfree(INOTIFY_E(fsn_event)); + } +diff --git a/fs/notify/notification.c b/fs/notify/notification.c +index 44bb10f507153..9022ae650cf86 100644 +--- a/fs/notify/notification.c ++++ b/fs/notify/notification.c +@@ -64,7 +64,7 @@ void fsnotify_destroy_event(struct fsnotify_group *group, + WARN_ON(!list_empty(&event->list)); + spin_unlock(&group->notification_lock); + } +- group->ops->free_event(event); ++ group->ops->free_event(group, event); + } + + /* +diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h +index b71dc788018e4..3a7c314361824 100644 +--- a/include/linux/fsnotify_backend.h ++++ b/include/linux/fsnotify_backend.h +@@ -156,7 +156,7 @@ struct fsnotify_ops { + const struct qstr *file_name, u32 cookie); + void (*free_group_priv)(struct fsnotify_group *group); + void (*freeing_mark)(struct fsnotify_mark *mark, struct fsnotify_group *group); +- void (*free_event)(struct fsnotify_event *event); ++ void (*free_event)(struct fsnotify_group *group, struct fsnotify_event *event); + /* called on final put+free to free memory */ + void (*free_mark)(struct fsnotify_mark *mark); + }; +-- +2.43.0 + diff --git a/queue-5.10/fsnotify-protect-fsnotify_handle_inode_event-from-no.patch b/queue-5.10/fsnotify-protect-fsnotify_handle_inode_event-from-no.patch new file mode 100644 index 00000000000..d2453186eec --- /dev/null +++ b/queue-5.10/fsnotify-protect-fsnotify_handle_inode_event-from-no.patch @@ -0,0 +1,72 @@ +From e64fc7bc1e6ddb32f490e2560fc2e373660f2492 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 Oct 2021 16:27:26 -0300 +Subject: fsnotify: Protect fsnotify_handle_inode_event from no-inode events + +From: Gabriel Krisman Bertazi + +[ Upstream commit 24dca90590509a7a6cbe0650100c90c5b8a3468a ] + +FAN_FS_ERROR allows events without inodes - i.e. for file system-wide +errors. Even though fsnotify_handle_inode_event is not currently used +by fanotify, this patch protects other backends from cases where neither +inode or dir are provided. Also document the constraints of the +interface (inode and dir cannot be both NULL). + +Link: https://lore.kernel.org/r/20211025192746.66445-12-krisman@collabora.com +Suggested-by: Amir Goldstein +Signed-off-by: Gabriel Krisman Bertazi +Reviewed-by: Amir Goldstein +Reviewed-by: Jan Kara +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 3 +++ + fs/notify/fsnotify.c | 3 +++ + include/linux/fsnotify_backend.h | 1 + + 3 files changed, 7 insertions(+) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index 87d984e0cdc0c..8cd7d5d6955a0 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -601,6 +601,9 @@ nfsd_file_fsnotify_handle_event(struct fsnotify_mark *mark, u32 mask, + struct inode *inode, struct inode *dir, + const struct qstr *name, u32 cookie) + { ++ if (WARN_ON_ONCE(!inode)) ++ return 0; ++ + trace_nfsd_file_fsnotify_handle_event(inode, mask); + + /* Should be no marks on non-regular files */ +diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c +index fde3a1115a170..4034ca566f95c 100644 +--- a/fs/notify/fsnotify.c ++++ b/fs/notify/fsnotify.c +@@ -252,6 +252,9 @@ static int fsnotify_handle_inode_event(struct fsnotify_group *group, + if (WARN_ON_ONCE(!ops->handle_inode_event)) + return 0; + ++ if (WARN_ON_ONCE(!inode && !dir)) ++ return 0; ++ + if ((inode_mark->mask & FS_EXCL_UNLINK) && + path && d_unlinked(path->dentry)) + return 0; +diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h +index 035438fe4a435..b71dc788018e4 100644 +--- a/include/linux/fsnotify_backend.h ++++ b/include/linux/fsnotify_backend.h +@@ -136,6 +136,7 @@ struct mem_cgroup; + * @dir: optional directory associated with event - + * if @file_name is not NULL, this is the directory that + * @file_name is relative to. ++ * Either @inode or @dir must be non-NULL. + * @file_name: optional file name associated with event + * @cookie: inotify rename cookie + * +-- +2.43.0 + diff --git a/queue-5.10/fsnotify-remove-redundant-parameter-judgment.patch b/queue-5.10/fsnotify-remove-redundant-parameter-judgment.patch new file mode 100644 index 00000000000..6b522d5d8fa --- /dev/null +++ b/queue-5.10/fsnotify-remove-redundant-parameter-judgment.patch @@ -0,0 +1,48 @@ +From e5d4e2e83a2e308eadc667cffaddeaeac3c22caf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 11 Mar 2022 23:12:40 +0800 +Subject: fsnotify: remove redundant parameter judgment + +From: Bang Li + +[ Upstream commit f92ca72b0263d601807bbd23ed25cbe6f4da89f4 ] + +iput() has already judged the incoming parameter, so there is no need to +repeat the judgment here. + +Link: https://lore.kernel.org/r/20220311151240.62045-1-libang.linuxer@gmail.com +Signed-off-by: Bang Li +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fsnotify.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c +index 494f653efbc6e..70a8516b78bc5 100644 +--- a/fs/notify/fsnotify.c ++++ b/fs/notify/fsnotify.c +@@ -70,8 +70,7 @@ static void fsnotify_unmount_inodes(struct super_block *sb) + spin_unlock(&inode->i_lock); + spin_unlock(&sb->s_inode_list_lock); + +- if (iput_inode) +- iput(iput_inode); ++ iput(iput_inode); + + /* for each watch, send FS_UNMOUNT and then remove it */ + fsnotify_inode(inode, FS_UNMOUNT); +@@ -85,8 +84,7 @@ static void fsnotify_unmount_inodes(struct super_block *sb) + } + spin_unlock(&sb->s_inode_list_lock); + +- if (iput_inode) +- iput(iput_inode); ++ iput(iput_inode); + } + + void fsnotify_sb_delete(struct super_block *sb) +-- +2.43.0 + diff --git a/queue-5.10/fsnotify-remove-unused-declaration.patch b/queue-5.10/fsnotify-remove-unused-declaration.patch new file mode 100644 index 00000000000..13d91e49e25 --- /dev/null +++ b/queue-5.10/fsnotify-remove-unused-declaration.patch @@ -0,0 +1,40 @@ +From 00fe6c27d4c86d7d9242c014154edc2ee08c74eb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Sep 2022 11:38:28 +0800 +Subject: fsnotify: remove unused declaration + +From: Gaosheng Cui + +[ Upstream commit f847c74d6e89f10926db58649a05b99237258691 ] + +fsnotify_alloc_event_holder() and fsnotify_destroy_event_holder() +has been removed since commit 7053aee26a35 ("fsnotify: do not share +events between notification groups"), so remove it. + +Reviewed-by: Ritesh Harjani (IBM) +Signed-off-by: Gaosheng Cui +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fsnotify.h | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/fs/notify/fsnotify.h b/fs/notify/fsnotify.h +index 87d8a50ee8038..fde74eb333cc9 100644 +--- a/fs/notify/fsnotify.h ++++ b/fs/notify/fsnotify.h +@@ -76,10 +76,6 @@ static inline void fsnotify_clear_marks_by_sb(struct super_block *sb) + */ + extern void __fsnotify_update_child_dentry_flags(struct inode *inode); + +-/* allocate and destroy and event holder to attach events to notification/access queues */ +-extern struct fsnotify_event_holder *fsnotify_alloc_event_holder(void); +-extern void fsnotify_destroy_event_holder(struct fsnotify_event_holder *holder); +- + extern struct kmem_cache *fsnotify_mark_connector_cachep; + + #endif /* __FS_NOTIFY_FSNOTIFY_H_ */ +-- +2.43.0 + diff --git a/queue-5.10/fsnotify-replace-igrab-with-ihold-on-attach-connecto.patch b/queue-5.10/fsnotify-replace-igrab-with-ihold-on-attach-connecto.patch new file mode 100644 index 00000000000..cbfdb0fd449 --- /dev/null +++ b/queue-5.10/fsnotify-replace-igrab-with-ihold-on-attach-connecto.patch @@ -0,0 +1,42 @@ +From 9e9faa98289c361324c9508f83eb20698e12ba10 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Aug 2021 18:12:17 +0300 +Subject: fsnotify: replace igrab() with ihold() on attach connector + +From: Amir Goldstein + +[ Upstream commit 09ddbe69c9925b42cb9529f60678c25b241d8b18 ] + +We must have a reference on inode, so ihold is cheaper. + +Link: https://lore.kernel.org/r/20210810151220.285179-2-amir73il@gmail.com +Reviewed-by: Matthew Bobrowski +Signed-off-by: Amir Goldstein +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/mark.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/fs/notify/mark.c b/fs/notify/mark.c +index 7af98a7c33c27..3c8fc77d3f072 100644 +--- a/fs/notify/mark.c ++++ b/fs/notify/mark.c +@@ -493,8 +493,11 @@ static int fsnotify_attach_connector_to_object(fsnotify_connp_t *connp, + conn->fsid.val[0] = conn->fsid.val[1] = 0; + conn->flags = 0; + } +- if (conn->type == FSNOTIFY_OBJ_TYPE_INODE) +- inode = igrab(fsnotify_conn_inode(conn)); ++ if (conn->type == FSNOTIFY_OBJ_TYPE_INODE) { ++ inode = fsnotify_conn_inode(conn); ++ ihold(inode); ++ } ++ + /* + * cmpxchg() provides the barrier so that readers of *connp can see + * only initialized structure +-- +2.43.0 + diff --git a/queue-5.10/fsnotify-retrieve-super-block-from-the-data-field.patch b/queue-5.10/fsnotify-retrieve-super-block-from-the-data-field.patch new file mode 100644 index 00000000000..9f78b34c88f --- /dev/null +++ b/queue-5.10/fsnotify-retrieve-super-block-from-the-data-field.patch @@ -0,0 +1,89 @@ +From 17b62abc478bac5394edbbbdd8a8511ddb150547 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 Oct 2021 16:27:25 -0300 +Subject: fsnotify: Retrieve super block from the data field + +From: Gabriel Krisman Bertazi + +[ Upstream commit 29335033c574a15334015d8c4e36862cff3d3384 ] + +Some file system events (i.e. FS_ERROR) might not be associated with an +inode or directory. For these, we can retrieve the super block from the +data field. But, since the super_block is available in the data field +on every event type, simplify the code to always retrieve it from there, +through a new helper. + +Link: https://lore.kernel.org/r/20211025192746.66445-11-krisman@collabora.com +Suggested-by: Jan Kara +Reviewed-by: Amir Goldstein +Reviewed-by: Jan Kara +Signed-off-by: Gabriel Krisman Bertazi +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fsnotify.c | 7 +++---- + include/linux/fsnotify_backend.h | 15 +++++++++++++++ + 2 files changed, 18 insertions(+), 4 deletions(-) + +diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c +index 963e6ce75b961..fde3a1115a170 100644 +--- a/fs/notify/fsnotify.c ++++ b/fs/notify/fsnotify.c +@@ -455,16 +455,16 @@ static void fsnotify_iter_next(struct fsnotify_iter_info *iter_info) + * @file_name is relative to + * @file_name: optional file name associated with event + * @inode: optional inode associated with event - +- * either @dir or @inode must be non-NULL. +- * if both are non-NULL event may be reported to both. ++ * If @dir and @inode are both non-NULL, event may be ++ * reported to both. + * @cookie: inotify rename cookie + */ + int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir, + const struct qstr *file_name, struct inode *inode, u32 cookie) + { + const struct path *path = fsnotify_data_path(data, data_type); ++ struct super_block *sb = fsnotify_data_sb(data, data_type); + struct fsnotify_iter_info iter_info = {}; +- struct super_block *sb; + struct mount *mnt = NULL; + struct inode *parent = NULL; + int ret = 0; +@@ -483,7 +483,6 @@ int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir, + */ + parent = dir; + } +- sb = inode->i_sb; + + /* + * Optimization: srcu_read_lock() has a memory barrier which can +diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h +index b323d0c4b9671..035438fe4a435 100644 +--- a/include/linux/fsnotify_backend.h ++++ b/include/linux/fsnotify_backend.h +@@ -289,6 +289,21 @@ static inline const struct path *fsnotify_data_path(const void *data, + } + } + ++static inline struct super_block *fsnotify_data_sb(const void *data, ++ int data_type) ++{ ++ switch (data_type) { ++ case FSNOTIFY_EVENT_INODE: ++ return ((struct inode *)data)->i_sb; ++ case FSNOTIFY_EVENT_DENTRY: ++ return ((struct dentry *)data)->d_sb; ++ case FSNOTIFY_EVENT_PATH: ++ return ((const struct path *)data)->dentry->d_sb; ++ default: ++ return NULL; ++ } ++} ++ + enum fsnotify_obj_type { + FSNOTIFY_OBJ_TYPE_INODE, + FSNOTIFY_OBJ_TYPE_PARENT, +-- +2.43.0 + diff --git a/queue-5.10/fsnotify-separate-mark-iterator-type-from-object-typ.patch b/queue-5.10/fsnotify-separate-mark-iterator-type-from-object-typ.patch new file mode 100644 index 00000000000..309e09a253a --- /dev/null +++ b/queue-5.10/fsnotify-separate-mark-iterator-type-from-object-typ.patch @@ -0,0 +1,247 @@ +From 814dc91c2387e740fd0a9ba51ad68962b0f8052e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Nov 2021 22:15:28 +0200 +Subject: fsnotify: separate mark iterator type from object type enum + +From: Amir Goldstein + +[ Upstream commit 1c9007d62bea6fd164285314f7553f73e5308863 ] + +They are two different types that use the same enum, so this confusing. + +Use the object type to indicate the type of object mark is attached to +and the iter type to indicate the type of watch. + +A group can have two different watches of the same object type (parent +and child watches) that match the same event. + +Link: https://lore.kernel.org/r/20211129201537.1932819-3-amir73il@gmail.com +Signed-off-by: Amir Goldstein +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify.c | 6 ++--- + fs/notify/fsnotify.c | 18 +++++++------- + fs/notify/mark.c | 4 ++-- + include/linux/fsnotify_backend.h | 41 ++++++++++++++++++++++---------- + 4 files changed, 42 insertions(+), 27 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c +index b6091775aa6ef..652fe84cb8acd 100644 +--- a/fs/notify/fanotify/fanotify.c ++++ b/fs/notify/fanotify/fanotify.c +@@ -299,7 +299,7 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group, + return 0; + } + +- fsnotify_foreach_obj_type(type) { ++ fsnotify_foreach_iter_type(type) { + if (!fsnotify_iter_should_report_type(iter_info, type)) + continue; + mark = iter_info->marks[type]; +@@ -318,7 +318,7 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group, + * If the event is on a child and this mark is on a parent not + * watching children, don't send it! + */ +- if (type == FSNOTIFY_OBJ_TYPE_PARENT && ++ if (type == FSNOTIFY_ITER_TYPE_PARENT && + !(mark->mask & FS_EVENT_ON_CHILD)) + continue; + +@@ -746,7 +746,7 @@ static __kernel_fsid_t fanotify_get_fsid(struct fsnotify_iter_info *iter_info) + int type; + __kernel_fsid_t fsid = {}; + +- fsnotify_foreach_obj_type(type) { ++ fsnotify_foreach_iter_type(type) { + struct fsnotify_mark_connector *conn; + + if (!fsnotify_iter_should_report_type(iter_info, type)) +diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c +index 4034ca566f95c..0c94457c625e2 100644 +--- a/fs/notify/fsnotify.c ++++ b/fs/notify/fsnotify.c +@@ -330,7 +330,7 @@ static int send_to_group(__u32 mask, const void *data, int data_type, + + /* clear ignored on inode modification */ + if (mask & FS_MODIFY) { +- fsnotify_foreach_obj_type(type) { ++ fsnotify_foreach_iter_type(type) { + if (!fsnotify_iter_should_report_type(iter_info, type)) + continue; + mark = iter_info->marks[type]; +@@ -340,7 +340,7 @@ static int send_to_group(__u32 mask, const void *data, int data_type, + } + } + +- fsnotify_foreach_obj_type(type) { ++ fsnotify_foreach_iter_type(type) { + if (!fsnotify_iter_should_report_type(iter_info, type)) + continue; + mark = iter_info->marks[type]; +@@ -405,7 +405,7 @@ static unsigned int fsnotify_iter_select_report_types( + int type; + + /* Choose max prio group among groups of all queue heads */ +- fsnotify_foreach_obj_type(type) { ++ fsnotify_foreach_iter_type(type) { + mark = iter_info->marks[type]; + if (mark && + fsnotify_compare_groups(max_prio_group, mark->group) > 0) +@@ -417,7 +417,7 @@ static unsigned int fsnotify_iter_select_report_types( + + /* Set the report mask for marks from same group as max prio group */ + iter_info->report_mask = 0; +- fsnotify_foreach_obj_type(type) { ++ fsnotify_foreach_iter_type(type) { + mark = iter_info->marks[type]; + if (mark && + fsnotify_compare_groups(max_prio_group, mark->group) == 0) +@@ -435,7 +435,7 @@ static void fsnotify_iter_next(struct fsnotify_iter_info *iter_info) + { + int type; + +- fsnotify_foreach_obj_type(type) { ++ fsnotify_foreach_iter_type(type) { + if (fsnotify_iter_should_report_type(iter_info, type)) + iter_info->marks[type] = + fsnotify_next_mark(iter_info->marks[type]); +@@ -519,18 +519,18 @@ int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir, + + iter_info.srcu_idx = srcu_read_lock(&fsnotify_mark_srcu); + +- iter_info.marks[FSNOTIFY_OBJ_TYPE_SB] = ++ iter_info.marks[FSNOTIFY_ITER_TYPE_SB] = + fsnotify_first_mark(&sb->s_fsnotify_marks); + if (mnt) { +- iter_info.marks[FSNOTIFY_OBJ_TYPE_VFSMOUNT] = ++ iter_info.marks[FSNOTIFY_ITER_TYPE_VFSMOUNT] = + fsnotify_first_mark(&mnt->mnt_fsnotify_marks); + } + if (inode) { +- iter_info.marks[FSNOTIFY_OBJ_TYPE_INODE] = ++ iter_info.marks[FSNOTIFY_ITER_TYPE_INODE] = + fsnotify_first_mark(&inode->i_fsnotify_marks); + } + if (parent) { +- iter_info.marks[FSNOTIFY_OBJ_TYPE_PARENT] = ++ iter_info.marks[FSNOTIFY_ITER_TYPE_PARENT] = + fsnotify_first_mark(&parent->i_fsnotify_marks); + } + +diff --git a/fs/notify/mark.c b/fs/notify/mark.c +index 7c0946e16918a..b42629d2fc1c6 100644 +--- a/fs/notify/mark.c ++++ b/fs/notify/mark.c +@@ -353,7 +353,7 @@ bool fsnotify_prepare_user_wait(struct fsnotify_iter_info *iter_info) + { + int type; + +- fsnotify_foreach_obj_type(type) { ++ fsnotify_foreach_iter_type(type) { + /* This can fail if mark is being removed */ + if (!fsnotify_get_mark_safe(iter_info->marks[type])) { + __release(&fsnotify_mark_srcu); +@@ -382,7 +382,7 @@ void fsnotify_finish_user_wait(struct fsnotify_iter_info *iter_info) + int type; + + iter_info->srcu_idx = srcu_read_lock(&fsnotify_mark_srcu); +- fsnotify_foreach_obj_type(type) ++ fsnotify_foreach_iter_type(type) + fsnotify_put_mark_wake(iter_info->marks[type]); + } + +diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h +index b9c84b1dbcc8f..73739fee1710f 100644 +--- a/include/linux/fsnotify_backend.h ++++ b/include/linux/fsnotify_backend.h +@@ -337,10 +337,25 @@ static inline struct fs_error_report *fsnotify_data_error_report( + } + } + ++/* ++ * Index to merged marks iterator array that correlates to a type of watch. ++ * The type of watched object can be deduced from the iterator type, but not ++ * the other way around, because an event can match different watched objects ++ * of the same object type. ++ * For example, both parent and child are watching an object of type inode. ++ */ ++enum fsnotify_iter_type { ++ FSNOTIFY_ITER_TYPE_INODE, ++ FSNOTIFY_ITER_TYPE_VFSMOUNT, ++ FSNOTIFY_ITER_TYPE_SB, ++ FSNOTIFY_ITER_TYPE_PARENT, ++ FSNOTIFY_ITER_TYPE_COUNT ++}; ++ ++/* The type of object that a mark is attached to */ + enum fsnotify_obj_type { + FSNOTIFY_OBJ_TYPE_ANY = -1, + FSNOTIFY_OBJ_TYPE_INODE, +- FSNOTIFY_OBJ_TYPE_PARENT, + FSNOTIFY_OBJ_TYPE_VFSMOUNT, + FSNOTIFY_OBJ_TYPE_SB, + FSNOTIFY_OBJ_TYPE_COUNT, +@@ -353,37 +368,37 @@ static inline bool fsnotify_valid_obj_type(unsigned int obj_type) + } + + struct fsnotify_iter_info { +- struct fsnotify_mark *marks[FSNOTIFY_OBJ_TYPE_COUNT]; ++ struct fsnotify_mark *marks[FSNOTIFY_ITER_TYPE_COUNT]; + unsigned int report_mask; + int srcu_idx; + }; + + static inline bool fsnotify_iter_should_report_type( +- struct fsnotify_iter_info *iter_info, int type) ++ struct fsnotify_iter_info *iter_info, int iter_type) + { +- return (iter_info->report_mask & (1U << type)); ++ return (iter_info->report_mask & (1U << iter_type)); + } + + static inline void fsnotify_iter_set_report_type( +- struct fsnotify_iter_info *iter_info, int type) ++ struct fsnotify_iter_info *iter_info, int iter_type) + { +- iter_info->report_mask |= (1U << type); ++ iter_info->report_mask |= (1U << iter_type); + } + + static inline void fsnotify_iter_set_report_type_mark( +- struct fsnotify_iter_info *iter_info, int type, ++ struct fsnotify_iter_info *iter_info, int iter_type, + struct fsnotify_mark *mark) + { +- iter_info->marks[type] = mark; +- iter_info->report_mask |= (1U << type); ++ iter_info->marks[iter_type] = mark; ++ iter_info->report_mask |= (1U << iter_type); + } + + #define FSNOTIFY_ITER_FUNCS(name, NAME) \ + static inline struct fsnotify_mark *fsnotify_iter_##name##_mark( \ + struct fsnotify_iter_info *iter_info) \ + { \ +- return (iter_info->report_mask & (1U << FSNOTIFY_OBJ_TYPE_##NAME)) ? \ +- iter_info->marks[FSNOTIFY_OBJ_TYPE_##NAME] : NULL; \ ++ return (iter_info->report_mask & (1U << FSNOTIFY_ITER_TYPE_##NAME)) ? \ ++ iter_info->marks[FSNOTIFY_ITER_TYPE_##NAME] : NULL; \ + } + + FSNOTIFY_ITER_FUNCS(inode, INODE) +@@ -391,8 +406,8 @@ FSNOTIFY_ITER_FUNCS(parent, PARENT) + FSNOTIFY_ITER_FUNCS(vfsmount, VFSMOUNT) + FSNOTIFY_ITER_FUNCS(sb, SB) + +-#define fsnotify_foreach_obj_type(type) \ +- for (type = 0; type < FSNOTIFY_OBJ_TYPE_COUNT; type++) ++#define fsnotify_foreach_iter_type(type) \ ++ for (type = 0; type < FSNOTIFY_ITER_TYPE_COUNT; type++) + + /* + * fsnotify_connp_t is what we embed in objects which connector can be attached +-- +2.43.0 + diff --git a/queue-5.10/fsnotify-support-fs_error-event-type.patch b/queue-5.10/fsnotify-support-fs_error-event-type.patch new file mode 100644 index 00000000000..2b91e5193c6 --- /dev/null +++ b/queue-5.10/fsnotify-support-fs_error-event-type.patch @@ -0,0 +1,122 @@ +From c188e018d55c39d12f7a37873fdc6b7cd956ff18 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 Oct 2021 16:27:32 -0300 +Subject: fsnotify: Support FS_ERROR event type + +From: Gabriel Krisman Bertazi + +[ Upstream commit 9daa811073fa19c08e8aad3b90f9235fed161acf ] + +Expose a new type of fsnotify event for filesystems to report errors for +userspace monitoring tools. fanotify will send this type of +notification for FAN_FS_ERROR events. This also introduce a helper for +generating the new event. + +Link: https://lore.kernel.org/r/20211025192746.66445-18-krisman@collabora.com +Reviewed-by: Amir Goldstein +Reviewed-by: Jan Kara +Signed-off-by: Gabriel Krisman Bertazi +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + include/linux/fsnotify.h | 13 +++++++++++++ + include/linux/fsnotify_backend.h | 32 +++++++++++++++++++++++++++++++- + 2 files changed, 44 insertions(+), 1 deletion(-) + +diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h +index addca4ea56ad9..bec1e23ecf787 100644 +--- a/include/linux/fsnotify.h ++++ b/include/linux/fsnotify.h +@@ -376,4 +376,17 @@ static inline void fsnotify_change(struct dentry *dentry, unsigned int ia_valid) + fsnotify_dentry(dentry, mask); + } + ++static inline int fsnotify_sb_error(struct super_block *sb, struct inode *inode, ++ int error) ++{ ++ struct fs_error_report report = { ++ .error = error, ++ .inode = inode, ++ .sb = sb, ++ }; ++ ++ return fsnotify(FS_ERROR, &report, FSNOTIFY_EVENT_ERROR, ++ NULL, NULL, NULL, 0); ++} ++ + #endif /* _LINUX_FS_NOTIFY_H */ +diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h +index 3a7c314361824..00dbaafbcf953 100644 +--- a/include/linux/fsnotify_backend.h ++++ b/include/linux/fsnotify_backend.h +@@ -42,6 +42,12 @@ + + #define FS_UNMOUNT 0x00002000 /* inode on umount fs */ + #define FS_Q_OVERFLOW 0x00004000 /* Event queued overflowed */ ++#define FS_ERROR 0x00008000 /* Filesystem Error (fanotify) */ ++ ++/* ++ * FS_IN_IGNORED overloads FS_ERROR. It is only used internally by inotify ++ * which does not support FS_ERROR. ++ */ + #define FS_IN_IGNORED 0x00008000 /* last inotify event here */ + + #define FS_OPEN_PERM 0x00010000 /* open event in an permission hook */ +@@ -95,7 +101,8 @@ + #define ALL_FSNOTIFY_EVENTS (ALL_FSNOTIFY_DIRENT_EVENTS | \ + FS_EVENTS_POSS_ON_CHILD | \ + FS_DELETE_SELF | FS_MOVE_SELF | FS_DN_RENAME | \ +- FS_UNMOUNT | FS_Q_OVERFLOW | FS_IN_IGNORED) ++ FS_UNMOUNT | FS_Q_OVERFLOW | FS_IN_IGNORED | \ ++ FS_ERROR) + + /* Extra flags that may be reported with event or control handling of events */ + #define ALL_FSNOTIFY_FLAGS (FS_EXCL_UNLINK | FS_ISDIR | FS_IN_ONESHOT | \ +@@ -250,6 +257,13 @@ enum fsnotify_data_type { + FSNOTIFY_EVENT_PATH, + FSNOTIFY_EVENT_INODE, + FSNOTIFY_EVENT_DENTRY, ++ FSNOTIFY_EVENT_ERROR, ++}; ++ ++struct fs_error_report { ++ int error; ++ struct inode *inode; ++ struct super_block *sb; + }; + + static inline struct inode *fsnotify_data_inode(const void *data, int data_type) +@@ -261,6 +275,8 @@ static inline struct inode *fsnotify_data_inode(const void *data, int data_type) + return d_inode(data); + case FSNOTIFY_EVENT_PATH: + return d_inode(((const struct path *)data)->dentry); ++ case FSNOTIFY_EVENT_ERROR: ++ return ((struct fs_error_report *)data)->inode; + default: + return NULL; + } +@@ -300,6 +316,20 @@ static inline struct super_block *fsnotify_data_sb(const void *data, + return ((struct dentry *)data)->d_sb; + case FSNOTIFY_EVENT_PATH: + return ((const struct path *)data)->dentry->d_sb; ++ case FSNOTIFY_EVENT_ERROR: ++ return ((struct fs_error_report *) data)->sb; ++ default: ++ return NULL; ++ } ++} ++ ++static inline struct fs_error_report *fsnotify_data_error_report( ++ const void *data, ++ int data_type) ++{ ++ switch (data_type) { ++ case FSNOTIFY_EVENT_ERROR: ++ return (struct fs_error_report *) data; + default: + return NULL; + } +-- +2.43.0 + diff --git a/queue-5.10/fsnotify-use-hash-table-for-faster-events-merge.patch b/queue-5.10/fsnotify-use-hash-table-for-faster-events-merge.patch new file mode 100644 index 00000000000..c18d937eedb --- /dev/null +++ b/queue-5.10/fsnotify-use-hash-table-for-faster-events-merge.patch @@ -0,0 +1,359 @@ +From 9d868e21f98b60e14d0711bfc83b8bdec62b8373 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 4 Mar 2021 12:48:25 +0200 +Subject: fsnotify: use hash table for faster events merge + +From: Amir Goldstein + +[ Upstream commit 94e00d28a680dff18805ca472b191364347d2234 ] + +In order to improve event merge performance, hash events in a 128 size +hash table by the event merge key. + +The fanotify_event size grows by two pointers, but we just reduced its +size by removing the objectid member, so overall its size is increased +by one pointer. + +Permission events and overflow event are not merged so they are also +not hashed. + +Link: https://lore.kernel.org/r/20210304104826.3993892-5-amir73il@gmail.com +Signed-off-by: Amir Goldstein +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify.c | 40 +++++++++++++++++++++++----- + fs/notify/fanotify/fanotify.h | 25 +++++++++++++++++ + fs/notify/fanotify/fanotify_user.c | 39 +++++++++++++++++++++++++++ + fs/notify/inotify/inotify_fsnotify.c | 7 ++--- + fs/notify/notification.c | 22 ++++++++++----- + include/linux/fsnotify_backend.h | 10 ++++--- + 6 files changed, 123 insertions(+), 20 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c +index 43a606f153702..50b3abc062156 100644 +--- a/fs/notify/fanotify/fanotify.c ++++ b/fs/notify/fanotify/fanotify.c +@@ -149,12 +149,15 @@ static bool fanotify_should_merge(struct fanotify_event *old, + } + + /* and the list better be locked by something too! */ +-static int fanotify_merge(struct list_head *list, struct fsnotify_event *event) ++static int fanotify_merge(struct fsnotify_group *group, ++ struct fsnotify_event *event) + { +- struct fsnotify_event *test_event; + struct fanotify_event *old, *new = FANOTIFY_E(event); ++ unsigned int bucket = fanotify_event_hash_bucket(group, new); ++ struct hlist_head *hlist = &group->fanotify_data.merge_hash[bucket]; + +- pr_debug("%s: list=%p event=%p\n", __func__, list, event); ++ pr_debug("%s: group=%p event=%p bucket=%u\n", __func__, ++ group, event, bucket); + + /* + * Don't merge a permission event with any other event so that we know +@@ -164,8 +167,7 @@ static int fanotify_merge(struct list_head *list, struct fsnotify_event *event) + if (fanotify_is_perm_event(new->mask)) + return 0; + +- list_for_each_entry_reverse(test_event, list, list) { +- old = FANOTIFY_E(test_event); ++ hlist_for_each_entry(old, hlist, merge_list) { + if (fanotify_should_merge(old, new)) { + old->mask |= new->mask; + return 1; +@@ -203,8 +205,11 @@ static int fanotify_get_response(struct fsnotify_group *group, + return ret; + } + /* Event not yet reported? Just remove it. */ +- if (event->state == FAN_EVENT_INIT) ++ if (event->state == FAN_EVENT_INIT) { + fsnotify_remove_queued_event(group, &event->fae.fse); ++ /* Permission events are not supposed to be hashed */ ++ WARN_ON_ONCE(!hlist_unhashed(&event->fae.merge_list)); ++ } + /* + * Event may be also answered in case signal delivery raced + * with wakeup. In that case we have nothing to do besides +@@ -679,6 +684,24 @@ static __kernel_fsid_t fanotify_get_fsid(struct fsnotify_iter_info *iter_info) + return fsid; + } + ++/* ++ * Add an event to hash table for faster merge. ++ */ ++static void fanotify_insert_event(struct fsnotify_group *group, ++ struct fsnotify_event *fsn_event) ++{ ++ struct fanotify_event *event = FANOTIFY_E(fsn_event); ++ unsigned int bucket = fanotify_event_hash_bucket(group, event); ++ struct hlist_head *hlist = &group->fanotify_data.merge_hash[bucket]; ++ ++ assert_spin_locked(&group->notification_lock); ++ ++ pr_debug("%s: group=%p event=%p bucket=%u\n", __func__, ++ group, event, bucket); ++ ++ hlist_add_head(&event->merge_list, hlist); ++} ++ + static int fanotify_handle_event(struct fsnotify_group *group, u32 mask, + const void *data, int data_type, + struct inode *dir, +@@ -749,7 +772,9 @@ static int fanotify_handle_event(struct fsnotify_group *group, u32 mask, + } + + fsn_event = &event->fse; +- ret = fsnotify_add_event(group, fsn_event, fanotify_merge); ++ ret = fsnotify_add_event(group, fsn_event, fanotify_merge, ++ fanotify_is_hashed_event(mask) ? ++ fanotify_insert_event : NULL); + if (ret) { + /* Permission events shouldn't be merged */ + BUG_ON(ret == 1 && mask & FANOTIFY_PERM_EVENTS); +@@ -772,6 +797,7 @@ static void fanotify_free_group_priv(struct fsnotify_group *group) + { + struct user_struct *user; + ++ kfree(group->fanotify_data.merge_hash); + user = group->fanotify_data.user; + atomic_dec(&user->fanotify_listeners); + free_uid(user); +diff --git a/fs/notify/fanotify/fanotify.h b/fs/notify/fanotify/fanotify.h +index 9871f76cd9c2c..4a5e555dc3d25 100644 +--- a/fs/notify/fanotify/fanotify.h ++++ b/fs/notify/fanotify/fanotify.h +@@ -3,6 +3,7 @@ + #include + #include + #include ++#include + + extern struct kmem_cache *fanotify_mark_cache; + extern struct kmem_cache *fanotify_fid_event_cachep; +@@ -150,6 +151,7 @@ enum fanotify_event_type { + + struct fanotify_event { + struct fsnotify_event fse; ++ struct hlist_node merge_list; /* List for hashed merge */ + u32 mask; + struct { + unsigned int type : FANOTIFY_EVENT_TYPE_BITS; +@@ -162,6 +164,7 @@ static inline void fanotify_init_event(struct fanotify_event *event, + unsigned int hash, u32 mask) + { + fsnotify_init_event(&event->fse); ++ INIT_HLIST_NODE(&event->merge_list); + event->hash = hash; + event->mask = mask; + event->pid = NULL; +@@ -299,3 +302,25 @@ static inline struct path *fanotify_event_path(struct fanotify_event *event) + else + return NULL; + } ++ ++/* ++ * Use 128 size hash table to speed up events merge. ++ */ ++#define FANOTIFY_HTABLE_BITS (7) ++#define FANOTIFY_HTABLE_SIZE (1 << FANOTIFY_HTABLE_BITS) ++#define FANOTIFY_HTABLE_MASK (FANOTIFY_HTABLE_SIZE - 1) ++ ++/* ++ * Permission events and overflow event do not get merged - don't hash them. ++ */ ++static inline bool fanotify_is_hashed_event(u32 mask) ++{ ++ return !fanotify_is_perm_event(mask) && !(mask & FS_Q_OVERFLOW); ++} ++ ++static inline unsigned int fanotify_event_hash_bucket( ++ struct fsnotify_group *group, ++ struct fanotify_event *event) ++{ ++ return event->hash & FANOTIFY_HTABLE_MASK; ++} +diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c +index 30651e8d1a6d5..1456470d0c4c6 100644 +--- a/fs/notify/fanotify/fanotify_user.c ++++ b/fs/notify/fanotify/fanotify_user.c +@@ -89,6 +89,23 @@ static int fanotify_event_info_len(unsigned int fid_mode, + return info_len; + } + ++/* ++ * Remove an hashed event from merge hash table. ++ */ ++static void fanotify_unhash_event(struct fsnotify_group *group, ++ struct fanotify_event *event) ++{ ++ assert_spin_locked(&group->notification_lock); ++ ++ pr_debug("%s: group=%p event=%p bucket=%u\n", __func__, ++ group, event, fanotify_event_hash_bucket(group, event)); ++ ++ if (WARN_ON_ONCE(hlist_unhashed(&event->merge_list))) ++ return; ++ ++ hlist_del_init(&event->merge_list); ++} ++ + /* + * Get an fanotify notification event if one exists and is small + * enough to fit in "count". Return an error pointer if the count +@@ -126,6 +143,8 @@ static struct fanotify_event *get_one_event(struct fsnotify_group *group, + fsnotify_remove_first_event(group); + if (fanotify_is_perm_event(event->mask)) + FANOTIFY_PERM(event)->state = FAN_EVENT_REPORTED; ++ if (fanotify_is_hashed_event(event->mask)) ++ fanotify_unhash_event(group, event); + out: + spin_unlock(&group->notification_lock); + return event; +@@ -925,6 +944,20 @@ static struct fsnotify_event *fanotify_alloc_overflow_event(void) + return &oevent->fse; + } + ++static struct hlist_head *fanotify_alloc_merge_hash(void) ++{ ++ struct hlist_head *hash; ++ ++ hash = kmalloc(sizeof(struct hlist_head) << FANOTIFY_HTABLE_BITS, ++ GFP_KERNEL_ACCOUNT); ++ if (!hash) ++ return NULL; ++ ++ __hash_init(hash, FANOTIFY_HTABLE_SIZE); ++ ++ return hash; ++} ++ + /* fanotify syscalls */ + SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) + { +@@ -993,6 +1026,12 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) + atomic_inc(&user->fanotify_listeners); + group->memcg = get_mem_cgroup_from_mm(current->mm); + ++ group->fanotify_data.merge_hash = fanotify_alloc_merge_hash(); ++ if (!group->fanotify_data.merge_hash) { ++ fd = -ENOMEM; ++ goto out_destroy_group; ++ } ++ + group->overflow_event = fanotify_alloc_overflow_event(); + if (unlikely(!group->overflow_event)) { + fd = -ENOMEM; +diff --git a/fs/notify/inotify/inotify_fsnotify.c b/fs/notify/inotify/inotify_fsnotify.c +index e2b124c0081dc..b0530f75b274a 100644 +--- a/fs/notify/inotify/inotify_fsnotify.c ++++ b/fs/notify/inotify/inotify_fsnotify.c +@@ -46,9 +46,10 @@ static bool event_compare(struct fsnotify_event *old_fsn, + return false; + } + +-static int inotify_merge(struct list_head *list, +- struct fsnotify_event *event) ++static int inotify_merge(struct fsnotify_group *group, ++ struct fsnotify_event *event) + { ++ struct list_head *list = &group->notification_list; + struct fsnotify_event *last_event; + + last_event = list_entry(list->prev, struct fsnotify_event, list); +@@ -122,7 +123,7 @@ int inotify_handle_inode_event(struct fsnotify_mark *inode_mark, u32 mask, + if (len) + strcpy(event->name, name->name); + +- ret = fsnotify_add_event(group, fsn_event, inotify_merge); ++ ret = fsnotify_add_event(group, fsn_event, inotify_merge, NULL); + if (ret) { + /* Our event wasn't used in the end. Free it. */ + fsnotify_destroy_event(group, fsn_event); +diff --git a/fs/notify/notification.c b/fs/notify/notification.c +index 001cfe7d2e4e7..32f45543b9c64 100644 +--- a/fs/notify/notification.c ++++ b/fs/notify/notification.c +@@ -68,16 +68,22 @@ void fsnotify_destroy_event(struct fsnotify_group *group, + } + + /* +- * Add an event to the group notification queue. The group can later pull this +- * event off the queue to deal with. The function returns 0 if the event was +- * added to the queue, 1 if the event was merged with some other queued event, ++ * Try to add an event to the notification queue. ++ * The group can later pull this event off the queue to deal with. ++ * The group can use the @merge hook to merge the event with a queued event. ++ * The group can use the @insert hook to insert the event into hash table. ++ * The function returns: ++ * 0 if the event was added to a queue ++ * 1 if the event was merged with some other queued event + * 2 if the event was not queued - either the queue of events has overflown +- * or the group is shutting down. ++ * or the group is shutting down. + */ + int fsnotify_add_event(struct fsnotify_group *group, + struct fsnotify_event *event, +- int (*merge)(struct list_head *, +- struct fsnotify_event *)) ++ int (*merge)(struct fsnotify_group *, ++ struct fsnotify_event *), ++ void (*insert)(struct fsnotify_group *, ++ struct fsnotify_event *)) + { + int ret = 0; + struct list_head *list = &group->notification_list; +@@ -104,7 +110,7 @@ int fsnotify_add_event(struct fsnotify_group *group, + } + + if (!list_empty(list) && merge) { +- ret = merge(list, event); ++ ret = merge(group, event); + if (ret) { + spin_unlock(&group->notification_lock); + return ret; +@@ -114,6 +120,8 @@ int fsnotify_add_event(struct fsnotify_group *group, + queue: + group->q_len++; + list_add_tail(&event->list, list); ++ if (insert) ++ insert(group, event); + spin_unlock(&group->notification_lock); + + wake_up(&group->notification_waitq); +diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h +index fc98f9f88d126..63fb766f0f3ec 100644 +--- a/include/linux/fsnotify_backend.h ++++ b/include/linux/fsnotify_backend.h +@@ -233,6 +233,8 @@ struct fsnotify_group { + #endif + #ifdef CONFIG_FANOTIFY + struct fanotify_group_private_data { ++ /* Hash table of events for merge */ ++ struct hlist_head *merge_hash; + /* allows a group to block waiting for a userspace response */ + struct list_head access_list; + wait_queue_head_t access_waitq; +@@ -486,12 +488,14 @@ extern void fsnotify_destroy_event(struct fsnotify_group *group, + /* attach the event to the group notification queue */ + extern int fsnotify_add_event(struct fsnotify_group *group, + struct fsnotify_event *event, +- int (*merge)(struct list_head *, +- struct fsnotify_event *)); ++ int (*merge)(struct fsnotify_group *, ++ struct fsnotify_event *), ++ void (*insert)(struct fsnotify_group *, ++ struct fsnotify_event *)); + /* Queue overflow event to a notification group */ + static inline void fsnotify_queue_overflow(struct fsnotify_group *group) + { +- fsnotify_add_event(group, group->overflow_event, NULL); ++ fsnotify_add_event(group, group->overflow_event, NULL, NULL); + } + + static inline bool fsnotify_notify_queue_is_empty(struct fsnotify_group *group) +-- +2.43.0 + diff --git a/queue-5.10/inotify-don-t-force-fs_in_ignored.patch b/queue-5.10/inotify-don-t-force-fs_in_ignored.patch new file mode 100644 index 00000000000..eb20f17c211 --- /dev/null +++ b/queue-5.10/inotify-don-t-force-fs_in_ignored.patch @@ -0,0 +1,52 @@ +From 44f6c399084b8e36d32d50467ec518842014ef1a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 25 Oct 2021 16:27:22 -0300 +Subject: inotify: Don't force FS_IN_IGNORED + +From: Gabriel Krisman Bertazi + +[ Upstream commit e0462f91d24756916fded4313d508e0fc52f39c9 ] + +According to Amir: + +"FS_IN_IGNORED is completely internal to inotify and there is no need +to set it in i_fsnotify_mask at all, so if we remove the bit from the +output of inotify_arg_to_mask() no functionality will change and we will +be able to overload the event bit for FS_ERROR." + +This is done in preparation to overload FS_ERROR with the notification +mechanism in fanotify. + +Link: https://lore.kernel.org/r/20211025192746.66445-8-krisman@collabora.com +Suggested-by: Amir Goldstein +Reviewed-by: Amir Goldstein +Reviewed-by: Jan Kara +Signed-off-by: Gabriel Krisman Bertazi +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/inotify/inotify_user.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c +index 62cd91bc00b83..9676c3f2df3d7 100644 +--- a/fs/notify/inotify/inotify_user.c ++++ b/fs/notify/inotify/inotify_user.c +@@ -89,10 +89,10 @@ static inline __u32 inotify_arg_to_mask(struct inode *inode, u32 arg) + __u32 mask; + + /* +- * Everything should accept their own ignored and should receive events +- * when the inode is unmounted. All directories care about children. ++ * Everything should receive events when the inode is unmounted. ++ * All directories care about children. + */ +- mask = (FS_IN_IGNORED | FS_UNMOUNT); ++ mask = (FS_UNMOUNT); + if (S_ISDIR(inode->i_mode)) + mask |= FS_EVENT_ON_CHILD; + +-- +2.43.0 + diff --git a/queue-5.10/inotify-increase-default-inotify.max_user_watches-li.patch b/queue-5.10/inotify-increase-default-inotify.max_user_watches-li.patch new file mode 100644 index 00000000000..2e4658f6f04 --- /dev/null +++ b/queue-5.10/inotify-increase-default-inotify.max_user_watches-li.patch @@ -0,0 +1,102 @@ +From d9a847bd1d332fbb3cf57526875e4f69d3ec15e6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 8 Nov 2020 22:59:31 -0500 +Subject: inotify: Increase default inotify.max_user_watches limit to 1048576 + +From: Waiman Long + +[ Upstream commit 92890123749bafc317bbfacbe0a62ce08d78efb7 ] + +The default value of inotify.max_user_watches sysctl parameter was set +to 8192 since the introduction of the inotify feature in 2005 by +commit 0eeca28300df ("[PATCH] inotify"). Today this value is just too +small for many modern usage. As a result, users have to explicitly set +it to a larger value to make it work. + +After some searching around the web, these are the +inotify.max_user_watches values used by some projects: + - vscode: 524288 + - dropbox support: 100000 + - users on stackexchange: 12228 + - lsyncd user: 2000000 + - code42 support: 1048576 + - monodevelop: 16384 + - tectonic: 524288 + - openshift origin: 65536 + +Each watch point adds an inotify_inode_mark structure to an inode to +be watched. It also pins the watched inode. + +Modeled after the epoll.max_user_watches behavior to adjust the default +value according to the amount of addressable memory available, make +inotify.max_user_watches behave in a similar way to make it use no more +than 1% of addressable memory within the range [8192, 1048576]. + +We estimate the amount of memory used by inotify mark to size of +inotify_inode_mark plus two times the size of struct inode (we double +the inode size to cover the additional filesystem private inode part). +That means that a 64-bit system with 128GB or more memory will likely +have the maximum value of 1048576 for inotify.max_user_watches. This +default should be big enough for most use cases. + +Link: https://lore.kernel.org/r/20201109035931.4740-1-longman@redhat.com +Reviewed-by: Amir Goldstein +Signed-off-by: Waiman Long +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/inotify/inotify_user.c | 23 ++++++++++++++++++++++- + 1 file changed, 22 insertions(+), 1 deletion(-) + +diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c +index 32b6b97021bef..b564a32403aa5 100644 +--- a/fs/notify/inotify/inotify_user.c ++++ b/fs/notify/inotify/inotify_user.c +@@ -37,6 +37,15 @@ + + #include + ++/* ++ * An inotify watch requires allocating an inotify_inode_mark structure as ++ * well as pinning the watched inode. Doubling the size of a VFS inode ++ * should be more than enough to cover the additional filesystem inode ++ * size increase. ++ */ ++#define INOTIFY_WATCH_COST (sizeof(struct inotify_inode_mark) + \ ++ 2 * sizeof(struct inode)) ++ + /* configurable via /proc/sys/fs/inotify/ */ + static int inotify_max_queued_events __read_mostly; + +@@ -797,6 +806,18 @@ SYSCALL_DEFINE2(inotify_rm_watch, int, fd, __s32, wd) + */ + static int __init inotify_user_setup(void) + { ++ unsigned long watches_max; ++ struct sysinfo si; ++ ++ si_meminfo(&si); ++ /* ++ * Allow up to 1% of addressable memory to be allocated for inotify ++ * watches (per user) limited to the range [8192, 1048576]. ++ */ ++ watches_max = (((si.totalram - si.totalhigh) / 100) << PAGE_SHIFT) / ++ INOTIFY_WATCH_COST; ++ watches_max = clamp(watches_max, 8192UL, 1048576UL); ++ + BUILD_BUG_ON(IN_ACCESS != FS_ACCESS); + BUILD_BUG_ON(IN_MODIFY != FS_MODIFY); + BUILD_BUG_ON(IN_ATTRIB != FS_ATTRIB); +@@ -823,7 +844,7 @@ static int __init inotify_user_setup(void) + + inotify_max_queued_events = 16384; + init_user_ns.ucount_max[UCOUNT_INOTIFY_INSTANCES] = 128; +- init_user_ns.ucount_max[UCOUNT_INOTIFY_WATCHES] = 8192; ++ init_user_ns.ucount_max[UCOUNT_INOTIFY_WATCHES] = watches_max; + + return 0; + } +-- +2.43.0 + diff --git a/queue-5.10/inotify-memcg-account-inotify-instances-to-kmemcg.patch b/queue-5.10/inotify-memcg-account-inotify-instances-to-kmemcg.patch new file mode 100644 index 00000000000..c86cf1c4874 --- /dev/null +++ b/queue-5.10/inotify-memcg-account-inotify-instances-to-kmemcg.patch @@ -0,0 +1,130 @@ +From ff827c1eae83681438649ed2dc137a3f7f7a16d5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 19 Dec 2020 20:46:08 -0800 +Subject: inotify, memcg: account inotify instances to kmemcg + +From: Shakeel Butt + +[ Upstream commit ac7b79fd190b02e7151bc7d2b9da692f537657f3 ] + +Currently the fs sysctl inotify/max_user_instances is used to limit the +number of inotify instances on the system. For systems running multiple +workloads, the per-user namespace sysctl max_inotify_instances can be +used to further partition inotify instances. However there is no easy +way to set a sensible system level max limit on inotify instances and +further partition it between the workloads. It is much easier to charge +the underlying resource (i.e. memory) behind the inotify instances to +the memcg of the workload and let their memory limits limit the number +of inotify instances they can create. + +With inotify instances charged to memcg, the admin can simply set +max_user_instances to INT_MAX and let the memcg limits of the jobs limit +their inotify instances. + +Link: https://lore.kernel.org/r/20201220044608.1258123-1-shakeelb@google.com +Reviewed-by: Amir Goldstein +Signed-off-by: Shakeel Butt +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify_user.c | 2 +- + fs/notify/group.c | 25 ++++++++++++++++++++----- + fs/notify/inotify/inotify_user.c | 4 ++-- + include/linux/fsnotify_backend.h | 1 + + 4 files changed, 24 insertions(+), 8 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c +index 84de9f97bbc09..3e905b2e1b9c3 100644 +--- a/fs/notify/fanotify/fanotify_user.c ++++ b/fs/notify/fanotify/fanotify_user.c +@@ -976,7 +976,7 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) + f_flags |= O_NONBLOCK; + + /* fsnotify_alloc_group takes a ref. Dropped in fanotify_release */ +- group = fsnotify_alloc_group(&fanotify_fsnotify_ops); ++ group = fsnotify_alloc_user_group(&fanotify_fsnotify_ops); + if (IS_ERR(group)) { + free_uid(user); + return PTR_ERR(group); +diff --git a/fs/notify/group.c b/fs/notify/group.c +index a4a4b1c64d32a..ffd723ffe46de 100644 +--- a/fs/notify/group.c ++++ b/fs/notify/group.c +@@ -111,14 +111,12 @@ void fsnotify_put_group(struct fsnotify_group *group) + } + EXPORT_SYMBOL_GPL(fsnotify_put_group); + +-/* +- * Create a new fsnotify_group and hold a reference for the group returned. +- */ +-struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops) ++static struct fsnotify_group *__fsnotify_alloc_group( ++ const struct fsnotify_ops *ops, gfp_t gfp) + { + struct fsnotify_group *group; + +- group = kzalloc(sizeof(struct fsnotify_group), GFP_KERNEL); ++ group = kzalloc(sizeof(struct fsnotify_group), gfp); + if (!group) + return ERR_PTR(-ENOMEM); + +@@ -139,8 +137,25 @@ struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops) + + return group; + } ++ ++/* ++ * Create a new fsnotify_group and hold a reference for the group returned. ++ */ ++struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops) ++{ ++ return __fsnotify_alloc_group(ops, GFP_KERNEL); ++} + EXPORT_SYMBOL_GPL(fsnotify_alloc_group); + ++/* ++ * Create a new fsnotify_group and hold a reference for the group returned. ++ */ ++struct fsnotify_group *fsnotify_alloc_user_group(const struct fsnotify_ops *ops) ++{ ++ return __fsnotify_alloc_group(ops, GFP_KERNEL_ACCOUNT); ++} ++EXPORT_SYMBOL_GPL(fsnotify_alloc_user_group); ++ + int fsnotify_fasync(int fd, struct file *file, int on) + { + struct fsnotify_group *group = file->private_data; +diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c +index b564a32403aa5..ad8fb4bca6dc1 100644 +--- a/fs/notify/inotify/inotify_user.c ++++ b/fs/notify/inotify/inotify_user.c +@@ -632,11 +632,11 @@ static struct fsnotify_group *inotify_new_group(unsigned int max_events) + struct fsnotify_group *group; + struct inotify_event_info *oevent; + +- group = fsnotify_alloc_group(&inotify_fsnotify_ops); ++ group = fsnotify_alloc_user_group(&inotify_fsnotify_ops); + if (IS_ERR(group)) + return group; + +- oevent = kmalloc(sizeof(struct inotify_event_info), GFP_KERNEL); ++ oevent = kmalloc(sizeof(struct inotify_event_info), GFP_KERNEL_ACCOUNT); + if (unlikely(!oevent)) { + fsnotify_destroy_group(group); + return ERR_PTR(-ENOMEM); +diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h +index a2e42d3cd87cf..e5409b83e7313 100644 +--- a/include/linux/fsnotify_backend.h ++++ b/include/linux/fsnotify_backend.h +@@ -470,6 +470,7 @@ static inline void fsnotify_update_flags(struct dentry *dentry) + + /* create a new group */ + extern struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops); ++extern struct fsnotify_group *fsnotify_alloc_user_group(const struct fsnotify_ops *ops); + /* get reference to a group */ + extern void fsnotify_get_group(struct fsnotify_group *group); + /* drop reference on a group from fsnotify_alloc_group */ +-- +2.43.0 + diff --git a/queue-5.10/inotify-move-control-flags-from-mask-to-mark-flags.patch b/queue-5.10/inotify-move-control-flags-from-mask-to-mark-flags.patch new file mode 100644 index 00000000000..8940e936677 --- /dev/null +++ b/queue-5.10/inotify-move-control-flags-from-mask-to-mark-flags.patch @@ -0,0 +1,228 @@ +From 2bb6d0ecb678cad3dde7ac69d455fdf4451c95d7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 Apr 2022 15:03:13 +0300 +Subject: inotify: move control flags from mask to mark flags + +From: Amir Goldstein + +[ Upstream commit 38035c04f5865c4ef9597d6beed6a7178f90f64a ] + +The inotify control flags in the mark mask (e.g. FS_IN_ONE_SHOT) are not +relevant to object interest mask, so move them to the mark flags. + +This frees up some bits in the object interest mask. + +Link: https://lore.kernel.org/r/20220422120327.3459282-3-amir73il@gmail.com +Signed-off-by: Amir Goldstein +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fsnotify.c | 4 +-- + fs/notify/inotify/inotify.h | 11 ++++++-- + fs/notify/inotify/inotify_fsnotify.c | 2 +- + fs/notify/inotify/inotify_user.c | 38 ++++++++++++++++++---------- + include/linux/fsnotify_backend.h | 16 +++++++----- + 5 files changed, 45 insertions(+), 26 deletions(-) + +diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c +index 70a8516b78bc5..6eee19d15e8cd 100644 +--- a/fs/notify/fsnotify.c ++++ b/fs/notify/fsnotify.c +@@ -253,7 +253,7 @@ static int fsnotify_handle_inode_event(struct fsnotify_group *group, + if (WARN_ON_ONCE(!inode && !dir)) + return 0; + +- if ((inode_mark->mask & FS_EXCL_UNLINK) && ++ if ((inode_mark->flags & FSNOTIFY_MARK_FLAG_EXCL_UNLINK) && + path && d_unlinked(path->dentry)) + return 0; + +@@ -581,7 +581,7 @@ static __init int fsnotify_init(void) + { + int ret; + +- BUILD_BUG_ON(HWEIGHT32(ALL_FSNOTIFY_BITS) != 25); ++ BUILD_BUG_ON(HWEIGHT32(ALL_FSNOTIFY_BITS) != 23); + + ret = init_srcu_struct(&fsnotify_mark_srcu); + if (ret) +diff --git a/fs/notify/inotify/inotify.h b/fs/notify/inotify/inotify.h +index 8f00151eb731f..7d5df7a215397 100644 +--- a/fs/notify/inotify/inotify.h ++++ b/fs/notify/inotify/inotify.h +@@ -27,11 +27,18 @@ static inline struct inotify_event_info *INOTIFY_E(struct fsnotify_event *fse) + * userspace. There is at least one bit (FS_EVENT_ON_CHILD) which is + * used only internally to the kernel. + */ +-#define INOTIFY_USER_MASK (IN_ALL_EVENTS | IN_ONESHOT | IN_EXCL_UNLINK) ++#define INOTIFY_USER_MASK (IN_ALL_EVENTS) + + static inline __u32 inotify_mark_user_mask(struct fsnotify_mark *fsn_mark) + { +- return fsn_mark->mask & INOTIFY_USER_MASK; ++ __u32 mask = fsn_mark->mask & INOTIFY_USER_MASK; ++ ++ if (fsn_mark->flags & FSNOTIFY_MARK_FLAG_EXCL_UNLINK) ++ mask |= IN_EXCL_UNLINK; ++ if (fsn_mark->flags & FSNOTIFY_MARK_FLAG_IN_ONESHOT) ++ mask |= IN_ONESHOT; ++ ++ return mask; + } + + extern void inotify_ignored_and_remove_idr(struct fsnotify_mark *fsn_mark, +diff --git a/fs/notify/inotify/inotify_fsnotify.c b/fs/notify/inotify/inotify_fsnotify.c +index 8279827836399..993375f0db673 100644 +--- a/fs/notify/inotify/inotify_fsnotify.c ++++ b/fs/notify/inotify/inotify_fsnotify.c +@@ -129,7 +129,7 @@ int inotify_handle_inode_event(struct fsnotify_mark *inode_mark, u32 mask, + fsnotify_destroy_event(group, fsn_event); + } + +- if (inode_mark->mask & IN_ONESHOT) ++ if (inode_mark->flags & FSNOTIFY_MARK_FLAG_IN_ONESHOT) + fsnotify_destroy_mark(inode_mark, group); + + return 0; +diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c +index 9676c3f2df3d7..861147e574581 100644 +--- a/fs/notify/inotify/inotify_user.c ++++ b/fs/notify/inotify/inotify_user.c +@@ -102,6 +102,21 @@ static inline __u32 inotify_arg_to_mask(struct inode *inode, u32 arg) + return mask; + } + ++#define INOTIFY_MARK_FLAGS \ ++ (FSNOTIFY_MARK_FLAG_EXCL_UNLINK | FSNOTIFY_MARK_FLAG_IN_ONESHOT) ++ ++static inline unsigned int inotify_arg_to_flags(u32 arg) ++{ ++ unsigned int flags = 0; ++ ++ if (arg & IN_EXCL_UNLINK) ++ flags |= FSNOTIFY_MARK_FLAG_EXCL_UNLINK; ++ if (arg & IN_ONESHOT) ++ flags |= FSNOTIFY_MARK_FLAG_IN_ONESHOT; ++ ++ return flags; ++} ++ + static inline u32 inotify_mask_to_arg(__u32 mask) + { + return mask & (IN_ALL_EVENTS | IN_ISDIR | IN_UNMOUNT | IN_IGNORED | +@@ -513,13 +528,10 @@ static int inotify_update_existing_watch(struct fsnotify_group *group, + struct fsnotify_mark *fsn_mark; + struct inotify_inode_mark *i_mark; + __u32 old_mask, new_mask; +- __u32 mask; +- int add = (arg & IN_MASK_ADD); ++ int replace = !(arg & IN_MASK_ADD); + int create = (arg & IN_MASK_CREATE); + int ret; + +- mask = inotify_arg_to_mask(inode, arg); +- + fsn_mark = fsnotify_find_mark(&inode->i_fsnotify_marks, group); + if (!fsn_mark) + return -ENOENT; +@@ -532,10 +544,12 @@ static int inotify_update_existing_watch(struct fsnotify_group *group, + + spin_lock(&fsn_mark->lock); + old_mask = fsn_mark->mask; +- if (add) +- fsn_mark->mask |= mask; +- else +- fsn_mark->mask = mask; ++ if (replace) { ++ fsn_mark->mask = 0; ++ fsn_mark->flags &= ~INOTIFY_MARK_FLAGS; ++ } ++ fsn_mark->mask |= inotify_arg_to_mask(inode, arg); ++ fsn_mark->flags |= inotify_arg_to_flags(arg); + new_mask = fsn_mark->mask; + spin_unlock(&fsn_mark->lock); + +@@ -566,19 +580,17 @@ static int inotify_new_watch(struct fsnotify_group *group, + u32 arg) + { + struct inotify_inode_mark *tmp_i_mark; +- __u32 mask; + int ret; + struct idr *idr = &group->inotify_data.idr; + spinlock_t *idr_lock = &group->inotify_data.idr_lock; + +- mask = inotify_arg_to_mask(inode, arg); +- + tmp_i_mark = kmem_cache_alloc(inotify_inode_mark_cachep, GFP_KERNEL); + if (unlikely(!tmp_i_mark)) + return -ENOMEM; + + fsnotify_init_mark(&tmp_i_mark->fsn_mark, group); +- tmp_i_mark->fsn_mark.mask = mask; ++ tmp_i_mark->fsn_mark.mask = inotify_arg_to_mask(inode, arg); ++ tmp_i_mark->fsn_mark.flags = inotify_arg_to_flags(arg); + tmp_i_mark->wd = -1; + + ret = inotify_add_to_idr(idr, idr_lock, tmp_i_mark); +@@ -832,9 +844,7 @@ static int __init inotify_user_setup(void) + BUILD_BUG_ON(IN_UNMOUNT != FS_UNMOUNT); + BUILD_BUG_ON(IN_Q_OVERFLOW != FS_Q_OVERFLOW); + BUILD_BUG_ON(IN_IGNORED != FS_IN_IGNORED); +- BUILD_BUG_ON(IN_EXCL_UNLINK != FS_EXCL_UNLINK); + BUILD_BUG_ON(IN_ISDIR != FS_ISDIR); +- BUILD_BUG_ON(IN_ONESHOT != FS_IN_ONESHOT); + + BUILD_BUG_ON(HWEIGHT32(ALL_INOTIFY_BITS) != 22); + +diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h +index 0805b74cae441..b1c72edd97845 100644 +--- a/include/linux/fsnotify_backend.h ++++ b/include/linux/fsnotify_backend.h +@@ -55,7 +55,6 @@ + #define FS_ACCESS_PERM 0x00020000 /* access event in a permissions hook */ + #define FS_OPEN_EXEC_PERM 0x00040000 /* open/exec event in a permission hook */ + +-#define FS_EXCL_UNLINK 0x04000000 /* do not send events if object is unlinked */ + /* + * Set on inode mark that cares about things that happen to its children. + * Always set for dnotify and inotify. +@@ -66,7 +65,6 @@ + #define FS_RENAME 0x10000000 /* File was renamed */ + #define FS_DN_MULTISHOT 0x20000000 /* dnotify multishot */ + #define FS_ISDIR 0x40000000 /* event occurred against dir */ +-#define FS_IN_ONESHOT 0x80000000 /* only send event once */ + + #define FS_MOVE (FS_MOVED_FROM | FS_MOVED_TO) + +@@ -106,8 +104,7 @@ + FS_ERROR) + + /* Extra flags that may be reported with event or control handling of events */ +-#define ALL_FSNOTIFY_FLAGS (FS_EXCL_UNLINK | FS_ISDIR | FS_IN_ONESHOT | \ +- FS_DN_MULTISHOT | FS_EVENT_ON_CHILD) ++#define ALL_FSNOTIFY_FLAGS (FS_ISDIR | FS_EVENT_ON_CHILD | FS_DN_MULTISHOT) + + #define ALL_FSNOTIFY_BITS (ALL_FSNOTIFY_EVENTS | ALL_FSNOTIFY_FLAGS) + +@@ -473,9 +470,14 @@ struct fsnotify_mark { + struct fsnotify_mark_connector *connector; + /* Events types to ignore [mark->lock, group->mark_mutex] */ + __u32 ignored_mask; +-#define FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY 0x01 +-#define FSNOTIFY_MARK_FLAG_ALIVE 0x02 +-#define FSNOTIFY_MARK_FLAG_ATTACHED 0x04 ++ /* General fsnotify mark flags */ ++#define FSNOTIFY_MARK_FLAG_ALIVE 0x0001 ++#define FSNOTIFY_MARK_FLAG_ATTACHED 0x0002 ++ /* inotify mark flags */ ++#define FSNOTIFY_MARK_FLAG_EXCL_UNLINK 0x0010 ++#define FSNOTIFY_MARK_FLAG_IN_ONESHOT 0x0020 ++ /* fanotify mark flags */ ++#define FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY 0x0100 + unsigned int flags; /* flags [mark->lock] */ + }; + +-- +2.43.0 + diff --git a/queue-5.10/inotify-use-fsnotify-group-lock-helpers.patch b/queue-5.10/inotify-use-fsnotify-group-lock-helpers.patch new file mode 100644 index 00000000000..1ffe72954f2 --- /dev/null +++ b/queue-5.10/inotify-use-fsnotify-group-lock-helpers.patch @@ -0,0 +1,46 @@ +From 9827c2e50489408daea94b235423c4182b2aecde Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 Apr 2022 15:03:18 +0300 +Subject: inotify: use fsnotify group lock helpers + +From: Amir Goldstein + +[ Upstream commit 642054b87058019be36033f73c3e48ffff1915aa ] + +inotify inode marks pin the inode so there is no need to set the +FSNOTIFY_GROUP_NOFS flag. + +Link: https://lore.kernel.org/r/20220422120327.3459282-8-amir73il@gmail.com +Suggested-by: Jan Kara +Link: https://lore.kernel.org/r/20220321112310.vpr7oxro2xkz5llh@quack3.lan/ +Signed-off-by: Amir Goldstein +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/inotify/inotify_user.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c +index 9e1cf8392385a..3d5d536f8fd63 100644 +--- a/fs/notify/inotify/inotify_user.c ++++ b/fs/notify/inotify/inotify_user.c +@@ -627,13 +627,13 @@ static int inotify_update_watch(struct fsnotify_group *group, struct inode *inod + { + int ret = 0; + +- mutex_lock(&group->mark_mutex); ++ fsnotify_group_lock(group); + /* try to update and existing watch with the new arg */ + ret = inotify_update_existing_watch(group, inode, arg); + /* no mark present, try to add a new one */ + if (ret == -ENOENT) + ret = inotify_new_watch(group, inode, arg); +- mutex_unlock(&group->mark_mutex); ++ fsnotify_group_unlock(group); + + return ret; + } +-- +2.43.0 + diff --git a/queue-5.10/kallsyms-only-build-module_-kallsyms_on_each_symbol-.patch b/queue-5.10/kallsyms-only-build-module_-kallsyms_on_each_symbol-.patch new file mode 100644 index 00000000000..fd9297329fe --- /dev/null +++ b/queue-5.10/kallsyms-only-build-module_-kallsyms_on_each_symbol-.patch @@ -0,0 +1,146 @@ +From 49c0ffd73e62266d92ae29d90c117923a79fe1bc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Feb 2021 13:13:27 +0100 +Subject: kallsyms: only build {,module_}kallsyms_on_each_symbol when required + +From: Christoph Hellwig + +[ Upstream commit 3e3552056ab42f883d7723eeb42fed712b66bacf ] + +kallsyms_on_each_symbol and module_kallsyms_on_each_symbol are only used +by the livepatching code, so don't build them if livepatching is not +enabled. + +Reviewed-by: Miroslav Benes +Signed-off-by: Christoph Hellwig +Signed-off-by: Jessica Yu +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + include/linux/kallsyms.h | 17 ++++------------- + include/linux/module.h | 16 ++++------------ + kernel/kallsyms.c | 2 ++ + kernel/module.c | 2 ++ + 4 files changed, 12 insertions(+), 25 deletions(-) + +diff --git a/include/linux/kallsyms.h b/include/linux/kallsyms.h +index 481273f0c72d4..465060acc9816 100644 +--- a/include/linux/kallsyms.h ++++ b/include/linux/kallsyms.h +@@ -71,15 +71,14 @@ static inline void *dereference_symbol_descriptor(void *ptr) + return ptr; + } + +-#ifdef CONFIG_KALLSYMS +-/* Lookup the address for a symbol. Returns 0 if not found. */ +-unsigned long kallsyms_lookup_name(const char *name); +- +-/* Call a function on each kallsyms symbol in the core kernel */ + int kallsyms_on_each_symbol(int (*fn)(void *, const char *, struct module *, + unsigned long), + void *data); + ++#ifdef CONFIG_KALLSYMS ++/* Lookup the address for a symbol. Returns 0 if not found. */ ++unsigned long kallsyms_lookup_name(const char *name); ++ + extern int kallsyms_lookup_size_offset(unsigned long addr, + unsigned long *symbolsize, + unsigned long *offset); +@@ -108,14 +107,6 @@ static inline unsigned long kallsyms_lookup_name(const char *name) + return 0; + } + +-static inline int kallsyms_on_each_symbol(int (*fn)(void *, const char *, +- struct module *, +- unsigned long), +- void *data) +-{ +- return 0; +-} +- + static inline int kallsyms_lookup_size_offset(unsigned long addr, + unsigned long *symbolsize, + unsigned long *offset) +diff --git a/include/linux/module.h b/include/linux/module.h +index 86fae5d1c0e39..59cbd8e1be2d6 100644 +--- a/include/linux/module.h ++++ b/include/linux/module.h +@@ -604,10 +604,6 @@ int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type, + /* Look for this name: can be of form module:name. */ + unsigned long module_kallsyms_lookup_name(const char *name); + +-int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *, +- struct module *, unsigned long), +- void *data); +- + extern void __noreturn __module_put_and_exit(struct module *mod, + long code); + #define module_put_and_exit(code) __module_put_and_exit(THIS_MODULE, code) +@@ -791,14 +787,6 @@ static inline unsigned long module_kallsyms_lookup_name(const char *name) + return 0; + } + +-static inline int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *, +- struct module *, +- unsigned long), +- void *data) +-{ +- return 0; +-} +- + static inline int register_module_notifier(struct notifier_block *nb) + { + /* no events will happen anyway, so this can always succeed */ +@@ -887,4 +875,8 @@ static inline bool module_sig_ok(struct module *module) + } + #endif /* CONFIG_MODULE_SIG */ + ++int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *, ++ struct module *, unsigned long), ++ void *data); ++ + #endif /* _LINUX_MODULE_H */ +diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c +index a0d3f0865916f..8043a90aa50ed 100644 +--- a/kernel/kallsyms.c ++++ b/kernel/kallsyms.c +@@ -177,6 +177,7 @@ unsigned long kallsyms_lookup_name(const char *name) + return module_kallsyms_lookup_name(name); + } + ++#ifdef CONFIG_LIVEPATCH + /* + * Iterate over all symbols in vmlinux. For symbols from modules use + * module_kallsyms_on_each_symbol instead. +@@ -198,6 +199,7 @@ int kallsyms_on_each_symbol(int (*fn)(void *, const char *, struct module *, + } + return 0; + } ++#endif /* CONFIG_LIVEPATCH */ + + static unsigned long get_symbol_pos(unsigned long addr, + unsigned long *symbolsize, +diff --git a/kernel/module.c b/kernel/module.c +index 330387d63c633..949d09d2d8297 100644 +--- a/kernel/module.c ++++ b/kernel/module.c +@@ -4444,6 +4444,7 @@ unsigned long module_kallsyms_lookup_name(const char *name) + return ret; + } + ++#ifdef CONFIG_LIVEPATCH + int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *, + struct module *, unsigned long), + void *data) +@@ -4474,6 +4475,7 @@ int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *, + mutex_unlock(&module_mutex); + return ret; + } ++#endif /* CONFIG_LIVEPATCH */ + #endif /* CONFIG_KALLSYMS */ + + /* Maximum number of characters written by module_flags() */ +-- +2.43.0 + diff --git a/queue-5.10/kallsyms-refactor-module_-kallsyms_on_each_symbol.patch b/queue-5.10/kallsyms-refactor-module_-kallsyms_on_each_symbol.patch new file mode 100644 index 00000000000..416f98f622c --- /dev/null +++ b/queue-5.10/kallsyms-refactor-module_-kallsyms_on_each_symbol.patch @@ -0,0 +1,113 @@ +From bf0f95dcf2e1d6c6a712e371348bbc31cd2165f8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Feb 2021 13:13:26 +0100 +Subject: kallsyms: refactor {,module_}kallsyms_on_each_symbol + +From: Christoph Hellwig + +[ Upstream commit 013c1667cf78c1d847152f7116436d82dcab3db4 ] + +Require an explicit call to module_kallsyms_on_each_symbol to look +for symbols in modules instead of the call from kallsyms_on_each_symbol, +and acquire module_mutex inside of module_kallsyms_on_each_symbol instead +of leaving that up to the caller. Note that this slightly changes the +behavior for the livepatch code in that the symbols from vmlinux are not +iterated anymore if objname is set, but that actually is the desired +behavior in this case. + +Reviewed-by: Petr Mladek +Acked-by: Miroslav Benes +Signed-off-by: Christoph Hellwig +Signed-off-by: Jessica Yu +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + kernel/kallsyms.c | 6 +++++- + kernel/livepatch/core.c | 2 -- + kernel/module.c | 13 ++++--------- + 3 files changed, 9 insertions(+), 12 deletions(-) + +diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c +index fe9de067771c3..a0d3f0865916f 100644 +--- a/kernel/kallsyms.c ++++ b/kernel/kallsyms.c +@@ -177,6 +177,10 @@ unsigned long kallsyms_lookup_name(const char *name) + return module_kallsyms_lookup_name(name); + } + ++/* ++ * Iterate over all symbols in vmlinux. For symbols from modules use ++ * module_kallsyms_on_each_symbol instead. ++ */ + int kallsyms_on_each_symbol(int (*fn)(void *, const char *, struct module *, + unsigned long), + void *data) +@@ -192,7 +196,7 @@ int kallsyms_on_each_symbol(int (*fn)(void *, const char *, struct module *, + if (ret != 0) + return ret; + } +- return module_kallsyms_on_each_symbol(fn, data); ++ return 0; + } + + static unsigned long get_symbol_pos(unsigned long addr, +diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c +index e660ea4f90a28..147ed154ebc77 100644 +--- a/kernel/livepatch/core.c ++++ b/kernel/livepatch/core.c +@@ -164,12 +164,10 @@ static int klp_find_object_symbol(const char *objname, const char *name, + .pos = sympos, + }; + +- mutex_lock(&module_mutex); + if (objname) + module_kallsyms_on_each_symbol(klp_find_callback, &args); + else + kallsyms_on_each_symbol(klp_find_callback, &args); +- mutex_unlock(&module_mutex); + + /* + * Ensure an address was found. If sympos is 0, ensure symbol is unique; +diff --git a/kernel/module.c b/kernel/module.c +index 1f9f6133c30ef..330387d63c633 100644 +--- a/kernel/module.c ++++ b/kernel/module.c +@@ -255,11 +255,6 @@ static void mod_update_bounds(struct module *mod) + struct list_head *kdb_modules = &modules; /* kdb needs the list of modules */ + #endif /* CONFIG_KGDB_KDB */ + +-static void module_assert_mutex(void) +-{ +- lockdep_assert_held(&module_mutex); +-} +- + static void module_assert_mutex_or_preempt(void) + { + #ifdef CONFIG_LOCKDEP +@@ -4457,8 +4452,7 @@ int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *, + unsigned int i; + int ret; + +- module_assert_mutex(); +- ++ mutex_lock(&module_mutex); + list_for_each_entry(mod, &modules, list) { + /* We hold module_mutex: no need for rcu_dereference_sched */ + struct mod_kallsyms *kallsyms = mod->kallsyms; +@@ -4474,10 +4468,11 @@ int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *, + ret = fn(data, kallsyms_symbol_name(kallsyms, i), + mod, kallsyms_symbol_value(sym)); + if (ret != 0) +- return ret; ++ break; + } + } +- return 0; ++ mutex_unlock(&module_mutex); ++ return ret; + } + #endif /* CONFIG_KALLSYMS */ + +-- +2.43.0 + diff --git a/queue-5.10/kcmp-in-get_file_raw_ptr-use-task_lookup_fd_rcu.patch b/queue-5.10/kcmp-in-get_file_raw_ptr-use-task_lookup_fd_rcu.patch new file mode 100644 index 00000000000..51e1ff4c181 --- /dev/null +++ b/queue-5.10/kcmp-in-get_file_raw_ptr-use-task_lookup_fd_rcu.patch @@ -0,0 +1,49 @@ +From b56ad751f0808be855ac2fe01472feda64ea992a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Nov 2020 17:14:30 -0600 +Subject: kcmp: In get_file_raw_ptr use task_lookup_fd_rcu + +From: Eric W. Biederman + +[ Upstream commit ed77e80e14a3cd55c73848b9e8043020e717ce12 ] + +Modify get_file_raw_ptr to use task_lookup_fd_rcu. The helper +task_lookup_fd_rcu does the work of taking the task lock and verifying +that task->files != NULL and then calls files_lookup_fd_rcu. So let +use the helper to make a simpler implementation of get_file_raw_ptr. + +Acked-by: Cyrill Gorcunov +Link: https://lkml.kernel.org/r/20201120231441.29911-13-ebiederm@xmission.com +Signed-off-by: Eric W. Biederman +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + kernel/kcmp.c | 9 ++------- + 1 file changed, 2 insertions(+), 7 deletions(-) + +diff --git a/kernel/kcmp.c b/kernel/kcmp.c +index 5b2435e030472..5353edfad8e11 100644 +--- a/kernel/kcmp.c ++++ b/kernel/kcmp.c +@@ -61,16 +61,11 @@ static int kcmp_ptr(void *v1, void *v2, enum kcmp_type type) + static struct file * + get_file_raw_ptr(struct task_struct *task, unsigned int idx) + { +- struct file *file = NULL; ++ struct file *file; + +- task_lock(task); + rcu_read_lock(); +- +- if (task->files) +- file = files_lookup_fd_rcu(task->files, idx); +- ++ file = task_lookup_fd_rcu(task, idx); + rcu_read_unlock(); +- task_unlock(task); + + return file; + } +-- +2.43.0 + diff --git a/queue-5.10/kcmp-in-kcmp_epoll_target-use-fget_task.patch b/queue-5.10/kcmp-in-kcmp_epoll_target-use-fget_task.patch new file mode 100644 index 00000000000..9a67e41b39d --- /dev/null +++ b/queue-5.10/kcmp-in-kcmp_epoll_target-use-fget_task.patch @@ -0,0 +1,71 @@ +From fe28056b78a495e482acfdded86390076b6374b0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Nov 2020 17:14:21 -0600 +Subject: kcmp: In kcmp_epoll_target use fget_task + +From: Eric W. Biederman + +[ Upstream commit f43c283a89a7dc531a47d4b1e001503cf3dc3234 ] + +Use the helper fget_task and simplify the code. + +As well as simplifying the code this removes one unnecessary increment of +struct files_struct. This unnecessary increment of files_struct.count can +result in exec unnecessarily unsharing files_struct and breaking posix +locks, and it can result in fget_light having to fallback to fget reducing +performance. + +Suggested-by: Oleg Nesterov +Reviewed-by: Cyrill Gorcunov +v1: https://lkml.kernel.org/r/20200817220425.9389-4-ebiederm@xmission.com +Link: https://lkml.kernel.org/r/20201120231441.29911-4-ebiederm@xmission.com +Signed-off-by: Eric W. Biederman +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + kernel/kcmp.c | 20 ++++---------------- + 1 file changed, 4 insertions(+), 16 deletions(-) + +diff --git a/kernel/kcmp.c b/kernel/kcmp.c +index c0d2ad9b4705d..bd6f9edf98fd3 100644 +--- a/kernel/kcmp.c ++++ b/kernel/kcmp.c +@@ -107,7 +107,6 @@ static int kcmp_epoll_target(struct task_struct *task1, + { + struct file *filp, *filp_epoll, *filp_tgt; + struct kcmp_epoll_slot slot; +- struct files_struct *files; + + if (copy_from_user(&slot, uslot, sizeof(slot))) + return -EFAULT; +@@ -116,23 +115,12 @@ static int kcmp_epoll_target(struct task_struct *task1, + if (!filp) + return -EBADF; + +- files = get_files_struct(task2); +- if (!files) ++ filp_epoll = fget_task(task2, slot.efd); ++ if (!filp_epoll) + return -EBADF; + +- spin_lock(&files->file_lock); +- filp_epoll = fcheck_files(files, slot.efd); +- if (filp_epoll) +- get_file(filp_epoll); +- else +- filp_tgt = ERR_PTR(-EBADF); +- spin_unlock(&files->file_lock); +- put_files_struct(files); +- +- if (filp_epoll) { +- filp_tgt = get_epoll_tfile_raw_ptr(filp_epoll, slot.tfd, slot.toff); +- fput(filp_epoll); +- } ++ filp_tgt = get_epoll_tfile_raw_ptr(filp_epoll, slot.tfd, slot.toff); ++ fput(filp_epoll); + + if (IS_ERR(filp_tgt)) + return PTR_ERR(filp_tgt); +-- +2.43.0 + diff --git a/queue-5.10/keep-read-and-write-fds-with-each-nlm_file.patch b/queue-5.10/keep-read-and-write-fds-with-each-nlm_file.patch new file mode 100644 index 00000000000..17d87c9797b --- /dev/null +++ b/queue-5.10/keep-read-and-write-fds-with-each-nlm_file.patch @@ -0,0 +1,450 @@ +From 24b83842bc3fc68ad075306baa3c578f7c8f19a7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Aug 2021 16:44:00 -0400 +Subject: Keep read and write fds with each nlm_file + +From: J. Bruce Fields + +[ Upstream commit 7f024fcd5c97dc70bb9121c80407cf3cf9be7159 ] + +We shouldn't really be using a read-only file descriptor to take a write +lock. + +Most filesystems will put up with it. But NFS, for example, won't. + +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/svc4proc.c | 4 +- + fs/lockd/svclock.c | 25 ++++++--- + fs/lockd/svcproc.c | 4 +- + fs/lockd/svcsubs.c | 102 +++++++++++++++++++++++++----------- + fs/nfsd/lockd.c | 8 ++- + include/linux/lockd/bind.h | 3 +- + include/linux/lockd/lockd.h | 9 +++- + 7 files changed, 111 insertions(+), 44 deletions(-) + +diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c +index bc496bbd696b8..e10ae2c41279e 100644 +--- a/fs/lockd/svc4proc.c ++++ b/fs/lockd/svc4proc.c +@@ -40,13 +40,15 @@ nlm4svc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp, + + /* Obtain file pointer. Not used by FREE_ALL call. */ + if (filp != NULL) { ++ int mode = lock_to_openmode(&lock->fl); ++ + error = nlm_lookup_file(rqstp, &file, lock); + if (error) + goto no_locks; + *filp = file; + + /* Set up the missing parts of the file_lock structure */ +- lock->fl.fl_file = file->f_file; ++ lock->fl.fl_file = file->f_file[mode]; + lock->fl.fl_pid = current->tgid; + lock->fl.fl_lmops = &nlmsvc_lock_operations; + nlmsvc_locks_init_private(&lock->fl, host, (pid_t)lock->svid); +diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c +index bcd180ba99576..a7b4c51667ada 100644 +--- a/fs/lockd/svclock.c ++++ b/fs/lockd/svclock.c +@@ -471,6 +471,7 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, + { + struct nlm_block *block = NULL; + int error; ++ int mode; + __be32 ret; + + dprintk("lockd: nlmsvc_lock(%s/%ld, ty=%d, pi=%d, %Ld-%Ld, bl=%d)\n", +@@ -524,7 +525,8 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, + + if (!wait) + lock->fl.fl_flags &= ~FL_SLEEP; +- error = vfs_lock_file(file->f_file, F_SETLK, &lock->fl, NULL); ++ mode = lock_to_openmode(&lock->fl); ++ error = vfs_lock_file(file->f_file[mode], F_SETLK, &lock->fl, NULL); + lock->fl.fl_flags &= ~FL_SLEEP; + + dprintk("lockd: vfs_lock_file returned %d\n", error); +@@ -577,6 +579,7 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file, + struct nlm_lock *conflock, struct nlm_cookie *cookie) + { + int error; ++ int mode; + __be32 ret; + struct nlm_lockowner *test_owner; + +@@ -595,7 +598,8 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file, + /* If there's a conflicting lock, remember to clean up the test lock */ + test_owner = (struct nlm_lockowner *)lock->fl.fl_owner; + +- error = vfs_test_lock(file->f_file, &lock->fl); ++ mode = lock_to_openmode(&lock->fl); ++ error = vfs_test_lock(file->f_file[mode], &lock->fl); + if (error) { + /* We can't currently deal with deferred test requests */ + if (error == FILE_LOCK_DEFERRED) +@@ -641,7 +645,7 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file, + __be32 + nlmsvc_unlock(struct net *net, struct nlm_file *file, struct nlm_lock *lock) + { +- int error; ++ int error = 0; + + dprintk("lockd: nlmsvc_unlock(%s/%ld, pi=%d, %Ld-%Ld)\n", + nlmsvc_file_inode(file)->i_sb->s_id, +@@ -654,7 +658,12 @@ nlmsvc_unlock(struct net *net, struct nlm_file *file, struct nlm_lock *lock) + nlmsvc_cancel_blocked(net, file, lock); + + lock->fl.fl_type = F_UNLCK; +- error = vfs_lock_file(file->f_file, F_SETLK, &lock->fl, NULL); ++ if (file->f_file[O_RDONLY]) ++ error = vfs_lock_file(file->f_file[O_RDONLY], F_SETLK, ++ &lock->fl, NULL); ++ if (file->f_file[O_WRONLY]) ++ error = vfs_lock_file(file->f_file[O_WRONLY], F_SETLK, ++ &lock->fl, NULL); + + return (error < 0)? nlm_lck_denied_nolocks : nlm_granted; + } +@@ -671,6 +680,7 @@ nlmsvc_cancel_blocked(struct net *net, struct nlm_file *file, struct nlm_lock *l + { + struct nlm_block *block; + int status = 0; ++ int mode; + + dprintk("lockd: nlmsvc_cancel(%s/%ld, pi=%d, %Ld-%Ld)\n", + nlmsvc_file_inode(file)->i_sb->s_id, +@@ -686,7 +696,8 @@ nlmsvc_cancel_blocked(struct net *net, struct nlm_file *file, struct nlm_lock *l + block = nlmsvc_lookup_block(file, lock); + mutex_unlock(&file->f_mutex); + if (block != NULL) { +- vfs_cancel_lock(block->b_file->f_file, ++ mode = lock_to_openmode(&lock->fl); ++ vfs_cancel_lock(block->b_file->f_file[mode], + &block->b_call->a_args.lock.fl); + status = nlmsvc_unlink_block(block); + nlmsvc_release_block(block); +@@ -803,6 +814,7 @@ nlmsvc_grant_blocked(struct nlm_block *block) + { + struct nlm_file *file = block->b_file; + struct nlm_lock *lock = &block->b_call->a_args.lock; ++ int mode; + int error; + loff_t fl_start, fl_end; + +@@ -828,7 +840,8 @@ nlmsvc_grant_blocked(struct nlm_block *block) + lock->fl.fl_flags |= FL_SLEEP; + fl_start = lock->fl.fl_start; + fl_end = lock->fl.fl_end; +- error = vfs_lock_file(file->f_file, F_SETLK, &lock->fl, NULL); ++ mode = lock_to_openmode(&lock->fl); ++ error = vfs_lock_file(file->f_file[mode], F_SETLK, &lock->fl, NULL); + lock->fl.fl_flags &= ~FL_SLEEP; + lock->fl.fl_start = fl_start; + lock->fl.fl_end = fl_end; +diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c +index f4e5e0eb30fd1..99696d3f6dd66 100644 +--- a/fs/lockd/svcproc.c ++++ b/fs/lockd/svcproc.c +@@ -55,6 +55,7 @@ nlmsvc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp, + struct nlm_host *host = NULL; + struct nlm_file *file = NULL; + struct nlm_lock *lock = &argp->lock; ++ int mode; + __be32 error = 0; + + /* nfsd callbacks must have been installed for this procedure */ +@@ -75,7 +76,8 @@ nlmsvc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp, + *filp = file; + + /* Set up the missing parts of the file_lock structure */ +- lock->fl.fl_file = file->f_file; ++ mode = lock_to_openmode(&lock->fl); ++ lock->fl.fl_file = file->f_file[mode]; + lock->fl.fl_pid = current->tgid; + lock->fl.fl_lmops = &nlmsvc_lock_operations; + nlmsvc_locks_init_private(&lock->fl, host, (pid_t)lock->svid); +diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c +index 13e6ffc219ec9..cb3a7512c33ec 100644 +--- a/fs/lockd/svcsubs.c ++++ b/fs/lockd/svcsubs.c +@@ -71,14 +71,35 @@ static inline unsigned int file_hash(struct nfs_fh *f) + return tmp & (FILE_NRHASH - 1); + } + ++int lock_to_openmode(struct file_lock *lock) ++{ ++ return (lock->fl_type == F_WRLCK) ? O_WRONLY : O_RDONLY; ++} ++ ++/* ++ * Open the file. Note that if we're reexporting, for example, ++ * this could block the lockd thread for a while. ++ * ++ * We have to make sure we have the right credential to open ++ * the file. ++ */ ++static __be32 nlm_do_fopen(struct svc_rqst *rqstp, ++ struct nlm_file *file, int mode) ++{ ++ struct file **fp = &file->f_file[mode]; ++ __be32 nfserr; ++ ++ if (*fp) ++ return 0; ++ nfserr = nlmsvc_ops->fopen(rqstp, &file->f_handle, fp, mode); ++ if (nfserr) ++ dprintk("lockd: open failed (error %d)\n", nfserr); ++ return nfserr; ++} ++ + /* + * Lookup file info. If it doesn't exist, create a file info struct + * and open a (VFS) file for the given inode. +- * +- * FIXME: +- * Note that we open the file O_RDONLY even when creating write locks. +- * This is not quite right, but for now, we assume the client performs +- * the proper R/W checking. + */ + __be32 + nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result, +@@ -87,42 +108,38 @@ nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result, + struct nlm_file *file; + unsigned int hash; + __be32 nfserr; ++ int mode; + + nlm_debug_print_fh("nlm_lookup_file", &lock->fh); + + hash = file_hash(&lock->fh); ++ mode = lock_to_openmode(&lock->fl); + + /* Lock file table */ + mutex_lock(&nlm_file_mutex); + + hlist_for_each_entry(file, &nlm_files[hash], f_list) +- if (!nfs_compare_fh(&file->f_handle, &lock->fh)) ++ if (!nfs_compare_fh(&file->f_handle, &lock->fh)) { ++ mutex_lock(&file->f_mutex); ++ nfserr = nlm_do_fopen(rqstp, file, mode); ++ mutex_unlock(&file->f_mutex); + goto found; +- ++ } + nlm_debug_print_fh("creating file for", &lock->fh); + + nfserr = nlm_lck_denied_nolocks; + file = kzalloc(sizeof(*file), GFP_KERNEL); + if (!file) +- goto out_unlock; ++ goto out_free; + + memcpy(&file->f_handle, &lock->fh, sizeof(struct nfs_fh)); + mutex_init(&file->f_mutex); + INIT_HLIST_NODE(&file->f_list); + INIT_LIST_HEAD(&file->f_blocks); + +- /* +- * Open the file. Note that if we're reexporting, for example, +- * this could block the lockd thread for a while. +- * +- * We have to make sure we have the right credential to open +- * the file. +- */ +- nfserr = nlmsvc_ops->fopen(rqstp, &lock->fh, &file->f_file); +- if (nfserr) { +- dprintk("lockd: open failed (error %d)\n", nfserr); +- goto out_free; +- } ++ nfserr = nlm_do_fopen(rqstp, file, mode); ++ if (nfserr) ++ goto out_unlock; + + hlist_add_head(&file->f_list, &nlm_files[hash]); + +@@ -130,7 +147,6 @@ nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result, + dprintk("lockd: found file %p (count %d)\n", file, file->f_count); + *result = file; + file->f_count++; +- nfserr = 0; + + out_unlock: + mutex_unlock(&nlm_file_mutex); +@@ -150,13 +166,34 @@ nlm_delete_file(struct nlm_file *file) + nlm_debug_print_file("closing file", file); + if (!hlist_unhashed(&file->f_list)) { + hlist_del(&file->f_list); +- nlmsvc_ops->fclose(file->f_file); ++ if (file->f_file[O_RDONLY]) ++ nlmsvc_ops->fclose(file->f_file[O_RDONLY]); ++ if (file->f_file[O_WRONLY]) ++ nlmsvc_ops->fclose(file->f_file[O_WRONLY]); + kfree(file); + } else { + printk(KERN_WARNING "lockd: attempt to release unknown file!\n"); + } + } + ++static int nlm_unlock_files(struct nlm_file *file) ++{ ++ struct file_lock lock; ++ struct file *f; ++ ++ lock.fl_type = F_UNLCK; ++ lock.fl_start = 0; ++ lock.fl_end = OFFSET_MAX; ++ for (f = file->f_file[0]; f <= file->f_file[1]; f++) { ++ if (f && vfs_lock_file(f, F_SETLK, &lock, NULL) < 0) { ++ pr_warn("lockd: unlock failure in %s:%d\n", ++ __FILE__, __LINE__); ++ return 1; ++ } ++ } ++ return 0; ++} ++ + /* + * Loop over all locks on the given file and perform the specified + * action. +@@ -184,17 +221,10 @@ nlm_traverse_locks(struct nlm_host *host, struct nlm_file *file, + + lockhost = ((struct nlm_lockowner *)fl->fl_owner)->host; + if (match(lockhost, host)) { +- struct file_lock lock = *fl; + + spin_unlock(&flctx->flc_lock); +- lock.fl_type = F_UNLCK; +- lock.fl_start = 0; +- lock.fl_end = OFFSET_MAX; +- if (vfs_lock_file(file->f_file, F_SETLK, &lock, NULL) < 0) { +- printk("lockd: unlock failure in %s:%d\n", +- __FILE__, __LINE__); ++ if (nlm_unlock_files(file)) + return 1; +- } + goto again; + } + } +@@ -248,6 +278,15 @@ nlm_file_inuse(struct nlm_file *file) + return 0; + } + ++static void nlm_close_files(struct nlm_file *file) ++{ ++ struct file *f; ++ ++ for (f = file->f_file[0]; f <= file->f_file[1]; f++) ++ if (f) ++ nlmsvc_ops->fclose(f); ++} ++ + /* + * Loop over all files in the file table. + */ +@@ -278,7 +317,7 @@ nlm_traverse_files(void *data, nlm_host_match_fn_t match, + if (list_empty(&file->f_blocks) && !file->f_locks + && !file->f_shares && !file->f_count) { + hlist_del(&file->f_list); +- nlmsvc_ops->fclose(file->f_file); ++ nlm_close_files(file); + kfree(file); + } + } +@@ -412,6 +451,7 @@ nlmsvc_invalidate_all(void) + nlm_traverse_files(NULL, nlmsvc_is_client, NULL); + } + ++ + static int + nlmsvc_match_sb(void *datap, struct nlm_file *file) + { +diff --git a/fs/nfsd/lockd.c b/fs/nfsd/lockd.c +index 3f5b3d7b62b71..606fa155c28ad 100644 +--- a/fs/nfsd/lockd.c ++++ b/fs/nfsd/lockd.c +@@ -25,9 +25,11 @@ + * Note: we hold the dentry use count while the file is open. + */ + static __be32 +-nlm_fopen(struct svc_rqst *rqstp, struct nfs_fh *f, struct file **filp) ++nlm_fopen(struct svc_rqst *rqstp, struct nfs_fh *f, struct file **filp, ++ int mode) + { + __be32 nfserr; ++ int access; + struct svc_fh fh; + + /* must initialize before using! but maxsize doesn't matter */ +@@ -36,7 +38,9 @@ nlm_fopen(struct svc_rqst *rqstp, struct nfs_fh *f, struct file **filp) + memcpy((char*)&fh.fh_handle.fh_base, f->data, f->size); + fh.fh_export = NULL; + +- nfserr = nfsd_open(rqstp, &fh, S_IFREG, NFSD_MAY_LOCK, filp); ++ access = (mode == O_WRONLY) ? NFSD_MAY_WRITE : NFSD_MAY_READ; ++ access |= NFSD_MAY_LOCK; ++ nfserr = nfsd_open(rqstp, &fh, S_IFREG, access, filp); + fh_put(&fh); + /* We return nlm error codes as nlm doesn't know + * about nfsd, but nfsd does know about nlm.. +diff --git a/include/linux/lockd/bind.h b/include/linux/lockd/bind.h +index 0520c0cd73f42..3bc9f7410e213 100644 +--- a/include/linux/lockd/bind.h ++++ b/include/linux/lockd/bind.h +@@ -27,7 +27,8 @@ struct rpc_task; + struct nlmsvc_binding { + __be32 (*fopen)(struct svc_rqst *, + struct nfs_fh *, +- struct file **); ++ struct file **, ++ int mode); + void (*fclose)(struct file *); + }; + +diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h +index 81b71ad2040ac..c4ae6506b8b36 100644 +--- a/include/linux/lockd/lockd.h ++++ b/include/linux/lockd/lockd.h +@@ -10,6 +10,8 @@ + #ifndef LINUX_LOCKD_LOCKD_H + #define LINUX_LOCKD_LOCKD_H + ++/* XXX: a lot of this should really be under fs/lockd. */ ++ + #include + #include + #include +@@ -154,7 +156,8 @@ struct nlm_rqst { + struct nlm_file { + struct hlist_node f_list; /* linked list */ + struct nfs_fh f_handle; /* NFS file handle */ +- struct file * f_file; /* VFS file pointer */ ++ struct file * f_file[2]; /* VFS file pointers, ++ indexed by O_ flags */ + struct nlm_share * f_shares; /* DOS shares */ + struct list_head f_blocks; /* blocked locks */ + unsigned int f_locks; /* guesstimate # of locks */ +@@ -267,6 +270,7 @@ typedef int (*nlm_host_match_fn_t)(void *cur, struct nlm_host *ref); + /* + * Server-side lock handling + */ ++int lock_to_openmode(struct file_lock *); + __be32 nlmsvc_lock(struct svc_rqst *, struct nlm_file *, + struct nlm_host *, struct nlm_lock *, int, + struct nlm_cookie *, int); +@@ -301,7 +305,8 @@ int nlmsvc_unlock_all_by_ip(struct sockaddr *server_addr); + + static inline struct inode *nlmsvc_file_inode(struct nlm_file *file) + { +- return locks_inode(file->f_file); ++ return locks_inode(file->f_file[O_RDONLY] ? ++ file->f_file[O_RDONLY] : file->f_file[O_WRONLY]); + } + + static inline int __nlm_privileged_request4(const struct sockaddr *sap) +-- +2.43.0 + diff --git a/queue-5.10/kernel-pid.c-implement-additional-checks-upon-pidfd_.patch b/queue-5.10/kernel-pid.c-implement-additional-checks-upon-pidfd_.patch new file mode 100644 index 00000000000..5594325be48 --- /dev/null +++ b/queue-5.10/kernel-pid.c-implement-additional-checks-upon-pidfd_.patch @@ -0,0 +1,60 @@ +From 42d0d77b31a67f091dccc2c6a198577e3816816d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 8 Aug 2021 15:25:05 +1000 +Subject: kernel/pid.c: implement additional checks upon pidfd_create() + parameters + +From: Matthew Bobrowski + +[ Upstream commit 490b9ba881e2c6337bb09b68010803ae98e59f4a ] + +By adding the pidfd_create() declaration to linux/pid.h, we +effectively expose this function to the rest of the kernel. In order +to avoid any unintended behavior, or set false expectations upon this +function, ensure that constraints are forced upon each of the passed +parameters. This includes the checking of whether the passed struct +pid is a thread-group leader as pidfd creation is currently limited to +such pid types. + +Link: https://lore.kernel.org/r/2e9b91c2d529d52a003b8b86c45f866153be9eb5.1628398044.git.repnop@google.com +Signed-off-by: Matthew Bobrowski +Acked-by: Christian Brauner +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + kernel/pid.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/kernel/pid.c b/kernel/pid.c +index 74f0466757cbf..0820f2c50bb0c 100644 +--- a/kernel/pid.c ++++ b/kernel/pid.c +@@ -559,6 +559,12 @@ int pidfd_create(struct pid *pid, unsigned int flags) + { + int fd; + ++ if (!pid || !pid_has_task(pid, PIDTYPE_TGID)) ++ return -EINVAL; ++ ++ if (flags & ~(O_NONBLOCK | O_RDWR | O_CLOEXEC)) ++ return -EINVAL; ++ + fd = anon_inode_getfd("[pidfd]", &pidfd_fops, get_pid(pid), + flags | O_RDWR | O_CLOEXEC); + if (fd < 0) +@@ -598,10 +604,7 @@ SYSCALL_DEFINE2(pidfd_open, pid_t, pid, unsigned int, flags) + if (!p) + return -ESRCH; + +- if (pid_has_task(p, PIDTYPE_TGID)) +- fd = pidfd_create(p, flags); +- else +- fd = -EINVAL; ++ fd = pidfd_create(p, flags); + + put_pid(p); + return fd; +-- +2.43.0 + diff --git a/queue-5.10/kernel-pid.c-remove-static-qualifier-from-pidfd_crea.patch b/queue-5.10/kernel-pid.c-remove-static-qualifier-from-pidfd_crea.patch new file mode 100644 index 00000000000..4ad7d110d02 --- /dev/null +++ b/queue-5.10/kernel-pid.c-remove-static-qualifier-from-pidfd_crea.patch @@ -0,0 +1,59 @@ +From ce17a49485781ae9d616beb8306b8efcc477f89d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 8 Aug 2021 15:24:33 +1000 +Subject: kernel/pid.c: remove static qualifier from pidfd_create() + +From: Matthew Bobrowski + +[ Upstream commit c576e0fcd6188d0edb50b0fb83f853433ef4819b ] + +With the idea of returning pidfds from the fanotify API, we need to +expose a mechanism for creating pidfds. We drop the static qualifier +from pidfd_create() and add its declaration to linux/pid.h so that the +pidfd_create() helper can be called from other kernel subsystems +i.e. fanotify. + +Link: https://lore.kernel.org/r/0c68653ec32f1b7143301f0231f7ed14062fd82b.1628398044.git.repnop@google.com +Signed-off-by: Matthew Bobrowski +Acked-by: Christian Brauner +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + include/linux/pid.h | 1 + + kernel/pid.c | 4 +++- + 2 files changed, 4 insertions(+), 1 deletion(-) + +diff --git a/include/linux/pid.h b/include/linux/pid.h +index fa10acb8d6a42..af308e15f174c 100644 +--- a/include/linux/pid.h ++++ b/include/linux/pid.h +@@ -78,6 +78,7 @@ struct file; + + extern struct pid *pidfd_pid(const struct file *file); + struct pid *pidfd_get_pid(unsigned int fd, unsigned int *flags); ++int pidfd_create(struct pid *pid, unsigned int flags); + + static inline struct pid *get_pid(struct pid *pid) + { +diff --git a/kernel/pid.c b/kernel/pid.c +index 4856818c9de1a..74f0466757cbf 100644 +--- a/kernel/pid.c ++++ b/kernel/pid.c +@@ -550,10 +550,12 @@ struct pid *pidfd_get_pid(unsigned int fd, unsigned int *flags) + * Note, that this function can only be called after the fd table has + * been unshared to avoid leaking the pidfd to the new process. + * ++ * This symbol should not be explicitly exported to loadable modules. ++ * + * Return: On success, a cloexec pidfd is returned. + * On error, a negative errno number will be returned. + */ +-static int pidfd_create(struct pid *pid, unsigned int flags) ++int pidfd_create(struct pid *pid, unsigned int flags) + { + int fd; + +-- +2.43.0 + diff --git a/queue-5.10/lockd-change-the-proc_handler-for-nsm_use_hostnames.patch b/queue-5.10/lockd-change-the-proc_handler-for-nsm_use_hostnames.patch new file mode 100644 index 00000000000..ccc5bb97928 --- /dev/null +++ b/queue-5.10/lockd-change-the-proc_handler-for-nsm_use_hostnames.patch @@ -0,0 +1,43 @@ +From 7e784a647a333dfa69e3cf719b179fe8b0247555 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Aug 2021 12:59:37 +0200 +Subject: lockd: change the proc_handler for nsm_use_hostnames + +From: Jia He + +[ Upstream commit d02a3a2cb25d384005a6e3446a445013342024b7 ] + +nsm_use_hostnames is a module parameter and it will be exported to sysctl +procfs. This is to let user sometimes change it from userspace. But the +minimal unit for sysctl procfs read/write it sizeof(int). +In big endian system, the converting from/to bool to/from int will cause +error for proc items. + +This patch use a new proc_handler proc_dobool to fix it. + +Signed-off-by: Jia He +Reviewed-by: Pan Xinhui +[thuth: Fix typo in commit message] +Signed-off-by: Thomas Huth +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/svc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c +index 2de048f80eb8c..0ab9756ed2359 100644 +--- a/fs/lockd/svc.c ++++ b/fs/lockd/svc.c +@@ -584,7 +584,7 @@ static struct ctl_table nlm_sysctls[] = { + .data = &nsm_use_hostnames, + .maxlen = sizeof(int), + .mode = 0644, +- .proc_handler = proc_dointvec, ++ .proc_handler = proc_dobool, + }, + { + .procname = "nsm_local_state", +-- +2.43.0 + diff --git a/queue-5.10/lockd-common-nlm-xdr-helpers.patch b/queue-5.10/lockd-common-nlm-xdr-helpers.patch new file mode 100644 index 00000000000..098750b68d9 --- /dev/null +++ b/queue-5.10/lockd-common-nlm-xdr-helpers.patch @@ -0,0 +1,181 @@ +From 880285e07a4fc0d848cd2d27b201abff5461bd0e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 3 Jun 2021 16:50:52 -0400 +Subject: lockd: Common NLM XDR helpers + +From: Chuck Lever + +[ Upstream commit a6a63ca5652ea05637ecfe349f9e895031529556 ] + +Add a .h file containing xdr_stream-based XDR helpers common to both +NLMv3 and NLMv4. + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/svcxdr.h | 151 ++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 151 insertions(+) + create mode 100644 fs/lockd/svcxdr.h + +diff --git a/fs/lockd/svcxdr.h b/fs/lockd/svcxdr.h +new file mode 100644 +index 0000000000000..c69a0bb76c940 +--- /dev/null ++++ b/fs/lockd/svcxdr.h +@@ -0,0 +1,151 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++/* ++ * Encode/decode NLM basic data types ++ * ++ * Basic NLMv3 XDR data types are not defined in an IETF standards ++ * document. X/Open has a description of these data types that ++ * is useful. See Chapter 10 of "Protocols for Interworking: ++ * XNFS, Version 3W". ++ * ++ * Basic NLMv4 XDR data types are defined in Appendix II.1.4 of ++ * RFC 1813: "NFS Version 3 Protocol Specification". ++ * ++ * Author: Chuck Lever ++ * ++ * Copyright (c) 2020, Oracle and/or its affiliates. ++ */ ++ ++#ifndef _LOCKD_SVCXDR_H_ ++#define _LOCKD_SVCXDR_H_ ++ ++static inline bool ++svcxdr_decode_stats(struct xdr_stream *xdr, __be32 *status) ++{ ++ __be32 *p; ++ ++ p = xdr_inline_decode(xdr, XDR_UNIT); ++ if (!p) ++ return false; ++ *status = *p; ++ ++ return true; ++} ++ ++static inline bool ++svcxdr_encode_stats(struct xdr_stream *xdr, __be32 status) ++{ ++ __be32 *p; ++ ++ p = xdr_reserve_space(xdr, XDR_UNIT); ++ if (!p) ++ return false; ++ *p = status; ++ ++ return true; ++} ++ ++static inline bool ++svcxdr_decode_string(struct xdr_stream *xdr, char **data, unsigned int *data_len) ++{ ++ __be32 *p; ++ u32 len; ++ ++ if (xdr_stream_decode_u32(xdr, &len) < 0) ++ return false; ++ if (len > NLM_MAXSTRLEN) ++ return false; ++ p = xdr_inline_decode(xdr, len); ++ if (!p) ++ return false; ++ *data_len = len; ++ *data = (char *)p; ++ ++ return true; ++} ++ ++/* ++ * NLM cookies are defined by specification to be a variable-length ++ * XDR opaque no longer than 1024 bytes. However, this implementation ++ * limits their length to 32 bytes, and treats zero-length cookies ++ * specially. ++ */ ++static inline bool ++svcxdr_decode_cookie(struct xdr_stream *xdr, struct nlm_cookie *cookie) ++{ ++ __be32 *p; ++ u32 len; ++ ++ if (xdr_stream_decode_u32(xdr, &len) < 0) ++ return false; ++ if (len > NLM_MAXCOOKIELEN) ++ return false; ++ if (!len) ++ goto out_hpux; ++ ++ p = xdr_inline_decode(xdr, len); ++ if (!p) ++ return false; ++ cookie->len = len; ++ memcpy(cookie->data, p, len); ++ ++ return true; ++ ++ /* apparently HPUX can return empty cookies */ ++out_hpux: ++ cookie->len = 4; ++ memset(cookie->data, 0, 4); ++ return true; ++} ++ ++static inline bool ++svcxdr_encode_cookie(struct xdr_stream *xdr, const struct nlm_cookie *cookie) ++{ ++ __be32 *p; ++ ++ if (xdr_stream_encode_u32(xdr, cookie->len) < 0) ++ return false; ++ p = xdr_reserve_space(xdr, cookie->len); ++ if (!p) ++ return false; ++ memcpy(p, cookie->data, cookie->len); ++ ++ return true; ++} ++ ++static inline bool ++svcxdr_decode_owner(struct xdr_stream *xdr, struct xdr_netobj *obj) ++{ ++ __be32 *p; ++ u32 len; ++ ++ if (xdr_stream_decode_u32(xdr, &len) < 0) ++ return false; ++ if (len > XDR_MAX_NETOBJ) ++ return false; ++ p = xdr_inline_decode(xdr, len); ++ if (!p) ++ return false; ++ obj->len = len; ++ obj->data = (u8 *)p; ++ ++ return true; ++} ++ ++static inline bool ++svcxdr_encode_owner(struct xdr_stream *xdr, const struct xdr_netobj *obj) ++{ ++ unsigned int quadlen = XDR_QUADLEN(obj->len); ++ __be32 *p; ++ ++ if (xdr_stream_encode_u32(xdr, obj->len) < 0) ++ return false; ++ p = xdr_reserve_space(xdr, obj->len); ++ if (!p) ++ return false; ++ p[quadlen - 1] = 0; /* XDR pad */ ++ memcpy(p, obj->data, obj->len); ++ ++ return true; ++} ++ ++#endif /* _LOCKD_SVCXDR_H_ */ +-- +2.43.0 + diff --git a/queue-5.10/lockd-create-a-simplified-.vs_dispatch-method-for-nl.patch b/queue-5.10/lockd-create-a-simplified-.vs_dispatch-method-for-nl.patch new file mode 100644 index 00000000000..84962682838 --- /dev/null +++ b/queue-5.10/lockd-create-a-simplified-.vs_dispatch-method-for-nl.patch @@ -0,0 +1,98 @@ +From 9b9cf3b7643b6b720b13587ca1088b18510f13a4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 3 Jun 2021 16:50:46 -0400 +Subject: lockd: Create a simplified .vs_dispatch method for NLM requests + +From: Chuck Lever + +[ Upstream commit a9ad1a8090f58b2ed1774dd0f4c7cdb8210a3793 ] + +To enable xdr_stream-based encoding and decoding, create a bespoke +RPC dispatch function for the lockd service. + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/svc.c | 43 +++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 43 insertions(+) + +diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c +index 1a639e34847dd..2de048f80eb8c 100644 +--- a/fs/lockd/svc.c ++++ b/fs/lockd/svc.c +@@ -766,6 +766,46 @@ static void __exit exit_nlm(void) + module_init(init_nlm); + module_exit(exit_nlm); + ++/** ++ * nlmsvc_dispatch - Process an NLM Request ++ * @rqstp: incoming request ++ * @statp: pointer to location of accept_stat field in RPC Reply buffer ++ * ++ * Return values: ++ * %0: Processing complete; do not send a Reply ++ * %1: Processing complete; send Reply in rqstp->rq_res ++ */ ++static int nlmsvc_dispatch(struct svc_rqst *rqstp, __be32 *statp) ++{ ++ const struct svc_procedure *procp = rqstp->rq_procinfo; ++ struct kvec *argv = rqstp->rq_arg.head; ++ struct kvec *resv = rqstp->rq_res.head; ++ ++ svcxdr_init_decode(rqstp); ++ if (!procp->pc_decode(rqstp, argv->iov_base)) ++ goto out_decode_err; ++ ++ *statp = procp->pc_func(rqstp); ++ if (*statp == rpc_drop_reply) ++ return 0; ++ if (*statp != rpc_success) ++ return 1; ++ ++ svcxdr_init_encode(rqstp); ++ if (!procp->pc_encode(rqstp, resv->iov_base + resv->iov_len)) ++ goto out_encode_err; ++ ++ return 1; ++ ++out_decode_err: ++ *statp = rpc_garbage_args; ++ return 1; ++ ++out_encode_err: ++ *statp = rpc_system_err; ++ return 1; ++} ++ + /* + * Define NLM program and procedures + */ +@@ -775,6 +815,7 @@ static const struct svc_version nlmsvc_version1 = { + .vs_nproc = 17, + .vs_proc = nlmsvc_procedures, + .vs_count = nlmsvc_version1_count, ++ .vs_dispatch = nlmsvc_dispatch, + .vs_xdrsize = NLMSVC_XDRSIZE, + }; + static unsigned int nlmsvc_version3_count[24]; +@@ -783,6 +824,7 @@ static const struct svc_version nlmsvc_version3 = { + .vs_nproc = 24, + .vs_proc = nlmsvc_procedures, + .vs_count = nlmsvc_version3_count, ++ .vs_dispatch = nlmsvc_dispatch, + .vs_xdrsize = NLMSVC_XDRSIZE, + }; + #ifdef CONFIG_LOCKD_V4 +@@ -792,6 +834,7 @@ static const struct svc_version nlmsvc_version4 = { + .vs_nproc = 24, + .vs_proc = nlmsvc_procedures4, + .vs_count = nlmsvc_version4_count, ++ .vs_dispatch = nlmsvc_dispatch, + .vs_xdrsize = NLMSVC_XDRSIZE, + }; + #endif +-- +2.43.0 + diff --git a/queue-5.10/lockd-detect-and-reject-lock-arguments-that-overflow.patch b/queue-5.10/lockd-detect-and-reject-lock-arguments-that-overflow.patch new file mode 100644 index 00000000000..a0213abdee8 --- /dev/null +++ b/queue-5.10/lockd-detect-and-reject-lock-arguments-that-overflow.patch @@ -0,0 +1,128 @@ +From 6ea04d475d0274e08a2efe90b5ac029ae004e061 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 1 Aug 2022 15:57:26 -0400 +Subject: lockd: detect and reject lock arguments that overflow + +From: Jeff Layton + +[ Upstream commit 6930bcbfb6ceda63e298c6af6d733ecdf6bd4cde ] + +lockd doesn't currently vet the start and length in nlm4 requests like +it should, and can end up generating lock requests with arguments that +overflow when passed to the filesystem. + +The NLM4 protocol uses unsigned 64-bit arguments for both start and +length, whereas struct file_lock tracks the start and end as loff_t +values. By the time we get around to calling nlm4svc_retrieve_args, +we've lost the information that would allow us to determine if there was +an overflow. + +Start tracking the actual start and len for NLM4 requests in the +nlm_lock. In nlm4svc_retrieve_args, vet these values to ensure they +won't cause an overflow, and return NLM4_FBIG if they do. + +Link: https://bugzilla.linux-nfs.org/show_bug.cgi?id=392 +Reported-by: Jan Kasiak +Signed-off-by: Jeff Layton +Signed-off-by: Chuck Lever +Cc: # 5.14+ +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/svc4proc.c | 8 ++++++++ + fs/lockd/xdr4.c | 19 ++----------------- + include/linux/lockd/xdr.h | 2 ++ + 3 files changed, 12 insertions(+), 17 deletions(-) + +diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c +index 4f247ab8be611..bf274f23969b3 100644 +--- a/fs/lockd/svc4proc.c ++++ b/fs/lockd/svc4proc.c +@@ -32,6 +32,10 @@ nlm4svc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp, + if (!nlmsvc_ops) + return nlm_lck_denied_nolocks; + ++ if (lock->lock_start > OFFSET_MAX || ++ (lock->lock_len && ((lock->lock_len - 1) > (OFFSET_MAX - lock->lock_start)))) ++ return nlm4_fbig; ++ + /* Obtain host handle */ + if (!(host = nlmsvc_lookup_host(rqstp, lock->caller, lock->len)) + || (argp->monitor && nsm_monitor(host) < 0)) +@@ -50,6 +54,10 @@ nlm4svc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp, + /* Set up the missing parts of the file_lock structure */ + lock->fl.fl_file = file->f_file[mode]; + lock->fl.fl_pid = current->tgid; ++ lock->fl.fl_start = (loff_t)lock->lock_start; ++ lock->fl.fl_end = lock->lock_len ? ++ (loff_t)(lock->lock_start + lock->lock_len - 1) : ++ OFFSET_MAX; + lock->fl.fl_lmops = &nlmsvc_lock_operations; + nlmsvc_locks_init_private(&lock->fl, host, (pid_t)lock->svid); + if (!lock->fl.fl_owner) { +diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c +index 856267c0864bd..712fdfeb8ef06 100644 +--- a/fs/lockd/xdr4.c ++++ b/fs/lockd/xdr4.c +@@ -20,13 +20,6 @@ + + #include "svcxdr.h" + +-static inline loff_t +-s64_to_loff_t(__s64 offset) +-{ +- return (loff_t)offset; +-} +- +- + static inline s64 + loff_t_to_s64(loff_t offset) + { +@@ -70,8 +63,6 @@ static bool + svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock) + { + struct file_lock *fl = &lock->fl; +- u64 len, start; +- s64 end; + + if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len)) + return false; +@@ -81,20 +72,14 @@ svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock) + return false; + if (xdr_stream_decode_u32(xdr, &lock->svid) < 0) + return false; +- if (xdr_stream_decode_u64(xdr, &start) < 0) ++ if (xdr_stream_decode_u64(xdr, &lock->lock_start) < 0) + return false; +- if (xdr_stream_decode_u64(xdr, &len) < 0) ++ if (xdr_stream_decode_u64(xdr, &lock->lock_len) < 0) + return false; + + locks_init_lock(fl); + fl->fl_flags = FL_POSIX; + fl->fl_type = F_RDLCK; +- end = start + len - 1; +- fl->fl_start = s64_to_loff_t(start); +- if (len == 0 || end < 0) +- fl->fl_end = OFFSET_MAX; +- else +- fl->fl_end = s64_to_loff_t(end); + + return true; + } +diff --git a/include/linux/lockd/xdr.h b/include/linux/lockd/xdr.h +index 398f70093cd35..67e4a2c5500bd 100644 +--- a/include/linux/lockd/xdr.h ++++ b/include/linux/lockd/xdr.h +@@ -41,6 +41,8 @@ struct nlm_lock { + struct nfs_fh fh; + struct xdr_netobj oh; + u32 svid; ++ u64 lock_start; ++ u64 lock_len; + struct file_lock fl; + }; + +-- +2.43.0 + diff --git a/queue-5.10/lockd-don-t-attempt-blocking-locks-on-nfs-reexports.patch b/queue-5.10/lockd-don-t-attempt-blocking-locks-on-nfs-reexports.patch new file mode 100644 index 00000000000..69a7066bee0 --- /dev/null +++ b/queue-5.10/lockd-don-t-attempt-blocking-locks-on-nfs-reexports.patch @@ -0,0 +1,76 @@ +From 98647285915659634342aa18626523cb298c2b7c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Aug 2021 17:02:05 -0400 +Subject: lockd: don't attempt blocking locks on nfs reexports + +From: J. Bruce Fields + +[ Upstream commit b840be2f00c0bc00d993f8f76e251052b83e4382 ] + +As in the v4 case, it doesn't work well to block waiting for a lock on +an nfs filesystem. + +As in the v4 case, that means we're depending on the client to poll. +It's probably incorrect to depend on that, but I *think* clients do poll +in practice. In any case, it's an improvement over hanging the lockd +thread indefinitely as we currently are. + +Signed-off-by: J. Bruce Fields +Acked-by: Anna Schumaker +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/svclock.c | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c +index a7b4c51667ada..e9b85d8fd5fe7 100644 +--- a/fs/lockd/svclock.c ++++ b/fs/lockd/svclock.c +@@ -31,6 +31,7 @@ + #include + #include + #include ++#include + + #define NLMDBG_FACILITY NLMDBG_SVCLOCK + +@@ -470,18 +471,24 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, + struct nlm_cookie *cookie, int reclaim) + { + struct nlm_block *block = NULL; ++ struct inode *inode = nlmsvc_file_inode(file); + int error; + int mode; ++ int async_block = 0; + __be32 ret; + + dprintk("lockd: nlmsvc_lock(%s/%ld, ty=%d, pi=%d, %Ld-%Ld, bl=%d)\n", +- nlmsvc_file_inode(file)->i_sb->s_id, +- nlmsvc_file_inode(file)->i_ino, ++ inode->i_sb->s_id, inode->i_ino, + lock->fl.fl_type, lock->fl.fl_pid, + (long long)lock->fl.fl_start, + (long long)lock->fl.fl_end, + wait); + ++ if (inode->i_sb->s_export_op->flags & EXPORT_OP_SYNC_LOCKS) { ++ async_block = wait; ++ wait = 0; ++ } ++ + /* Lock file against concurrent access */ + mutex_lock(&file->f_mutex); + /* Get existing block (in case client is busy-waiting) +@@ -542,7 +549,7 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, + */ + if (wait) + break; +- ret = nlm_lck_denied; ++ ret = async_block ? nlm_lck_blocked : nlm_lck_denied; + goto out; + case FILE_LOCK_DEFERRED: + if (wait) +-- +2.43.0 + diff --git a/queue-5.10/lockd-drop-inappropriate-svc_get-from-locked_get.patch b/queue-5.10/lockd-drop-inappropriate-svc_get-from-locked_get.patch new file mode 100644 index 00000000000..f1a9cbc1a12 --- /dev/null +++ b/queue-5.10/lockd-drop-inappropriate-svc_get-from-locked_get.patch @@ -0,0 +1,57 @@ +From 1bdd3c410860bb07915f07b977dcca37b8779436 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 3 Jun 2023 07:14:14 +1000 +Subject: lockd: drop inappropriate svc_get() from locked_get() + +From: NeilBrown + +[ Upstream commit 665e89ab7c5af1f2d260834c861a74b01a30f95f ] + +The below-mentioned patch was intended to simplify refcounting on the +svc_serv used by locked. The goal was to only ever have a single +reference from the single thread. To that end we dropped a call to +lockd_start_svc() (except when creating thread) which would take a +reference, and dropped the svc_put(serv) that would drop that reference. + +Unfortunately we didn't also remove the svc_get() from +lockd_create_svc() in the case where the svc_serv already existed. +So after the patch: + - on the first call the svc_serv was allocated and the one reference + was given to the thread, so there are no extra references + - on subsequent calls svc_get() was called so there is now an extra + reference. +This is clearly not consistent. + +The inconsistency is also clear in the current code in lockd_get() +takes *two* references, one on nlmsvc_serv and one by incrementing +nlmsvc_users. This clearly does not match lockd_put(). + +So: drop that svc_get() from lockd_get() (which used to be in +lockd_create_svc(). + +Reported-by: Ido Schimmel +Closes: https://lore.kernel.org/linux-nfs/ZHsI%2FH16VX9kJQX1@shredder/T/#u +Fixes: b73a2972041b ("lockd: move lockd_start_svc() call into lockd_create_svc()") +Signed-off-by: NeilBrown +Tested-by: Ido Schimmel +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/svc.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c +index 59ef8a1f843f3..5579e67da17db 100644 +--- a/fs/lockd/svc.c ++++ b/fs/lockd/svc.c +@@ -355,7 +355,6 @@ static int lockd_get(void) + int error; + + if (nlmsvc_serv) { +- svc_get(nlmsvc_serv); + nlmsvc_users++; + return 0; + } +-- +2.43.0 + diff --git a/queue-5.10/lockd-ensure-we-use-the-correct-file-descriptor-when.patch b/queue-5.10/lockd-ensure-we-use-the-correct-file-descriptor-when.patch new file mode 100644 index 00000000000..5a734d8339f --- /dev/null +++ b/queue-5.10/lockd-ensure-we-use-the-correct-file-descriptor-when.patch @@ -0,0 +1,45 @@ +From 38fc5b7d7be63f008e7ec29cfc816a5064761a04 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 11 Nov 2022 14:36:37 -0500 +Subject: lockd: ensure we use the correct file descriptor when unlocking + +From: Jeff Layton + +[ Upstream commit 69efce009f7df888e1fede3cb2913690eb829f52 ] + +Shared locks are set on O_RDONLY descriptors and exclusive locks are set +on O_WRONLY ones. nlmsvc_unlock however calls vfs_lock_file twice, once +for each descriptor, but it doesn't reset fl_file. Ensure that it does. + +Signed-off-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/svclock.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c +index 9c1aa75441e1c..9eae99e08e699 100644 +--- a/fs/lockd/svclock.c ++++ b/fs/lockd/svclock.c +@@ -659,11 +659,13 @@ nlmsvc_unlock(struct net *net, struct nlm_file *file, struct nlm_lock *lock) + nlmsvc_cancel_blocked(net, file, lock); + + lock->fl.fl_type = F_UNLCK; +- if (file->f_file[O_RDONLY]) +- error = vfs_lock_file(file->f_file[O_RDONLY], F_SETLK, ++ lock->fl.fl_file = file->f_file[O_RDONLY]; ++ if (lock->fl.fl_file) ++ error = vfs_lock_file(lock->fl.fl_file, F_SETLK, + &lock->fl, NULL); +- if (file->f_file[O_WRONLY]) +- error = vfs_lock_file(file->f_file[O_WRONLY], F_SETLK, ++ lock->fl.fl_file = file->f_file[O_WRONLY]; ++ if (lock->fl.fl_file) ++ error |= vfs_lock_file(lock->fl.fl_file, F_SETLK, + &lock->fl, NULL); + + return (error < 0)? nlm_lck_denied_nolocks : nlm_granted; +-- +2.43.0 + diff --git a/queue-5.10/lockd-fix-failure-to-cleanup-client-locks.patch b/queue-5.10/lockd-fix-failure-to-cleanup-client-locks.patch new file mode 100644 index 00000000000..35a8cfb336b --- /dev/null +++ b/queue-5.10/lockd-fix-failure-to-cleanup-client-locks.patch @@ -0,0 +1,46 @@ +From f2790c63d6870c588952f2fbdc4e55683479ff49 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 18 Jan 2022 17:00:51 -0500 +Subject: lockd: fix failure to cleanup client locks + +From: J. Bruce Fields + +[ Upstream commit d19a7af73b5ecaac8168712d18be72b9db166768 ] + +In my testing, we're sometimes hitting the request->fl_flags & FL_EXISTS +case in posix_lock_inode, presumably just by random luck since we're not +actually initializing fl_flags here. + +This probably didn't matter before commit 7f024fcd5c97 ("Keep read and +write fds with each nlm_file") since we wouldn't previously unlock +unless we knew there were locks. + +But now it causes lockd to give up on removing more locks. + +We could just initialize fl_flags, but really it seems dubious to be +calling vfs_lock_file with random values in some of the fields. + +Fixes: 7f024fcd5c97 ("Keep read and write fds with each nlm_file") +Signed-off-by: J. Bruce Fields +[ cel: fixed checkpatch.pl nit ] +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/svcsubs.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c +index 54c2e42130ca2..0a22a2faf5522 100644 +--- a/fs/lockd/svcsubs.c ++++ b/fs/lockd/svcsubs.c +@@ -180,6 +180,7 @@ static int nlm_unlock_files(struct nlm_file *file) + { + struct file_lock lock; + ++ locks_init_lock(&lock); + lock.fl_type = F_UNLCK; + lock.fl_start = 0; + lock.fl_end = OFFSET_MAX; +-- +2.43.0 + diff --git a/queue-5.10/lockd-fix-file-selection-in-nlmsvc_cancel_blocked.patch b/queue-5.10/lockd-fix-file-selection-in-nlmsvc_cancel_blocked.patch new file mode 100644 index 00000000000..7e934185ae6 --- /dev/null +++ b/queue-5.10/lockd-fix-file-selection-in-nlmsvc_cancel_blocked.patch @@ -0,0 +1,43 @@ +From 97417dba8915fba6cf1520a6989eb517571dddd4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 11 Nov 2022 14:36:38 -0500 +Subject: lockd: fix file selection in nlmsvc_cancel_blocked + +From: Jeff Layton + +[ Upstream commit 9f27783b4dd235ef3c8dbf69fc6322777450323c ] + +We currently do a lock_to_openmode call based on the arguments from the +NLM_UNLOCK call, but that will always set the fl_type of the lock to +F_UNLCK, and the O_RDONLY descriptor is always chosen. + +Fix it to use the file_lock from the block instead. + +Signed-off-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/svclock.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c +index 9eae99e08e699..4e30f3c509701 100644 +--- a/fs/lockd/svclock.c ++++ b/fs/lockd/svclock.c +@@ -699,9 +699,10 @@ nlmsvc_cancel_blocked(struct net *net, struct nlm_file *file, struct nlm_lock *l + block = nlmsvc_lookup_block(file, lock); + mutex_unlock(&file->f_mutex); + if (block != NULL) { +- mode = lock_to_openmode(&lock->fl); +- vfs_cancel_lock(block->b_file->f_file[mode], +- &block->b_call->a_args.lock.fl); ++ struct file_lock *fl = &block->b_call->a_args.lock.fl; ++ ++ mode = lock_to_openmode(fl); ++ vfs_cancel_lock(block->b_file->f_file[mode], fl); + status = nlmsvc_unlink_block(block); + nlmsvc_release_block(block); + } +-- +2.43.0 + diff --git a/queue-5.10/lockd-fix-nlm_close_files.patch b/queue-5.10/lockd-fix-nlm_close_files.patch new file mode 100644 index 00000000000..b02f6bf4630 --- /dev/null +++ b/queue-5.10/lockd-fix-nlm_close_files.patch @@ -0,0 +1,44 @@ +From 3b5b7a58a6508272f2a471ec58c32844d6786638 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 Jul 2022 14:30:14 -0400 +Subject: lockd: fix nlm_close_files + +From: Jeff Layton + +[ Upstream commit 1197eb5906a5464dbaea24cac296dfc38499cc00 ] + +This loop condition tries a bit too hard to be clever. Just test for +the two indices we care about explicitly. + +Cc: J. Bruce Fields +Fixes: 7f024fcd5c97 ("Keep read and write fds with each nlm_file") +Signed-off-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/svcsubs.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c +index b2f277727469c..e1c4617de7714 100644 +--- a/fs/lockd/svcsubs.c ++++ b/fs/lockd/svcsubs.c +@@ -283,11 +283,10 @@ nlm_file_inuse(struct nlm_file *file) + + static void nlm_close_files(struct nlm_file *file) + { +- struct file *f; +- +- for (f = file->f_file[0]; f <= file->f_file[1]; f++) +- if (f) +- nlmsvc_ops->fclose(f); ++ if (file->f_file[O_RDONLY]) ++ nlmsvc_ops->fclose(file->f_file[O_RDONLY]); ++ if (file->f_file[O_WRONLY]) ++ nlmsvc_ops->fclose(file->f_file[O_WRONLY]); + } + + /* +-- +2.43.0 + diff --git a/queue-5.10/lockd-fix-server-crash-on-reboot-of-client-holding-l.patch b/queue-5.10/lockd-fix-server-crash-on-reboot-of-client-holding-l.patch new file mode 100644 index 00000000000..3dbaf9e0d01 --- /dev/null +++ b/queue-5.10/lockd-fix-server-crash-on-reboot-of-client-holding-l.patch @@ -0,0 +1,62 @@ +From 9feb01213455b3eeeefecc8972e42a2ca5f150dd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 18 Jan 2022 17:00:16 -0500 +Subject: lockd: fix server crash on reboot of client holding lock + +From: J. Bruce Fields + +[ Upstream commit 6e7f90d163afa8fc2efd6ae318e7c20156a5621f ] + +I thought I was iterating over the array when actually the iteration is +over the values contained in the array? + +Ugh, keep it simple. + +Symptoms were a null deference in vfs_lock_file() when an NFSv3 client +that previously held a lock came back up and sent a notify. + +Reported-by: Jonathan Woithe +Fixes: 7f024fcd5c97 ("Keep read and write fds with each nlm_file") +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/svcsubs.c | 17 +++++++++-------- + 1 file changed, 9 insertions(+), 8 deletions(-) + +diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c +index cb3a7512c33ec..54c2e42130ca2 100644 +--- a/fs/lockd/svcsubs.c ++++ b/fs/lockd/svcsubs.c +@@ -179,19 +179,20 @@ nlm_delete_file(struct nlm_file *file) + static int nlm_unlock_files(struct nlm_file *file) + { + struct file_lock lock; +- struct file *f; + + lock.fl_type = F_UNLCK; + lock.fl_start = 0; + lock.fl_end = OFFSET_MAX; +- for (f = file->f_file[0]; f <= file->f_file[1]; f++) { +- if (f && vfs_lock_file(f, F_SETLK, &lock, NULL) < 0) { +- pr_warn("lockd: unlock failure in %s:%d\n", +- __FILE__, __LINE__); +- return 1; +- } +- } ++ if (file->f_file[O_RDONLY] && ++ vfs_lock_file(file->f_file[O_RDONLY], F_SETLK, &lock, NULL)) ++ goto out_err; ++ if (file->f_file[O_WRONLY] && ++ vfs_lock_file(file->f_file[O_WRONLY], F_SETLK, &lock, NULL)) ++ goto out_err; + return 0; ++out_err: ++ pr_warn("lockd: unlock failure in %s:%d\n", __FILE__, __LINE__); ++ return 1; + } + + /* +-- +2.43.0 + diff --git a/queue-5.10/lockd-introduce-lockd_put.patch b/queue-5.10/lockd-introduce-lockd_put.patch new file mode 100644 index 00000000000..40b28462f18 --- /dev/null +++ b/queue-5.10/lockd-introduce-lockd_put.patch @@ -0,0 +1,127 @@ +From bc7846e44c4955949b9bc2ccdc54f45b2ec25d99 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Nov 2021 15:51:25 +1100 +Subject: lockd: introduce lockd_put() + +From: NeilBrown + +[ Upstream commit 865b674069e05e5779fcf8cf7a166d2acb7e930b ] + +There is some cleanup that is duplicated in lockd_down() and the failure +path of lockd_up(). +Factor these out into a new lockd_put() and call it from both places. + +lockd_put() does *not* take the mutex - that must be held by the caller. +It decrements nlmsvc_users and if that reaches zero, it cleans up. + +Signed-off-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/svc.c | 64 +++++++++++++++++++++----------------------------- + 1 file changed, 27 insertions(+), 37 deletions(-) + +diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c +index 9aa499a761591..7f12c280fd30d 100644 +--- a/fs/lockd/svc.c ++++ b/fs/lockd/svc.c +@@ -351,14 +351,6 @@ static struct notifier_block lockd_inet6addr_notifier = { + }; + #endif + +-static void lockd_unregister_notifiers(void) +-{ +- unregister_inetaddr_notifier(&lockd_inetaddr_notifier); +-#if IS_ENABLED(CONFIG_IPV6) +- unregister_inet6addr_notifier(&lockd_inet6addr_notifier); +-#endif +-} +- + static int lockd_start_svc(struct svc_serv *serv) + { + int error; +@@ -450,6 +442,27 @@ static int lockd_create_svc(void) + return 0; + } + ++static void lockd_put(void) ++{ ++ if (WARN(nlmsvc_users <= 0, "lockd_down: no users!\n")) ++ return; ++ if (--nlmsvc_users) ++ return; ++ ++ unregister_inetaddr_notifier(&lockd_inetaddr_notifier); ++#if IS_ENABLED(CONFIG_IPV6) ++ unregister_inet6addr_notifier(&lockd_inet6addr_notifier); ++#endif ++ ++ if (nlmsvc_task) { ++ kthread_stop(nlmsvc_task); ++ dprintk("lockd_down: service stopped\n"); ++ nlmsvc_task = NULL; ++ } ++ nlmsvc_serv = NULL; ++ dprintk("lockd_down: service destroyed\n"); ++} ++ + /* + * Bring up the lockd process if it's not already up. + */ +@@ -461,21 +474,16 @@ int lockd_up(struct net *net, const struct cred *cred) + + error = lockd_create_svc(); + if (error) +- goto err_create; ++ goto err; ++ nlmsvc_users++; + + error = lockd_up_net(nlmsvc_serv, net, cred); + if (error < 0) { +- goto err_put; ++ lockd_put(); ++ goto err; + } + +- nlmsvc_users++; +-err_put: +- if (nlmsvc_users == 0) { +- lockd_unregister_notifiers(); +- kthread_stop(nlmsvc_task); +- nlmsvc_serv = NULL; +- } +-err_create: ++err: + mutex_unlock(&nlmsvc_mutex); + return error; + } +@@ -489,25 +497,7 @@ lockd_down(struct net *net) + { + mutex_lock(&nlmsvc_mutex); + lockd_down_net(nlmsvc_serv, net); +- if (nlmsvc_users) { +- if (--nlmsvc_users) +- goto out; +- } else { +- printk(KERN_ERR "lockd_down: no users! task=%p\n", +- nlmsvc_task); +- BUG(); +- } +- +- if (!nlmsvc_task) { +- printk(KERN_ERR "lockd_down: no lockd running.\n"); +- BUG(); +- } +- lockd_unregister_notifiers(); +- kthread_stop(nlmsvc_task); +- dprintk("lockd_down: service destroyed\n"); +- nlmsvc_serv = NULL; +- nlmsvc_task = NULL; +-out: ++ lockd_put(); + mutex_unlock(&nlmsvc_mutex); + } + EXPORT_SYMBOL_GPL(lockd_down); +-- +2.43.0 + diff --git a/queue-5.10/lockd-introduce-nlmsvc_serv.patch b/queue-5.10/lockd-introduce-nlmsvc_serv.patch new file mode 100644 index 00000000000..3e4405d2bde --- /dev/null +++ b/queue-5.10/lockd-introduce-nlmsvc_serv.patch @@ -0,0 +1,152 @@ +From da0effacad97c182b51fc96fbf3d47760a937acc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Nov 2021 15:51:25 +1100 +Subject: lockd: introduce nlmsvc_serv + +From: NeilBrown + +[ Upstream commit 2840fe864c91a0fe822169b1fbfddbcac9aeac43 ] + +lockd has two globals - nlmsvc_task and nlmsvc_rqst - but mostly it +wants the 'struct svc_serv', and when it doesn't want it exactly it can +get to what it wants from the serv. + +This patch is a first step to removing nlmsvc_task and nlmsvc_rqst. It +introduces nlmsvc_serv to store the 'struct svc_serv*'. This is set as +soon as the serv is created, and cleared only when it is destroyed. + +Signed-off-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/svc.c | 36 ++++++++++++++++++++---------------- + 1 file changed, 20 insertions(+), 16 deletions(-) + +diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c +index a9669b106dbde..83874878f41d8 100644 +--- a/fs/lockd/svc.c ++++ b/fs/lockd/svc.c +@@ -54,6 +54,7 @@ EXPORT_SYMBOL_GPL(nlmsvc_ops); + + static DEFINE_MUTEX(nlmsvc_mutex); + static unsigned int nlmsvc_users; ++static struct svc_serv *nlmsvc_serv; + static struct task_struct *nlmsvc_task; + static struct svc_rqst *nlmsvc_rqst; + unsigned long nlmsvc_timeout; +@@ -306,13 +307,12 @@ static int lockd_inetaddr_event(struct notifier_block *this, + !atomic_inc_not_zero(&nlm_ntf_refcnt)) + goto out; + +- if (nlmsvc_rqst) { ++ if (nlmsvc_serv) { + dprintk("lockd_inetaddr_event: removed %pI4\n", + &ifa->ifa_local); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = ifa->ifa_local; +- svc_age_temp_xprts_now(nlmsvc_rqst->rq_server, +- (struct sockaddr *)&sin); ++ svc_age_temp_xprts_now(nlmsvc_serv, (struct sockaddr *)&sin); + } + atomic_dec(&nlm_ntf_refcnt); + wake_up(&nlm_ntf_wq); +@@ -336,14 +336,13 @@ static int lockd_inet6addr_event(struct notifier_block *this, + !atomic_inc_not_zero(&nlm_ntf_refcnt)) + goto out; + +- if (nlmsvc_rqst) { ++ if (nlmsvc_serv) { + dprintk("lockd_inet6addr_event: removed %pI6\n", &ifa->addr); + sin6.sin6_family = AF_INET6; + sin6.sin6_addr = ifa->addr; + if (ipv6_addr_type(&sin6.sin6_addr) & IPV6_ADDR_LINKLOCAL) + sin6.sin6_scope_id = ifa->idev->dev->ifindex; +- svc_age_temp_xprts_now(nlmsvc_rqst->rq_server, +- (struct sockaddr *)&sin6); ++ svc_age_temp_xprts_now(nlmsvc_serv, (struct sockaddr *)&sin6); + } + atomic_dec(&nlm_ntf_refcnt); + wake_up(&nlm_ntf_wq); +@@ -423,15 +422,17 @@ static const struct svc_serv_ops lockd_sv_ops = { + .svo_enqueue_xprt = svc_xprt_do_enqueue, + }; + +-static struct svc_serv *lockd_create_svc(void) ++static int lockd_create_svc(void) + { + struct svc_serv *serv; + + /* + * Check whether we're already up and running. + */ +- if (nlmsvc_rqst) +- return svc_get(nlmsvc_rqst->rq_server); ++ if (nlmsvc_serv) { ++ svc_get(nlmsvc_serv); ++ return 0; ++ } + + /* + * Sanity check: if there's no pid, +@@ -448,14 +449,15 @@ static struct svc_serv *lockd_create_svc(void) + serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, &lockd_sv_ops); + if (!serv) { + printk(KERN_WARNING "lockd_up: create service failed\n"); +- return ERR_PTR(-ENOMEM); ++ return -ENOMEM; + } ++ nlmsvc_serv = serv; + register_inetaddr_notifier(&lockd_inetaddr_notifier); + #if IS_ENABLED(CONFIG_IPV6) + register_inet6addr_notifier(&lockd_inet6addr_notifier); + #endif + dprintk("lockd_up: service created\n"); +- return serv; ++ return 0; + } + + /* +@@ -468,11 +470,10 @@ int lockd_up(struct net *net, const struct cred *cred) + + mutex_lock(&nlmsvc_mutex); + +- serv = lockd_create_svc(); +- if (IS_ERR(serv)) { +- error = PTR_ERR(serv); ++ error = lockd_create_svc(); ++ if (error) + goto err_create; +- } ++ serv = nlmsvc_serv; + + error = lockd_up_net(serv, net, cred); + if (error < 0) { +@@ -487,6 +488,8 @@ int lockd_up(struct net *net, const struct cred *cred) + } + nlmsvc_users++; + err_put: ++ if (nlmsvc_users == 0) ++ nlmsvc_serv = NULL; + svc_put(serv); + err_create: + mutex_unlock(&nlmsvc_mutex); +@@ -501,7 +504,7 @@ void + lockd_down(struct net *net) + { + mutex_lock(&nlmsvc_mutex); +- lockd_down_net(nlmsvc_rqst->rq_server, net); ++ lockd_down_net(nlmsvc_serv, net); + if (nlmsvc_users) { + if (--nlmsvc_users) + goto out; +@@ -519,6 +522,7 @@ lockd_down(struct net *net) + dprintk("lockd_down: service stopped\n"); + lockd_svc_exit_thread(); + dprintk("lockd_down: service destroyed\n"); ++ nlmsvc_serv = NULL; + nlmsvc_task = NULL; + nlmsvc_rqst = NULL; + out: +-- +2.43.0 + diff --git a/queue-5.10/lockd-move-from-strlcpy-with-unused-retval-to-strscp.patch b/queue-5.10/lockd-move-from-strlcpy-with-unused-retval-to-strscp.patch new file mode 100644 index 00000000000..103a332ac24 --- /dev/null +++ b/queue-5.10/lockd-move-from-strlcpy-with-unused-retval-to-strscp.patch @@ -0,0 +1,37 @@ +From e72e73c004e91be1a32be04311b222da18e4fa2a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Aug 2022 23:01:16 +0200 +Subject: lockd: move from strlcpy with unused retval to strscpy + +From: Wolfram Sang + +[ Upstream commit 97f8e62572555f8ad578d7b1739ba64d5d2cac0f ] + +Follow the advice of the below link and prefer 'strscpy' in this +subsystem. Conversion is 1:1 because the return value is not used. +Generated by a coccinelle script. + +Link: https://lore.kernel.org/r/CAHk-=wgfRnXz0W3D37d01q3JFkr_i_uTL=V6A6G1oUZcprmknw@mail.gmail.com/ +Signed-off-by: Wolfram Sang +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/host.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/lockd/host.c b/fs/lockd/host.c +index f802223e71abe..cdc8e12cdac44 100644 +--- a/fs/lockd/host.c ++++ b/fs/lockd/host.c +@@ -164,7 +164,7 @@ static struct nlm_host *nlm_alloc_host(struct nlm_lookup_host_info *ni, + host->h_addrbuf = nsm->sm_addrbuf; + host->net = ni->net; + host->h_cred = get_cred(ni->cred); +- strlcpy(host->nodename, utsname()->nodename, sizeof(host->nodename)); ++ strscpy(host->nodename, utsname()->nodename, sizeof(host->nodename)); + + out: + return host; +-- +2.43.0 + diff --git a/queue-5.10/lockd-move-lockd_start_svc-call-into-lockd_create_sv.patch b/queue-5.10/lockd-move-lockd_start_svc-call-into-lockd_create_sv.patch new file mode 100644 index 00000000000..7bbc2461e2f --- /dev/null +++ b/queue-5.10/lockd-move-lockd_start_svc-call-into-lockd_create_sv.patch @@ -0,0 +1,105 @@ +From 4cf68b925fa4e97b297230505ca239e03dfa938b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Nov 2021 15:51:25 +1100 +Subject: lockd: move lockd_start_svc() call into lockd_create_svc() + +From: NeilBrown + +[ Upstream commit b73a2972041bee70eb0cbbb25fa77828c63c916b ] + +lockd_start_svc() only needs to be called once, just after the svc is +created. If the start fails, the svc is discarded too. + +It thus makes sense to call lockd_start_svc() from lockd_create_svc(). +This allows us to remove the test against nlmsvc_rqst at the start of +lockd_start_svc() - it must always be NULL. + +lockd_up() only held an extra reference on the svc until a thread was +created - then it dropped it. The thread - and thus the extra reference +- will remain until kthread_stop() is called. +Now that the thread is created in lockd_create_svc(), the extra +reference can be dropped there. So the 'serv' variable is no longer +needed in lockd_up(). + +Signed-off-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/svc.c | 22 ++++++++++------------ + 1 file changed, 10 insertions(+), 12 deletions(-) + +diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c +index 20cebb191350f..91e7c839841ec 100644 +--- a/fs/lockd/svc.c ++++ b/fs/lockd/svc.c +@@ -359,9 +359,6 @@ static int lockd_start_svc(struct svc_serv *serv) + { + int error; + +- if (nlmsvc_rqst) +- return 0; +- + /* + * Create the kernel thread and wait for it to start. + */ +@@ -406,6 +403,7 @@ static const struct svc_serv_ops lockd_sv_ops = { + static int lockd_create_svc(void) + { + struct svc_serv *serv; ++ int error; + + /* + * Check whether we're already up and running. +@@ -432,6 +430,13 @@ static int lockd_create_svc(void) + printk(KERN_WARNING "lockd_up: create service failed\n"); + return -ENOMEM; + } ++ ++ error = lockd_start_svc(serv); ++ /* The thread now holds the only reference */ ++ svc_put(serv); ++ if (error < 0) ++ return error; ++ + nlmsvc_serv = serv; + register_inetaddr_notifier(&lockd_inetaddr_notifier); + #if IS_ENABLED(CONFIG_IPV6) +@@ -446,7 +451,6 @@ static int lockd_create_svc(void) + */ + int lockd_up(struct net *net, const struct cred *cred) + { +- struct svc_serv *serv; + int error; + + mutex_lock(&nlmsvc_mutex); +@@ -454,25 +458,19 @@ int lockd_up(struct net *net, const struct cred *cred) + error = lockd_create_svc(); + if (error) + goto err_create; +- serv = nlmsvc_serv; + +- error = lockd_up_net(serv, net, cred); ++ error = lockd_up_net(nlmsvc_serv, net, cred); + if (error < 0) { + goto err_put; + } + +- error = lockd_start_svc(serv); +- if (error < 0) { +- lockd_down_net(serv, net); +- goto err_put; +- } + nlmsvc_users++; + err_put: + if (nlmsvc_users == 0) { + lockd_unregister_notifiers(); ++ kthread_stop(nlmsvc_task); + nlmsvc_serv = NULL; + } +- svc_put(serv); + err_create: + mutex_unlock(&nlmsvc_mutex); + return error; +-- +2.43.0 + diff --git a/queue-5.10/lockd-move-svc_exit_thread-into-the-thread.patch b/queue-5.10/lockd-move-svc_exit_thread-into-the-thread.patch new file mode 100644 index 00000000000..0f26d06255b --- /dev/null +++ b/queue-5.10/lockd-move-svc_exit_thread-into-the-thread.patch @@ -0,0 +1,106 @@ +From dd14a9c872d087c0c8b380572a632e6bc9a93081 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Nov 2021 15:51:25 +1100 +Subject: lockd: move svc_exit_thread() into the thread + +From: NeilBrown + +[ Upstream commit 6a4e2527a63620a820c4ebf3596b57176da26fb3 ] + +The normal place to call svc_exit_thread() is from the thread itself +just before it exists. +Do this for lockd. + +This means that nlmsvc_rqst is not used out side of lockd_start_svc(), +so it can be made local to that function, and renamed to 'rqst'. + +Signed-off-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/svc.c | 23 ++++++++++++----------- + 1 file changed, 12 insertions(+), 11 deletions(-) + +diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c +index 91e7c839841ec..9aa499a761591 100644 +--- a/fs/lockd/svc.c ++++ b/fs/lockd/svc.c +@@ -56,7 +56,6 @@ static DEFINE_MUTEX(nlmsvc_mutex); + static unsigned int nlmsvc_users; + static struct svc_serv *nlmsvc_serv; + static struct task_struct *nlmsvc_task; +-static struct svc_rqst *nlmsvc_rqst; + unsigned long nlmsvc_timeout; + + unsigned int lockd_net_id; +@@ -182,6 +181,11 @@ lockd(void *vrqstp) + nlm_shutdown_hosts(); + cancel_delayed_work_sync(&ln->grace_period_end); + locks_end_grace(&ln->lockd_manager); ++ ++ dprintk("lockd_down: service stopped\n"); ++ ++ svc_exit_thread(rqstp); ++ + return 0; + } + +@@ -358,13 +362,14 @@ static void lockd_unregister_notifiers(void) + static int lockd_start_svc(struct svc_serv *serv) + { + int error; ++ struct svc_rqst *rqst; + + /* + * Create the kernel thread and wait for it to start. + */ +- nlmsvc_rqst = svc_prepare_thread(serv, &serv->sv_pools[0], NUMA_NO_NODE); +- if (IS_ERR(nlmsvc_rqst)) { +- error = PTR_ERR(nlmsvc_rqst); ++ rqst = svc_prepare_thread(serv, &serv->sv_pools[0], NUMA_NO_NODE); ++ if (IS_ERR(rqst)) { ++ error = PTR_ERR(rqst); + printk(KERN_WARNING + "lockd_up: svc_rqst allocation failed, error=%d\n", + error); +@@ -374,24 +379,23 @@ static int lockd_start_svc(struct svc_serv *serv) + svc_sock_update_bufs(serv); + serv->sv_maxconn = nlm_max_connections; + +- nlmsvc_task = kthread_create(lockd, nlmsvc_rqst, "%s", serv->sv_name); ++ nlmsvc_task = kthread_create(lockd, rqst, "%s", serv->sv_name); + if (IS_ERR(nlmsvc_task)) { + error = PTR_ERR(nlmsvc_task); + printk(KERN_WARNING + "lockd_up: kthread_run failed, error=%d\n", error); + goto out_task; + } +- nlmsvc_rqst->rq_task = nlmsvc_task; ++ rqst->rq_task = nlmsvc_task; + wake_up_process(nlmsvc_task); + + dprintk("lockd_up: service started\n"); + return 0; + + out_task: +- svc_exit_thread(nlmsvc_rqst); ++ svc_exit_thread(rqst); + nlmsvc_task = NULL; + out_rqst: +- nlmsvc_rqst = NULL; + return error; + } + +@@ -500,9 +504,6 @@ lockd_down(struct net *net) + } + lockd_unregister_notifiers(); + kthread_stop(nlmsvc_task); +- dprintk("lockd_down: service stopped\n"); +- svc_exit_thread(nlmsvc_rqst); +- nlmsvc_rqst = NULL; + dprintk("lockd_down: service destroyed\n"); + nlmsvc_serv = NULL; + nlmsvc_task = NULL; +-- +2.43.0 + diff --git a/queue-5.10/lockd-remove-stale-comments.patch b/queue-5.10/lockd-remove-stale-comments.patch new file mode 100644 index 00000000000..b3882327d5d --- /dev/null +++ b/queue-5.10/lockd-remove-stale-comments.patch @@ -0,0 +1,55 @@ +From 76215ca3c737de24086611a905a56c5b2fdf3fd2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 3 Jun 2021 16:50:40 -0400 +Subject: lockd: Remove stale comments + +From: Chuck Lever + +[ Upstream commit 99cdf57b33e68df7afc876739c93a11f0b1ba807 ] + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + include/linux/lockd/xdr.h | 6 ------ + include/linux/lockd/xdr4.h | 7 +------ + 2 files changed, 1 insertion(+), 12 deletions(-) + +diff --git a/include/linux/lockd/xdr.h b/include/linux/lockd/xdr.h +index 7ab9f264313f0..a98309c0121cb 100644 +--- a/include/linux/lockd/xdr.h ++++ b/include/linux/lockd/xdr.h +@@ -109,11 +109,5 @@ int nlmsvc_decode_shareargs(struct svc_rqst *, __be32 *); + int nlmsvc_encode_shareres(struct svc_rqst *, __be32 *); + int nlmsvc_decode_notify(struct svc_rqst *, __be32 *); + int nlmsvc_decode_reboot(struct svc_rqst *, __be32 *); +-/* +-int nlmclt_encode_testargs(struct rpc_rqst *, u32 *, struct nlm_args *); +-int nlmclt_encode_lockargs(struct rpc_rqst *, u32 *, struct nlm_args *); +-int nlmclt_encode_cancargs(struct rpc_rqst *, u32 *, struct nlm_args *); +-int nlmclt_encode_unlockargs(struct rpc_rqst *, u32 *, struct nlm_args *); +- */ + + #endif /* LOCKD_XDR_H */ +diff --git a/include/linux/lockd/xdr4.h b/include/linux/lockd/xdr4.h +index e709fe5924f2b..5ae766f26e04f 100644 +--- a/include/linux/lockd/xdr4.h ++++ b/include/linux/lockd/xdr4.h +@@ -37,12 +37,7 @@ int nlm4svc_decode_shareargs(struct svc_rqst *, __be32 *); + int nlm4svc_encode_shareres(struct svc_rqst *, __be32 *); + int nlm4svc_decode_notify(struct svc_rqst *, __be32 *); + int nlm4svc_decode_reboot(struct svc_rqst *, __be32 *); +-/* +-int nlmclt_encode_testargs(struct rpc_rqst *, u32 *, struct nlm_args *); +-int nlmclt_encode_lockargs(struct rpc_rqst *, u32 *, struct nlm_args *); +-int nlmclt_encode_cancargs(struct rpc_rqst *, u32 *, struct nlm_args *); +-int nlmclt_encode_unlockargs(struct rpc_rqst *, u32 *, struct nlm_args *); +- */ ++ + extern const struct rpc_version nlm_version4; + + #endif /* LOCKD_XDR4_H */ +-- +2.43.0 + diff --git a/queue-5.10/lockd-rename-lockd_create_svc-to-lockd_get.patch b/queue-5.10/lockd-rename-lockd_create_svc-to-lockd_get.patch new file mode 100644 index 00000000000..d144547e695 --- /dev/null +++ b/queue-5.10/lockd-rename-lockd_create_svc-to-lockd_get.patch @@ -0,0 +1,71 @@ +From 3a293cec3dda526b399fd42b40ee008cedf4e35b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Nov 2021 15:51:25 +1100 +Subject: lockd: rename lockd_create_svc() to lockd_get() + +From: NeilBrown + +[ Upstream commit ecd3ad68d2c6d3ae178a63a2d9a02c392904fd36 ] + +lockd_create_svc() already does an svc_get() if the service already +exists, so it is more like a "get" than a "create". + +So: + - Move the increment of nlmsvc_users into the function as well + - rename to lockd_get(). + +It is now the inverse of lockd_put(). + +Signed-off-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/svc.c | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) + +diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c +index 7f12c280fd30d..1a7c11118b320 100644 +--- a/fs/lockd/svc.c ++++ b/fs/lockd/svc.c +@@ -396,16 +396,14 @@ static const struct svc_serv_ops lockd_sv_ops = { + .svo_enqueue_xprt = svc_xprt_do_enqueue, + }; + +-static int lockd_create_svc(void) ++static int lockd_get(void) + { + struct svc_serv *serv; + int error; + +- /* +- * Check whether we're already up and running. +- */ + if (nlmsvc_serv) { + svc_get(nlmsvc_serv); ++ nlmsvc_users++; + return 0; + } + +@@ -439,6 +437,7 @@ static int lockd_create_svc(void) + register_inet6addr_notifier(&lockd_inet6addr_notifier); + #endif + dprintk("lockd_up: service created\n"); ++ nlmsvc_users++; + return 0; + } + +@@ -472,10 +471,9 @@ int lockd_up(struct net *net, const struct cred *cred) + + mutex_lock(&nlmsvc_mutex); + +- error = lockd_create_svc(); ++ error = lockd_get(); + if (error) + goto err; +- nlmsvc_users++; + + error = lockd_up_net(nlmsvc_serv, net, cred); + if (error < 0) { +-- +2.43.0 + diff --git a/queue-5.10/lockd-set-file_lock-start-and-end-when-decoding-nlm4.patch b/queue-5.10/lockd-set-file_lock-start-and-end-when-decoding-nlm4.patch new file mode 100644 index 00000000000..f7057a89c10 --- /dev/null +++ b/queue-5.10/lockd-set-file_lock-start-and-end-when-decoding-nlm4.patch @@ -0,0 +1,105 @@ +From 93a98b6041d4a966533d7e6c56650e524530f691 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Mar 2023 06:20:58 -0400 +Subject: lockd: set file_lock start and end when decoding nlm4 testargs + +From: Jeff Layton + +[ Upstream commit 7ff84910c66c9144cc0de9d9deed9fb84c03aff0 ] + +Commit 6930bcbfb6ce dropped the setting of the file_lock range when +decoding a nlm_lock off the wire. This causes the client side grant +callback to miss matching blocks and reject the lock, only to rerequest +it 30s later. + +Add a helper function to set the file_lock range from the start and end +values that the protocol uses, and have the nlm_lock decoder call that to +set up the file_lock args properly. + +Fixes: 6930bcbfb6ce ("lockd: detect and reject lock arguments that overflow") +Reported-by: Amir Goldstein +Signed-off-by: Jeff Layton +Tested-by: Amir Goldstein +Cc: stable@vger.kernel.org #6.0 +Signed-off-by: Anna Schumaker +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/clnt4xdr.c | 9 +-------- + fs/lockd/xdr4.c | 13 ++++++++++++- + include/linux/lockd/xdr4.h | 1 + + 3 files changed, 14 insertions(+), 9 deletions(-) + +diff --git a/fs/lockd/clnt4xdr.c b/fs/lockd/clnt4xdr.c +index 7df6324ccb8ab..8161667c976f8 100644 +--- a/fs/lockd/clnt4xdr.c ++++ b/fs/lockd/clnt4xdr.c +@@ -261,7 +261,6 @@ static int decode_nlm4_holder(struct xdr_stream *xdr, struct nlm_res *result) + u32 exclusive; + int error; + __be32 *p; +- s32 end; + + memset(lock, 0, sizeof(*lock)); + locks_init_lock(fl); +@@ -285,13 +284,7 @@ static int decode_nlm4_holder(struct xdr_stream *xdr, struct nlm_res *result) + fl->fl_type = exclusive != 0 ? F_WRLCK : F_RDLCK; + p = xdr_decode_hyper(p, &l_offset); + xdr_decode_hyper(p, &l_len); +- end = l_offset + l_len - 1; +- +- fl->fl_start = (loff_t)l_offset; +- if (l_len == 0 || end < 0) +- fl->fl_end = OFFSET_MAX; +- else +- fl->fl_end = (loff_t)end; ++ nlm4svc_set_file_lock_range(fl, l_offset, l_len); + error = 0; + out: + return error; +diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c +index 712fdfeb8ef06..5fcbf30cd2759 100644 +--- a/fs/lockd/xdr4.c ++++ b/fs/lockd/xdr4.c +@@ -33,6 +33,17 @@ loff_t_to_s64(loff_t offset) + return res; + } + ++void nlm4svc_set_file_lock_range(struct file_lock *fl, u64 off, u64 len) ++{ ++ s64 end = off + len - 1; ++ ++ fl->fl_start = off; ++ if (len == 0 || end < 0) ++ fl->fl_end = OFFSET_MAX; ++ else ++ fl->fl_end = end; ++} ++ + /* + * NLM file handles are defined by specification to be a variable-length + * XDR opaque no longer than 1024 bytes. However, this implementation +@@ -80,7 +91,7 @@ svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock) + locks_init_lock(fl); + fl->fl_flags = FL_POSIX; + fl->fl_type = F_RDLCK; +- ++ nlm4svc_set_file_lock_range(fl, lock->lock_start, lock->lock_len); + return true; + } + +diff --git a/include/linux/lockd/xdr4.h b/include/linux/lockd/xdr4.h +index 9a6b55da8fd64..72831e35dca32 100644 +--- a/include/linux/lockd/xdr4.h ++++ b/include/linux/lockd/xdr4.h +@@ -22,6 +22,7 @@ + #define nlm4_fbig cpu_to_be32(NLM_FBIG) + #define nlm4_failed cpu_to_be32(NLM_FAILED) + ++void nlm4svc_set_file_lock_range(struct file_lock *fl, u64 off, u64 len); + bool nlm4svc_decode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr); + bool nlm4svc_decode_testargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); + bool nlm4svc_decode_lockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-- +2.43.0 + diff --git a/queue-5.10/lockd-set-fl_owner-when-unlocking-files.patch b/queue-5.10/lockd-set-fl_owner-when-unlocking-files.patch new file mode 100644 index 00000000000..45df8de1d29 --- /dev/null +++ b/queue-5.10/lockd-set-fl_owner-when-unlocking-files.patch @@ -0,0 +1,54 @@ +From 8a8d542992697c34389356b30291d1e608dba858 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 11 Jul 2022 14:30:13 -0400 +Subject: lockd: set fl_owner when unlocking files + +From: Jeff Layton + +[ Upstream commit aec158242b87a43d83322e99bc71ab4428e5ab79 ] + +Unlocking a POSIX lock on an inode with vfs_lock_file only works if +the owner matches. Ensure we set it in the request. + +Cc: J. Bruce Fields +Fixes: 7f024fcd5c97 ("Keep read and write fds with each nlm_file") +Signed-off-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/svcsubs.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c +index 0a22a2faf5522..b2f277727469c 100644 +--- a/fs/lockd/svcsubs.c ++++ b/fs/lockd/svcsubs.c +@@ -176,7 +176,7 @@ nlm_delete_file(struct nlm_file *file) + } + } + +-static int nlm_unlock_files(struct nlm_file *file) ++static int nlm_unlock_files(struct nlm_file *file, fl_owner_t owner) + { + struct file_lock lock; + +@@ -184,6 +184,7 @@ static int nlm_unlock_files(struct nlm_file *file) + lock.fl_type = F_UNLCK; + lock.fl_start = 0; + lock.fl_end = OFFSET_MAX; ++ lock.fl_owner = owner; + if (file->f_file[O_RDONLY] && + vfs_lock_file(file->f_file[O_RDONLY], F_SETLK, &lock, NULL)) + goto out_err; +@@ -225,7 +226,7 @@ nlm_traverse_locks(struct nlm_host *host, struct nlm_file *file, + if (match(lockhost, host)) { + + spin_unlock(&flctx->flc_lock); +- if (nlm_unlock_files(file)) ++ if (nlm_unlock_files(file, fl->fl_owner)) + return 1; + goto again; + } +-- +2.43.0 + diff --git a/queue-5.10/lockd-set-missing-fl_flags-field-when-retrieving-arg.patch b/queue-5.10/lockd-set-missing-fl_flags-field-when-retrieving-arg.patch new file mode 100644 index 00000000000..743b477dcd9 --- /dev/null +++ b/queue-5.10/lockd-set-missing-fl_flags-field-when-retrieving-arg.patch @@ -0,0 +1,44 @@ +From 88ee58a4f6c899c1e42f6b8d6b9e010f2a01211c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 11 Nov 2022 14:36:36 -0500 +Subject: lockd: set missing fl_flags field when retrieving args + +From: Jeff Layton + +[ Upstream commit 75c7940d2a86d3f1b60a0a265478cb8fc887b970 ] + +Signed-off-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/svc4proc.c | 1 + + fs/lockd/svcproc.c | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c +index 284b019cb6529..b72023a6b4c16 100644 +--- a/fs/lockd/svc4proc.c ++++ b/fs/lockd/svc4proc.c +@@ -52,6 +52,7 @@ nlm4svc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp, + *filp = file; + + /* Set up the missing parts of the file_lock structure */ ++ lock->fl.fl_flags = FL_POSIX; + lock->fl.fl_file = file->f_file[mode]; + lock->fl.fl_pid = current->tgid; + lock->fl.fl_start = (loff_t)lock->lock_start; +diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c +index e35c05e278061..32784f508c810 100644 +--- a/fs/lockd/svcproc.c ++++ b/fs/lockd/svcproc.c +@@ -77,6 +77,7 @@ nlmsvc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp, + + /* Set up the missing parts of the file_lock structure */ + mode = lock_to_openmode(&lock->fl); ++ lock->fl.fl_flags = FL_POSIX; + lock->fl.fl_file = file->f_file[mode]; + lock->fl.fl_pid = current->tgid; + lock->fl.fl_lmops = &nlmsvc_lock_operations; +-- +2.43.0 + diff --git a/queue-5.10/lockd-set-other-missing-fields-when-unlocking-files.patch b/queue-5.10/lockd-set-other-missing-fields-when-unlocking-files.patch new file mode 100644 index 00000000000..28a92794797 --- /dev/null +++ b/queue-5.10/lockd-set-other-missing-fields-when-unlocking-files.patch @@ -0,0 +1,69 @@ +From cc50b42b4e6c3e698c9874b4d641d00167ff8070 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 6 Nov 2022 14:02:39 -0500 +Subject: lockd: set other missing fields when unlocking files + +From: Trond Myklebust + +[ Upstream commit 18ebd35b61b4693a0ddc270b6d4f18def232e770 ] + +vfs_lock_file() expects the struct file_lock to be fully initialised by +the caller. Re-exported NFSv3 has been seen to Oops if the fl_file field +is NULL. + +Fixes: aec158242b87 ("lockd: set fl_owner when unlocking files") +Signed-off-by: Trond Myklebust +Reviewed-by: Jeff Layton +Link: https://bugzilla.kernel.org/show_bug.cgi?id=216582 +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/svcsubs.c | 17 ++++++++++------- + 1 file changed, 10 insertions(+), 7 deletions(-) + +diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c +index 720684345817c..e3b6229e7ae5c 100644 +--- a/fs/lockd/svcsubs.c ++++ b/fs/lockd/svcsubs.c +@@ -176,7 +176,7 @@ nlm_delete_file(struct nlm_file *file) + } + } + +-static int nlm_unlock_files(struct nlm_file *file, fl_owner_t owner) ++static int nlm_unlock_files(struct nlm_file *file, const struct file_lock *fl) + { + struct file_lock lock; + +@@ -184,12 +184,15 @@ static int nlm_unlock_files(struct nlm_file *file, fl_owner_t owner) + lock.fl_type = F_UNLCK; + lock.fl_start = 0; + lock.fl_end = OFFSET_MAX; +- lock.fl_owner = owner; +- if (file->f_file[O_RDONLY] && +- vfs_lock_file(file->f_file[O_RDONLY], F_SETLK, &lock, NULL)) ++ lock.fl_owner = fl->fl_owner; ++ lock.fl_pid = fl->fl_pid; ++ lock.fl_flags = FL_POSIX; ++ ++ lock.fl_file = file->f_file[O_RDONLY]; ++ if (lock.fl_file && vfs_lock_file(lock.fl_file, F_SETLK, &lock, NULL)) + goto out_err; +- if (file->f_file[O_WRONLY] && +- vfs_lock_file(file->f_file[O_WRONLY], F_SETLK, &lock, NULL)) ++ lock.fl_file = file->f_file[O_WRONLY]; ++ if (lock.fl_file && vfs_lock_file(lock.fl_file, F_SETLK, &lock, NULL)) + goto out_err; + return 0; + out_err: +@@ -226,7 +229,7 @@ nlm_traverse_locks(struct nlm_host *host, struct nlm_file *file, + if (match(lockhost, host)) { + + spin_unlock(&flctx->flc_lock); +- if (nlm_unlock_files(file, fl->fl_owner)) ++ if (nlm_unlock_files(file, fl)) + return 1; + goto again; + } +-- +2.43.0 + diff --git a/queue-5.10/lockd-simplify-management-of-network-status-notifier.patch b/queue-5.10/lockd-simplify-management-of-network-status-notifier.patch new file mode 100644 index 00000000000..9dd232bb96e --- /dev/null +++ b/queue-5.10/lockd-simplify-management-of-network-status-notifier.patch @@ -0,0 +1,157 @@ +From f3fa439f1b26e3899d51baf76e205f6746bfa14d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Nov 2021 15:51:25 +1100 +Subject: lockd: simplify management of network status notifiers + +From: NeilBrown + +[ Upstream commit 5a8a7ff57421b7de3ae72019938ffb5daaee36e7 ] + +Now that the network status notifiers use nlmsvc_serv rather then +nlmsvc_rqst the management can be simplified. + +Notifier unregistration synchronises with any pending notifications so +providing we unregister before nlm_serv is freed no further interlock +is required. + +So we move the unregister call to just before the thread is killed +(which destroys the service) and just before the service is destroyed in +the failure-path of lockd_up(). + +Then nlm_ntf_refcnt and nlm_ntf_wq can be removed. + +Signed-off-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/svc.c | 35 +++++++++-------------------------- + 1 file changed, 9 insertions(+), 26 deletions(-) + +diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c +index 83874878f41d8..20cebb191350f 100644 +--- a/fs/lockd/svc.c ++++ b/fs/lockd/svc.c +@@ -59,9 +59,6 @@ static struct task_struct *nlmsvc_task; + static struct svc_rqst *nlmsvc_rqst; + unsigned long nlmsvc_timeout; + +-static atomic_t nlm_ntf_refcnt = ATOMIC_INIT(0); +-static DECLARE_WAIT_QUEUE_HEAD(nlm_ntf_wq); +- + unsigned int lockd_net_id; + + /* +@@ -303,8 +300,7 @@ static int lockd_inetaddr_event(struct notifier_block *this, + struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; + struct sockaddr_in sin; + +- if ((event != NETDEV_DOWN) || +- !atomic_inc_not_zero(&nlm_ntf_refcnt)) ++ if (event != NETDEV_DOWN) + goto out; + + if (nlmsvc_serv) { +@@ -314,8 +310,6 @@ static int lockd_inetaddr_event(struct notifier_block *this, + sin.sin_addr.s_addr = ifa->ifa_local; + svc_age_temp_xprts_now(nlmsvc_serv, (struct sockaddr *)&sin); + } +- atomic_dec(&nlm_ntf_refcnt); +- wake_up(&nlm_ntf_wq); + + out: + return NOTIFY_DONE; +@@ -332,8 +326,7 @@ static int lockd_inet6addr_event(struct notifier_block *this, + struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr; + struct sockaddr_in6 sin6; + +- if ((event != NETDEV_DOWN) || +- !atomic_inc_not_zero(&nlm_ntf_refcnt)) ++ if (event != NETDEV_DOWN) + goto out; + + if (nlmsvc_serv) { +@@ -344,8 +337,6 @@ static int lockd_inet6addr_event(struct notifier_block *this, + sin6.sin6_scope_id = ifa->idev->dev->ifindex; + svc_age_temp_xprts_now(nlmsvc_serv, (struct sockaddr *)&sin6); + } +- atomic_dec(&nlm_ntf_refcnt); +- wake_up(&nlm_ntf_wq); + + out: + return NOTIFY_DONE; +@@ -362,14 +353,6 @@ static void lockd_unregister_notifiers(void) + #if IS_ENABLED(CONFIG_IPV6) + unregister_inet6addr_notifier(&lockd_inet6addr_notifier); + #endif +- wait_event(nlm_ntf_wq, atomic_read(&nlm_ntf_refcnt) == 0); +-} +- +-static void lockd_svc_exit_thread(void) +-{ +- atomic_dec(&nlm_ntf_refcnt); +- lockd_unregister_notifiers(); +- svc_exit_thread(nlmsvc_rqst); + } + + static int lockd_start_svc(struct svc_serv *serv) +@@ -388,11 +371,9 @@ static int lockd_start_svc(struct svc_serv *serv) + printk(KERN_WARNING + "lockd_up: svc_rqst allocation failed, error=%d\n", + error); +- lockd_unregister_notifiers(); + goto out_rqst; + } + +- atomic_inc(&nlm_ntf_refcnt); + svc_sock_update_bufs(serv); + serv->sv_maxconn = nlm_max_connections; + +@@ -410,7 +391,7 @@ static int lockd_start_svc(struct svc_serv *serv) + return 0; + + out_task: +- lockd_svc_exit_thread(); ++ svc_exit_thread(nlmsvc_rqst); + nlmsvc_task = NULL; + out_rqst: + nlmsvc_rqst = NULL; +@@ -477,7 +458,6 @@ int lockd_up(struct net *net, const struct cred *cred) + + error = lockd_up_net(serv, net, cred); + if (error < 0) { +- lockd_unregister_notifiers(); + goto err_put; + } + +@@ -488,8 +468,10 @@ int lockd_up(struct net *net, const struct cred *cred) + } + nlmsvc_users++; + err_put: +- if (nlmsvc_users == 0) ++ if (nlmsvc_users == 0) { ++ lockd_unregister_notifiers(); + nlmsvc_serv = NULL; ++ } + svc_put(serv); + err_create: + mutex_unlock(&nlmsvc_mutex); +@@ -518,13 +500,14 @@ lockd_down(struct net *net) + printk(KERN_ERR "lockd_down: no lockd running.\n"); + BUG(); + } ++ lockd_unregister_notifiers(); + kthread_stop(nlmsvc_task); + dprintk("lockd_down: service stopped\n"); +- lockd_svc_exit_thread(); ++ svc_exit_thread(nlmsvc_rqst); ++ nlmsvc_rqst = NULL; + dprintk("lockd_down: service destroyed\n"); + nlmsvc_serv = NULL; + nlmsvc_task = NULL; +- nlmsvc_rqst = NULL; + out: + mutex_unlock(&nlmsvc_mutex); + } +-- +2.43.0 + diff --git a/queue-5.10/lockd-update-nlm_lookup_file-reexport-comment.patch b/queue-5.10/lockd-update-nlm_lookup_file-reexport-comment.patch new file mode 100644 index 00000000000..d2e2e32b2da --- /dev/null +++ b/queue-5.10/lockd-update-nlm_lookup_file-reexport-comment.patch @@ -0,0 +1,38 @@ +From 00960ca0fc56e6b954071edfb7c4ef238af1e7b8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Aug 2021 17:02:02 -0400 +Subject: lockd: update nlm_lookup_file reexport comment + +From: J. Bruce Fields + +[ Upstream commit b661601a9fdf1af8516e1100de8bba84bd41cca4 ] + +Update comment to reflect that we *do* allow reexport, whether it's a +good idea or not.... + +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/svcsubs.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c +index e02951f8a28f5..13e6ffc219ec9 100644 +--- a/fs/lockd/svcsubs.c ++++ b/fs/lockd/svcsubs.c +@@ -111,8 +111,9 @@ nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result, + INIT_HLIST_NODE(&file->f_list); + INIT_LIST_HEAD(&file->f_blocks); + +- /* Open the file. Note that this must not sleep for too long, else +- * we would lock up lockd:-) So no NFS re-exports, folks. ++ /* ++ * Open the file. Note that if we're reexporting, for example, ++ * this could block the lockd thread for a while. + * + * We have to make sure we have the right credential to open + * the file. +-- +2.43.0 + diff --git a/queue-5.10/lockd-update-the-nlmv1-cancel-arguments-decoder-to-u.patch b/queue-5.10/lockd-update-the-nlmv1-cancel-arguments-decoder-to-u.patch new file mode 100644 index 00000000000..68c16fdbe96 --- /dev/null +++ b/queue-5.10/lockd-update-the-nlmv1-cancel-arguments-decoder-to-u.patch @@ -0,0 +1,75 @@ +From 95f2275234cf8e8bdd9fd5bf04b06b4f339092f2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 3 Jun 2021 16:51:16 -0400 +Subject: lockd: Update the NLMv1 CANCEL arguments decoder to use struct + xdr_stream + +From: Chuck Lever + +[ Upstream commit f4e08f3ac8c4945ea54a740e3afcf44b34e7cf44 ] + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/xdr.c | 34 +++++++++++++++++++--------------- + 1 file changed, 19 insertions(+), 15 deletions(-) + +diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c +index 8a9f02e45df2d..ef38f07d1224c 100644 +--- a/fs/lockd/xdr.c ++++ b/fs/lockd/xdr.c +@@ -294,30 +294,34 @@ nlmsvc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p) ++nlmsvc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p) + { +- struct nlm_res *resp = rqstp->rq_resp; ++ struct xdr_stream *xdr = &rqstp->rq_arg_stream; ++ struct nlm_args *argp = rqstp->rq_argp; ++ u32 exclusive; + +- if (!(p = nlm_encode_testres(p, resp))) ++ if (!svcxdr_decode_cookie(xdr, &argp->cookie)) + return 0; +- return xdr_ressize_check(rqstp, p); ++ if (xdr_stream_decode_bool(xdr, &argp->block) < 0) ++ return 0; ++ if (xdr_stream_decode_bool(xdr, &exclusive) < 0) ++ return 0; ++ if (!svcxdr_decode_lock(xdr, &argp->lock)) ++ return 0; ++ if (exclusive) ++ argp->lock.fl.fl_type = F_WRLCK; ++ ++ return 1; + } + + int +-nlmsvc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p) ++nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p) + { +- struct nlm_args *argp = rqstp->rq_argp; +- u32 exclusive; ++ struct nlm_res *resp = rqstp->rq_resp; + +- if (!(p = nlm_decode_cookie(p, &argp->cookie))) +- return 0; +- argp->block = ntohl(*p++); +- exclusive = ntohl(*p++); +- if (!(p = nlm_decode_lock(p, &argp->lock))) ++ if (!(p = nlm_encode_testres(p, resp))) + return 0; +- if (exclusive) +- argp->lock.fl.fl_type = F_WRLCK; +- return xdr_argsize_check(rqstp, p); ++ return xdr_ressize_check(rqstp, p); + } + + int +-- +2.43.0 + diff --git a/queue-5.10/lockd-update-the-nlmv1-free_all-arguments-decoder-to.patch b/queue-5.10/lockd-update-the-nlmv1-free_all-arguments-decoder-to.patch new file mode 100644 index 00000000000..7e01786ebcd --- /dev/null +++ b/queue-5.10/lockd-update-the-nlmv1-free_all-arguments-decoder-to.patch @@ -0,0 +1,67 @@ +From 9ff5f7c0b510da6066abf53971adc67fc517d342 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 3 Jun 2021 16:51:46 -0400 +Subject: lockd: Update the NLMv1 FREE_ALL arguments decoder to use struct + xdr_stream + +From: Chuck Lever + +[ Upstream commit 14e105256b9dcdf50a003e2e9a0da77e06770a4b ] + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/xdr.c | 28 +++++++++++++++------------- + 1 file changed, 15 insertions(+), 13 deletions(-) + +diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c +index c496f18eff06e..091c8c463ab40 100644 +--- a/fs/lockd/xdr.c ++++ b/fs/lockd/xdr.c +@@ -316,6 +316,21 @@ nlmsvc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p) + return 1; + } + ++int ++nlmsvc_decode_notify(struct svc_rqst *rqstp, __be32 *p) ++{ ++ struct xdr_stream *xdr = &rqstp->rq_arg_stream; ++ struct nlm_args *argp = rqstp->rq_argp; ++ struct nlm_lock *lock = &argp->lock; ++ ++ if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len)) ++ return 0; ++ if (xdr_stream_decode_u32(xdr, &argp->state) < 0) ++ return 0; ++ ++ return 1; ++} ++ + int + nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p) + { +@@ -349,19 +364,6 @@ nlmsvc_encode_res(struct svc_rqst *rqstp, __be32 *p) + return xdr_ressize_check(rqstp, p); + } + +-int +-nlmsvc_decode_notify(struct svc_rqst *rqstp, __be32 *p) +-{ +- struct nlm_args *argp = rqstp->rq_argp; +- struct nlm_lock *lock = &argp->lock; +- +- if (!(p = xdr_decode_string_inplace(p, &lock->caller, +- &lock->len, NLM_MAXSTRLEN))) +- return 0; +- argp->state = ntohl(*p++); +- return xdr_argsize_check(rqstp, p); +-} +- + int + nlmsvc_encode_void(struct svc_rqst *rqstp, __be32 *p) + { +-- +2.43.0 + diff --git a/queue-5.10/lockd-update-the-nlmv1-lock-arguments-decoder-to-use.patch b/queue-5.10/lockd-update-the-nlmv1-lock-arguments-decoder-to-use.patch new file mode 100644 index 00000000000..37e239bda54 --- /dev/null +++ b/queue-5.10/lockd-update-the-nlmv1-lock-arguments-decoder-to-use.patch @@ -0,0 +1,84 @@ +From 3bbd68fd6cb9b8f2eda374830d62f7db9d50350f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 3 Jun 2021 16:51:10 -0400 +Subject: lockd: Update the NLMv1 LOCK arguments decoder to use struct + xdr_stream + +From: Chuck Lever + +[ Upstream commit c1adb8c672ca2b085c400695ef064547d77eda29 ] + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/xdr.c | 41 +++++++++++++++++++++++------------------ + 1 file changed, 23 insertions(+), 18 deletions(-) + +diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c +index 56982edd47667..8a9f02e45df2d 100644 +--- a/fs/lockd/xdr.c ++++ b/fs/lockd/xdr.c +@@ -267,35 +267,40 @@ nlmsvc_decode_testargs(struct svc_rqst *rqstp, __be32 *p) + return 1; + } + +-int +-nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p) +-{ +- struct nlm_res *resp = rqstp->rq_resp; +- +- if (!(p = nlm_encode_testres(p, resp))) +- return 0; +- return xdr_ressize_check(rqstp, p); +-} +- + int + nlmsvc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nlm_args *argp = rqstp->rq_argp; +- u32 exclusive; ++ u32 exclusive; + +- if (!(p = nlm_decode_cookie(p, &argp->cookie))) ++ if (!svcxdr_decode_cookie(xdr, &argp->cookie)) + return 0; +- argp->block = ntohl(*p++); +- exclusive = ntohl(*p++); +- if (!(p = nlm_decode_lock(p, &argp->lock))) ++ if (xdr_stream_decode_bool(xdr, &argp->block) < 0) ++ return 0; ++ if (xdr_stream_decode_bool(xdr, &exclusive) < 0) ++ return 0; ++ if (!svcxdr_decode_lock(xdr, &argp->lock)) + return 0; + if (exclusive) + argp->lock.fl.fl_type = F_WRLCK; +- argp->reclaim = ntohl(*p++); +- argp->state = ntohl(*p++); ++ if (xdr_stream_decode_bool(xdr, &argp->reclaim) < 0) ++ return 0; ++ if (xdr_stream_decode_u32(xdr, &argp->state) < 0) ++ return 0; + argp->monitor = 1; /* monitor client by default */ + +- return xdr_argsize_check(rqstp, p); ++ return 1; ++} ++ ++int ++nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p) ++{ ++ struct nlm_res *resp = rqstp->rq_resp; ++ ++ if (!(p = nlm_encode_testres(p, resp))) ++ return 0; ++ return xdr_ressize_check(rqstp, p); + } + + int +-- +2.43.0 + diff --git a/queue-5.10/lockd-update-the-nlmv1-nlm_res-arguments-decoder-to-.patch b/queue-5.10/lockd-update-the-nlmv1-nlm_res-arguments-decoder-to-.patch new file mode 100644 index 00000000000..124c90d0dfa --- /dev/null +++ b/queue-5.10/lockd-update-the-nlmv1-nlm_res-arguments-decoder-to-.patch @@ -0,0 +1,64 @@ +From fa03f3002993f3df15a2ee6fdfef9b5775f6a4a9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 3 Jun 2021 16:51:28 -0400 +Subject: lockd: Update the NLMv1 nlm_res arguments decoder to use struct + xdr_stream + +From: Chuck Lever + +[ Upstream commit 16ddcabe6240c4fb01c97f6fce6c35ddf8626ad5 ] + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/xdr.c | 25 ++++++++++++++----------- + 1 file changed, 14 insertions(+), 11 deletions(-) + +diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c +index b59e02b4417c8..911b6377a6da4 100644 +--- a/fs/lockd/xdr.c ++++ b/fs/lockd/xdr.c +@@ -299,6 +299,20 @@ nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p) + return 1; + } + ++int ++nlmsvc_decode_res(struct svc_rqst *rqstp, __be32 *p) ++{ ++ struct xdr_stream *xdr = &rqstp->rq_arg_stream; ++ struct nlm_res *resp = rqstp->rq_argp; ++ ++ if (!svcxdr_decode_cookie(xdr, &resp->cookie)) ++ return 0; ++ if (!svcxdr_decode_stats(xdr, &resp->status)) ++ return 0; ++ ++ return 1; ++} ++ + int + nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p) + { +@@ -379,17 +393,6 @@ nlmsvc_decode_reboot(struct svc_rqst *rqstp, __be32 *p) + return xdr_argsize_check(rqstp, p); + } + +-int +-nlmsvc_decode_res(struct svc_rqst *rqstp, __be32 *p) +-{ +- struct nlm_res *resp = rqstp->rq_argp; +- +- if (!(p = nlm_decode_cookie(p, &resp->cookie))) +- return 0; +- resp->status = *p++; +- return xdr_argsize_check(rqstp, p); +-} +- + int + nlmsvc_encode_void(struct svc_rqst *rqstp, __be32 *p) + { +-- +2.43.0 + diff --git a/queue-5.10/lockd-update-the-nlmv1-nlm_res-results-encoder-to-us.patch b/queue-5.10/lockd-update-the-nlmv1-nlm_res-results-encoder-to-us.patch new file mode 100644 index 00000000000..20f440fe922 --- /dev/null +++ b/queue-5.10/lockd-update-the-nlmv1-nlm_res-results-encoder-to-us.patch @@ -0,0 +1,56 @@ +From ad69ac3ecba86e1b448ff16af493aab5dee0a805 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 3 Jun 2021 16:52:04 -0400 +Subject: lockd: Update the NLMv1 nlm_res results encoder to use struct + xdr_stream + +From: Chuck Lever + +[ Upstream commit e96735a6980574ecbdb24c760b8d294095e47074 ] + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/xdr.c | 13 ++++++------- + 1 file changed, 6 insertions(+), 7 deletions(-) + +diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c +index daf3524040d66..4fb6090bc9158 100644 +--- a/fs/lockd/xdr.c ++++ b/fs/lockd/xdr.c +@@ -349,24 +349,23 @@ nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nlmsvc_encode_shareres(struct svc_rqst *rqstp, __be32 *p) ++nlmsvc_encode_res(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nlm_res *resp = rqstp->rq_resp; + +- if (!(p = nlm_encode_cookie(p, &resp->cookie))) +- return 0; +- *p++ = resp->status; +- *p++ = xdr_zero; /* sequence argument */ +- return xdr_ressize_check(rqstp, p); ++ return svcxdr_encode_cookie(xdr, &resp->cookie) && ++ svcxdr_encode_stats(xdr, resp->status); + } + + int +-nlmsvc_encode_res(struct svc_rqst *rqstp, __be32 *p) ++nlmsvc_encode_shareres(struct svc_rqst *rqstp, __be32 *p) + { + struct nlm_res *resp = rqstp->rq_resp; + + if (!(p = nlm_encode_cookie(p, &resp->cookie))) + return 0; + *p++ = resp->status; ++ *p++ = xdr_zero; /* sequence argument */ + return xdr_ressize_check(rqstp, p); + } +-- +2.43.0 + diff --git a/queue-5.10/lockd-update-the-nlmv1-share-arguments-decoder-to-us.patch b/queue-5.10/lockd-update-the-nlmv1-share-arguments-decoder-to-us.patch new file mode 100644 index 00000000000..4004b6eb146 --- /dev/null +++ b/queue-5.10/lockd-update-the-nlmv1-share-arguments-decoder-to-us.patch @@ -0,0 +1,166 @@ +From 90253185f5f209655d8cf63529bb45d3523761c9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 3 Jun 2021 16:51:40 -0400 +Subject: lockd: Update the NLMv1 SHARE arguments decoder to use struct + xdr_stream + +From: Chuck Lever + +[ Upstream commit 890939e1266b9adf3b0acd5e0385b39813cb8f11 ] + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/xdr.c | 96 ++++++++++++++------------------------------------ + 1 file changed, 26 insertions(+), 70 deletions(-) + +diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c +index 421613170e5f9..c496f18eff06e 100644 +--- a/fs/lockd/xdr.c ++++ b/fs/lockd/xdr.c +@@ -21,8 +21,6 @@ + + #include "svcxdr.h" + +-#define NLMDBG_FACILITY NLMDBG_XDR +- + + static inline loff_t + s32_to_loff_t(__s32 offset) +@@ -46,33 +44,6 @@ loff_t_to_s32(loff_t offset) + /* + * XDR functions for basic NLM types + */ +-static __be32 *nlm_decode_cookie(__be32 *p, struct nlm_cookie *c) +-{ +- unsigned int len; +- +- len = ntohl(*p++); +- +- if(len==0) +- { +- c->len=4; +- memset(c->data, 0, 4); /* hockeypux brain damage */ +- } +- else if(len<=NLM_MAXCOOKIELEN) +- { +- c->len=len; +- memcpy(c->data, p, len); +- p+=XDR_QUADLEN(len); +- } +- else +- { +- dprintk("lockd: bad cookie size %d (only cookies under " +- "%d bytes are supported.)\n", +- len, NLM_MAXCOOKIELEN); +- return NULL; +- } +- return p; +-} +- + static inline __be32 * + nlm_encode_cookie(__be32 *p, struct nlm_cookie *c) + { +@@ -82,22 +53,6 @@ nlm_encode_cookie(__be32 *p, struct nlm_cookie *c) + return p; + } + +-static __be32 * +-nlm_decode_fh(__be32 *p, struct nfs_fh *f) +-{ +- unsigned int len; +- +- if ((len = ntohl(*p++)) != NFS2_FHSIZE) { +- dprintk("lockd: bad fhandle size %d (should be %d)\n", +- len, NFS2_FHSIZE); +- return NULL; +- } +- f->size = NFS2_FHSIZE; +- memset(f->data, 0, sizeof(f->data)); +- memcpy(f->data, p, NFS2_FHSIZE); +- return p + XDR_QUADLEN(NFS2_FHSIZE); +-} +- + /* + * NLM file handles are defined by specification to be a variable-length + * XDR opaque no longer than 1024 bytes. However, this implementation +@@ -128,12 +83,6 @@ svcxdr_decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh) + /* + * Encode and decode owner handle + */ +-static inline __be32 * +-nlm_decode_oh(__be32 *p, struct xdr_netobj *oh) +-{ +- return xdr_decode_netobj(p, oh); +-} +- + static inline __be32 * + nlm_encode_oh(__be32 *p, struct xdr_netobj *oh) + { +@@ -339,35 +288,42 @@ nlmsvc_decode_reboot(struct svc_rqst *rqstp, __be32 *p) + return 1; + } + +-int +-nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p) +-{ +- struct nlm_res *resp = rqstp->rq_resp; +- +- if (!(p = nlm_encode_testres(p, resp))) +- return 0; +- return xdr_ressize_check(rqstp, p); +-} +- + int + nlmsvc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nlm_args *argp = rqstp->rq_argp; + struct nlm_lock *lock = &argp->lock; + + memset(lock, 0, sizeof(*lock)); + locks_init_lock(&lock->fl); +- lock->svid = ~(u32) 0; ++ lock->svid = ~(u32)0; + +- if (!(p = nlm_decode_cookie(p, &argp->cookie)) +- || !(p = xdr_decode_string_inplace(p, &lock->caller, +- &lock->len, NLM_MAXSTRLEN)) +- || !(p = nlm_decode_fh(p, &lock->fh)) +- || !(p = nlm_decode_oh(p, &lock->oh))) ++ if (!svcxdr_decode_cookie(xdr, &argp->cookie)) + return 0; +- argp->fsm_mode = ntohl(*p++); +- argp->fsm_access = ntohl(*p++); +- return xdr_argsize_check(rqstp, p); ++ if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len)) ++ return 0; ++ if (!svcxdr_decode_fhandle(xdr, &lock->fh)) ++ return 0; ++ if (!svcxdr_decode_owner(xdr, &lock->oh)) ++ return 0; ++ /* XXX: Range checks are missing in the original code */ ++ if (xdr_stream_decode_u32(xdr, &argp->fsm_mode) < 0) ++ return 0; ++ if (xdr_stream_decode_u32(xdr, &argp->fsm_access) < 0) ++ return 0; ++ ++ return 1; ++} ++ ++int ++nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p) ++{ ++ struct nlm_res *resp = rqstp->rq_resp; ++ ++ if (!(p = nlm_encode_testres(p, resp))) ++ return 0; ++ return xdr_ressize_check(rqstp, p); + } + + int +-- +2.43.0 + diff --git a/queue-5.10/lockd-update-the-nlmv1-share-results-encoder-to-use-.patch b/queue-5.10/lockd-update-the-nlmv1-share-results-encoder-to-use-.patch new file mode 100644 index 00000000000..dd2aa52e400 --- /dev/null +++ b/queue-5.10/lockd-update-the-nlmv1-share-results-encoder-to-use-.patch @@ -0,0 +1,65 @@ +From 01ccb013e2f1dc16d8664a240dbdb5fd10fca8bf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 3 Jun 2021 16:52:10 -0400 +Subject: lockd: Update the NLMv1 SHARE results encoder to use struct + xdr_stream + +From: Chuck Lever + +[ Upstream commit 529ca3a116e8978575fec061a71fa6865a344891 ] + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/xdr.c | 25 +++++++++---------------- + 1 file changed, 9 insertions(+), 16 deletions(-) + +diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c +index 4fb6090bc9158..9235e60b17694 100644 +--- a/fs/lockd/xdr.c ++++ b/fs/lockd/xdr.c +@@ -41,18 +41,6 @@ loff_t_to_s32(loff_t offset) + return res; + } + +-/* +- * XDR functions for basic NLM types +- */ +-static inline __be32 * +-nlm_encode_cookie(__be32 *p, struct nlm_cookie *c) +-{ +- *p++ = htonl(c->len); +- memcpy(p, c->data, c->len); +- p+=XDR_QUADLEN(c->len); +- return p; +-} +- + /* + * NLM file handles are defined by specification to be a variable-length + * XDR opaque no longer than 1024 bytes. However, this implementation +@@ -361,11 +349,16 @@ nlmsvc_encode_res(struct svc_rqst *rqstp, __be32 *p) + int + nlmsvc_encode_shareres(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nlm_res *resp = rqstp->rq_resp; + +- if (!(p = nlm_encode_cookie(p, &resp->cookie))) ++ if (!svcxdr_encode_cookie(xdr, &resp->cookie)) + return 0; +- *p++ = resp->status; +- *p++ = xdr_zero; /* sequence argument */ +- return xdr_ressize_check(rqstp, p); ++ if (!svcxdr_encode_stats(xdr, resp->status)) ++ return 0; ++ /* sequence */ ++ if (xdr_stream_encode_u32(xdr, 0) < 0) ++ return 0; ++ ++ return 1; + } +-- +2.43.0 + diff --git a/queue-5.10/lockd-update-the-nlmv1-sm_notify-arguments-decoder-t.patch b/queue-5.10/lockd-update-the-nlmv1-sm_notify-arguments-decoder-t.patch new file mode 100644 index 00000000000..e9c37afb91b --- /dev/null +++ b/queue-5.10/lockd-update-the-nlmv1-sm_notify-arguments-decoder-t.patch @@ -0,0 +1,78 @@ +From b9760077e058bba40bdcc0cc372f8a9d8d3f9c5d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 3 Jun 2021 16:51:34 -0400 +Subject: lockd: Update the NLMv1 SM_NOTIFY arguments decoder to use struct + xdr_stream + +From: Chuck Lever + +[ Upstream commit 137e05e2f735f696e117553f7fa5ef8fb09953e1 ] + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/xdr.c | 39 ++++++++++++++++++++++++++------------- + 1 file changed, 26 insertions(+), 13 deletions(-) + +diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c +index 911b6377a6da4..421613170e5f9 100644 +--- a/fs/lockd/xdr.c ++++ b/fs/lockd/xdr.c +@@ -313,6 +313,32 @@ nlmsvc_decode_res(struct svc_rqst *rqstp, __be32 *p) + return 1; + } + ++int ++nlmsvc_decode_reboot(struct svc_rqst *rqstp, __be32 *p) ++{ ++ struct xdr_stream *xdr = &rqstp->rq_arg_stream; ++ struct nlm_reboot *argp = rqstp->rq_argp; ++ u32 len; ++ ++ if (xdr_stream_decode_u32(xdr, &len) < 0) ++ return 0; ++ if (len > SM_MAXSTRLEN) ++ return 0; ++ p = xdr_inline_decode(xdr, len); ++ if (!p) ++ return 0; ++ argp->len = len; ++ argp->mon = (char *)p; ++ if (xdr_stream_decode_u32(xdr, &argp->state) < 0) ++ return 0; ++ p = xdr_inline_decode(xdr, SM_PRIV_SIZE); ++ if (!p) ++ return 0; ++ memcpy(&argp->priv.data, p, sizeof(argp->priv.data)); ++ ++ return 1; ++} ++ + int + nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p) + { +@@ -380,19 +406,6 @@ nlmsvc_decode_notify(struct svc_rqst *rqstp, __be32 *p) + return xdr_argsize_check(rqstp, p); + } + +-int +-nlmsvc_decode_reboot(struct svc_rqst *rqstp, __be32 *p) +-{ +- struct nlm_reboot *argp = rqstp->rq_argp; +- +- if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN))) +- return 0; +- argp->state = ntohl(*p++); +- memcpy(&argp->priv.data, p, sizeof(argp->priv.data)); +- p += XDR_QUADLEN(SM_PRIV_SIZE); +- return xdr_argsize_check(rqstp, p); +-} +- + int + nlmsvc_encode_void(struct svc_rqst *rqstp, __be32 *p) + { +-- +2.43.0 + diff --git a/queue-5.10/lockd-update-the-nlmv1-test-arguments-decoder-to-use.patch b/queue-5.10/lockd-update-the-nlmv1-test-arguments-decoder-to-use.patch new file mode 100644 index 00000000000..cf917653d47 --- /dev/null +++ b/queue-5.10/lockd-update-the-nlmv1-test-arguments-decoder-to-use.patch @@ -0,0 +1,125 @@ +From 3aa76a75c4181776bddad6a30004aae4db5f7837 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 3 Jun 2021 16:51:04 -0400 +Subject: lockd: Update the NLMv1 TEST arguments decoder to use struct + xdr_stream + +From: Chuck Lever + +[ Upstream commit 2fd0c67aabcf0f8821450b00ee511faa0b7761bf ] + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/xdr.c | 72 +++++++++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 66 insertions(+), 6 deletions(-) + +diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c +index 8be42a23679e9..56982edd47667 100644 +--- a/fs/lockd/xdr.c ++++ b/fs/lockd/xdr.c +@@ -98,6 +98,33 @@ nlm_decode_fh(__be32 *p, struct nfs_fh *f) + return p + XDR_QUADLEN(NFS2_FHSIZE); + } + ++/* ++ * NLM file handles are defined by specification to be a variable-length ++ * XDR opaque no longer than 1024 bytes. However, this implementation ++ * constrains their length to exactly the length of an NFSv2 file ++ * handle. ++ */ ++static bool ++svcxdr_decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh) ++{ ++ __be32 *p; ++ u32 len; ++ ++ if (xdr_stream_decode_u32(xdr, &len) < 0) ++ return false; ++ if (len != NFS2_FHSIZE) ++ return false; ++ ++ p = xdr_inline_decode(xdr, len); ++ if (!p) ++ return false; ++ fh->size = NFS2_FHSIZE; ++ memcpy(fh->data, p, len); ++ memset(fh->data + NFS2_FHSIZE, 0, sizeof(fh->data) - NFS2_FHSIZE); ++ ++ return true; ++} ++ + /* + * Encode and decode owner handle + */ +@@ -143,6 +170,38 @@ nlm_decode_lock(__be32 *p, struct nlm_lock *lock) + return p; + } + ++static bool ++svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock) ++{ ++ struct file_lock *fl = &lock->fl; ++ s32 start, len, end; ++ ++ if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len)) ++ return false; ++ if (!svcxdr_decode_fhandle(xdr, &lock->fh)) ++ return false; ++ if (!svcxdr_decode_owner(xdr, &lock->oh)) ++ return false; ++ if (xdr_stream_decode_u32(xdr, &lock->svid) < 0) ++ return false; ++ if (xdr_stream_decode_u32(xdr, &start) < 0) ++ return false; ++ if (xdr_stream_decode_u32(xdr, &len) < 0) ++ return false; ++ ++ locks_init_lock(fl); ++ fl->fl_flags = FL_POSIX; ++ fl->fl_type = F_RDLCK; ++ end = start + len - 1; ++ fl->fl_start = s32_to_loff_t(start); ++ if (len == 0 || end < 0) ++ fl->fl_end = OFFSET_MAX; ++ else ++ fl->fl_end = s32_to_loff_t(end); ++ ++ return true; ++} ++ + /* + * Encode result of a TEST/TEST_MSG call + */ +@@ -192,19 +251,20 @@ nlmsvc_decode_void(struct svc_rqst *rqstp, __be32 *p) + int + nlmsvc_decode_testargs(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nlm_args *argp = rqstp->rq_argp; +- u32 exclusive; ++ u32 exclusive; + +- if (!(p = nlm_decode_cookie(p, &argp->cookie))) ++ if (!svcxdr_decode_cookie(xdr, &argp->cookie)) + return 0; +- +- exclusive = ntohl(*p++); +- if (!(p = nlm_decode_lock(p, &argp->lock))) ++ if (xdr_stream_decode_bool(xdr, &exclusive) < 0) ++ return 0; ++ if (!svcxdr_decode_lock(xdr, &argp->lock)) + return 0; + if (exclusive) + argp->lock.fl.fl_type = F_WRLCK; + +- return xdr_argsize_check(rqstp, p); ++ return 1; + } + + int +-- +2.43.0 + diff --git a/queue-5.10/lockd-update-the-nlmv1-test-results-encoder-to-use-s.patch b/queue-5.10/lockd-update-the-nlmv1-test-results-encoder-to-use-s.patch new file mode 100644 index 00000000000..8128947cf8b --- /dev/null +++ b/queue-5.10/lockd-update-the-nlmv1-test-results-encoder-to-use-s.patch @@ -0,0 +1,127 @@ +From a1de0088e661dc9ef1086151d50536f2cc63cbf6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 3 Jun 2021 16:51:58 -0400 +Subject: lockd: Update the NLMv1 TEST results encoder to use struct xdr_stream + +From: Chuck Lever + +[ Upstream commit adf98a4850b9ede9fc174c78a885845fb08499a5 ] + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/xdr.c | 74 ++++++++++++++++++++++++-------------------------- + 1 file changed, 35 insertions(+), 39 deletions(-) + +diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c +index 840fa8ff84269..daf3524040d66 100644 +--- a/fs/lockd/xdr.c ++++ b/fs/lockd/xdr.c +@@ -80,15 +80,6 @@ svcxdr_decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh) + return true; + } + +-/* +- * Encode and decode owner handle +- */ +-static inline __be32 * +-nlm_encode_oh(__be32 *p, struct xdr_netobj *oh) +-{ +- return xdr_encode_netobj(p, oh); +-} +- + static bool + svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock) + { +@@ -121,39 +112,44 @@ svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock) + return true; + } + +-/* +- * Encode result of a TEST/TEST_MSG call +- */ +-static __be32 * +-nlm_encode_testres(__be32 *p, struct nlm_res *resp) ++static bool ++svcxdr_encode_holder(struct xdr_stream *xdr, const struct nlm_lock *lock) + { +- s32 start, len; +- +- if (!(p = nlm_encode_cookie(p, &resp->cookie))) +- return NULL; +- *p++ = resp->status; ++ const struct file_lock *fl = &lock->fl; ++ s32 start, len; + +- if (resp->status == nlm_lck_denied) { +- struct file_lock *fl = &resp->lock.fl; +- +- *p++ = (fl->fl_type == F_RDLCK)? xdr_zero : xdr_one; +- *p++ = htonl(resp->lock.svid); +- +- /* Encode owner handle. */ +- if (!(p = xdr_encode_netobj(p, &resp->lock.oh))) +- return NULL; ++ /* exclusive */ ++ if (xdr_stream_encode_bool(xdr, fl->fl_type != F_RDLCK) < 0) ++ return false; ++ if (xdr_stream_encode_u32(xdr, lock->svid) < 0) ++ return false; ++ if (!svcxdr_encode_owner(xdr, &lock->oh)) ++ return false; ++ start = loff_t_to_s32(fl->fl_start); ++ if (fl->fl_end == OFFSET_MAX) ++ len = 0; ++ else ++ len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1); ++ if (xdr_stream_encode_u32(xdr, start) < 0) ++ return false; ++ if (xdr_stream_encode_u32(xdr, len) < 0) ++ return false; + +- start = loff_t_to_s32(fl->fl_start); +- if (fl->fl_end == OFFSET_MAX) +- len = 0; +- else +- len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1); ++ return true; ++} + +- *p++ = htonl(start); +- *p++ = htonl(len); ++static bool ++svcxdr_encode_testrply(struct xdr_stream *xdr, const struct nlm_res *resp) ++{ ++ if (!svcxdr_encode_stats(xdr, resp->status)) ++ return false; ++ switch (resp->status) { ++ case nlm_lck_denied: ++ if (!svcxdr_encode_holder(xdr, &resp->lock)) ++ return false; + } + +- return p; ++ return true; + } + + +@@ -345,11 +341,11 @@ nlmsvc_encode_void(struct svc_rqst *rqstp, __be32 *p) + int + nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nlm_res *resp = rqstp->rq_resp; + +- if (!(p = nlm_encode_testres(p, resp))) +- return 0; +- return xdr_ressize_check(rqstp, p); ++ return svcxdr_encode_cookie(xdr, &resp->cookie) && ++ svcxdr_encode_testrply(xdr, resp); + } + + int +-- +2.43.0 + diff --git a/queue-5.10/lockd-update-the-nlmv1-unlock-arguments-decoder-to-u.patch b/queue-5.10/lockd-update-the-nlmv1-unlock-arguments-decoder-to-u.patch new file mode 100644 index 00000000000..e2bd995dffe --- /dev/null +++ b/queue-5.10/lockd-update-the-nlmv1-unlock-arguments-decoder-to-u.patch @@ -0,0 +1,101 @@ +From dc7c681270bef8dc8dabbf51a143c77ef551782a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 3 Jun 2021 16:51:22 -0400 +Subject: lockd: Update the NLMv1 UNLOCK arguments decoder to use struct + xdr_stream + +From: Chuck Lever + +[ Upstream commit c27045d302b022ed11d24a2653bceb6af56c6327 ] + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/xdr.c | 53 +++++++++++++------------------------------------- + 1 file changed, 13 insertions(+), 40 deletions(-) + +diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c +index ef38f07d1224c..b59e02b4417c8 100644 +--- a/fs/lockd/xdr.c ++++ b/fs/lockd/xdr.c +@@ -140,36 +140,6 @@ nlm_encode_oh(__be32 *p, struct xdr_netobj *oh) + return xdr_encode_netobj(p, oh); + } + +-static __be32 * +-nlm_decode_lock(__be32 *p, struct nlm_lock *lock) +-{ +- struct file_lock *fl = &lock->fl; +- s32 start, len, end; +- +- if (!(p = xdr_decode_string_inplace(p, &lock->caller, +- &lock->len, +- NLM_MAXSTRLEN)) +- || !(p = nlm_decode_fh(p, &lock->fh)) +- || !(p = nlm_decode_oh(p, &lock->oh))) +- return NULL; +- lock->svid = ntohl(*p++); +- +- locks_init_lock(fl); +- fl->fl_flags = FL_POSIX; +- fl->fl_type = F_RDLCK; /* as good as anything else */ +- start = ntohl(*p++); +- len = ntohl(*p++); +- end = start + len - 1; +- +- fl->fl_start = s32_to_loff_t(start); +- +- if (len == 0 || end < 0) +- fl->fl_end = OFFSET_MAX; +- else +- fl->fl_end = s32_to_loff_t(end); +- return p; +-} +- + static bool + svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock) + { +@@ -315,25 +285,28 @@ nlmsvc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p) ++nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p) + { +- struct nlm_res *resp = rqstp->rq_resp; ++ struct xdr_stream *xdr = &rqstp->rq_arg_stream; ++ struct nlm_args *argp = rqstp->rq_argp; + +- if (!(p = nlm_encode_testres(p, resp))) ++ if (!svcxdr_decode_cookie(xdr, &argp->cookie)) + return 0; +- return xdr_ressize_check(rqstp, p); ++ if (!svcxdr_decode_lock(xdr, &argp->lock)) ++ return 0; ++ argp->lock.fl.fl_type = F_UNLCK; ++ ++ return 1; + } + + int +-nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p) ++nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p) + { +- struct nlm_args *argp = rqstp->rq_argp; ++ struct nlm_res *resp = rqstp->rq_resp; + +- if (!(p = nlm_decode_cookie(p, &argp->cookie)) +- || !(p = nlm_decode_lock(p, &argp->lock))) ++ if (!(p = nlm_encode_testres(p, resp))) + return 0; +- argp->lock.fl.fl_type = F_UNLCK; +- return xdr_argsize_check(rqstp, p); ++ return xdr_ressize_check(rqstp, p); + } + + int +-- +2.43.0 + diff --git a/queue-5.10/lockd-update-the-nlmv1-void-argument-decoder-to-use-.patch b/queue-5.10/lockd-update-the-nlmv1-void-argument-decoder-to-use-.patch new file mode 100644 index 00000000000..d52dec916a5 --- /dev/null +++ b/queue-5.10/lockd-update-the-nlmv1-void-argument-decoder-to-use-.patch @@ -0,0 +1,64 @@ +From 0ce019ac0baf8504df3b850ea89cce86723409cc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 3 Jun 2021 16:50:58 -0400 +Subject: lockd: Update the NLMv1 void argument decoder to use struct + xdr_stream + +From: Chuck Lever + +[ Upstream commit cc1029b51273da5b342683e9ae14ab4eeaa15997 ] + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/xdr.c | 17 ++++++++++------- + 1 file changed, 10 insertions(+), 7 deletions(-) + +diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c +index 982629f7b120a..8be42a23679e9 100644 +--- a/fs/lockd/xdr.c ++++ b/fs/lockd/xdr.c +@@ -19,6 +19,8 @@ + + #include + ++#include "svcxdr.h" ++ + #define NLMDBG_FACILITY NLMDBG_XDR + + +@@ -178,8 +180,15 @@ nlm_encode_testres(__be32 *p, struct nlm_res *resp) + + + /* +- * First, the server side XDR functions ++ * Decode Call arguments + */ ++ ++int ++nlmsvc_decode_void(struct svc_rqst *rqstp, __be32 *p) ++{ ++ return 1; ++} ++ + int + nlmsvc_decode_testargs(struct svc_rqst *rqstp, __be32 *p) + { +@@ -339,12 +348,6 @@ nlmsvc_decode_res(struct svc_rqst *rqstp, __be32 *p) + return xdr_argsize_check(rqstp, p); + } + +-int +-nlmsvc_decode_void(struct svc_rqst *rqstp, __be32 *p) +-{ +- return xdr_argsize_check(rqstp, p); +-} +- + int + nlmsvc_encode_void(struct svc_rqst *rqstp, __be32 *p) + { +-- +2.43.0 + diff --git a/queue-5.10/lockd-update-the-nlmv1-void-results-encoder-to-use-s.patch b/queue-5.10/lockd-update-the-nlmv1-void-results-encoder-to-use-s.patch new file mode 100644 index 00000000000..712cf25bca1 --- /dev/null +++ b/queue-5.10/lockd-update-the-nlmv1-void-results-encoder-to-use-s.patch @@ -0,0 +1,52 @@ +From 2e790aa2fec64d9cfeccea272aaae086a04a73d9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 3 Jun 2021 16:51:52 -0400 +Subject: lockd: Update the NLMv1 void results encoder to use struct xdr_stream + +From: Chuck Lever + +[ Upstream commit e26ec898b68b2ab64f379ba0fc0a615b2ad41f40 ] + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/xdr.c | 17 +++++++++++------ + 1 file changed, 11 insertions(+), 6 deletions(-) + +diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c +index 091c8c463ab40..840fa8ff84269 100644 +--- a/fs/lockd/xdr.c ++++ b/fs/lockd/xdr.c +@@ -331,6 +331,17 @@ nlmsvc_decode_notify(struct svc_rqst *rqstp, __be32 *p) + return 1; + } + ++ ++/* ++ * Encode Reply results ++ */ ++ ++int ++nlmsvc_encode_void(struct svc_rqst *rqstp, __be32 *p) ++{ ++ return 1; ++} ++ + int + nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p) + { +@@ -363,9 +374,3 @@ nlmsvc_encode_res(struct svc_rqst *rqstp, __be32 *p) + *p++ = resp->status; + return xdr_ressize_check(rqstp, p); + } +- +-int +-nlmsvc_encode_void(struct svc_rqst *rqstp, __be32 *p) +-{ +- return xdr_ressize_check(rqstp, p); +-} +-- +2.43.0 + diff --git a/queue-5.10/lockd-update-the-nlmv4-cancel-arguments-decoder-to-u.patch b/queue-5.10/lockd-update-the-nlmv4-cancel-arguments-decoder-to-u.patch new file mode 100644 index 00000000000..2653bffb509 --- /dev/null +++ b/queue-5.10/lockd-update-the-nlmv4-cancel-arguments-decoder-to-u.patch @@ -0,0 +1,74 @@ +From ee170e99fd64c8cb1822ea3c818db1b5dc6e4c7e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 3 Jun 2021 16:52:34 -0400 +Subject: lockd: Update the NLMv4 CANCEL arguments decoder to use struct + xdr_stream + +From: Chuck Lever + +[ Upstream commit 1e1f38dcf3c031715191e1fd26f70a0affca4dbd ] + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/xdr4.c | 33 ++++++++++++++++++--------------- + 1 file changed, 18 insertions(+), 15 deletions(-) + +diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c +index 1d3e780c25fd5..37d45f1d71999 100644 +--- a/fs/lockd/xdr4.c ++++ b/fs/lockd/xdr4.c +@@ -291,30 +291,33 @@ nlm4svc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p) ++nlm4svc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p) + { +- struct nlm_res *resp = rqstp->rq_resp; ++ struct xdr_stream *xdr = &rqstp->rq_arg_stream; ++ struct nlm_args *argp = rqstp->rq_argp; ++ u32 exclusive; + +- if (!(p = nlm4_encode_testres(p, resp))) ++ if (!svcxdr_decode_cookie(xdr, &argp->cookie)) + return 0; +- return xdr_ressize_check(rqstp, p); ++ if (xdr_stream_decode_bool(xdr, &argp->block) < 0) ++ return 0; ++ if (xdr_stream_decode_bool(xdr, &exclusive) < 0) ++ return 0; ++ if (!svcxdr_decode_lock(xdr, &argp->lock)) ++ return 0; ++ if (exclusive) ++ argp->lock.fl.fl_type = F_WRLCK; ++ return 1; + } + + int +-nlm4svc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p) ++nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p) + { +- struct nlm_args *argp = rqstp->rq_argp; +- u32 exclusive; ++ struct nlm_res *resp = rqstp->rq_resp; + +- if (!(p = nlm4_decode_cookie(p, &argp->cookie))) +- return 0; +- argp->block = ntohl(*p++); +- exclusive = ntohl(*p++); +- if (!(p = nlm4_decode_lock(p, &argp->lock))) ++ if (!(p = nlm4_encode_testres(p, resp))) + return 0; +- if (exclusive) +- argp->lock.fl.fl_type = F_WRLCK; +- return xdr_argsize_check(rqstp, p); ++ return xdr_ressize_check(rqstp, p); + } + + int +-- +2.43.0 + diff --git a/queue-5.10/lockd-update-the-nlmv4-free_all-arguments-decoder-to.patch b/queue-5.10/lockd-update-the-nlmv4-free_all-arguments-decoder-to.patch new file mode 100644 index 00000000000..1e562a0497a --- /dev/null +++ b/queue-5.10/lockd-update-the-nlmv4-free_all-arguments-decoder-to.patch @@ -0,0 +1,67 @@ +From f10f99b207cae3323b7e29d5da779eb2f5a4e5f0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 3 Jun 2021 16:53:04 -0400 +Subject: lockd: Update the NLMv4 FREE_ALL arguments decoder to use struct + xdr_stream + +From: Chuck Lever + +[ Upstream commit 3049e974a7c7cfa0c15fb807f4a3e75b2ab8517a ] + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/xdr4.c | 28 +++++++++++++++------------- + 1 file changed, 15 insertions(+), 13 deletions(-) + +diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c +index e6bab1d1e41fb..6c5383bef2bf7 100644 +--- a/fs/lockd/xdr4.c ++++ b/fs/lockd/xdr4.c +@@ -309,6 +309,21 @@ nlm4svc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p) + return 1; + } + ++int ++nlm4svc_decode_notify(struct svc_rqst *rqstp, __be32 *p) ++{ ++ struct xdr_stream *xdr = &rqstp->rq_arg_stream; ++ struct nlm_args *argp = rqstp->rq_argp; ++ struct nlm_lock *lock = &argp->lock; ++ ++ if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len)) ++ return 0; ++ if (xdr_stream_decode_u32(xdr, &argp->state) < 0) ++ return 0; ++ ++ return 1; ++} ++ + int + nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p) + { +@@ -342,19 +357,6 @@ nlm4svc_encode_res(struct svc_rqst *rqstp, __be32 *p) + return xdr_ressize_check(rqstp, p); + } + +-int +-nlm4svc_decode_notify(struct svc_rqst *rqstp, __be32 *p) +-{ +- struct nlm_args *argp = rqstp->rq_argp; +- struct nlm_lock *lock = &argp->lock; +- +- if (!(p = xdr_decode_string_inplace(p, &lock->caller, +- &lock->len, NLM_MAXSTRLEN))) +- return 0; +- argp->state = ntohl(*p++); +- return xdr_argsize_check(rqstp, p); +-} +- + int + nlm4svc_encode_void(struct svc_rqst *rqstp, __be32 *p) + { +-- +2.43.0 + diff --git a/queue-5.10/lockd-update-the-nlmv4-lock-arguments-decoder-to-use.patch b/queue-5.10/lockd-update-the-nlmv4-lock-arguments-decoder-to-use.patch new file mode 100644 index 00000000000..70729212806 --- /dev/null +++ b/queue-5.10/lockd-update-the-nlmv4-lock-arguments-decoder-to-use.patch @@ -0,0 +1,84 @@ +From 14d4d414ec88acdf0404161790e41fa9528b3aab Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 3 Jun 2021 16:52:28 -0400 +Subject: lockd: Update the NLMv4 LOCK arguments decoder to use struct + xdr_stream + +From: Chuck Lever + +[ Upstream commit 0e5977af4fdc277984fca7d8c2e0c880935775a0 ] + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/xdr4.c | 41 +++++++++++++++++++++++------------------ + 1 file changed, 23 insertions(+), 18 deletions(-) + +diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c +index cf64794fdc1fa..1d3e780c25fd5 100644 +--- a/fs/lockd/xdr4.c ++++ b/fs/lockd/xdr4.c +@@ -264,35 +264,40 @@ nlm4svc_decode_testargs(struct svc_rqst *rqstp, __be32 *p) + return 1; + } + +-int +-nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p) +-{ +- struct nlm_res *resp = rqstp->rq_resp; +- +- if (!(p = nlm4_encode_testres(p, resp))) +- return 0; +- return xdr_ressize_check(rqstp, p); +-} +- + int + nlm4svc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nlm_args *argp = rqstp->rq_argp; +- u32 exclusive; ++ u32 exclusive; + +- if (!(p = nlm4_decode_cookie(p, &argp->cookie))) ++ if (!svcxdr_decode_cookie(xdr, &argp->cookie)) + return 0; +- argp->block = ntohl(*p++); +- exclusive = ntohl(*p++); +- if (!(p = nlm4_decode_lock(p, &argp->lock))) ++ if (xdr_stream_decode_bool(xdr, &argp->block) < 0) ++ return 0; ++ if (xdr_stream_decode_bool(xdr, &exclusive) < 0) ++ return 0; ++ if (!svcxdr_decode_lock(xdr, &argp->lock)) + return 0; + if (exclusive) + argp->lock.fl.fl_type = F_WRLCK; +- argp->reclaim = ntohl(*p++); +- argp->state = ntohl(*p++); ++ if (xdr_stream_decode_bool(xdr, &argp->reclaim) < 0) ++ return 0; ++ if (xdr_stream_decode_u32(xdr, &argp->state) < 0) ++ return 0; + argp->monitor = 1; /* monitor client by default */ + +- return xdr_argsize_check(rqstp, p); ++ return 1; ++} ++ ++int ++nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p) ++{ ++ struct nlm_res *resp = rqstp->rq_resp; ++ ++ if (!(p = nlm4_encode_testres(p, resp))) ++ return 0; ++ return xdr_ressize_check(rqstp, p); + } + + int +-- +2.43.0 + diff --git a/queue-5.10/lockd-update-the-nlmv4-nlm_res-arguments-decoder-to-.patch b/queue-5.10/lockd-update-the-nlmv4-nlm_res-arguments-decoder-to-.patch new file mode 100644 index 00000000000..d1f4ded67fb --- /dev/null +++ b/queue-5.10/lockd-update-the-nlmv4-nlm_res-arguments-decoder-to-.patch @@ -0,0 +1,64 @@ +From 7416e32143160e3c0c56abe954a1f19fe44f6a83 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 3 Jun 2021 16:52:46 -0400 +Subject: lockd: Update the NLMv4 nlm_res arguments decoder to use struct + xdr_stream + +From: Chuck Lever + +[ Upstream commit b4c24b5a41da63e5f3a9b6ea56cbe2a1efe49579 ] + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/xdr4.c | 25 ++++++++++++++----------- + 1 file changed, 14 insertions(+), 11 deletions(-) + +diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c +index 47a87ea4a99b1..6bd3bfb69ed7f 100644 +--- a/fs/lockd/xdr4.c ++++ b/fs/lockd/xdr4.c +@@ -295,6 +295,20 @@ nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p) + return 1; + } + ++int ++nlm4svc_decode_res(struct svc_rqst *rqstp, __be32 *p) ++{ ++ struct xdr_stream *xdr = &rqstp->rq_arg_stream; ++ struct nlm_res *resp = rqstp->rq_argp; ++ ++ if (!svcxdr_decode_cookie(xdr, &resp->cookie)) ++ return 0; ++ if (!svcxdr_decode_stats(xdr, &resp->status)) ++ return 0; ++ ++ return 1; ++} ++ + int + nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p) + { +@@ -375,17 +389,6 @@ nlm4svc_decode_reboot(struct svc_rqst *rqstp, __be32 *p) + return xdr_argsize_check(rqstp, p); + } + +-int +-nlm4svc_decode_res(struct svc_rqst *rqstp, __be32 *p) +-{ +- struct nlm_res *resp = rqstp->rq_argp; +- +- if (!(p = nlm4_decode_cookie(p, &resp->cookie))) +- return 0; +- resp->status = *p++; +- return xdr_argsize_check(rqstp, p); +-} +- + int + nlm4svc_encode_void(struct svc_rqst *rqstp, __be32 *p) + { +-- +2.43.0 + diff --git a/queue-5.10/lockd-update-the-nlmv4-nlm_res-results-encoder-to-us.patch b/queue-5.10/lockd-update-the-nlmv4-nlm_res-results-encoder-to-us.patch new file mode 100644 index 00000000000..84f3d998825 --- /dev/null +++ b/queue-5.10/lockd-update-the-nlmv4-nlm_res-results-encoder-to-us.patch @@ -0,0 +1,56 @@ +From a8096ccef5e3f9afae4d07667275002f848fc861 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 3 Jun 2021 16:53:23 -0400 +Subject: lockd: Update the NLMv4 nlm_res results encoder to use struct + xdr_stream + +From: Chuck Lever + +[ Upstream commit 447c14d48968d0d4c2733c3f8052cb63aa1deb38 ] + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/xdr4.c | 13 ++++++------- + 1 file changed, 6 insertions(+), 7 deletions(-) + +diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c +index 9b8a7afb935ca..efdede71b9511 100644 +--- a/fs/lockd/xdr4.c ++++ b/fs/lockd/xdr4.c +@@ -344,24 +344,23 @@ nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nlm4svc_encode_shareres(struct svc_rqst *rqstp, __be32 *p) ++nlm4svc_encode_res(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nlm_res *resp = rqstp->rq_resp; + +- if (!(p = nlm4_encode_cookie(p, &resp->cookie))) +- return 0; +- *p++ = resp->status; +- *p++ = xdr_zero; /* sequence argument */ +- return xdr_ressize_check(rqstp, p); ++ return svcxdr_encode_cookie(xdr, &resp->cookie) && ++ svcxdr_encode_stats(xdr, resp->status); + } + + int +-nlm4svc_encode_res(struct svc_rqst *rqstp, __be32 *p) ++nlm4svc_encode_shareres(struct svc_rqst *rqstp, __be32 *p) + { + struct nlm_res *resp = rqstp->rq_resp; + + if (!(p = nlm4_encode_cookie(p, &resp->cookie))) + return 0; + *p++ = resp->status; ++ *p++ = xdr_zero; /* sequence argument */ + return xdr_ressize_check(rqstp, p); + } +-- +2.43.0 + diff --git a/queue-5.10/lockd-update-the-nlmv4-share-arguments-decoder-to-us.patch b/queue-5.10/lockd-update-the-nlmv4-share-arguments-decoder-to-us.patch new file mode 100644 index 00000000000..5fb78ed8c1d --- /dev/null +++ b/queue-5.10/lockd-update-the-nlmv4-share-arguments-decoder-to-us.patch @@ -0,0 +1,162 @@ +From 7776f11cfabf35f96c843bd2a58ffecacf52f6de Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 3 Jun 2021 16:52:58 -0400 +Subject: lockd: Update the NLMv4 SHARE arguments decoder to use struct + xdr_stream + +From: Chuck Lever + +[ Upstream commit 7cf96b6d0104b12aa30961901879e428884b1695 ] + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/xdr4.c | 99 +++++++++++++------------------------------------ + 1 file changed, 26 insertions(+), 73 deletions(-) + +diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c +index 2dbf82c2726be..e6bab1d1e41fb 100644 +--- a/fs/lockd/xdr4.c ++++ b/fs/lockd/xdr4.c +@@ -42,37 +42,6 @@ loff_t_to_s64(loff_t offset) + return res; + } + +-/* +- * XDR functions for basic NLM types +- */ +-static __be32 * +-nlm4_decode_cookie(__be32 *p, struct nlm_cookie *c) +-{ +- unsigned int len; +- +- len = ntohl(*p++); +- +- if(len==0) +- { +- c->len=4; +- memset(c->data, 0, 4); /* hockeypux brain damage */ +- } +- else if(len<=NLM_MAXCOOKIELEN) +- { +- c->len=len; +- memcpy(c->data, p, len); +- p+=XDR_QUADLEN(len); +- } +- else +- { +- dprintk("lockd: bad cookie size %d (only cookies under " +- "%d bytes are supported.)\n", +- len, NLM_MAXCOOKIELEN); +- return NULL; +- } +- return p; +-} +- + static __be32 * + nlm4_encode_cookie(__be32 *p, struct nlm_cookie *c) + { +@@ -82,20 +51,6 @@ nlm4_encode_cookie(__be32 *p, struct nlm_cookie *c) + return p; + } + +-static __be32 * +-nlm4_decode_fh(__be32 *p, struct nfs_fh *f) +-{ +- memset(f->data, 0, sizeof(f->data)); +- f->size = ntohl(*p++); +- if (f->size > NFS_MAXFHSIZE) { +- dprintk("lockd: bad fhandle size %d (should be <=%d)\n", +- f->size, NFS_MAXFHSIZE); +- return NULL; +- } +- memcpy(f->data, p, f->size); +- return p + XDR_QUADLEN(f->size); +-} +- + /* + * NLM file handles are defined by specification to be a variable-length + * XDR opaque no longer than 1024 bytes. However, this implementation +@@ -122,15 +77,6 @@ svcxdr_decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh) + return true; + } + +-/* +- * Encode and decode owner handle +- */ +-static __be32 * +-nlm4_decode_oh(__be32 *p, struct xdr_netobj *oh) +-{ +- return xdr_decode_netobj(p, oh); +-} +- + static bool + svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock) + { +@@ -335,35 +281,42 @@ nlm4svc_decode_reboot(struct svc_rqst *rqstp, __be32 *p) + return 1; + } + +-int +-nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p) +-{ +- struct nlm_res *resp = rqstp->rq_resp; +- +- if (!(p = nlm4_encode_testres(p, resp))) +- return 0; +- return xdr_ressize_check(rqstp, p); +-} +- + int + nlm4svc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nlm_args *argp = rqstp->rq_argp; + struct nlm_lock *lock = &argp->lock; + + memset(lock, 0, sizeof(*lock)); + locks_init_lock(&lock->fl); +- lock->svid = ~(u32) 0; ++ lock->svid = ~(u32)0; + +- if (!(p = nlm4_decode_cookie(p, &argp->cookie)) +- || !(p = xdr_decode_string_inplace(p, &lock->caller, +- &lock->len, NLM_MAXSTRLEN)) +- || !(p = nlm4_decode_fh(p, &lock->fh)) +- || !(p = nlm4_decode_oh(p, &lock->oh))) ++ if (!svcxdr_decode_cookie(xdr, &argp->cookie)) + return 0; +- argp->fsm_mode = ntohl(*p++); +- argp->fsm_access = ntohl(*p++); +- return xdr_argsize_check(rqstp, p); ++ if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len)) ++ return 0; ++ if (!svcxdr_decode_fhandle(xdr, &lock->fh)) ++ return 0; ++ if (!svcxdr_decode_owner(xdr, &lock->oh)) ++ return 0; ++ /* XXX: Range checks are missing in the original code */ ++ if (xdr_stream_decode_u32(xdr, &argp->fsm_mode) < 0) ++ return 0; ++ if (xdr_stream_decode_u32(xdr, &argp->fsm_access) < 0) ++ return 0; ++ ++ return 1; ++} ++ ++int ++nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p) ++{ ++ struct nlm_res *resp = rqstp->rq_resp; ++ ++ if (!(p = nlm4_encode_testres(p, resp))) ++ return 0; ++ return xdr_ressize_check(rqstp, p); + } + + int +-- +2.43.0 + diff --git a/queue-5.10/lockd-update-the-nlmv4-share-results-encoder-to-use-.patch b/queue-5.10/lockd-update-the-nlmv4-share-results-encoder-to-use-.patch new file mode 100644 index 00000000000..7516739357a --- /dev/null +++ b/queue-5.10/lockd-update-the-nlmv4-share-results-encoder-to-use-.patch @@ -0,0 +1,61 @@ +From 67b33b7732c6dcab6694fdf8aea0afbf4af0e0c6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 3 Jun 2021 16:53:29 -0400 +Subject: lockd: Update the NLMv4 SHARE results encoder to use struct + xdr_stream + +From: Chuck Lever + +[ Upstream commit 0ff5b50ab1f7f39862d0cdf6803978d31b27f25e ] + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Sasha Levin +--- + fs/lockd/xdr4.c | 22 +++++++++------------- + 1 file changed, 9 insertions(+), 13 deletions(-) + +diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c +index efdede71b9511..98e957e4566c2 100644 +--- a/fs/lockd/xdr4.c ++++ b/fs/lockd/xdr4.c +@@ -40,15 +40,6 @@ loff_t_to_s64(loff_t offset) + return res; + } + +-static __be32 * +-nlm4_encode_cookie(__be32 *p, struct nlm_cookie *c) +-{ +- *p++ = htonl(c->len); +- memcpy(p, c->data, c->len); +- p+=XDR_QUADLEN(c->len); +- return p; +-} +- + /* + * NLM file handles are defined by specification to be a variable-length + * XDR opaque no longer than 1024 bytes. However, this implementation +@@ -356,11 +347,16 @@ nlm4svc_encode_res(struct svc_rqst *rqstp, __be32 *p) + int + nlm4svc_encode_shareres(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nlm_res *resp = rqstp->rq_resp; + +- if (!(p = nlm4_encode_cookie(p, &resp->cookie))) ++ if (!svcxdr_encode_cookie(xdr, &resp->cookie)) + return 0; +- *p++ = resp->status; +- *p++ = xdr_zero; /* sequence argument */ +- return xdr_ressize_check(rqstp, p); ++ if (!svcxdr_encode_stats(xdr, resp->status)) ++ return 0; ++ /* sequence */ ++ if (xdr_stream_encode_u32(xdr, 0) < 0) ++ return 0; ++ ++ return 1; + } +-- +2.43.0 + diff --git a/queue-5.10/lockd-update-the-nlmv4-sm_notify-arguments-decoder-t.patch b/queue-5.10/lockd-update-the-nlmv4-sm_notify-arguments-decoder-t.patch new file mode 100644 index 00000000000..cccaaa981f7 --- /dev/null +++ b/queue-5.10/lockd-update-the-nlmv4-sm_notify-arguments-decoder-t.patch @@ -0,0 +1,78 @@ +From b44b7c87c13cb73e3979a4659a6876652c935ccb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 3 Jun 2021 16:52:52 -0400 +Subject: lockd: Update the NLMv4 SM_NOTIFY arguments decoder to use struct + xdr_stream + +From: Chuck Lever + +[ Upstream commit bc3665fd718b325cfff3abd383b00d1a87e028dc ] + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/xdr4.c | 39 ++++++++++++++++++++++++++------------- + 1 file changed, 26 insertions(+), 13 deletions(-) + +diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c +index 6bd3bfb69ed7f..2dbf82c2726be 100644 +--- a/fs/lockd/xdr4.c ++++ b/fs/lockd/xdr4.c +@@ -309,6 +309,32 @@ nlm4svc_decode_res(struct svc_rqst *rqstp, __be32 *p) + return 1; + } + ++int ++nlm4svc_decode_reboot(struct svc_rqst *rqstp, __be32 *p) ++{ ++ struct xdr_stream *xdr = &rqstp->rq_arg_stream; ++ struct nlm_reboot *argp = rqstp->rq_argp; ++ u32 len; ++ ++ if (xdr_stream_decode_u32(xdr, &len) < 0) ++ return 0; ++ if (len > SM_MAXSTRLEN) ++ return 0; ++ p = xdr_inline_decode(xdr, len); ++ if (!p) ++ return 0; ++ argp->len = len; ++ argp->mon = (char *)p; ++ if (xdr_stream_decode_u32(xdr, &argp->state) < 0) ++ return 0; ++ p = xdr_inline_decode(xdr, SM_PRIV_SIZE); ++ if (!p) ++ return 0; ++ memcpy(&argp->priv.data, p, sizeof(argp->priv.data)); ++ ++ return 1; ++} ++ + int + nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p) + { +@@ -376,19 +402,6 @@ nlm4svc_decode_notify(struct svc_rqst *rqstp, __be32 *p) + return xdr_argsize_check(rqstp, p); + } + +-int +-nlm4svc_decode_reboot(struct svc_rqst *rqstp, __be32 *p) +-{ +- struct nlm_reboot *argp = rqstp->rq_argp; +- +- if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN))) +- return 0; +- argp->state = ntohl(*p++); +- memcpy(&argp->priv.data, p, sizeof(argp->priv.data)); +- p += XDR_QUADLEN(SM_PRIV_SIZE); +- return xdr_argsize_check(rqstp, p); +-} +- + int + nlm4svc_encode_void(struct svc_rqst *rqstp, __be32 *p) + { +-- +2.43.0 + diff --git a/queue-5.10/lockd-update-the-nlmv4-test-arguments-decoder-to-use.patch b/queue-5.10/lockd-update-the-nlmv4-test-arguments-decoder-to-use.patch new file mode 100644 index 00000000000..e72bf0be104 --- /dev/null +++ b/queue-5.10/lockd-update-the-nlmv4-test-arguments-decoder-to-use.patch @@ -0,0 +1,125 @@ +From 28fcc3348878621e5a38411bd068528b52ece9dd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 3 Jun 2021 16:52:22 -0400 +Subject: lockd: Update the NLMv4 TEST arguments decoder to use struct + xdr_stream + +From: Chuck Lever + +[ Upstream commit 345b4159a075b15dc4ae70f1db90fa8abf85d2e7 ] + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/xdr4.c | 72 ++++++++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 66 insertions(+), 6 deletions(-) + +diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c +index d0960a8551f8b..cf64794fdc1fa 100644 +--- a/fs/lockd/xdr4.c ++++ b/fs/lockd/xdr4.c +@@ -96,6 +96,32 @@ nlm4_decode_fh(__be32 *p, struct nfs_fh *f) + return p + XDR_QUADLEN(f->size); + } + ++/* ++ * NLM file handles are defined by specification to be a variable-length ++ * XDR opaque no longer than 1024 bytes. However, this implementation ++ * limits their length to the size of an NFSv3 file handle. ++ */ ++static bool ++svcxdr_decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh) ++{ ++ __be32 *p; ++ u32 len; ++ ++ if (xdr_stream_decode_u32(xdr, &len) < 0) ++ return false; ++ if (len > NFS_MAXFHSIZE) ++ return false; ++ ++ p = xdr_inline_decode(xdr, len); ++ if (!p) ++ return false; ++ fh->size = len; ++ memcpy(fh->data, p, len); ++ memset(fh->data + len, 0, sizeof(fh->data) - len); ++ ++ return true; ++} ++ + /* + * Encode and decode owner handle + */ +@@ -135,6 +161,39 @@ nlm4_decode_lock(__be32 *p, struct nlm_lock *lock) + return p; + } + ++static bool ++svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock) ++{ ++ struct file_lock *fl = &lock->fl; ++ u64 len, start; ++ s64 end; ++ ++ if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len)) ++ return false; ++ if (!svcxdr_decode_fhandle(xdr, &lock->fh)) ++ return false; ++ if (!svcxdr_decode_owner(xdr, &lock->oh)) ++ return false; ++ if (xdr_stream_decode_u32(xdr, &lock->svid) < 0) ++ return false; ++ if (xdr_stream_decode_u64(xdr, &start) < 0) ++ return false; ++ if (xdr_stream_decode_u64(xdr, &len) < 0) ++ return false; ++ ++ locks_init_lock(fl); ++ fl->fl_flags = FL_POSIX; ++ fl->fl_type = F_RDLCK; ++ end = start + len - 1; ++ fl->fl_start = s64_to_loff_t(start); ++ if (len == 0 || end < 0) ++ fl->fl_end = OFFSET_MAX; ++ else ++ fl->fl_end = s64_to_loff_t(end); ++ ++ return true; ++} ++ + /* + * Encode result of a TEST/TEST_MSG call + */ +@@ -189,19 +248,20 @@ nlm4svc_decode_void(struct svc_rqst *rqstp, __be32 *p) + int + nlm4svc_decode_testargs(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nlm_args *argp = rqstp->rq_argp; +- u32 exclusive; ++ u32 exclusive; + +- if (!(p = nlm4_decode_cookie(p, &argp->cookie))) ++ if (!svcxdr_decode_cookie(xdr, &argp->cookie)) + return 0; +- +- exclusive = ntohl(*p++); +- if (!(p = nlm4_decode_lock(p, &argp->lock))) ++ if (xdr_stream_decode_bool(xdr, &exclusive) < 0) ++ return 0; ++ if (!svcxdr_decode_lock(xdr, &argp->lock)) + return 0; + if (exclusive) + argp->lock.fl.fl_type = F_WRLCK; + +- return xdr_argsize_check(rqstp, p); ++ return 1; + } + + int +-- +2.43.0 + diff --git a/queue-5.10/lockd-update-the-nlmv4-test-results-encoder-to-use-s.patch b/queue-5.10/lockd-update-the-nlmv4-test-results-encoder-to-use-s.patch new file mode 100644 index 00000000000..904477a4538 --- /dev/null +++ b/queue-5.10/lockd-update-the-nlmv4-test-results-encoder-to-use-s.patch @@ -0,0 +1,126 @@ +From 330557b868a42d2fa861671cad6fc80f13f2926a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 3 Jun 2021 16:53:17 -0400 +Subject: lockd: Update the NLMv4 TEST results encoder to use struct xdr_stream + +From: Chuck Lever + +[ Upstream commit 1beef1473ccaa70a2d54f9e76fba5f534931ea23 ] + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/xdr4.c | 74 ++++++++++++++++++++++++------------------------- + 1 file changed, 36 insertions(+), 38 deletions(-) + +diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c +index 0db142e203d2b..9b8a7afb935ca 100644 +--- a/fs/lockd/xdr4.c ++++ b/fs/lockd/xdr4.c +@@ -20,8 +20,6 @@ + + #include "svcxdr.h" + +-#define NLMDBG_FACILITY NLMDBG_XDR +- + static inline loff_t + s64_to_loff_t(__s64 offset) + { +@@ -110,44 +108,44 @@ svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock) + return true; + } + +-/* +- * Encode result of a TEST/TEST_MSG call +- */ +-static __be32 * +-nlm4_encode_testres(__be32 *p, struct nlm_res *resp) ++static bool ++svcxdr_encode_holder(struct xdr_stream *xdr, const struct nlm_lock *lock) + { +- s64 start, len; ++ const struct file_lock *fl = &lock->fl; ++ s64 start, len; + +- dprintk("xdr: before encode_testres (p %p resp %p)\n", p, resp); +- if (!(p = nlm4_encode_cookie(p, &resp->cookie))) +- return NULL; +- *p++ = resp->status; ++ /* exclusive */ ++ if (xdr_stream_encode_bool(xdr, fl->fl_type != F_RDLCK) < 0) ++ return false; ++ if (xdr_stream_encode_u32(xdr, lock->svid) < 0) ++ return false; ++ if (!svcxdr_encode_owner(xdr, &lock->oh)) ++ return false; ++ start = loff_t_to_s64(fl->fl_start); ++ if (fl->fl_end == OFFSET_MAX) ++ len = 0; ++ else ++ len = loff_t_to_s64(fl->fl_end - fl->fl_start + 1); ++ if (xdr_stream_encode_u64(xdr, start) < 0) ++ return false; ++ if (xdr_stream_encode_u64(xdr, len) < 0) ++ return false; ++ ++ return true; ++} + +- if (resp->status == nlm_lck_denied) { +- struct file_lock *fl = &resp->lock.fl; +- +- *p++ = (fl->fl_type == F_RDLCK)? xdr_zero : xdr_one; +- *p++ = htonl(resp->lock.svid); +- +- /* Encode owner handle. */ +- if (!(p = xdr_encode_netobj(p, &resp->lock.oh))) +- return NULL; +- +- start = loff_t_to_s64(fl->fl_start); +- if (fl->fl_end == OFFSET_MAX) +- len = 0; +- else +- len = loff_t_to_s64(fl->fl_end - fl->fl_start + 1); +- +- p = xdr_encode_hyper(p, start); +- p = xdr_encode_hyper(p, len); +- dprintk("xdr: encode_testres (status %u pid %d type %d start %Ld end %Ld)\n", +- resp->status, (int)resp->lock.svid, fl->fl_type, +- (long long)fl->fl_start, (long long)fl->fl_end); ++static bool ++svcxdr_encode_testrply(struct xdr_stream *xdr, const struct nlm_res *resp) ++{ ++ if (!svcxdr_encode_stats(xdr, resp->status)) ++ return false; ++ switch (resp->status) { ++ case nlm_lck_denied: ++ if (!svcxdr_encode_holder(xdr, &resp->lock)) ++ return false; + } + +- dprintk("xdr: after encode_testres (p %p resp %p)\n", p, resp); +- return p; ++ return true; + } + + +@@ -338,11 +336,11 @@ nlm4svc_encode_void(struct svc_rqst *rqstp, __be32 *p) + int + nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nlm_res *resp = rqstp->rq_resp; + +- if (!(p = nlm4_encode_testres(p, resp))) +- return 0; +- return xdr_ressize_check(rqstp, p); ++ return svcxdr_encode_cookie(xdr, &resp->cookie) && ++ svcxdr_encode_testrply(xdr, resp); + } + + int +-- +2.43.0 + diff --git a/queue-5.10/lockd-update-the-nlmv4-unlock-arguments-decoder-to-u.patch b/queue-5.10/lockd-update-the-nlmv4-unlock-arguments-decoder-to-u.patch new file mode 100644 index 00000000000..5728e573fbf --- /dev/null +++ b/queue-5.10/lockd-update-the-nlmv4-unlock-arguments-decoder-to-u.patch @@ -0,0 +1,101 @@ +From e3d9ab8a9baf7a94cf6ad409af610324b0b551fe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 3 Jun 2021 16:52:40 -0400 +Subject: lockd: Update the NLMv4 UNLOCK arguments decoder to use struct + xdr_stream + +From: Chuck Lever + +[ Upstream commit d76d8c25cea794f65615f3a2324052afa4b5f900 ] + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/xdr4.c | 53 ++++++++++++------------------------------------- + 1 file changed, 13 insertions(+), 40 deletions(-) + +diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c +index 37d45f1d71999..47a87ea4a99b1 100644 +--- a/fs/lockd/xdr4.c ++++ b/fs/lockd/xdr4.c +@@ -131,36 +131,6 @@ nlm4_decode_oh(__be32 *p, struct xdr_netobj *oh) + return xdr_decode_netobj(p, oh); + } + +-static __be32 * +-nlm4_decode_lock(__be32 *p, struct nlm_lock *lock) +-{ +- struct file_lock *fl = &lock->fl; +- __u64 len, start; +- __s64 end; +- +- if (!(p = xdr_decode_string_inplace(p, &lock->caller, +- &lock->len, NLM_MAXSTRLEN)) +- || !(p = nlm4_decode_fh(p, &lock->fh)) +- || !(p = nlm4_decode_oh(p, &lock->oh))) +- return NULL; +- lock->svid = ntohl(*p++); +- +- locks_init_lock(fl); +- fl->fl_flags = FL_POSIX; +- fl->fl_type = F_RDLCK; /* as good as anything else */ +- p = xdr_decode_hyper(p, &start); +- p = xdr_decode_hyper(p, &len); +- end = start + len - 1; +- +- fl->fl_start = s64_to_loff_t(start); +- +- if (len == 0 || end < 0) +- fl->fl_end = OFFSET_MAX; +- else +- fl->fl_end = s64_to_loff_t(end); +- return p; +-} +- + static bool + svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock) + { +@@ -311,25 +281,28 @@ nlm4svc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p) ++nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p) + { +- struct nlm_res *resp = rqstp->rq_resp; ++ struct xdr_stream *xdr = &rqstp->rq_arg_stream; ++ struct nlm_args *argp = rqstp->rq_argp; + +- if (!(p = nlm4_encode_testres(p, resp))) ++ if (!svcxdr_decode_cookie(xdr, &argp->cookie)) + return 0; +- return xdr_ressize_check(rqstp, p); ++ if (!svcxdr_decode_lock(xdr, &argp->lock)) ++ return 0; ++ argp->lock.fl.fl_type = F_UNLCK; ++ ++ return 1; + } + + int +-nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p) ++nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p) + { +- struct nlm_args *argp = rqstp->rq_argp; ++ struct nlm_res *resp = rqstp->rq_resp; + +- if (!(p = nlm4_decode_cookie(p, &argp->cookie)) +- || !(p = nlm4_decode_lock(p, &argp->lock))) ++ if (!(p = nlm4_encode_testres(p, resp))) + return 0; +- argp->lock.fl.fl_type = F_UNLCK; +- return xdr_argsize_check(rqstp, p); ++ return xdr_ressize_check(rqstp, p); + } + + int +-- +2.43.0 + diff --git a/queue-5.10/lockd-update-the-nlmv4-void-arguments-decoder-to-use.patch b/queue-5.10/lockd-update-the-nlmv4-void-arguments-decoder-to-use.patch new file mode 100644 index 00000000000..7043a787336 --- /dev/null +++ b/queue-5.10/lockd-update-the-nlmv4-void-arguments-decoder-to-use.patch @@ -0,0 +1,64 @@ +From 4b2cf2db93f0e2a4d22db37e8b58d1930604e82f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 3 Jun 2021 16:52:16 -0400 +Subject: lockd: Update the NLMv4 void arguments decoder to use struct + xdr_stream + +From: Chuck Lever + +[ Upstream commit 7956521aac58e434a05cf3c68c1b66c1312e5649 ] + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/xdr4.c | 17 ++++++++++------- + 1 file changed, 10 insertions(+), 7 deletions(-) + +diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c +index 5fa9f48a9dba7..d0960a8551f8b 100644 +--- a/fs/lockd/xdr4.c ++++ b/fs/lockd/xdr4.c +@@ -18,6 +18,8 @@ + #include + #include + ++#include "svcxdr.h" ++ + #define NLMDBG_FACILITY NLMDBG_XDR + + static inline loff_t +@@ -175,8 +177,15 @@ nlm4_encode_testres(__be32 *p, struct nlm_res *resp) + + + /* +- * First, the server side XDR functions ++ * Decode Call arguments + */ ++ ++int ++nlm4svc_decode_void(struct svc_rqst *rqstp, __be32 *p) ++{ ++ return 1; ++} ++ + int + nlm4svc_decode_testargs(struct svc_rqst *rqstp, __be32 *p) + { +@@ -336,12 +345,6 @@ nlm4svc_decode_res(struct svc_rqst *rqstp, __be32 *p) + return xdr_argsize_check(rqstp, p); + } + +-int +-nlm4svc_decode_void(struct svc_rqst *rqstp, __be32 *p) +-{ +- return xdr_argsize_check(rqstp, p); +-} +- + int + nlm4svc_encode_void(struct svc_rqst *rqstp, __be32 *p) + { +-- +2.43.0 + diff --git a/queue-5.10/lockd-update-the-nlmv4-void-results-encoder-to-use-s.patch b/queue-5.10/lockd-update-the-nlmv4-void-results-encoder-to-use-s.patch new file mode 100644 index 00000000000..451f06e1222 --- /dev/null +++ b/queue-5.10/lockd-update-the-nlmv4-void-results-encoder-to-use-s.patch @@ -0,0 +1,52 @@ +From 15ef2c02a9cfc59d81568827fbbf5710c7d05968 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 3 Jun 2021 16:53:11 -0400 +Subject: lockd: Update the NLMv4 void results encoder to use struct xdr_stream + +From: Chuck Lever + +[ Upstream commit ec757e423b4fcd6e5ea4405d1e8243c040458d78 ] + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/xdr4.c | 17 +++++++++++------ + 1 file changed, 11 insertions(+), 6 deletions(-) + +diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c +index 6c5383bef2bf7..0db142e203d2b 100644 +--- a/fs/lockd/xdr4.c ++++ b/fs/lockd/xdr4.c +@@ -324,6 +324,17 @@ nlm4svc_decode_notify(struct svc_rqst *rqstp, __be32 *p) + return 1; + } + ++ ++/* ++ * Encode Reply results ++ */ ++ ++int ++nlm4svc_encode_void(struct svc_rqst *rqstp, __be32 *p) ++{ ++ return 1; ++} ++ + int + nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p) + { +@@ -356,9 +367,3 @@ nlm4svc_encode_res(struct svc_rqst *rqstp, __be32 *p) + *p++ = resp->status; + return xdr_ressize_check(rqstp, p); + } +- +-int +-nlm4svc_encode_void(struct svc_rqst *rqstp, __be32 *p) +-{ +- return xdr_ressize_check(rqstp, p); +-} +-- +2.43.0 + diff --git a/queue-5.10/lockd-use-locks_inode_context-helper.patch b/queue-5.10/lockd-use-locks_inode_context-helper.patch new file mode 100644 index 00000000000..519de4612a0 --- /dev/null +++ b/queue-5.10/lockd-use-locks_inode_context-helper.patch @@ -0,0 +1,49 @@ +From 391274c1cf8114f0d346b393d311f0fac8403a30 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 16 Nov 2022 09:19:43 -0500 +Subject: lockd: use locks_inode_context helper + +From: Jeff Layton + +[ Upstream commit 98b41ffe0afdfeaa1439a5d6bd2db4a94277e31b ] + +lockd currently doesn't access i_flctx safely. This requires a +smp_load_acquire, as the pointer is set via cmpxchg (a release +operation). + +Cc: Trond Myklebust +Cc: Anna Schumaker +Cc: Chuck Lever +Reviewed-by: Christoph Hellwig +Signed-off-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/svcsubs.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c +index e1c4617de7714..720684345817c 100644 +--- a/fs/lockd/svcsubs.c ++++ b/fs/lockd/svcsubs.c +@@ -207,7 +207,7 @@ nlm_traverse_locks(struct nlm_host *host, struct nlm_file *file, + { + struct inode *inode = nlmsvc_file_inode(file); + struct file_lock *fl; +- struct file_lock_context *flctx = inode->i_flctx; ++ struct file_lock_context *flctx = locks_inode_context(inode); + struct nlm_host *lockhost; + + if (!flctx || list_empty_careful(&flctx->flc_posix)) +@@ -262,7 +262,7 @@ nlm_file_inuse(struct nlm_file *file) + { + struct inode *inode = nlmsvc_file_inode(file); + struct file_lock *fl; +- struct file_lock_context *flctx = inode->i_flctx; ++ struct file_lock_context *flctx = locks_inode_context(inode); + + if (file->f_count || !list_empty(&file->f_blocks) || file->f_shares) + return 1; +-- +2.43.0 + diff --git a/queue-5.10/lockd-use-svc_set_num_threads-for-thread-start-and-s.patch b/queue-5.10/lockd-use-svc_set_num_threads-for-thread-start-and-s.patch new file mode 100644 index 00000000000..dfdfc2913d8 --- /dev/null +++ b/queue-5.10/lockd-use-svc_set_num_threads-for-thread-start-and-s.patch @@ -0,0 +1,189 @@ +From be2a2c213797926b31219ff3a0d9f840ffa0adf7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Nov 2021 15:51:25 +1100 +Subject: lockd: use svc_set_num_threads() for thread start and stop + +From: NeilBrown + +[ Upstream commit 6b044fbaab02292fedb17565dbb3f2528083b169 ] + +svc_set_num_threads() does everything that lockd_start_svc() does, except +set sv_maxconn. It also (when passed 0) finds the threads and +stops them with kthread_stop(). + +So move the setting for sv_maxconn, and use svc_set_num_thread() + +We now don't need nlmsvc_task. + +Now that we use svc_set_num_threads() it makes sense to set svo_module. +This request that the thread exists with module_put_and_exit(). +Also fix the documentation for svo_module to make this explicit. + +svc_prepare_thread is now only used where it is defined, so it can be +made static. + +Signed-off-by: NeilBrown +[ cel: address merge conflict with fd2468fa1301 ] +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/svc.c | 58 ++++++-------------------------------- + include/linux/sunrpc/svc.h | 6 ++-- + net/sunrpc/svc.c | 3 +- + 3 files changed, 12 insertions(+), 55 deletions(-) + +diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c +index 1a7c11118b320..0475c5a5d061e 100644 +--- a/fs/lockd/svc.c ++++ b/fs/lockd/svc.c +@@ -55,7 +55,6 @@ EXPORT_SYMBOL_GPL(nlmsvc_ops); + static DEFINE_MUTEX(nlmsvc_mutex); + static unsigned int nlmsvc_users; + static struct svc_serv *nlmsvc_serv; +-static struct task_struct *nlmsvc_task; + unsigned long nlmsvc_timeout; + + unsigned int lockd_net_id; +@@ -186,7 +185,7 @@ lockd(void *vrqstp) + + svc_exit_thread(rqstp); + +- return 0; ++ module_put_and_kthread_exit(0); + } + + static int create_lockd_listener(struct svc_serv *serv, const char *name, +@@ -292,8 +291,8 @@ static void lockd_down_net(struct svc_serv *serv, struct net *net) + __func__, net->ns.inum); + } + } else { +- pr_err("%s: no users! task=%p, net=%x\n", +- __func__, nlmsvc_task, net->ns.inum); ++ pr_err("%s: no users! net=%x\n", ++ __func__, net->ns.inum); + BUG(); + } + } +@@ -351,49 +350,11 @@ static struct notifier_block lockd_inet6addr_notifier = { + }; + #endif + +-static int lockd_start_svc(struct svc_serv *serv) +-{ +- int error; +- struct svc_rqst *rqst; +- +- /* +- * Create the kernel thread and wait for it to start. +- */ +- rqst = svc_prepare_thread(serv, &serv->sv_pools[0], NUMA_NO_NODE); +- if (IS_ERR(rqst)) { +- error = PTR_ERR(rqst); +- printk(KERN_WARNING +- "lockd_up: svc_rqst allocation failed, error=%d\n", +- error); +- goto out_rqst; +- } +- +- svc_sock_update_bufs(serv); +- serv->sv_maxconn = nlm_max_connections; +- +- nlmsvc_task = kthread_create(lockd, rqst, "%s", serv->sv_name); +- if (IS_ERR(nlmsvc_task)) { +- error = PTR_ERR(nlmsvc_task); +- printk(KERN_WARNING +- "lockd_up: kthread_run failed, error=%d\n", error); +- goto out_task; +- } +- rqst->rq_task = nlmsvc_task; +- wake_up_process(nlmsvc_task); +- +- dprintk("lockd_up: service started\n"); +- return 0; +- +-out_task: +- svc_exit_thread(rqst); +- nlmsvc_task = NULL; +-out_rqst: +- return error; +-} +- + static const struct svc_serv_ops lockd_sv_ops = { + .svo_shutdown = svc_rpcb_cleanup, ++ .svo_function = lockd, + .svo_enqueue_xprt = svc_xprt_do_enqueue, ++ .svo_module = THIS_MODULE, + }; + + static int lockd_get(void) +@@ -425,7 +386,8 @@ static int lockd_get(void) + return -ENOMEM; + } + +- error = lockd_start_svc(serv); ++ serv->sv_maxconn = nlm_max_connections; ++ error = svc_set_num_threads(serv, NULL, 1); + /* The thread now holds the only reference */ + svc_put(serv); + if (error < 0) +@@ -453,11 +415,7 @@ static void lockd_put(void) + unregister_inet6addr_notifier(&lockd_inet6addr_notifier); + #endif + +- if (nlmsvc_task) { +- kthread_stop(nlmsvc_task); +- dprintk("lockd_down: service stopped\n"); +- nlmsvc_task = NULL; +- } ++ svc_set_num_threads(nlmsvc_serv, NULL, 0); + nlmsvc_serv = NULL; + dprintk("lockd_down: service destroyed\n"); + } +diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h +index 89e9d00af601b..f116141ea64d0 100644 +--- a/include/linux/sunrpc/svc.h ++++ b/include/linux/sunrpc/svc.h +@@ -64,7 +64,9 @@ struct svc_serv_ops { + /* queue up a transport for servicing */ + void (*svo_enqueue_xprt)(struct svc_xprt *); + +- /* optional module to count when adding threads (pooled svcs only) */ ++ /* optional module to count when adding threads. ++ * Thread function must call module_put_and_kthread_exit() to exit. ++ */ + struct module *svo_module; + }; + +@@ -507,8 +509,6 @@ struct svc_serv *svc_create(struct svc_program *, unsigned int, + const struct svc_serv_ops *); + struct svc_rqst *svc_rqst_alloc(struct svc_serv *serv, + struct svc_pool *pool, int node); +-struct svc_rqst *svc_prepare_thread(struct svc_serv *serv, +- struct svc_pool *pool, int node); + void svc_rqst_replace_page(struct svc_rqst *rqstp, + struct page *page); + void svc_rqst_free(struct svc_rqst *); +diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c +index ceccd4ae5f797..d34d03b0bf76b 100644 +--- a/net/sunrpc/svc.c ++++ b/net/sunrpc/svc.c +@@ -650,7 +650,7 @@ svc_rqst_alloc(struct svc_serv *serv, struct svc_pool *pool, int node) + } + EXPORT_SYMBOL_GPL(svc_rqst_alloc); + +-struct svc_rqst * ++static struct svc_rqst * + svc_prepare_thread(struct svc_serv *serv, struct svc_pool *pool, int node) + { + struct svc_rqst *rqstp; +@@ -670,7 +670,6 @@ svc_prepare_thread(struct svc_serv *serv, struct svc_pool *pool, int node) + spin_unlock_bh(&pool->sp_lock); + return rqstp; + } +-EXPORT_SYMBOL_GPL(svc_prepare_thread); + + /* + * Choose a pool in which to create a new thread, for svc_set_num_threads +-- +2.43.0 + diff --git a/queue-5.10/module-unexport-find_module-and-module_mutex.patch b/queue-5.10/module-unexport-find_module-and-module_mutex.patch new file mode 100644 index 00000000000..ba282df43b0 --- /dev/null +++ b/queue-5.10/module-unexport-find_module-and-module_mutex.patch @@ -0,0 +1,44 @@ +From e559164ad53e3b22aa23a25d6a661ee8d992445a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Feb 2021 13:13:24 +0100 +Subject: module: unexport find_module and module_mutex + +From: Christoph Hellwig + +[ Upstream commit 089049f6c9956c5cf1fc89fe10229c76e99f4bef ] + +find_module is not used by modular code any more, and random driver code +has no business calling it to start with. + +Reviewed-by: Miroslav Benes +Signed-off-by: Christoph Hellwig +Signed-off-by: Jessica Yu +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + kernel/module.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/kernel/module.c b/kernel/module.c +index 72a5dcdccf7b1..c0e51ffe26f0a 100644 +--- a/kernel/module.c ++++ b/kernel/module.c +@@ -88,7 +88,6 @@ + * 3) module_addr_min/module_addr_max. + * (delete and add uses RCU list operations). */ + DEFINE_MUTEX(module_mutex); +-EXPORT_SYMBOL_GPL(module_mutex); + static LIST_HEAD(modules); + + /* Work queue for freeing init sections in success case */ +@@ -645,7 +644,6 @@ struct module *find_module(const char *name) + module_assert_mutex(); + return find_module_all(name, strlen(name), false); + } +-EXPORT_SYMBOL_GPL(find_module); + + #ifdef CONFIG_SMP + +-- +2.43.0 + diff --git a/queue-5.10/module-use-rcu-to-synchronize-find_module.patch b/queue-5.10/module-use-rcu-to-synchronize-find_module.patch new file mode 100644 index 00000000000..e9e815a57b8 --- /dev/null +++ b/queue-5.10/module-use-rcu-to-synchronize-find_module.patch @@ -0,0 +1,101 @@ +From 9c4174bb60699f54ee7f2c1dca8a4db4b5f0a022 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Feb 2021 13:13:25 +0100 +Subject: module: use RCU to synchronize find_module + +From: Christoph Hellwig + +[ Upstream commit a006050575745ca2be25118b90f1c37f454ac542 ] + +Allow for a RCU-sched critical section around find_module, following +the lower level find_module_all helper, and switch the two callers +outside of module.c to use such a RCU-sched critical section instead +of module_mutex. + +Reviewed-by: Petr Mladek +Acked-by: Miroslav Benes +Signed-off-by: Christoph Hellwig +Signed-off-by: Jessica Yu +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + include/linux/module.h | 2 +- + kernel/livepatch/core.c | 5 +++-- + kernel/module.c | 1 - + kernel/trace/trace_kprobe.c | 4 ++-- + 4 files changed, 6 insertions(+), 6 deletions(-) + +diff --git a/include/linux/module.h b/include/linux/module.h +index 6264617bab4d4..86fae5d1c0e39 100644 +--- a/include/linux/module.h ++++ b/include/linux/module.h +@@ -582,7 +582,7 @@ static inline bool within_module(unsigned long addr, const struct module *mod) + return within_module_init(addr, mod) || within_module_core(addr, mod); + } + +-/* Search for module by name: must hold module_mutex. */ ++/* Search for module by name: must be in a RCU-sched critical section. */ + struct module *find_module(const char *name); + + struct symsearch { +diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c +index f5faf935c2d8f..e660ea4f90a28 100644 +--- a/kernel/livepatch/core.c ++++ b/kernel/livepatch/core.c +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + #include + #include "core.h" + #include "patch.h" +@@ -57,7 +58,7 @@ static void klp_find_object_module(struct klp_object *obj) + if (!klp_is_module(obj)) + return; + +- mutex_lock(&module_mutex); ++ rcu_read_lock_sched(); + /* + * We do not want to block removal of patched modules and therefore + * we do not take a reference here. The patches are removed by +@@ -74,7 +75,7 @@ static void klp_find_object_module(struct klp_object *obj) + if (mod && mod->klp_alive) + obj->mod = mod; + +- mutex_unlock(&module_mutex); ++ rcu_read_unlock_sched(); + } + + static bool klp_initialized(void) +diff --git a/kernel/module.c b/kernel/module.c +index c0e51ffe26f0a..1f9f6133c30ef 100644 +--- a/kernel/module.c ++++ b/kernel/module.c +@@ -641,7 +641,6 @@ static struct module *find_module_all(const char *name, size_t len, + + struct module *find_module(const char *name) + { +- module_assert_mutex(); + return find_module_all(name, strlen(name), false); + } + +diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c +index 7183572898998..5453af26ff764 100644 +--- a/kernel/trace/trace_kprobe.c ++++ b/kernel/trace/trace_kprobe.c +@@ -124,9 +124,9 @@ static nokprobe_inline bool trace_kprobe_module_exist(struct trace_kprobe *tk) + if (!p) + return true; + *p = '\0'; +- mutex_lock(&module_mutex); ++ rcu_read_lock_sched(); + ret = !!find_module(tk->symbol); +- mutex_unlock(&module_mutex); ++ rcu_read_unlock_sched(); + *p = ':'; + + return ret; +-- +2.43.0 + diff --git a/queue-5.10/namei-introduce-struct-renamedata.patch b/queue-5.10/namei-introduce-struct-renamedata.patch new file mode 100644 index 00000000000..4b9e435ea7c --- /dev/null +++ b/queue-5.10/namei-introduce-struct-renamedata.patch @@ -0,0 +1,196 @@ +From 55a1a5bbf52f2f4a644a5bd129d46fd2fc2e7adc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 Jan 2021 14:19:32 +0100 +Subject: namei: introduce struct renamedata + +From: Christian Brauner + +[ Upstream commit 9fe61450972d3900bffb1dc26a17ebb9cdd92db2 ] + +In order to handle idmapped mounts we will extend the vfs rename helper +to take two new arguments in follow up patches. Since this operations +already takes a bunch of arguments add a simple struct renamedata and +make the current helper use it before we extend it. + +Link: https://lore.kernel.org/r/20210121131959.646623-14-christian.brauner@ubuntu.com +Cc: Christoph Hellwig +Cc: David Howells +Cc: Al Viro +Cc: linux-fsdevel@vger.kernel.org +Reviewed-by: Christoph Hellwig +[ cel: backported to 5.10.y, prior to idmapped mounts ] +Signed-off-by: Christian Brauner +Signed-off-by: Sasha Levin +--- + fs/cachefiles/namei.c | 9 +++++++-- + fs/ecryptfs/inode.c | 10 +++++++--- + fs/namei.c | 21 +++++++++++++++------ + fs/nfsd/vfs.c | 8 +++++++- + fs/overlayfs/overlayfs.h | 9 ++++++++- + include/linux/fs.h | 12 +++++++++++- + 6 files changed, 55 insertions(+), 14 deletions(-) + +diff --git a/fs/cachefiles/namei.c b/fs/cachefiles/namei.c +index ecc8ecbbfa5ac..7b987de0babe8 100644 +--- a/fs/cachefiles/namei.c ++++ b/fs/cachefiles/namei.c +@@ -412,9 +412,14 @@ static int cachefiles_bury_object(struct cachefiles_cache *cache, + if (ret < 0) { + cachefiles_io_error(cache, "Rename security error %d", ret); + } else { ++ struct renamedata rd = { ++ .old_dir = d_inode(dir), ++ .old_dentry = rep, ++ .new_dir = d_inode(cache->graveyard), ++ .new_dentry = grave, ++ }; + trace_cachefiles_rename(object, rep, grave, why); +- ret = vfs_rename(d_inode(dir), rep, +- d_inode(cache->graveyard), grave, NULL, 0); ++ ret = vfs_rename(&rd); + if (ret != 0 && ret != -ENOMEM) + cachefiles_io_error(cache, + "Rename failed with error %d", ret); +diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c +index c867a0d62f360..1dbe0c3ff38ea 100644 +--- a/fs/ecryptfs/inode.c ++++ b/fs/ecryptfs/inode.c +@@ -598,6 +598,7 @@ ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry, + struct dentry *lower_new_dir_dentry; + struct dentry *trap; + struct inode *target_inode; ++ struct renamedata rd = {}; + + if (flags) + return -EINVAL; +@@ -627,9 +628,12 @@ ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry, + rc = -ENOTEMPTY; + goto out_lock; + } +- rc = vfs_rename(d_inode(lower_old_dir_dentry), lower_old_dentry, +- d_inode(lower_new_dir_dentry), lower_new_dentry, +- NULL, 0); ++ ++ rd.old_dir = d_inode(lower_old_dir_dentry); ++ rd.old_dentry = lower_old_dentry; ++ rd.new_dir = d_inode(lower_new_dir_dentry); ++ rd.new_dentry = lower_new_dentry; ++ rc = vfs_rename(&rd); + if (rc) + goto out_lock; + if (target_inode) +diff --git a/fs/namei.c b/fs/namei.c +index cb37d7c477e0b..72521a614514b 100644 +--- a/fs/namei.c ++++ b/fs/namei.c +@@ -4277,11 +4277,14 @@ SYSCALL_DEFINE2(link, const char __user *, oldname, const char __user *, newname + * ->i_mutex on parents, which works but leads to some truly excessive + * locking]. + */ +-int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, +- struct inode *new_dir, struct dentry *new_dentry, +- struct inode **delegated_inode, unsigned int flags) ++int vfs_rename(struct renamedata *rd) + { + int error; ++ struct inode *old_dir = rd->old_dir, *new_dir = rd->new_dir; ++ struct dentry *old_dentry = rd->old_dentry; ++ struct dentry *new_dentry = rd->new_dentry; ++ struct inode **delegated_inode = rd->delegated_inode; ++ unsigned int flags = rd->flags; + bool is_dir = d_is_dir(old_dentry); + struct inode *source = old_dentry->d_inode; + struct inode *target = new_dentry->d_inode; +@@ -4429,6 +4432,7 @@ EXPORT_SYMBOL(vfs_rename); + int do_renameat2(int olddfd, struct filename *from, int newdfd, + struct filename *to, unsigned int flags) + { ++ struct renamedata rd; + struct dentry *old_dentry, *new_dentry; + struct dentry *trap; + struct path old_path, new_path; +@@ -4532,9 +4536,14 @@ int do_renameat2(int olddfd, struct filename *from, int newdfd, + &new_path, new_dentry, flags); + if (error) + goto exit5; +- error = vfs_rename(old_path.dentry->d_inode, old_dentry, +- new_path.dentry->d_inode, new_dentry, +- &delegated_inode, flags); ++ ++ rd.old_dir = old_path.dentry->d_inode; ++ rd.old_dentry = old_dentry; ++ rd.new_dir = new_path.dentry->d_inode; ++ rd.new_dentry = new_dentry; ++ rd.delegated_inode = &delegated_inode; ++ rd.flags = flags; ++ error = vfs_rename(&rd); + exit5: + dput(new_dentry); + exit4: +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index 3e30788e0046b..d12c3e71ca10e 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -1812,7 +1812,13 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, + close_cached = true; + goto out_dput_old; + } else { +- host_err = vfs_rename(fdir, odentry, tdir, ndentry, NULL, 0); ++ struct renamedata rd = { ++ .old_dir = fdir, ++ .old_dentry = odentry, ++ .new_dir = tdir, ++ .new_dentry = ndentry, ++ }; ++ host_err = vfs_rename(&rd); + if (!host_err) { + host_err = commit_metadata(tfhp); + if (!host_err) +diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h +index 26f91868fbdaf..87b7a4a74f4ed 100644 +--- a/fs/overlayfs/overlayfs.h ++++ b/fs/overlayfs/overlayfs.h +@@ -212,9 +212,16 @@ static inline int ovl_do_rename(struct inode *olddir, struct dentry *olddentry, + unsigned int flags) + { + int err; ++ struct renamedata rd = { ++ .old_dir = olddir, ++ .old_dentry = olddentry, ++ .new_dir = newdir, ++ .new_dentry = newdentry, ++ .flags = flags, ++ }; + + pr_debug("rename(%pd2, %pd2, 0x%x)\n", olddentry, newdentry, flags); +- err = vfs_rename(olddir, olddentry, newdir, newdentry, NULL, flags); ++ err = vfs_rename(&rd); + if (err) { + pr_debug("...rename(%pd2, %pd2, ...) = %i\n", + olddentry, newdentry, err); +diff --git a/include/linux/fs.h b/include/linux/fs.h +index 0974e8160f50c..cc3b6ddf58223 100644 +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -1780,7 +1780,17 @@ extern int vfs_symlink(struct inode *, struct dentry *, const char *); + extern int vfs_link(struct dentry *, struct inode *, struct dentry *, struct inode **); + extern int vfs_rmdir(struct inode *, struct dentry *); + extern int vfs_unlink(struct inode *, struct dentry *, struct inode **); +-extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *, struct inode **, unsigned int); ++ ++struct renamedata { ++ struct inode *old_dir; ++ struct dentry *old_dentry; ++ struct inode *new_dir; ++ struct dentry *new_dentry; ++ struct inode **delegated_inode; ++ unsigned int flags; ++} __randomize_layout; ++ ++int vfs_rename(struct renamedata *); + + static inline int vfs_whiteout(struct inode *dir, struct dentry *dentry) + { +-- +2.43.0 + diff --git a/queue-5.10/nfs-add-a-private-local-dispatcher-for-nfsv4-callbac.patch b/queue-5.10/nfs-add-a-private-local-dispatcher-for-nfsv4-callbac.patch new file mode 100644 index 00000000000..2218899c29c --- /dev/null +++ b/queue-5.10/nfs-add-a-private-local-dispatcher-for-nfsv4-callbac.patch @@ -0,0 +1,64 @@ +From 6305b02f35c378de8feddc4ff0a6f85a5580a458 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jul 2021 15:52:25 -0400 +Subject: NFS: Add a private local dispatcher for NFSv4 callback operations + +From: Chuck Lever + +[ Upstream commit 7d34c96217cf3c2d37ca0a56ca0bc3c3bef1e189 ] + +The client's NFSv4 callback service is the only remaining user of +svc_generic_dispatch(). + +Note that the NFSv4 callback service doesn't use the .pc_encode and +.pc_decode callouts in any substantial way, so they are removed. + +Signed-off-by: Chuck Lever +Signed-off-by: Anna Schumaker +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfs/callback_xdr.c | 13 +++++++++++-- + 1 file changed, 11 insertions(+), 2 deletions(-) + +diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c +index 0559e8b6a8ec4..e7d1efd45fa46 100644 +--- a/fs/nfs/callback_xdr.c ++++ b/fs/nfs/callback_xdr.c +@@ -988,6 +988,15 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp) + return rpc_success; + } + ++static int ++nfs_callback_dispatch(struct svc_rqst *rqstp, __be32 *statp) ++{ ++ const struct svc_procedure *procp = rqstp->rq_procinfo; ++ ++ *statp = procp->pc_func(rqstp); ++ return 1; ++} ++ + /* + * Define NFS4 callback COMPOUND ops. + */ +@@ -1076,7 +1085,7 @@ const struct svc_version nfs4_callback_version1 = { + .vs_proc = nfs4_callback_procedures1, + .vs_count = nfs4_callback_count1, + .vs_xdrsize = NFS4_CALLBACK_XDRSIZE, +- .vs_dispatch = NULL, ++ .vs_dispatch = nfs_callback_dispatch, + .vs_hidden = true, + .vs_need_cong_ctrl = true, + }; +@@ -1088,7 +1097,7 @@ const struct svc_version nfs4_callback_version4 = { + .vs_proc = nfs4_callback_procedures1, + .vs_count = nfs4_callback_count4, + .vs_xdrsize = NFS4_CALLBACK_XDRSIZE, +- .vs_dispatch = NULL, ++ .vs_dispatch = nfs_callback_dispatch, + .vs_hidden = true, + .vs_need_cong_ctrl = true, + }; +-- +2.43.0 + diff --git a/queue-5.10/nfs-block-notification-on-fs-with-its-own-lock.patch b/queue-5.10/nfs-block-notification-on-fs-with-its-own-lock.patch new file mode 100644 index 00000000000..abae05edd43 --- /dev/null +++ b/queue-5.10/nfs-block-notification-on-fs-with-its-own-lock.patch @@ -0,0 +1,184 @@ +From 0a3575e340de0dea720b3bed8e5fd122cb3082f4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Dec 2021 12:20:13 -0500 +Subject: nfs: block notification on fs with its own ->lock + +From: J. Bruce Fields + +[ Upstream commit 40595cdc93edf4110c0f0c0b06f8d82008f23929 ] + +NFSv4.1 supports an optional lock notification feature which notifies +the client when a lock comes available. (Normally NFSv4 clients just +poll for locks if necessary.) To make that work, we need to request a +blocking lock from the filesystem. + +We turned that off for NFS in commit f657f8eef3ff ("nfs: don't atempt +blocking locks on nfs reexports") [sic] because it actually blocks the +nfsd thread while waiting for the lock. + +Thanks to Vasily Averin for pointing out that NFS isn't the only +filesystem with that problem. + +Any filesystem that leaves ->lock NULL will use posix_lock_file(), which +does the right thing. Simplest is just to assume that any filesystem +that defines its own ->lock is not safe to request a blocking lock from. + +So, this patch mostly reverts commit f657f8eef3ff ("nfs: don't atempt +blocking locks on nfs reexports") [sic] and commit b840be2f00c0 ("lockd: +don't attempt blocking locks on nfs reexports"), and instead uses a +check of ->lock (Vasily's suggestion) to decide whether to support +blocking lock notifications on a given filesystem. Also add a little +documentation. + +Perhaps someday we could add back an export flag later to allow +filesystems with "good" ->lock methods to support blocking lock +notifications. + +Reported-by: Vasily Averin +Signed-off-by: J. Bruce Fields +[ cel: Description rewritten to address checkpatch nits ] +[ cel: Fixed warning when SUNRPC debugging is disabled ] +[ cel: Fixed NULL check ] +Signed-off-by: Chuck Lever +Reviewed-by: Vasily Averin +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/svclock.c | 6 ++++-- + fs/nfs/export.c | 2 +- + fs/nfsd/nfs4state.c | 18 ++++++++++++------ + include/linux/exportfs.h | 2 -- + include/linux/lockd/lockd.h | 9 +++++++-- + 5 files changed, 24 insertions(+), 13 deletions(-) + +diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c +index e9b85d8fd5fe7..cb3658ab9b7ae 100644 +--- a/fs/lockd/svclock.c ++++ b/fs/lockd/svclock.c +@@ -470,8 +470,10 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, + struct nlm_host *host, struct nlm_lock *lock, int wait, + struct nlm_cookie *cookie, int reclaim) + { +- struct nlm_block *block = NULL; ++#if IS_ENABLED(CONFIG_SUNRPC_DEBUG) + struct inode *inode = nlmsvc_file_inode(file); ++#endif ++ struct nlm_block *block = NULL; + int error; + int mode; + int async_block = 0; +@@ -484,7 +486,7 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, + (long long)lock->fl.fl_end, + wait); + +- if (inode->i_sb->s_export_op->flags & EXPORT_OP_SYNC_LOCKS) { ++ if (nlmsvc_file_file(file)->f_op->lock) { + async_block = wait; + wait = 0; + } +diff --git a/fs/nfs/export.c b/fs/nfs/export.c +index 40beac65d1355..b347e3ce0cc8e 100644 +--- a/fs/nfs/export.c ++++ b/fs/nfs/export.c +@@ -184,5 +184,5 @@ const struct export_operations nfs_export_ops = { + .fetch_iversion = nfs_fetch_iversion, + .flags = EXPORT_OP_NOWCC|EXPORT_OP_NOSUBTREECHK| + EXPORT_OP_CLOSE_BEFORE_UNLINK|EXPORT_OP_REMOTE_FS| +- EXPORT_OP_NOATOMIC_ATTR|EXPORT_OP_SYNC_LOCKS, ++ EXPORT_OP_NOATOMIC_ATTR, + }; +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 3b8c5f2283975..36ae55fbfbc67 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -6884,7 +6884,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + struct nfsd4_blocked_lock *nbl = NULL; + struct file_lock *file_lock = NULL; + struct file_lock *conflock = NULL; +- struct super_block *sb; + __be32 status = 0; + int lkflg; + int err; +@@ -6906,7 +6905,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + dprintk("NFSD: nfsd4_lock: permission denied!\n"); + return status; + } +- sb = cstate->current_fh.fh_dentry->d_sb; + + if (lock->lk_is_new) { + if (nfsd4_has_session(cstate)) +@@ -6958,8 +6956,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + fp = lock_stp->st_stid.sc_file; + switch (lock->lk_type) { + case NFS4_READW_LT: +- if (nfsd4_has_session(cstate) && +- !(sb->s_export_op->flags & EXPORT_OP_SYNC_LOCKS)) ++ if (nfsd4_has_session(cstate)) + fl_flags |= FL_SLEEP; + fallthrough; + case NFS4_READ_LT: +@@ -6971,8 +6968,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + fl_type = F_RDLCK; + break; + case NFS4_WRITEW_LT: +- if (nfsd4_has_session(cstate) && +- !(sb->s_export_op->flags & EXPORT_OP_SYNC_LOCKS)) ++ if (nfsd4_has_session(cstate)) + fl_flags |= FL_SLEEP; + fallthrough; + case NFS4_WRITE_LT: +@@ -6993,6 +6989,16 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + goto out; + } + ++ /* ++ * Most filesystems with their own ->lock operations will block ++ * the nfsd thread waiting to acquire the lock. That leads to ++ * deadlocks (we don't want every nfsd thread tied up waiting ++ * for file locks), so don't attempt blocking lock notifications ++ * on those filesystems: ++ */ ++ if (nf->nf_file->f_op->lock) ++ fl_flags &= ~FL_SLEEP; ++ + nbl = find_or_allocate_block(lock_sop, &fp->fi_fhandle, nn); + if (!nbl) { + dprintk("NFSD: %s: unable to allocate block!\n", __func__); +diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h +index 3260fe7148462..fe848901fcc3a 100644 +--- a/include/linux/exportfs.h ++++ b/include/linux/exportfs.h +@@ -221,8 +221,6 @@ struct export_operations { + #define EXPORT_OP_NOATOMIC_ATTR (0x10) /* Filesystem cannot supply + atomic attribute updates + */ +-#define EXPORT_OP_SYNC_LOCKS (0x20) /* Filesystem can't do +- asychronous blocking locks */ + unsigned long flags; + }; + +diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h +index c4ae6506b8b36..fcef192e5e45e 100644 +--- a/include/linux/lockd/lockd.h ++++ b/include/linux/lockd/lockd.h +@@ -303,10 +303,15 @@ void nlmsvc_invalidate_all(void); + int nlmsvc_unlock_all_by_sb(struct super_block *sb); + int nlmsvc_unlock_all_by_ip(struct sockaddr *server_addr); + ++static inline struct file *nlmsvc_file_file(struct nlm_file *file) ++{ ++ return file->f_file[O_RDONLY] ? ++ file->f_file[O_RDONLY] : file->f_file[O_WRONLY]; ++} ++ + static inline struct inode *nlmsvc_file_inode(struct nlm_file *file) + { +- return locks_inode(file->f_file[O_RDONLY] ? +- file->f_file[O_RDONLY] : file->f_file[O_WRONLY]); ++ return locks_inode(nlmsvc_file_file(file)); + } + + static inline int __nlm_privileged_request4(const struct sockaddr *sap) +-- +2.43.0 + diff --git a/queue-5.10/nfs-don-t-allow-reexport-reclaims.patch b/queue-5.10/nfs-don-t-allow-reexport-reclaims.patch new file mode 100644 index 00000000000..ef86591c838 --- /dev/null +++ b/queue-5.10/nfs-don-t-allow-reexport-reclaims.patch @@ -0,0 +1,99 @@ +From b012c492a25db8ab031497c0da3ef1341f142285 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Aug 2021 17:02:06 -0400 +Subject: nfs: don't allow reexport reclaims + +From: J. Bruce Fields + +[ Upstream commit bb0a55bb7148a49e549ee992200860e7a040d3a5 ] + +In the reexport case, nfsd is currently passing along locks with the +reclaim bit set. The client sends a new lock request, which is granted +if there's currently no conflict--even if it's possible a conflicting +lock could have been briefly held in the interim. + +We don't currently have any way to safely grant reclaim, so for now +let's just deny them all. + +I'm doing this by passing the reclaim bit to nfs and letting it fail the +call, with the idea that eventually the client might be able to do +something more forgiving here. + +Signed-off-by: J. Bruce Fields +Acked-by: Anna Schumaker +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfs/file.c | 3 +++ + fs/nfsd/nfs4state.c | 3 +++ + fs/nfsd/nfsproc.c | 1 + + include/linux/errno.h | 1 + + include/linux/fs.h | 1 + + 5 files changed, 9 insertions(+) + +diff --git a/fs/nfs/file.c b/fs/nfs/file.c +index 7be1a7f7fcb2a..d35aae47b062b 100644 +--- a/fs/nfs/file.c ++++ b/fs/nfs/file.c +@@ -798,6 +798,9 @@ int nfs_lock(struct file *filp, int cmd, struct file_lock *fl) + + nfs_inc_stats(inode, NFSIOS_VFSLOCK); + ++ if (fl->fl_flags & FL_RECLAIM) ++ return -ENOGRACE; ++ + /* No mandatory locks over NFS */ + if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK) + goto out_err; +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index fd3bdf0bf0052..e9ac77c28741e 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -6946,6 +6946,9 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + if (!locks_in_grace(net) && lock->lk_reclaim) + goto out; + ++ if (lock->lk_reclaim) ++ fl_flags |= FL_RECLAIM; ++ + fp = lock_stp->st_stid.sc_file; + switch (lock->lk_type) { + case NFS4_READW_LT: +diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c +index 72f8bc4a7ea48..78bdfdc253fd3 100644 +--- a/fs/nfsd/nfsproc.c ++++ b/fs/nfsd/nfsproc.c +@@ -881,6 +881,7 @@ nfserrno (int errno) + { nfserr_serverfault, -ENFILE }, + { nfserr_io, -EUCLEAN }, + { nfserr_perm, -ENOKEY }, ++ { nfserr_no_grace, -ENOGRACE}, + }; + int i; + +diff --git a/include/linux/errno.h b/include/linux/errno.h +index d73f597a24849..8b0c754bab025 100644 +--- a/include/linux/errno.h ++++ b/include/linux/errno.h +@@ -31,5 +31,6 @@ + #define EJUKEBOX 528 /* Request initiated, but will not complete before timeout */ + #define EIOCBQUEUED 529 /* iocb queued, will get completion event */ + #define ERECALLCONFLICT 530 /* conflict with recalled state */ ++#define ENOGRACE 531 /* NFS file lock reclaim refused */ + + #endif +diff --git a/include/linux/fs.h b/include/linux/fs.h +index a9ac60d3be1d6..c0459446e1440 100644 +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -996,6 +996,7 @@ static inline struct file *get_file(struct file *f) + #define FL_UNLOCK_PENDING 512 /* Lease is being broken */ + #define FL_OFDLCK 1024 /* lock is "owned" by struct file */ + #define FL_LAYOUT 2048 /* outstanding pNFS layout */ ++#define FL_RECLAIM 4096 /* reclaiming from a reboot server */ + + #define FL_CLOSE_POSIX (FL_POSIX | FL_CLOSE) + +-- +2.43.0 + diff --git a/queue-5.10/nfs-don-t-atempt-blocking-locks-on-nfs-reexports.patch b/queue-5.10/nfs-don-t-atempt-blocking-locks-on-nfs-reexports.patch new file mode 100644 index 00000000000..db3848a9532 --- /dev/null +++ b/queue-5.10/nfs-don-t-atempt-blocking-locks-on-nfs-reexports.patch @@ -0,0 +1,98 @@ +From 1f46d71fc8731c28978641a0a96a0bb62d194dd6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Aug 2021 17:02:04 -0400 +Subject: nfs: don't atempt blocking locks on nfs reexports + +From: J. Bruce Fields + +[ Upstream commit f657f8eef3ff870552c9fd2839e0061046f44618 ] + +NFS implements blocking locks by blocking inside its lock method. In +the reexport case, this blocks the nfs server thread, which could lead +to deadlocks since an nfs server thread might be required to unlock the +conflicting lock. It also causes a crash, since the nfs server thread +assumes it can free the lock when its lm_notify lock callback is called. + +Ideal would be to make the nfs lock method return without blocking in +this case, but for now it works just not to attempt blocking locks. The +difference is just that the original client will have to poll (as it +does in the v4.0 case) instead of getting a callback when the lock's +available. + +Signed-off-by: J. Bruce Fields +Acked-by: Anna Schumaker +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfs/export.c | 2 +- + fs/nfsd/nfs4state.c | 8 ++++++-- + include/linux/exportfs.h | 2 ++ + 3 files changed, 9 insertions(+), 3 deletions(-) + +diff --git a/fs/nfs/export.c b/fs/nfs/export.c +index b347e3ce0cc8e..40beac65d1355 100644 +--- a/fs/nfs/export.c ++++ b/fs/nfs/export.c +@@ -184,5 +184,5 @@ const struct export_operations nfs_export_ops = { + .fetch_iversion = nfs_fetch_iversion, + .flags = EXPORT_OP_NOWCC|EXPORT_OP_NOSUBTREECHK| + EXPORT_OP_CLOSE_BEFORE_UNLINK|EXPORT_OP_REMOTE_FS| +- EXPORT_OP_NOATOMIC_ATTR, ++ EXPORT_OP_NOATOMIC_ATTR|EXPORT_OP_SYNC_LOCKS, + }; +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 401f0f2743717..fd3bdf0bf0052 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -6878,6 +6878,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + struct nfsd4_blocked_lock *nbl = NULL; + struct file_lock *file_lock = NULL; + struct file_lock *conflock = NULL; ++ struct super_block *sb; + __be32 status = 0; + int lkflg; + int err; +@@ -6899,6 +6900,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + dprintk("NFSD: nfsd4_lock: permission denied!\n"); + return status; + } ++ sb = cstate->current_fh.fh_dentry->d_sb; + + if (lock->lk_is_new) { + if (nfsd4_has_session(cstate)) +@@ -6947,7 +6949,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + fp = lock_stp->st_stid.sc_file; + switch (lock->lk_type) { + case NFS4_READW_LT: +- if (nfsd4_has_session(cstate)) ++ if (nfsd4_has_session(cstate) && ++ !(sb->s_export_op->flags & EXPORT_OP_SYNC_LOCKS)) + fl_flags |= FL_SLEEP; + fallthrough; + case NFS4_READ_LT: +@@ -6959,7 +6962,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + fl_type = F_RDLCK; + break; + case NFS4_WRITEW_LT: +- if (nfsd4_has_session(cstate)) ++ if (nfsd4_has_session(cstate) && ++ !(sb->s_export_op->flags & EXPORT_OP_SYNC_LOCKS)) + fl_flags |= FL_SLEEP; + fallthrough; + case NFS4_WRITE_LT: +diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h +index fe848901fcc3a..3260fe7148462 100644 +--- a/include/linux/exportfs.h ++++ b/include/linux/exportfs.h +@@ -221,6 +221,8 @@ struct export_operations { + #define EXPORT_OP_NOATOMIC_ATTR (0x10) /* Filesystem cannot supply + atomic attribute updates + */ ++#define EXPORT_OP_SYNC_LOCKS (0x20) /* Filesystem can't do ++ asychronous blocking locks */ + unsigned long flags; + }; + +-- +2.43.0 + diff --git a/queue-5.10/nfs-fix-nfs_fetch_iversion.patch b/queue-5.10/nfs-fix-nfs_fetch_iversion.patch new file mode 100644 index 00000000000..964d2fc46ea --- /dev/null +++ b/queue-5.10/nfs-fix-nfs_fetch_iversion.patch @@ -0,0 +1,49 @@ +From 93c843c093f4a2a3385e19e18e733a469a0439e1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 24 Mar 2021 15:32:21 -0400 +Subject: NFS: fix nfs_fetch_iversion() + +From: Trond Myklebust + +[ Upstream commit b876d708316bf9b6b9678eb2beb289b93cfe6369 ] + +The change attribute is always set by all NFS client versions so get rid +of the open-coded version. + +Fixes: 3cc55f4434b4 ("nfs: use change attribute for NFS re-exports") +Signed-off-by: Trond Myklebust +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfs/export.c | 15 ++++----------- + 1 file changed, 4 insertions(+), 11 deletions(-) + +diff --git a/fs/nfs/export.c b/fs/nfs/export.c +index f2b34cfe286c2..b347e3ce0cc8e 100644 +--- a/fs/nfs/export.c ++++ b/fs/nfs/export.c +@@ -171,17 +171,10 @@ static u64 nfs_fetch_iversion(struct inode *inode) + { + struct nfs_server *server = NFS_SERVER(inode); + +- /* Is this the right call?: */ +- nfs_revalidate_inode(server, inode); +- /* +- * Also, note we're ignoring any returned error. That seems to be +- * the practice for cache consistency information elsewhere in +- * the server, but I'm not sure why. +- */ +- if (server->nfs_client->rpc_ops->version >= 4) +- return inode_peek_iversion_raw(inode); +- else +- return time_to_chattr(&inode->i_ctime); ++ if (nfs_check_cache_invalid(inode, NFS_INO_INVALID_CHANGE | ++ NFS_INO_REVAL_PAGECACHE)) ++ __nfs_revalidate_inode(server, inode); ++ return inode_peek_iversion_raw(inode); + } + + const struct export_operations nfs_export_ops = { +-- +2.43.0 + diff --git a/queue-5.10/nfs-remove-unused-callback-void-decoder.patch b/queue-5.10/nfs-remove-unused-callback-void-decoder.patch new file mode 100644 index 00000000000..7e2cded741c --- /dev/null +++ b/queue-5.10/nfs-remove-unused-callback-void-decoder.patch @@ -0,0 +1,52 @@ +From 243fd94e96fcfd44833269849d0625c0eb89662b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jul 2021 15:52:31 -0400 +Subject: NFS: Remove unused callback void decoder + +From: Chuck Lever + +[ Upstream commit c35a810ce59524971c4a3b45faed4d0121e5a305 ] + +Clean up: The callback RPC dispatcher no longer invokes these call +outs, although svc_process_common() relies on seeing a .pc_encode +function. + +Signed-off-by: Chuck Lever +Signed-off-by: Anna Schumaker +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfs/callback_xdr.c | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) + +diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c +index e7d1efd45fa46..600e640682401 100644 +--- a/fs/nfs/callback_xdr.c ++++ b/fs/nfs/callback_xdr.c +@@ -63,11 +63,10 @@ static __be32 nfs4_callback_null(struct svc_rqst *rqstp) + return htonl(NFS4_OK); + } + +-static int nfs4_decode_void(struct svc_rqst *rqstp, __be32 *p) +-{ +- return xdr_argsize_check(rqstp, p); +-} +- ++/* ++ * svc_process_common() looks for an XDR encoder to know when ++ * not to drop a Reply. ++ */ + static int nfs4_encode_void(struct svc_rqst *rqstp, __be32 *p) + { + return xdr_ressize_check(rqstp, p); +@@ -1063,7 +1062,6 @@ static struct callback_op callback_ops[] = { + static const struct svc_procedure nfs4_callback_procedures1[] = { + [CB_NULL] = { + .pc_func = nfs4_callback_null, +- .pc_decode = nfs4_decode_void, + .pc_encode = nfs4_encode_void, + .pc_xdrressize = 1, + .pc_name = "NULL", +-- +2.43.0 + diff --git a/queue-5.10/nfs-restore-module-put-when-manager-exits.patch b/queue-5.10/nfs-restore-module-put-when-manager-exits.patch new file mode 100644 index 00000000000..830e8754af9 --- /dev/null +++ b/queue-5.10/nfs-restore-module-put-when-manager-exits.patch @@ -0,0 +1,46 @@ +From 8348c644bb201097bb9e9cdc39d488eeb4c87531 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Jun 2022 14:47:34 +1000 +Subject: NFS: restore module put when manager exits. + +From: NeilBrown + +[ Upstream commit 080abad71e99d2becf38c978572982130b927a28 ] + +Commit f49169c97fce ("NFSD: Remove svc_serv_ops::svo_module") removed +calls to module_put_and_kthread_exit() from threads that acted as SUNRPC +servers and had a related svc_serv_ops structure. This was correct. + +It ALSO removed the module_put_and_kthread_exit() call from +nfs4_run_state_manager() which is NOT a SUNRPC service. + +Consequently every time the NFSv4 state manager runs the module count +increments and won't be decremented. So the nfsv4 module cannot be +unloaded. + +So restore the module_put_and_kthread_exit() call. + +Fixes: f49169c97fce ("NFSD: Remove svc_serv_ops::svo_module") +Signed-off-by: NeilBrown +Signed-off-by: Anna Schumaker +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfs/nfs4state.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c +index ae2da65ffbafb..d8fc5d72a161c 100644 +--- a/fs/nfs/nfs4state.c ++++ b/fs/nfs/nfs4state.c +@@ -2757,6 +2757,7 @@ static int nfs4_run_state_manager(void *ptr) + goto again; + + nfs_put_client(clp); ++ module_put_and_kthread_exit(0); + return 0; + } + +-- +2.43.0 + diff --git a/queue-5.10/nfs-switch-the-callback-service-back-to-non-pooled.patch b/queue-5.10/nfs-switch-the-callback-service-back-to-non-pooled.patch new file mode 100644 index 00000000000..abb228309f2 --- /dev/null +++ b/queue-5.10/nfs-switch-the-callback-service-back-to-non-pooled.patch @@ -0,0 +1,40 @@ +From 6b02922bc0e6efac9cba78dedddcdbc537980ad2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Nov 2021 15:51:25 +1100 +Subject: NFS: switch the callback service back to non-pooled. + +From: NeilBrown + +[ Upstream commit 23a1a573c61ccb5e7829c1f5472d3e025293a031 ] + +Now that thread management is consistent there is no need for +nfs-callback to use svc_create_pooled() as introduced in Commit +df807fffaabd ("NFSv4.x/callback: Create the callback service through +svc_create_pooled"). So switch back to svc_create(). + +If service pools were configured, but the number of threads were left at +'1', nfs callback may not work reliably when svc_create_pooled() is used. + +Signed-off-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfs/callback.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c +index 422055a1092f0..054cc1255fac6 100644 +--- a/fs/nfs/callback.c ++++ b/fs/nfs/callback.c +@@ -286,7 +286,7 @@ static struct svc_serv *nfs_callback_create_svc(int minorversion) + printk(KERN_WARNING "nfs_callback_create_svc: no kthread, %d users??\n", + cb_info->users); + +- serv = svc_create_pooled(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, sv_ops); ++ serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, sv_ops); + if (!serv) { + printk(KERN_ERR "nfs_callback_create_svc: create service failed\n"); + return ERR_PTR(-ENOMEM); +-- +2.43.0 + diff --git a/queue-5.10/nfs-use-change-attribute-for-nfs-re-exports.patch b/queue-5.10/nfs-use-change-attribute-for-nfs-re-exports.patch new file mode 100644 index 00000000000..c2a52abc6c6 --- /dev/null +++ b/queue-5.10/nfs-use-change-attribute-for-nfs-re-exports.patch @@ -0,0 +1,101 @@ +From 5d0337d52981d9d5c0ecd7171dec9be30c777303 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 Jan 2021 14:26:29 -0500 +Subject: nfs: use change attribute for NFS re-exports + +From: J. Bruce Fields + +[ Upstream commit 3cc55f4434b421d37300aa9a167ace7d60b45ccf ] + +When exporting NFS, we may as well use the real change attribute +returned by the original server instead of faking up a change attribute +from the ctime. + +Note we can't do that by setting I_VERSION--that would also turn on the +logic in iversion.h which treats the lower bit specially, and that +doesn't make sense for NFS. + +So instead we define a new export operation for filesystems like NFS +that want to manage the change attribute themselves. + +Signed-off-by: J. Bruce Fields +Reviewed-by: Christoph Hellwig +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfs/export.c | 18 ++++++++++++++++++ + fs/nfsd/nfsfh.h | 5 ++++- + include/linux/exportfs.h | 1 + + 3 files changed, 23 insertions(+), 1 deletion(-) + +diff --git a/fs/nfs/export.c b/fs/nfs/export.c +index 7412bb164fa77..f2b34cfe286c2 100644 +--- a/fs/nfs/export.c ++++ b/fs/nfs/export.c +@@ -167,10 +167,28 @@ nfs_get_parent(struct dentry *dentry) + return parent; + } + ++static u64 nfs_fetch_iversion(struct inode *inode) ++{ ++ struct nfs_server *server = NFS_SERVER(inode); ++ ++ /* Is this the right call?: */ ++ nfs_revalidate_inode(server, inode); ++ /* ++ * Also, note we're ignoring any returned error. That seems to be ++ * the practice for cache consistency information elsewhere in ++ * the server, but I'm not sure why. ++ */ ++ if (server->nfs_client->rpc_ops->version >= 4) ++ return inode_peek_iversion_raw(inode); ++ else ++ return time_to_chattr(&inode->i_ctime); ++} ++ + const struct export_operations nfs_export_ops = { + .encode_fh = nfs_encode_fh, + .fh_to_dentry = nfs_fh_to_dentry, + .get_parent = nfs_get_parent, ++ .fetch_iversion = nfs_fetch_iversion, + .flags = EXPORT_OP_NOWCC|EXPORT_OP_NOSUBTREECHK| + EXPORT_OP_CLOSE_BEFORE_UNLINK|EXPORT_OP_REMOTE_FS| + EXPORT_OP_NOATOMIC_ATTR, +diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h +index cb20c2cd34695..f58933519f380 100644 +--- a/fs/nfsd/nfsfh.h ++++ b/fs/nfsd/nfsfh.h +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + + static inline __u32 ino_t_to_u32(ino_t ino) + { +@@ -264,7 +265,9 @@ fh_clear_wcc(struct svc_fh *fhp) + static inline u64 nfsd4_change_attribute(struct kstat *stat, + struct inode *inode) + { +- if (IS_I_VERSION(inode)) { ++ if (inode->i_sb->s_export_op->fetch_iversion) ++ return inode->i_sb->s_export_op->fetch_iversion(inode); ++ else if (IS_I_VERSION(inode)) { + u64 chattr; + + chattr = stat->ctime.tv_sec; +diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h +index 9f4d4bcbf251d..fe848901fcc3a 100644 +--- a/include/linux/exportfs.h ++++ b/include/linux/exportfs.h +@@ -213,6 +213,7 @@ struct export_operations { + bool write, u32 *device_generation); + int (*commit_blocks)(struct inode *inode, struct iomap *iomaps, + int nr_iomaps, struct iattr *iattr); ++ u64 (*fetch_iversion)(struct inode *); + #define EXPORT_OP_NOWCC (0x1) /* don't collect v3 wcc data */ + #define EXPORT_OP_NOSUBTREECHK (0x2) /* no subtree checking */ + #define EXPORT_OP_CLOSE_BEFORE_UNLINK (0x4) /* close files before unlink */ +-- +2.43.0 + diff --git a/queue-5.10/nfsd-a-semicolon-is-not-needed-after-a-switch-statem.patch b/queue-5.10/nfsd-a-semicolon-is-not-needed-after-a-switch-statem.patch new file mode 100644 index 00000000000..db9cc10d515 --- /dev/null +++ b/queue-5.10/nfsd-a-semicolon-is-not-needed-after-a-switch-statem.patch @@ -0,0 +1,32 @@ +From e5b2440600972f029bb7dc7262519d54773e2e2b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 1 Nov 2020 07:32:34 -0800 +Subject: NFSD: A semicolon is not needed after a switch statement. + +From: Tom Rix + +[ Upstream commit 25fef48bdbe7cac5ba5577eab6a750e1caea43bc ] + +Signed-off-by: Tom Rix +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 4b3344296ed0e..fd9107332a20f 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -2558,7 +2558,7 @@ static u32 nfs4_file_type(umode_t mode) + case S_IFREG: return NF4REG; + case S_IFSOCK: return NF4SOCK; + default: return NF4BAD; +- }; ++ } + } + + static inline __be32 +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-a-couple-more-nfsd_clid_expired-call-sites.patch b/queue-5.10/nfsd-add-a-couple-more-nfsd_clid_expired-call-sites.patch new file mode 100644 index 00000000000..c93585ede2e --- /dev/null +++ b/queue-5.10/nfsd-add-a-couple-more-nfsd_clid_expired-call-sites.patch @@ -0,0 +1,87 @@ +From 5c714cd3fd04f0983208837d7e7a1a6077b700ef Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 14 May 2021 15:56:06 -0400 +Subject: NFSD: Add a couple more nfsd_clid_expired call sites + +From: Chuck Lever + +[ Upstream commit 2958d2ee71021b6c44212ec6c2a39cc71d9cd4a9 ] + +Improve observation of NFSv4 lease expiry. + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +[ cel: adjusted to apply to v5.10.y ] +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 9 ++++++--- + fs/nfsd/trace.h | 3 ++- + 2 files changed, 8 insertions(+), 4 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 6f04a84f76c0e..7e8752f4affda 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -2687,6 +2687,8 @@ static void force_expire_client(struct nfs4_client *clp) + struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); + bool already_expired; + ++ trace_nfsd_clid_admin_expired(&clp->cl_clientid); ++ + spin_lock(&nn->client_lock); + clp->cl_time = 0; + spin_unlock(&nn->client_lock); +@@ -3233,6 +3235,7 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + status = mark_client_expired_locked(conf); + if (status) + goto out; ++ trace_nfsd_clid_replaced(&conf->cl_clientid); + } + new->cl_minorversion = cstate->minorversion; + new->cl_spo_must_allow.u.words[0] = exid->spo_must_allow[0]; +@@ -3472,6 +3475,7 @@ nfsd4_create_session(struct svc_rqst *rqstp, + old = NULL; + goto out_free_conn; + } ++ trace_nfsd_clid_replaced(&old->cl_clientid); + } + move_to_confirmed(unconf); + conf = unconf; +@@ -4112,6 +4116,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, + old = NULL; + goto out; + } ++ trace_nfsd_clid_replaced(&old->cl_clientid); + } + move_to_confirmed(unconf); + conf = unconf; +@@ -5550,10 +5555,8 @@ nfs4_laundromat(struct nfsd_net *nn) + clp = list_entry(pos, struct nfs4_client, cl_lru); + if (!state_expired(<, clp->cl_time)) + break; +- if (mark_client_expired_locked(clp)) { +- trace_nfsd_clid_expired(&clp->cl_clientid); ++ if (mark_client_expired_locked(clp)) + continue; +- } + list_add(&clp->cl_lru, &reaplist); + } + spin_unlock(&nn->client_lock); +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index 3aca6dcba90a5..3271d925abf2e 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -514,7 +514,8 @@ DEFINE_EVENT(nfsd_clientid_class, nfsd_clid_##name, \ + DEFINE_CLIENTID_EVENT(reclaim_complete); + DEFINE_CLIENTID_EVENT(confirmed); + DEFINE_CLIENTID_EVENT(destroyed); +-DEFINE_CLIENTID_EVENT(expired); ++DEFINE_CLIENTID_EVENT(admin_expired); ++DEFINE_CLIENTID_EVENT(replaced); + DEFINE_CLIENTID_EVENT(purged); + DEFINE_CLIENTID_EVENT(renew); + DEFINE_CLIENTID_EVENT(stale); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-a-helper-that-encodes-nfsv3-directory-offse.patch b/queue-5.10/nfsd-add-a-helper-that-encodes-nfsv3-directory-offse.patch new file mode 100644 index 00000000000..84643f50c62 --- /dev/null +++ b/queue-5.10/nfsd-add-a-helper-that-encodes-nfsv3-directory-offse.patch @@ -0,0 +1,132 @@ +From c41a6774cf9b62d3f8c0eae4edc1842a97160e77 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Nov 2020 09:57:14 -0500 +Subject: NFSD: Add a helper that encodes NFSv3 directory offset cookies + +From: Chuck Lever + +[ Upstream commit a161e6c76aeba835e475a2f27dbbe5c37e565e94 ] + +Refactor: De-duplicate identical code that handles encoding of +directory offset cookies across page boundaries. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3proc.c | 24 ++---------------------- + fs/nfsd/nfs3xdr.c | 36 +++++++++++++++++++++++------------- + fs/nfsd/xdr3.h | 2 ++ + 3 files changed, 27 insertions(+), 35 deletions(-) + +diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c +index 201f2009b540b..acb0a2d37dcbb 100644 +--- a/fs/nfsd/nfs3proc.c ++++ b/fs/nfsd/nfs3proc.c +@@ -500,17 +500,7 @@ nfsd3_proc_readdir(struct svc_rqst *rqstp) + count += PAGE_SIZE; + } + resp->count = count >> 2; +- if (resp->offset) { +- if (unlikely(resp->offset1)) { +- /* we ended up with offset on a page boundary */ +- *resp->offset = htonl(offset >> 32); +- *resp->offset1 = htonl(offset & 0xffffffff); +- resp->offset1 = NULL; +- } else { +- xdr_encode_hyper(resp->offset, offset); +- } +- resp->offset = NULL; +- } ++ nfs3svc_encode_cookie3(resp, offset); + + return rpc_success; + } +@@ -565,17 +555,7 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp) + count += PAGE_SIZE; + } + resp->count = count >> 2; +- if (resp->offset) { +- if (unlikely(resp->offset1)) { +- /* we ended up with offset on a page boundary */ +- *resp->offset = htonl(offset >> 32); +- *resp->offset1 = htonl(offset & 0xffffffff); +- resp->offset1 = NULL; +- } else { +- xdr_encode_hyper(resp->offset, offset); +- } +- resp->offset = NULL; +- } ++ nfs3svc_encode_cookie3(resp, offset); + + out: + return rpc_success; +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index eab14b52db202..e334a1454edbb 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -1219,6 +1219,28 @@ static __be32 *encode_entryplus_baggage(struct nfsd3_readdirres *cd, __be32 *p, + return p; + } + ++/** ++ * nfs3svc_encode_cookie3 - Encode a directory offset cookie ++ * @resp: readdir result context ++ * @offset: offset cookie to encode ++ * ++ */ ++void nfs3svc_encode_cookie3(struct nfsd3_readdirres *resp, u64 offset) ++{ ++ if (!resp->offset) ++ return; ++ ++ if (resp->offset1) { ++ /* we ended up with offset on a page boundary */ ++ *resp->offset = cpu_to_be32(offset >> 32); ++ *resp->offset1 = cpu_to_be32(offset & 0xffffffff); ++ resp->offset1 = NULL; ++ } else { ++ xdr_encode_hyper(resp->offset, offset); ++ } ++ resp->offset = NULL; ++} ++ + /* + * Encode a directory entry. This one works for both normal readdir + * and readdirplus. +@@ -1244,19 +1266,7 @@ encode_entry(struct readdir_cd *ccd, const char *name, int namlen, + int elen; /* estimated entry length in words */ + int num_entry_words = 0; /* actual number of words */ + +- if (cd->offset) { +- u64 offset64 = offset; +- +- if (unlikely(cd->offset1)) { +- /* we ended up with offset on a page boundary */ +- *cd->offset = htonl(offset64 >> 32); +- *cd->offset1 = htonl(offset64 & 0xffffffff); +- cd->offset1 = NULL; +- } else { +- xdr_encode_hyper(cd->offset, offset64); +- } +- cd->offset = NULL; +- } ++ nfs3svc_encode_cookie3(cd, offset); + + /* + dprintk("encode_entry(%.*s @%ld%s)\n", +diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h +index 8073350418ae0..e76e9230827e4 100644 +--- a/fs/nfsd/xdr3.h ++++ b/fs/nfsd/xdr3.h +@@ -300,6 +300,8 @@ int nfs3svc_encode_commitres(struct svc_rqst *, __be32 *); + + void nfs3svc_release_fhandle(struct svc_rqst *); + void nfs3svc_release_fhandle2(struct svc_rqst *); ++ ++void nfs3svc_encode_cookie3(struct nfsd3_readdirres *resp, u64 offset); + int nfs3svc_encode_entry(void *, const char *name, + int namlen, loff_t offset, u64 ino, + unsigned int); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-a-helper-that-encodes-nfsv3-directory-offse.patch-18644 b/queue-5.10/nfsd-add-a-helper-that-encodes-nfsv3-directory-offse.patch-18644 new file mode 100644 index 00000000000..58cad743ff1 --- /dev/null +++ b/queue-5.10/nfsd-add-a-helper-that-encodes-nfsv3-directory-offse.patch-18644 @@ -0,0 +1,84 @@ +From 91240b794bdf578894a7daae9ab7fe23f0d849e3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Nov 2020 16:53:17 -0500 +Subject: NFSD: Add a helper that encodes NFSv3 directory offset cookies + +From: Chuck Lever + +[ Upstream commit d52532002ffa217ad3fa4c3ba86c95203d21dd21 ] + +Refactor: Add helper function similar to nfs3svc_encode_cookie3(). + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsproc.c | 3 +-- + fs/nfsd/nfsxdr.c | 18 ++++++++++++++++-- + fs/nfsd/xdr.h | 1 + + 3 files changed, 18 insertions(+), 4 deletions(-) + +diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c +index 1fd91e00b97ba..2d3d7cdffd52f 100644 +--- a/fs/nfsd/nfsproc.c ++++ b/fs/nfsd/nfsproc.c +@@ -595,8 +595,7 @@ nfsd_proc_readdir(struct svc_rqst *rqstp) + &resp->common, nfssvc_encode_entry); + + resp->count = resp->buffer - buffer; +- if (resp->offset) +- *resp->offset = htonl(offset); ++ nfssvc_encode_nfscookie(resp, offset); + + fh_put(&argp->fh); + return rpc_success; +diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c +index 39d296aecd3e7..a87b21cfe0d03 100644 +--- a/fs/nfsd/nfsxdr.c ++++ b/fs/nfsd/nfsxdr.c +@@ -614,6 +614,21 @@ nfssvc_encode_statfsres(struct svc_rqst *rqstp, __be32 *p) + return 1; + } + ++/** ++ * nfssvc_encode_nfscookie - Encode a directory offset cookie ++ * @resp: readdir result context ++ * @offset: offset cookie to encode ++ * ++ */ ++void nfssvc_encode_nfscookie(struct nfsd_readdirres *resp, u32 offset) ++{ ++ if (!resp->offset) ++ return; ++ ++ *resp->offset = cpu_to_be32(offset); ++ resp->offset = NULL; ++} ++ + int + nfssvc_encode_entry(void *ccdv, const char *name, + int namlen, loff_t offset, u64 ino, unsigned int d_type) +@@ -632,8 +647,7 @@ nfssvc_encode_entry(void *ccdv, const char *name, + cd->common.err = nfserr_fbig; + return -EINVAL; + } +- if (cd->offset) +- *cd->offset = htonl(offset); ++ nfssvc_encode_nfscookie(cd, offset); + + /* truncate filename */ + namlen = min(namlen, NFS2_MAXNAMLEN); +diff --git a/fs/nfsd/xdr.h b/fs/nfsd/xdr.h +index 337c581e15b4c..75b3b31445340 100644 +--- a/fs/nfsd/xdr.h ++++ b/fs/nfsd/xdr.h +@@ -157,6 +157,7 @@ int nfssvc_encode_readres(struct svc_rqst *, __be32 *); + int nfssvc_encode_statfsres(struct svc_rqst *, __be32 *); + int nfssvc_encode_readdirres(struct svc_rqst *, __be32 *); + ++void nfssvc_encode_nfscookie(struct nfsd_readdirres *resp, u32 offset); + int nfssvc_encode_entry(void *, const char *name, + int namlen, loff_t offset, u64 ino, unsigned int); + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-a-helper-to-decode-channel_attrs4.patch b/queue-5.10/nfsd-add-a-helper-to-decode-channel_attrs4.patch new file mode 100644 index 00000000000..3b8ec44bbb5 --- /dev/null +++ b/queue-5.10/nfsd-add-a-helper-to-decode-channel_attrs4.patch @@ -0,0 +1,109 @@ +From 7128238ee7ab66cf05f45501956bc2167d926f3b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Nov 2020 15:35:05 -0500 +Subject: NFSD: Add a helper to decode channel_attrs4 + +From: Chuck Lever + +[ Upstream commit 3a3f1fbacb0960b628e5a9f07c78287312f7a99d ] + +De-duplicate some code. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 71 +++++++++++++++++++++++++---------------------- + 1 file changed, 38 insertions(+), 33 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index e06e657c3d91c..716a16961ff48 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -1614,6 +1614,38 @@ nfsd4_decode_exchange_id(struct nfsd4_compoundargs *argp, + return nfsd4_decode_nfs_impl_id4(argp, exid); + } + ++static __be32 ++nfsd4_decode_channel_attrs4(struct nfsd4_compoundargs *argp, ++ struct nfsd4_channel_attrs *ca) ++{ ++ __be32 *p; ++ ++ p = xdr_inline_decode(argp->xdr, XDR_UNIT * 7); ++ if (!p) ++ return nfserr_bad_xdr; ++ ++ /* headerpadsz is ignored */ ++ p++; ++ ca->maxreq_sz = be32_to_cpup(p++); ++ ca->maxresp_sz = be32_to_cpup(p++); ++ ca->maxresp_cached = be32_to_cpup(p++); ++ ca->maxops = be32_to_cpup(p++); ++ ca->maxreqs = be32_to_cpup(p++); ++ ca->nr_rdma_attrs = be32_to_cpup(p); ++ switch (ca->nr_rdma_attrs) { ++ case 0: ++ break; ++ case 1: ++ if (xdr_stream_decode_u32(argp->xdr, &ca->rdma_attrs) < 0) ++ return nfserr_bad_xdr; ++ break; ++ default: ++ return nfserr_bad_xdr; ++ } ++ ++ return nfs_ok; ++} ++ + static __be32 + nfsd4_decode_create_session(struct nfsd4_compoundargs *argp, + struct nfsd4_create_session *sess) +@@ -1625,39 +1657,12 @@ nfsd4_decode_create_session(struct nfsd4_compoundargs *argp, + sess->seqid = be32_to_cpup(p++); + sess->flags = be32_to_cpup(p++); + +- /* Fore channel attrs */ +- READ_BUF(28); +- p++; /* headerpadsz is always 0 */ +- sess->fore_channel.maxreq_sz = be32_to_cpup(p++); +- sess->fore_channel.maxresp_sz = be32_to_cpup(p++); +- sess->fore_channel.maxresp_cached = be32_to_cpup(p++); +- sess->fore_channel.maxops = be32_to_cpup(p++); +- sess->fore_channel.maxreqs = be32_to_cpup(p++); +- sess->fore_channel.nr_rdma_attrs = be32_to_cpup(p++); +- if (sess->fore_channel.nr_rdma_attrs == 1) { +- READ_BUF(4); +- sess->fore_channel.rdma_attrs = be32_to_cpup(p++); +- } else if (sess->fore_channel.nr_rdma_attrs > 1) { +- dprintk("Too many fore channel attr bitmaps!\n"); +- goto xdr_error; +- } +- +- /* Back channel attrs */ +- READ_BUF(28); +- p++; /* headerpadsz is always 0 */ +- sess->back_channel.maxreq_sz = be32_to_cpup(p++); +- sess->back_channel.maxresp_sz = be32_to_cpup(p++); +- sess->back_channel.maxresp_cached = be32_to_cpup(p++); +- sess->back_channel.maxops = be32_to_cpup(p++); +- sess->back_channel.maxreqs = be32_to_cpup(p++); +- sess->back_channel.nr_rdma_attrs = be32_to_cpup(p++); +- if (sess->back_channel.nr_rdma_attrs == 1) { +- READ_BUF(4); +- sess->back_channel.rdma_attrs = be32_to_cpup(p++); +- } else if (sess->back_channel.nr_rdma_attrs > 1) { +- dprintk("Too many back channel attr bitmaps!\n"); +- goto xdr_error; +- } ++ status = nfsd4_decode_channel_attrs4(argp, &sess->fore_channel); ++ if (status) ++ return status; ++ status = nfsd4_decode_channel_attrs4(argp, &sess->back_channel); ++ if (status) ++ return status; + + READ_BUF(4); + sess->callback_prog = be32_to_cpup(p++); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-a-helper-to-decode-nfs_impl_id4.patch b/queue-5.10/nfsd-add-a-helper-to-decode-nfs_impl_id4.patch new file mode 100644 index 00000000000..53ba7ae83e2 --- /dev/null +++ b/queue-5.10/nfsd-add-a-helper-to-decode-nfs_impl_id4.patch @@ -0,0 +1,105 @@ +From 164baa0a578754d94d38019eca346578e9f8959c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Nov 2020 15:21:55 -0500 +Subject: NFSD: Add a helper to decode nfs_impl_id4 + +From: Chuck Lever + +[ Upstream commit 10ff84228197f47401833495ba19a50131323b4a ] + +Refactor for clarity. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 63 ++++++++++++++++++++++++++++------------------- + 1 file changed, 38 insertions(+), 25 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 6a4ab81e01ffc..e06e657c3d91c 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -1558,12 +1558,47 @@ nfsd4_decode_state_protect4_a(struct nfsd4_compoundargs *argp, + return nfs_ok; + } + ++static __be32 ++nfsd4_decode_nfs_impl_id4(struct nfsd4_compoundargs *argp, ++ struct nfsd4_exchange_id *exid) ++{ ++ __be32 status; ++ u32 count; ++ ++ if (xdr_stream_decode_u32(argp->xdr, &count) < 0) ++ return nfserr_bad_xdr; ++ switch (count) { ++ case 0: ++ break; ++ case 1: ++ /* Note that RFC 8881 places no length limit on ++ * nii_domain, but this implementation permits no ++ * more than NFS4_OPAQUE_LIMIT bytes */ ++ status = nfsd4_decode_opaque(argp, &exid->nii_domain); ++ if (status) ++ return status; ++ /* Note that RFC 8881 places no length limit on ++ * nii_name, but this implementation permits no ++ * more than NFS4_OPAQUE_LIMIT bytes */ ++ status = nfsd4_decode_opaque(argp, &exid->nii_name); ++ if (status) ++ return status; ++ status = nfsd4_decode_nfstime4(argp, &exid->nii_time); ++ if (status) ++ return status; ++ break; ++ default: ++ return nfserr_bad_xdr; ++ } ++ ++ return nfs_ok; ++} ++ + static __be32 + nfsd4_decode_exchange_id(struct nfsd4_compoundargs *argp, + struct nfsd4_exchange_id *exid) + { +- DECODE_HEAD; +- int dummy; ++ __be32 status; + + status = nfsd4_decode_verifier4(argp, &exid->verifier); + if (status) +@@ -1576,29 +1611,7 @@ nfsd4_decode_exchange_id(struct nfsd4_compoundargs *argp, + status = nfsd4_decode_state_protect4_a(argp, exid); + if (status) + return status; +- +- READ_BUF(4); /* nfs_impl_id4 array length */ +- dummy = be32_to_cpup(p++); +- +- if (dummy > 1) +- goto xdr_error; +- +- if (dummy == 1) { +- status = nfsd4_decode_opaque(argp, &exid->nii_domain); +- if (status) +- goto xdr_error; +- +- /* nii_name */ +- status = nfsd4_decode_opaque(argp, &exid->nii_name); +- if (status) +- goto xdr_error; +- +- /* nii_date */ +- status = nfsd4_decode_time(argp, &exid->nii_time); +- if (status) +- goto xdr_error; +- } +- DECODE_TAIL; ++ return nfsd4_decode_nfs_impl_id4(argp, exid); + } + + static __be32 +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-a-helper-to-decode-state_protect4_a.patch b/queue-5.10/nfsd-add-a-helper-to-decode-state_protect4_a.patch new file mode 100644 index 00000000000..7313e2f2235 --- /dev/null +++ b/queue-5.10/nfsd-add-a-helper-to-decode-state_protect4_a.patch @@ -0,0 +1,119 @@ +From b2482e308911b50d22e4e28265462a0644071ab0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 Nov 2020 15:19:12 -0500 +Subject: NFSD: Add a helper to decode state_protect4_a + +From: Chuck Lever + +[ Upstream commit 523ec6ed6fb80fd1537d748a06bffd060a8b3235 ] + +Refactor for clarity. + +Also, remove a stale comment. Commit ed94164398c9 ("nfsd: implement +machine credential support for some operations") added support for +SP4_MACH_CRED, so state_protect_a is no longer completely ignored. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 2 +- + fs/nfsd/nfs4xdr.c | 44 +++++++++++++++++++++++++++----------------- + fs/nfsd/xdr4.h | 2 +- + 3 files changed, 29 insertions(+), 19 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index d402ca0b535f0..e7ec7593eaaa3 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -3089,7 +3089,7 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + + rpc_ntop(sa, addr_str, sizeof(addr_str)); + dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p " +- "ip_addr=%s flags %x, spa_how %d\n", ++ "ip_addr=%s flags %x, spa_how %u\n", + __func__, rqstp, exid, exid->clname.len, exid->clname.data, + addr_str, exid->flags, exid->spa_how); + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 8c5701367e4af..6a4ab81e01ffc 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -1531,25 +1531,13 @@ nfsd4_decode_ssv_sp_parms(struct nfsd4_compoundargs *argp, + } + + static __be32 +-nfsd4_decode_exchange_id(struct nfsd4_compoundargs *argp, +- struct nfsd4_exchange_id *exid) ++nfsd4_decode_state_protect4_a(struct nfsd4_compoundargs *argp, ++ struct nfsd4_exchange_id *exid) + { +- DECODE_HEAD; +- int dummy; +- +- READ_BUF(NFS4_VERIFIER_SIZE); +- COPYMEM(exid->verifier.data, NFS4_VERIFIER_SIZE); ++ __be32 status; + +- status = nfsd4_decode_opaque(argp, &exid->clname); +- if (status) ++ if (xdr_stream_decode_u32(argp->xdr, &exid->spa_how) < 0) + return nfserr_bad_xdr; +- +- READ_BUF(4); +- exid->flags = be32_to_cpup(p++); +- +- /* Ignore state_protect4_a */ +- READ_BUF(4); +- exid->spa_how = be32_to_cpup(p++); + switch (exid->spa_how) { + case SP4_NONE: + break; +@@ -1564,9 +1552,31 @@ nfsd4_decode_exchange_id(struct nfsd4_compoundargs *argp, + return status; + break; + default: +- goto xdr_error; ++ return nfserr_bad_xdr; + } + ++ return nfs_ok; ++} ++ ++static __be32 ++nfsd4_decode_exchange_id(struct nfsd4_compoundargs *argp, ++ struct nfsd4_exchange_id *exid) ++{ ++ DECODE_HEAD; ++ int dummy; ++ ++ status = nfsd4_decode_verifier4(argp, &exid->verifier); ++ if (status) ++ return status; ++ status = nfsd4_decode_opaque(argp, &exid->clname); ++ if (status) ++ return status; ++ if (xdr_stream_decode_u32(argp->xdr, &exid->flags) < 0) ++ return nfserr_bad_xdr; ++ status = nfsd4_decode_state_protect4_a(argp, exid); ++ if (status) ++ return status; ++ + READ_BUF(4); /* nfs_impl_id4 array length */ + dummy = be32_to_cpup(p++); + +diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h +index 6245004a9993b..232529bc1b798 100644 +--- a/fs/nfsd/xdr4.h ++++ b/fs/nfsd/xdr4.h +@@ -433,7 +433,7 @@ struct nfsd4_exchange_id { + u32 flags; + clientid_t clientid; + u32 seqid; +- int spa_how; ++ u32 spa_how; + u32 spo_must_enforce[3]; + u32 spo_must_allow[3]; + struct xdr_netobj nii_domain; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-a-mechanism-to-wait-for-a-delegreturn.patch b/queue-5.10/nfsd-add-a-mechanism-to-wait-for-a-delegreturn.patch new file mode 100644 index 00000000000..84b48f8959e --- /dev/null +++ b/queue-5.10/nfsd-add-a-mechanism-to-wait-for-a-delegreturn.patch @@ -0,0 +1,145 @@ +From db8e5dec491f49bd538964ee3051fc903b430f9b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Sep 2022 18:14:00 -0400 +Subject: NFSD: Add a mechanism to wait for a DELEGRETURN + +From: Chuck Lever + +[ Upstream commit c035362eb935fe9381d9d1cc453bc2a37460e24c ] + +Subsequent patches will use this mechanism to wake up an operation +that is waiting for a client to return a delegation. + +The new tracepoint records whether the wait timed out or was +properly awoken by the expected DELEGRETURN: + + nfsd-1155 [002] 83799.493199: nfsd_delegret_wakeup: xid=0x14b7d6ef fh_hash=0xf6826792 (timed out) + +Suggested-by: Jeff Layton +Signed-off-by: Chuck Lever +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 30 ++++++++++++++++++++++++++++++ + fs/nfsd/nfsd.h | 7 +++++++ + fs/nfsd/trace.h | 23 +++++++++++++++++++++++ + 3 files changed, 60 insertions(+) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 8bbff388e4f03..2bb78ab4f6c31 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -4734,6 +4734,35 @@ nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type) + return ret; + } + ++static bool nfsd4_deleg_present(const struct inode *inode) ++{ ++ struct file_lock_context *ctx = smp_load_acquire(&inode->i_flctx); ++ ++ return ctx && !list_empty_careful(&ctx->flc_lease); ++} ++ ++/** ++ * nfsd_wait_for_delegreturn - wait for delegations to be returned ++ * @rqstp: the RPC transaction being executed ++ * @inode: in-core inode of the file being waited for ++ * ++ * The timeout prevents deadlock if all nfsd threads happen to be ++ * tied up waiting for returning delegations. ++ * ++ * Return values: ++ * %true: delegation was returned ++ * %false: timed out waiting for delegreturn ++ */ ++bool nfsd_wait_for_delegreturn(struct svc_rqst *rqstp, struct inode *inode) ++{ ++ long __maybe_unused timeo; ++ ++ timeo = wait_var_event_timeout(inode, !nfsd4_deleg_present(inode), ++ NFSD_DELEGRETURN_TIMEOUT); ++ trace_nfsd_delegret_wakeup(rqstp, inode, timeo); ++ return timeo > 0; ++} ++ + static void nfsd4_cb_recall_prepare(struct nfsd4_callback *cb) + { + struct nfs4_delegation *dp = cb_to_delegation(cb); +@@ -6811,6 +6840,7 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + if (status) + goto put_stateid; + ++ wake_up_var(d_inode(cstate->current_fh.fh_dentry)); + destroy_delegation(dp); + put_stateid: + nfs4_put_stid(&dp->dl_stid); +diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h +index 57a468ed85c35..6ab4ad41ae84e 100644 +--- a/fs/nfsd/nfsd.h ++++ b/fs/nfsd/nfsd.h +@@ -164,6 +164,7 @@ char * nfs4_recoverydir(void); + bool nfsd4_spo_must_allow(struct svc_rqst *rqstp); + int nfsd4_create_laundry_wq(void); + void nfsd4_destroy_laundry_wq(void); ++bool nfsd_wait_for_delegreturn(struct svc_rqst *rqstp, struct inode *inode); + #else + static inline int nfsd4_init_slabs(void) { return 0; } + static inline void nfsd4_free_slabs(void) { } +@@ -179,6 +180,11 @@ static inline bool nfsd4_spo_must_allow(struct svc_rqst *rqstp) + } + static inline int nfsd4_create_laundry_wq(void) { return 0; }; + static inline void nfsd4_destroy_laundry_wq(void) {}; ++static inline bool nfsd_wait_for_delegreturn(struct svc_rqst *rqstp, ++ struct inode *inode) ++{ ++ return false; ++} + #endif + + /* +@@ -343,6 +349,7 @@ void nfsd_lockd_shutdown(void); + #define NFSD_COURTESY_CLIENT_TIMEOUT (24 * 60 * 60) /* seconds */ + #define NFSD_CLIENT_MAX_TRIM_PER_RUN 128 + #define NFS4_CLIENTS_PER_GB 1024 ++#define NFSD_DELEGRETURN_TIMEOUT (HZ / 34) /* 30ms */ + + /* + * The following attributes are currently not supported by the NFSv4 server: +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index 0ee4220a289a0..6803ac877ff70 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -454,6 +454,29 @@ DEFINE_NFSD_COPY_ERR_EVENT(clone_file_range_err); + #include "filecache.h" + #include "vfs.h" + ++TRACE_EVENT(nfsd_delegret_wakeup, ++ TP_PROTO( ++ const struct svc_rqst *rqstp, ++ const struct inode *inode, ++ long timeo ++ ), ++ TP_ARGS(rqstp, inode, timeo), ++ TP_STRUCT__entry( ++ __field(u32, xid) ++ __field(const void *, inode) ++ __field(long, timeo) ++ ), ++ TP_fast_assign( ++ __entry->xid = be32_to_cpu(rqstp->rq_xid); ++ __entry->inode = inode; ++ __entry->timeo = timeo; ++ ), ++ TP_printk("xid=0x%08x inode=%p%s", ++ __entry->xid, __entry->inode, ++ __entry->timeo == 0 ? " (timed out)" : "" ++ ) ++); ++ + DECLARE_EVENT_CLASS(nfsd_stateid_class, + TP_PROTO(stateid_t *stp), + TP_ARGS(stp), +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-a-new-export_op_nowcc-flag-to-struct-export.patch b/queue-5.10/nfsd-add-a-new-export_op_nowcc-flag-to-struct-export.patch new file mode 100644 index 00000000000..b5774890127 --- /dev/null +++ b/queue-5.10/nfsd-add-a-new-export_op_nowcc-flag-to-struct-export.patch @@ -0,0 +1,219 @@ +From 5e5b38f619cb38aa7c815992782dad156a7d8024 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Nov 2020 17:03:14 -0500 +Subject: nfsd: add a new EXPORT_OP_NOWCC flag to struct export_operations + +From: Jeff Layton + +[ Upstream commit daab110e47f8d7aa6da66923e3ac1a8dbd2b2a72 ] + +With NFSv3 nfsd will always attempt to send along WCC data to the +client. This generally involves saving off the in-core inode information +prior to doing the operation on the given filehandle, and then issuing a +vfs_getattr to it after the op. + +Some filesystems (particularly clustered or networked ones) have an +expensive ->getattr inode operation. Atomicity is also often difficult +or impossible to guarantee on such filesystems. For those, we're best +off not trying to provide WCC information to the client at all, and to +simply allow it to poll for that information as needed with a GETATTR +RPC. + +This patch adds a new flags field to struct export_operations, and +defines a new EXPORT_OP_NOWCC flag that filesystems can use to indicate +that nfsd should not attempt to provide WCC info in NFSv3 replies. It +also adds a blurb about the new flags field and flag to the exporting +documentation. + +The server will also now skip collecting this information for NFSv2 as +well, since that info is never used there anyway. + +Note that this patch does not add this flag to any filesystem +export_operations structures. This was originally developed to allow +reexporting nfs via nfsd. + +Other filesystems may want to consider enabling this flag too. It's hard +to tell however which ones have export operations to enable export via +knfsd and which ones mostly rely on them for open-by-filehandle support, +so I'm leaving that up to the individual maintainers to decide. I am +cc'ing the relevant lists for those filesystems that I think may want to +consider adding this though. + +Cc: HPDD-discuss@lists.01.org +Cc: ceph-devel@vger.kernel.org +Cc: cluster-devel@redhat.com +Cc: fuse-devel@lists.sourceforge.net +Cc: ocfs2-devel@oss.oracle.com +Signed-off-by: Jeff Layton +Signed-off-by: Lance Shelton +Signed-off-by: Trond Myklebust +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + Documentation/filesystems/nfs/exporting.rst | 27 +++++++++++++++++++++ + fs/nfs/export.c | 1 + + fs/nfsd/nfs3xdr.c | 7 ++++-- + fs/nfsd/nfsfh.c | 14 +++++++++++ + fs/nfsd/nfsfh.h | 2 +- + include/linux/exportfs.h | 2 ++ + 6 files changed, 50 insertions(+), 3 deletions(-) + +diff --git a/Documentation/filesystems/nfs/exporting.rst b/Documentation/filesystems/nfs/exporting.rst +index 33d588a01ace1..cbe542ad52333 100644 +--- a/Documentation/filesystems/nfs/exporting.rst ++++ b/Documentation/filesystems/nfs/exporting.rst +@@ -154,6 +154,11 @@ struct which has the following members: + to find potential names, and matches inode numbers to find the correct + match. + ++ flags ++ Some filesystems may need to be handled differently than others. The ++ export_operations struct also includes a flags field that allows the ++ filesystem to communicate such information to nfsd. See the Export ++ Operations Flags section below for more explanation. + + A filehandle fragment consists of an array of 1 or more 4byte words, + together with a one byte "type". +@@ -163,3 +168,25 @@ generated by encode_fh, in which case it will have been padded with + nuls. Rather, the encode_fh routine should choose a "type" which + indicates the decode_fh how much of the filehandle is valid, and how + it should be interpreted. ++ ++Export Operations Flags ++----------------------- ++In addition to the operation vector pointers, struct export_operations also ++contains a "flags" field that allows the filesystem to communicate to nfsd ++that it may want to do things differently when dealing with it. The ++following flags are defined: ++ ++ EXPORT_OP_NOWCC - disable NFSv3 WCC attributes on this filesystem ++ RFC 1813 recommends that servers always send weak cache consistency ++ (WCC) data to the client after each operation. The server should ++ atomically collect attributes about the inode, do an operation on it, ++ and then collect the attributes afterward. This allows the client to ++ skip issuing GETATTRs in some situations but means that the server ++ is calling vfs_getattr for almost all RPCs. On some filesystems ++ (particularly those that are clustered or networked) this is expensive ++ and atomicity is difficult to guarantee. This flag indicates to nfsd ++ that it should skip providing WCC attributes to the client in NFSv3 ++ replies when doing operations on this filesystem. Consider enabling ++ this on filesystems that have an expensive ->getattr inode operation, ++ or when atomicity between pre and post operation attribute collection ++ is impossible to guarantee. +diff --git a/fs/nfs/export.c b/fs/nfs/export.c +index 3430d6891e89f..8f4c528865c57 100644 +--- a/fs/nfs/export.c ++++ b/fs/nfs/export.c +@@ -171,4 +171,5 @@ const struct export_operations nfs_export_ops = { + .encode_fh = nfs_encode_fh, + .fh_to_dentry = nfs_fh_to_dentry, + .get_parent = nfs_get_parent, ++ .flags = EXPORT_OP_NOWCC, + }; +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index 7d44e10a5f5dd..34b880211e5ea 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -206,7 +206,7 @@ static __be32 * + encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp) + { + struct dentry *dentry = fhp->fh_dentry; +- if (dentry && d_really_is_positive(dentry)) { ++ if (!fhp->fh_no_wcc && dentry && d_really_is_positive(dentry)) { + __be32 err; + struct kstat stat; + +@@ -262,7 +262,7 @@ void fill_pre_wcc(struct svc_fh *fhp) + bool v4 = (fhp->fh_maxsize == NFS4_FHSIZE); + __be32 err; + +- if (fhp->fh_pre_saved) ++ if (fhp->fh_no_wcc || fhp->fh_pre_saved) + return; + inode = d_inode(fhp->fh_dentry); + err = fh_getattr(fhp, &stat); +@@ -290,6 +290,9 @@ void fill_post_wcc(struct svc_fh *fhp) + struct inode *inode = d_inode(fhp->fh_dentry); + __be32 err; + ++ if (fhp->fh_no_wcc) ++ return; ++ + if (fhp->fh_post_saved) + printk("nfsd: inode locked twice during operation.\n"); + +diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c +index c81dbbad87920..9c29a523f4848 100644 +--- a/fs/nfsd/nfsfh.c ++++ b/fs/nfsd/nfsfh.c +@@ -291,6 +291,16 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp) + + fhp->fh_dentry = dentry; + fhp->fh_export = exp; ++ ++ switch (rqstp->rq_vers) { ++ case 3: ++ if (dentry->d_sb->s_export_op->flags & EXPORT_OP_NOWCC) ++ fhp->fh_no_wcc = true; ++ break; ++ case 2: ++ fhp->fh_no_wcc = true; ++ } ++ + return 0; + out: + exp_put(exp); +@@ -559,6 +569,9 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, + */ + set_version_and_fsid_type(fhp, exp, ref_fh); + ++ /* If we have a ref_fh, then copy the fh_no_wcc setting from it. */ ++ fhp->fh_no_wcc = ref_fh ? ref_fh->fh_no_wcc : false; ++ + if (ref_fh == fhp) + fh_put(ref_fh); + +@@ -662,6 +675,7 @@ fh_put(struct svc_fh *fhp) + exp_put(exp); + fhp->fh_export = NULL; + } ++ fhp->fh_no_wcc = false; + return; + } + +diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h +index 45bd776290d52..347d10aa62655 100644 +--- a/fs/nfsd/nfsfh.h ++++ b/fs/nfsd/nfsfh.h +@@ -35,6 +35,7 @@ typedef struct svc_fh { + + bool fh_locked; /* inode locked by us */ + bool fh_want_write; /* remount protection taken */ ++ bool fh_no_wcc; /* no wcc data needed */ + int fh_flags; /* FH flags */ + #ifdef CONFIG_NFSD_V3 + bool fh_post_saved; /* post-op attrs saved */ +@@ -54,7 +55,6 @@ typedef struct svc_fh { + struct kstat fh_post_attr; /* full attrs after operation */ + u64 fh_post_change; /* nfsv4 change; see above */ + #endif /* CONFIG_NFSD_V3 */ +- + } svc_fh; + #define NFSD4_FH_FOREIGN (1<<0) + #define SET_FH_FLAG(c, f) ((c)->fh_flags |= (f)) +diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h +index 3ceb72b67a7aa..e7de0103a32e8 100644 +--- a/include/linux/exportfs.h ++++ b/include/linux/exportfs.h +@@ -213,6 +213,8 @@ struct export_operations { + bool write, u32 *device_generation); + int (*commit_blocks)(struct inode *inode, struct iomap *iomaps, + int nr_iomaps, struct iattr *iattr); ++#define EXPORT_OP_NOWCC (0x1) /* Don't collect wcc data for NFSv3 replies */ ++ unsigned long flags; + }; + + extern int exportfs_encode_inode_fh(struct inode *inode, struct fid *fid, +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-a-nfsd4_file_hash_remove-helper.patch b/queue-5.10/nfsd-add-a-nfsd4_file_hash_remove-helper.patch new file mode 100644 index 00000000000..b214ac81a02 --- /dev/null +++ b/queue-5.10/nfsd-add-a-nfsd4_file_hash_remove-helper.patch @@ -0,0 +1,66 @@ +From fc22ed44c67ef1e0da1492b198f9d1bfc743e6f1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Oct 2022 10:47:34 -0400 +Subject: NFSD: Add a nfsd4_file_hash_remove() helper + +From: Chuck Lever + +[ Upstream commit 3341678f2fd6106055cead09e513fad6950a0d19 ] + +Refactor to relocate hash deletion operation to a helper function +that is close to most other nfs4_file data structure operations. + +The "noinline" annotation will become useful in a moment when the +hlist_del_rcu() is replaced with a more complex rhash remove +operation. It also guarantees that hash remove operations can be +traced with "-p function -l remove_nfs4_file_locked". + +This also simplifies the organization of forward declarations: the +to-be-added rhashtable and its param structure will be defined +/after/ put_nfs4_file(). + +Signed-off-by: Chuck Lever +Reviewed-by: NeilBrown +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index d6e0052b3f682..c464403c23a25 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -84,6 +84,7 @@ static bool check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner) + static void nfs4_free_ol_stateid(struct nfs4_stid *stid); + void nfsd4_end_grace(struct nfsd_net *nn); + static void _free_cpntf_state_locked(struct nfsd_net *nn, struct nfs4_cpntf_state *cps); ++static void nfsd4_file_hash_remove(struct nfs4_file *fi); + + /* Locking: */ + +@@ -591,7 +592,7 @@ put_nfs4_file(struct nfs4_file *fi) + might_lock(&state_lock); + + if (refcount_dec_and_lock(&fi->fi_ref, &state_lock)) { +- hlist_del_rcu(&fi->fi_hash); ++ nfsd4_file_hash_remove(fi); + spin_unlock(&state_lock); + WARN_ON_ONCE(!list_empty(&fi->fi_clnt_odstate)); + WARN_ON_ONCE(!list_empty(&fi->fi_delegations)); +@@ -4749,6 +4750,11 @@ find_or_add_file(struct nfs4_file *new, struct svc_fh *fh) + return insert_file(new, fh, hashval); + } + ++static noinline_for_stack void nfsd4_file_hash_remove(struct nfs4_file *fi) ++{ ++ hlist_del_rcu(&fi->fi_hash); ++} ++ + /* + * Called to check deny when READ with all zero stateid or + * WRITE with all zero or all one stateid +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-a-separate-decoder-for-ssv_sp_parms.patch b/queue-5.10/nfsd-add-a-separate-decoder-for-ssv_sp_parms.patch new file mode 100644 index 00000000000..ad056b2c83b --- /dev/null +++ b/queue-5.10/nfsd-add-a-separate-decoder-for-ssv_sp_parms.patch @@ -0,0 +1,115 @@ +From 34dd465a72c46cb114182bb0ec3a4855d4b9075d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Nov 2020 11:17:50 -0500 +Subject: NFSD: Add a separate decoder for ssv_sp_parms + +From: Chuck Lever + +[ Upstream commit 547bfeb4cd8d491aabbd656d5a6f410cb4249b4e ] + +Refactor for clarity. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 70 +++++++++++++++++++++++++++++------------------ + 1 file changed, 44 insertions(+), 26 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 15535b14328e4..8c5701367e4af 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -1488,12 +1488,54 @@ nfsd4_decode_state_protect_ops(struct nfsd4_compoundargs *argp, + return nfs_ok; + } + ++/* ++ * This implementation currently does not support SP4_SSV. ++ * This decoder simply skips over these arguments. ++ */ ++static noinline __be32 ++nfsd4_decode_ssv_sp_parms(struct nfsd4_compoundargs *argp, ++ struct nfsd4_exchange_id *exid) ++{ ++ u32 count, window, num_gss_handles; ++ __be32 status; ++ ++ /* ssp_ops */ ++ status = nfsd4_decode_state_protect_ops(argp, exid); ++ if (status) ++ return status; ++ ++ /* ssp_hash_algs<> */ ++ if (xdr_stream_decode_u32(argp->xdr, &count) < 0) ++ return nfserr_bad_xdr; ++ while (count--) { ++ status = nfsd4_decode_ignored_string(argp, 0); ++ if (status) ++ return status; ++ } ++ ++ /* ssp_encr_algs<> */ ++ if (xdr_stream_decode_u32(argp->xdr, &count) < 0) ++ return nfserr_bad_xdr; ++ while (count--) { ++ status = nfsd4_decode_ignored_string(argp, 0); ++ if (status) ++ return status; ++ } ++ ++ if (xdr_stream_decode_u32(argp->xdr, &window) < 0) ++ return nfserr_bad_xdr; ++ if (xdr_stream_decode_u32(argp->xdr, &num_gss_handles) < 0) ++ return nfserr_bad_xdr; ++ ++ return nfs_ok; ++} ++ + static __be32 + nfsd4_decode_exchange_id(struct nfsd4_compoundargs *argp, + struct nfsd4_exchange_id *exid) + { +- int dummy, tmp; + DECODE_HEAD; ++ int dummy; + + READ_BUF(NFS4_VERIFIER_SIZE); + COPYMEM(exid->verifier.data, NFS4_VERIFIER_SIZE); +@@ -1517,33 +1559,9 @@ nfsd4_decode_exchange_id(struct nfsd4_compoundargs *argp, + return status; + break; + case SP4_SSV: +- /* ssp_ops */ +- status = nfsd4_decode_state_protect_ops(argp, exid); ++ status = nfsd4_decode_ssv_sp_parms(argp, exid); + if (status) + return status; +- +- /* ssp_hash_algs<> */ +- READ_BUF(4); +- tmp = be32_to_cpup(p++); +- while (tmp--) { +- READ_BUF(4); +- dummy = be32_to_cpup(p++); +- READ_BUF(dummy); +- p += XDR_QUADLEN(dummy); +- } +- +- /* ssp_encr_algs<> */ +- READ_BUF(4); +- tmp = be32_to_cpup(p++); +- while (tmp--) { +- READ_BUF(4); +- dummy = be32_to_cpup(p++); +- READ_BUF(dummy); +- p += XDR_QUADLEN(dummy); +- } +- +- /* ignore ssp_window and ssp_num_gss_handles: */ +- READ_BUF(8); + break; + default: + goto xdr_error; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-a-separate-decoder-to-handle-state_protect_.patch b/queue-5.10/nfsd-add-a-separate-decoder-to-handle-state_protect_.patch new file mode 100644 index 00000000000..155b6de21ec --- /dev/null +++ b/queue-5.10/nfsd-add-a-separate-decoder-to-handle-state_protect_.patch @@ -0,0 +1,115 @@ +From 143051192b5db48edf97d76c219f01f9af45d4ac Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Nov 2020 11:13:00 -0500 +Subject: NFSD: Add a separate decoder to handle state_protect_ops + +From: Chuck Lever + +[ Upstream commit 2548aa784d760567c2a77cbd8b7c55b211167c37 ] + +Refactor for clarity and de-duplication of code. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 66 +++++++++++++++++------------------------------ + 1 file changed, 23 insertions(+), 43 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 5dad32ab02ec4..15535b14328e4 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -315,32 +315,6 @@ nfsd4_decode_verifier4(struct nfsd4_compoundargs *argp, nfs4_verifier *verf) + return nfs_ok; + } + +-static __be32 +-nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval) +-{ +- u32 bmlen; +- DECODE_HEAD; +- +- bmval[0] = 0; +- bmval[1] = 0; +- bmval[2] = 0; +- +- READ_BUF(4); +- bmlen = be32_to_cpup(p++); +- if (bmlen > 1000) +- goto xdr_error; +- +- READ_BUF(bmlen << 2); +- if (bmlen > 0) +- bmval[0] = be32_to_cpup(p++); +- if (bmlen > 1) +- bmval[1] = be32_to_cpup(p++); +- if (bmlen > 2) +- bmval[2] = be32_to_cpup(p++); +- +- DECODE_TAIL; +-} +- + /** + * nfsd4_decode_bitmap4 - Decode an NFSv4 bitmap4 + * @argp: NFSv4 compound argument structure +@@ -1496,6 +1470,24 @@ static __be32 nfsd4_decode_bind_conn_to_session(struct nfsd4_compoundargs *argp, + return nfs_ok; + } + ++static __be32 ++nfsd4_decode_state_protect_ops(struct nfsd4_compoundargs *argp, ++ struct nfsd4_exchange_id *exid) ++{ ++ __be32 status; ++ ++ status = nfsd4_decode_bitmap4(argp, exid->spo_must_enforce, ++ ARRAY_SIZE(exid->spo_must_enforce)); ++ if (status) ++ return nfserr_bad_xdr; ++ status = nfsd4_decode_bitmap4(argp, exid->spo_must_allow, ++ ARRAY_SIZE(exid->spo_must_allow)); ++ if (status) ++ return nfserr_bad_xdr; ++ ++ return nfs_ok; ++} ++ + static __be32 + nfsd4_decode_exchange_id(struct nfsd4_compoundargs *argp, + struct nfsd4_exchange_id *exid) +@@ -1520,27 +1512,15 @@ nfsd4_decode_exchange_id(struct nfsd4_compoundargs *argp, + case SP4_NONE: + break; + case SP4_MACH_CRED: +- /* spo_must_enforce */ +- status = nfsd4_decode_bitmap(argp, +- exid->spo_must_enforce); +- if (status) +- goto out; +- /* spo_must_allow */ +- status = nfsd4_decode_bitmap(argp, exid->spo_must_allow); ++ status = nfsd4_decode_state_protect_ops(argp, exid); + if (status) +- goto out; ++ return status; + break; + case SP4_SSV: + /* ssp_ops */ +- READ_BUF(4); +- dummy = be32_to_cpup(p++); +- READ_BUF(dummy * 4); +- p += dummy; +- +- READ_BUF(4); +- dummy = be32_to_cpup(p++); +- READ_BUF(dummy * 4); +- p += dummy; ++ status = nfsd4_decode_state_protect_ops(argp, exid); ++ if (status) ++ return status; + + /* ssp_hash_algs<> */ + READ_BUF(4); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-a-tracepoint-for-errors-in-nfsd4_clone_file.patch b/queue-5.10/nfsd-add-a-tracepoint-for-errors-in-nfsd4_clone_file.patch new file mode 100644 index 00000000000..aa5eea0e2e9 --- /dev/null +++ b/queue-5.10/nfsd-add-a-tracepoint-for-errors-in-nfsd4_clone_file.patch @@ -0,0 +1,158 @@ +From 1b12441039170bb6bc7c9ae67b9e4b576c6c574d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 18 Dec 2021 20:38:00 -0500 +Subject: nfsd: Add a tracepoint for errors in nfsd4_clone_file_range() + +From: Trond Myklebust + +[ Upstream commit a2f4c3fa4db94ba44d32a72201927cfd132a8e82 ] + +Since a clone error commit can cause the boot verifier to change, +we should trace those errors. + +Signed-off-by: Trond Myklebust +Signed-off-by: Chuck Lever +[ cel: Addressed a checkpatch.pl splat in fs/nfsd/vfs.h ] +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 2 +- + fs/nfsd/trace.h | 50 ++++++++++++++++++++++++++++++++++++++++++++++ + fs/nfsd/vfs.c | 18 +++++++++++++++-- + fs/nfsd/vfs.h | 3 ++- + 4 files changed, 69 insertions(+), 4 deletions(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index eaf2f95d059ca..0f2025b7a6415 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -1104,7 +1104,7 @@ nfsd4_clone(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + if (status) + goto out; + +- status = nfsd4_clone_file_range(src, clone->cl_src_pos, ++ status = nfsd4_clone_file_range(rqstp, src, clone->cl_src_pos, + dst, clone->cl_dst_pos, clone->cl_count, + EX_ISSYNC(cstate->current_fh.fh_export)); + +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index cba38e0b204b9..199b485c77179 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -400,6 +400,56 @@ TRACE_EVENT(nfsd_dirent, + __entry->len, __get_str(name)) + ) + ++DECLARE_EVENT_CLASS(nfsd_copy_err_class, ++ TP_PROTO(struct svc_rqst *rqstp, ++ struct svc_fh *src_fhp, ++ loff_t src_offset, ++ struct svc_fh *dst_fhp, ++ loff_t dst_offset, ++ u64 count, ++ int status), ++ TP_ARGS(rqstp, src_fhp, src_offset, dst_fhp, dst_offset, count, status), ++ TP_STRUCT__entry( ++ __field(u32, xid) ++ __field(u32, src_fh_hash) ++ __field(loff_t, src_offset) ++ __field(u32, dst_fh_hash) ++ __field(loff_t, dst_offset) ++ __field(u64, count) ++ __field(int, status) ++ ), ++ TP_fast_assign( ++ __entry->xid = be32_to_cpu(rqstp->rq_xid); ++ __entry->src_fh_hash = knfsd_fh_hash(&src_fhp->fh_handle); ++ __entry->src_offset = src_offset; ++ __entry->dst_fh_hash = knfsd_fh_hash(&dst_fhp->fh_handle); ++ __entry->dst_offset = dst_offset; ++ __entry->count = count; ++ __entry->status = status; ++ ), ++ TP_printk("xid=0x%08x src_fh_hash=0x%08x src_offset=%lld " ++ "dst_fh_hash=0x%08x dst_offset=%lld " ++ "count=%llu status=%d", ++ __entry->xid, __entry->src_fh_hash, __entry->src_offset, ++ __entry->dst_fh_hash, __entry->dst_offset, ++ (unsigned long long)__entry->count, ++ __entry->status) ++) ++ ++#define DEFINE_NFSD_COPY_ERR_EVENT(name) \ ++DEFINE_EVENT(nfsd_copy_err_class, nfsd_##name, \ ++ TP_PROTO(struct svc_rqst *rqstp, \ ++ struct svc_fh *src_fhp, \ ++ loff_t src_offset, \ ++ struct svc_fh *dst_fhp, \ ++ loff_t dst_offset, \ ++ u64 count, \ ++ int status), \ ++ TP_ARGS(rqstp, src_fhp, src_offset, dst_fhp, dst_offset, \ ++ count, status)) ++ ++DEFINE_NFSD_COPY_ERR_EVENT(clone_file_range_err); ++ + #include "state.h" + #include "filecache.h" + #include "vfs.h" +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index 2e3b0bd560fcc..b1ce38c642cde 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -40,6 +40,7 @@ + #include "../internal.h" + #include "acl.h" + #include "idmap.h" ++#include "xdr4.h" + #endif /* CONFIG_NFSD_V4 */ + + #include "nfsd.h" +@@ -530,8 +531,15 @@ __be32 nfsd4_set_nfs4_label(struct svc_rqst *rqstp, struct svc_fh *fhp, + } + #endif + +-__be32 nfsd4_clone_file_range(struct nfsd_file *nf_src, u64 src_pos, +- struct nfsd_file *nf_dst, u64 dst_pos, u64 count, bool sync) ++static struct nfsd4_compound_state *nfsd4_get_cstate(struct svc_rqst *rqstp) ++{ ++ return &((struct nfsd4_compoundres *)rqstp->rq_resp)->cstate; ++} ++ ++__be32 nfsd4_clone_file_range(struct svc_rqst *rqstp, ++ struct nfsd_file *nf_src, u64 src_pos, ++ struct nfsd_file *nf_dst, u64 dst_pos, ++ u64 count, bool sync) + { + struct file *src = nf_src->nf_file; + struct file *dst = nf_dst->nf_file; +@@ -558,6 +566,12 @@ __be32 nfsd4_clone_file_range(struct nfsd_file *nf_src, u64 src_pos, + if (!status) + status = commit_inode_metadata(file_inode(src)); + if (status < 0) { ++ trace_nfsd_clone_file_range_err(rqstp, ++ &nfsd4_get_cstate(rqstp)->save_fh, ++ src_pos, ++ &nfsd4_get_cstate(rqstp)->current_fh, ++ dst_pos, ++ count, status); + nfsd_reset_boot_verifier(net_generic(nf_dst->nf_net, + nfsd_net_id)); + ret = nfserrno(status); +diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h +index b21b76e6b9a87..9f56dcb22ff72 100644 +--- a/fs/nfsd/vfs.h ++++ b/fs/nfsd/vfs.h +@@ -57,7 +57,8 @@ __be32 nfsd4_set_nfs4_label(struct svc_rqst *, struct svc_fh *, + struct xdr_netobj *); + __be32 nfsd4_vfs_fallocate(struct svc_rqst *, struct svc_fh *, + struct file *, loff_t, loff_t, int); +-__be32 nfsd4_clone_file_range(struct nfsd_file *nf_src, u64 src_pos, ++__be32 nfsd4_clone_file_range(struct svc_rqst *rqstp, ++ struct nfsd_file *nf_src, u64 src_pos, + struct nfsd_file *nf_dst, u64 dst_pos, + u64 count, bool sync); + #endif /* CONFIG_NFSD_V4 */ +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-a-tracepoint-to-record-directory-entry-enco.patch b/queue-5.10/nfsd-add-a-tracepoint-to-record-directory-entry-enco.patch new file mode 100644 index 00000000000..25b7879b2b3 --- /dev/null +++ b/queue-5.10/nfsd-add-a-tracepoint-to-record-directory-entry-enco.patch @@ -0,0 +1,102 @@ +From 56d2ba3649bb6958500352ce6d4a6e96f937cede Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 5 Mar 2021 13:57:40 -0500 +Subject: NFSD: Add a tracepoint to record directory entry encoding + +From: Chuck Lever + +[ Upstream commit 6019ce0742ca55d3e45279a19b07d1542747a098 ] + +Enable watching the progress of directory encoding to capture the +timing of any issues with reading or encoding a directory. The +new tracepoint captures dirent encoding for all NFS versions. + +For example, here's what a few NFSv4 directory entries might look +like: + +nfsd-989 [002] 468.596265: nfsd_dirent: fh_hash=0x5d162594 ino=2 name=. +nfsd-989 [002] 468.596267: nfsd_dirent: fh_hash=0x5d162594 ino=1 name=.. +nfsd-989 [002] 468.596299: nfsd_dirent: fh_hash=0x5d162594 ino=3827 name=zlib.c +nfsd-989 [002] 468.596325: nfsd_dirent: fh_hash=0x5d162594 ino=3811 name=xdiff +nfsd-989 [002] 468.596351: nfsd_dirent: fh_hash=0x5d162594 ino=3810 name=xdiff-interface.h +nfsd-989 [002] 468.596377: nfsd_dirent: fh_hash=0x5d162594 ino=3809 name=xdiff-interface.c + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/trace.h | 24 ++++++++++++++++++++++++ + fs/nfsd/vfs.c | 9 ++++++--- + 2 files changed, 30 insertions(+), 3 deletions(-) + +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index 2bc2a888f7fa8..d20ab767ba26a 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -391,6 +391,30 @@ DEFINE_EVENT(nfsd_err_class, nfsd_##name, \ + DEFINE_NFSD_ERR_EVENT(read_err); + DEFINE_NFSD_ERR_EVENT(write_err); + ++TRACE_EVENT(nfsd_dirent, ++ TP_PROTO(struct svc_fh *fhp, ++ u64 ino, ++ const char *name, ++ int namlen), ++ TP_ARGS(fhp, ino, name, namlen), ++ TP_STRUCT__entry( ++ __field(u32, fh_hash) ++ __field(u64, ino) ++ __field(int, len) ++ __dynamic_array(unsigned char, name, namlen) ++ ), ++ TP_fast_assign( ++ __entry->fh_hash = fhp ? knfsd_fh_hash(&fhp->fh_handle) : 0; ++ __entry->ino = ino; ++ __entry->len = namlen; ++ memcpy(__get_str(name), name, namlen); ++ __assign_str(name, name); ++ ), ++ TP_printk("fh_hash=0x%08x ino=%llu name=%.*s", ++ __entry->fh_hash, __entry->ino, ++ __entry->len, __get_str(name)) ++) ++ + #include "state.h" + #include "filecache.h" + #include "vfs.h" +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index d12c3e71ca10e..520e55c35e742 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -1979,8 +1979,9 @@ static int nfsd_buffered_filldir(struct dir_context *ctx, const char *name, + return 0; + } + +-static __be32 nfsd_buffered_readdir(struct file *file, nfsd_filldir_t func, +- struct readdir_cd *cdp, loff_t *offsetp) ++static __be32 nfsd_buffered_readdir(struct file *file, struct svc_fh *fhp, ++ nfsd_filldir_t func, struct readdir_cd *cdp, ++ loff_t *offsetp) + { + struct buffered_dirent *de; + int host_err; +@@ -2026,6 +2027,8 @@ static __be32 nfsd_buffered_readdir(struct file *file, nfsd_filldir_t func, + if (cdp->err != nfs_ok) + break; + ++ trace_nfsd_dirent(fhp, de->ino, de->name, de->namlen); ++ + reclen = ALIGN(sizeof(*de) + de->namlen, + sizeof(u64)); + size -= reclen; +@@ -2073,7 +2076,7 @@ nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t *offsetp, + goto out_close; + } + +- err = nfsd_buffered_readdir(file, func, cdp, offsetp); ++ err = nfsd_buffered_readdir(file, fhp, func, cdp, offsetp); + + if (err == nfserr_eof || err == nfserr_toosmall) + err = nfs_ok; /* can still be found in ->err */ +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-an-nfsd4_encode_nfstime4-helper.patch b/queue-5.10/nfsd-add-an-nfsd4_encode_nfstime4-helper.patch new file mode 100644 index 00000000000..f243e1d067b --- /dev/null +++ b/queue-5.10/nfsd-add-an-nfsd4_encode_nfstime4-helper.patch @@ -0,0 +1,97 @@ +From ad4b2940d61fa52bcdab329794072bdd058dc910 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Jun 2023 10:13:39 -0400 +Subject: NFSD: Add an nfsd4_encode_nfstime4() helper + +From: Chuck Lever + +[ Upstream commit 262176798b18b12fd8ab84c94cfece0a6a652476 ] + +Clean up: de-duplicate some common code. + +Reviewed-by: Jeff Layton +Acked-by: Tom Talpey +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 46 ++++++++++++++++++++++++++-------------------- + 1 file changed, 26 insertions(+), 20 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index d62382dfc135e..a81938c1e3efb 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -2541,6 +2541,20 @@ static __be32 *encode_change(__be32 *p, struct kstat *stat, struct inode *inode, + return p; + } + ++static __be32 nfsd4_encode_nfstime4(struct xdr_stream *xdr, ++ struct timespec64 *tv) ++{ ++ __be32 *p; ++ ++ p = xdr_reserve_space(xdr, XDR_UNIT * 3); ++ if (!p) ++ return nfserr_resource; ++ ++ p = xdr_encode_hyper(p, (s64)tv->tv_sec); ++ *p = cpu_to_be32(tv->tv_nsec); ++ return nfs_ok; ++} ++ + /* + * ctime (in NFSv4, time_metadata) is not writeable, and the client + * doesn't really care what resolution could theoretically be stored by +@@ -3346,11 +3360,9 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, + p = xdr_encode_hyper(p, dummy64); + } + if (bmval1 & FATTR4_WORD1_TIME_ACCESS) { +- p = xdr_reserve_space(xdr, 12); +- if (!p) +- goto out_resource; +- p = xdr_encode_hyper(p, (s64)stat.atime.tv_sec); +- *p++ = cpu_to_be32(stat.atime.tv_nsec); ++ status = nfsd4_encode_nfstime4(xdr, &stat.atime); ++ if (status) ++ goto out; + } + if (bmval1 & FATTR4_WORD1_TIME_DELTA) { + p = xdr_reserve_space(xdr, 12); +@@ -3359,25 +3371,19 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, + p = encode_time_delta(p, d_inode(dentry)); + } + if (bmval1 & FATTR4_WORD1_TIME_METADATA) { +- p = xdr_reserve_space(xdr, 12); +- if (!p) +- goto out_resource; +- p = xdr_encode_hyper(p, (s64)stat.ctime.tv_sec); +- *p++ = cpu_to_be32(stat.ctime.tv_nsec); ++ status = nfsd4_encode_nfstime4(xdr, &stat.ctime); ++ if (status) ++ goto out; + } + if (bmval1 & FATTR4_WORD1_TIME_MODIFY) { +- p = xdr_reserve_space(xdr, 12); +- if (!p) +- goto out_resource; +- p = xdr_encode_hyper(p, (s64)stat.mtime.tv_sec); +- *p++ = cpu_to_be32(stat.mtime.tv_nsec); ++ status = nfsd4_encode_nfstime4(xdr, &stat.mtime); ++ if (status) ++ goto out; + } + if (bmval1 & FATTR4_WORD1_TIME_CREATE) { +- p = xdr_reserve_space(xdr, 12); +- if (!p) +- goto out_resource; +- p = xdr_encode_hyper(p, (s64)stat.btime.tv_sec); +- *p++ = cpu_to_be32(stat.btime.tv_nsec); ++ status = nfsd4_encode_nfstime4(xdr, &stat.btime); ++ if (status) ++ goto out; + } + if (bmval1 & FATTR4_WORD1_MOUNTED_ON_FILEID) { + u64 ino = stat.ino; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-an-nfsd4_read-rd_eof-field.patch b/queue-5.10/nfsd-add-an-nfsd4_read-rd_eof-field.patch new file mode 100644 index 00000000000..324627a9236 --- /dev/null +++ b/queue-5.10/nfsd-add-an-nfsd4_read-rd_eof-field.patch @@ -0,0 +1,97 @@ +From af510dc0a87957a9a48db1e7ebcf78937feb4ab6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 Jul 2022 16:08:57 -0400 +Subject: NFSD: Add an nfsd4_read::rd_eof field + +From: Chuck Lever + +[ Upstream commit 24c7fb85498eda1d4c6b42cc4886328429814990 ] + +Refactor: Make the EOF result available in the entire NFSv4 READ +path. + +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 11 +++++------ + fs/nfsd/xdr4.h | 5 +++-- + 2 files changed, 8 insertions(+), 8 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 059e920c21919..8437a390480df 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -3890,7 +3890,6 @@ static __be32 nfsd4_encode_splice_read( + struct xdr_stream *xdr = resp->xdr; + struct xdr_buf *buf = xdr->buf; + int status, space_left; +- u32 eof; + __be32 nfserr; + __be32 *p = xdr->p - 2; + +@@ -3899,7 +3898,8 @@ static __be32 nfsd4_encode_splice_read( + return nfserr_resource; + + nfserr = nfsd_splice_read(read->rd_rqstp, read->rd_fhp, +- file, read->rd_offset, &maxcount, &eof); ++ file, read->rd_offset, &maxcount, ++ &read->rd_eof); + read->rd_length = maxcount; + if (nfserr) + goto out_err; +@@ -3910,7 +3910,7 @@ static __be32 nfsd4_encode_splice_read( + goto out_err; + } + +- *(p++) = htonl(eof); ++ *(p++) = htonl(read->rd_eof); + *(p++) = htonl(maxcount); + + buf->page_len = maxcount; +@@ -3954,7 +3954,6 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp, + struct file *file, unsigned long maxcount) + { + struct xdr_stream *xdr = resp->xdr; +- u32 eof; + int starting_len = xdr->buf->len - 8; + __be32 nfserr; + __be32 tmp; +@@ -3966,7 +3965,7 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp, + + nfserr = nfsd_readv(resp->rqstp, read->rd_fhp, file, read->rd_offset, + resp->rqstp->rq_vec, read->rd_vlen, &maxcount, +- &eof); ++ &read->rd_eof); + read->rd_length = maxcount; + if (nfserr) + return nfserr; +@@ -3974,7 +3973,7 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp, + return nfserr_io; + xdr_truncate_encode(xdr, starting_len + 8 + xdr_align_size(maxcount)); + +- tmp = htonl(eof); ++ tmp = htonl(read->rd_eof); + write_bytes_to_xdr_buf(xdr->buf, starting_len , &tmp, 4); + tmp = htonl(maxcount); + write_bytes_to_xdr_buf(xdr->buf, starting_len + 4, &tmp, 4); +diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h +index 448b687943cd3..32617639a3ece 100644 +--- a/fs/nfsd/xdr4.h ++++ b/fs/nfsd/xdr4.h +@@ -302,9 +302,10 @@ struct nfsd4_read { + u32 rd_length; /* request */ + int rd_vlen; + struct nfsd_file *rd_nf; +- ++ + struct svc_rqst *rd_rqstp; /* response */ +- struct svc_fh *rd_fhp; /* response */ ++ struct svc_fh *rd_fhp; /* response */ ++ u32 rd_eof; /* response */ + }; + + struct nfsd4_readdir { +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-an-nfsd_cb_lm_notify-tracepoint.patch b/queue-5.10/nfsd-add-an-nfsd_cb_lm_notify-tracepoint.patch new file mode 100644 index 00000000000..064655f1732 --- /dev/null +++ b/queue-5.10/nfsd-add-an-nfsd_cb_lm_notify-tracepoint.patch @@ -0,0 +1,81 @@ +From 7b3d780e8eedc9da77d38ce6f46e3a8ea7c5dad6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 14 May 2021 15:57:08 -0400 +Subject: NFSD: Add an nfsd_cb_lm_notify tracepoint + +From: Chuck Lever + +[ Upstream commit 2cde7f8118f0fea29ad73ddcf28817f95adeffd5 ] + +When the server kicks off a CB_LM_NOTIFY callback, record its +arguments so we can better observe asynchronous locking behavior. +For example: + + nfsd-998 [002] 1471.705873: nfsd_cb_notify_lock: addr=192.168.2.51:0 client 6092a47c:35a43fc1 fh_hash=0x8950b23a + +Signed-off-by: Chuck Lever +Cc: Jeff Layton +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 4 +++- + fs/nfsd/trace.h | 26 ++++++++++++++++++++++++++ + 2 files changed, 29 insertions(+), 1 deletion(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index a8aa3680605bb..89054fe68aca6 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -6494,8 +6494,10 @@ nfsd4_lm_notify(struct file_lock *fl) + } + spin_unlock(&nn->blocked_locks_lock); + +- if (queue) ++ if (queue) { ++ trace_nfsd_cb_notify_lock(lo, nbl); + nfsd4_run_cb(&nbl->nbl_cb); ++ } + } + + static const struct lock_manager_operations nfsd_posix_mng_ops = { +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index 86e0656bdb779..bed7d5d49fee4 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -1027,6 +1027,32 @@ TRACE_EVENT(nfsd_cb_done, + __entry->status) + ); + ++TRACE_EVENT(nfsd_cb_notify_lock, ++ TP_PROTO( ++ const struct nfs4_lockowner *lo, ++ const struct nfsd4_blocked_lock *nbl ++ ), ++ TP_ARGS(lo, nbl), ++ TP_STRUCT__entry( ++ __field(u32, cl_boot) ++ __field(u32, cl_id) ++ __field(u32, fh_hash) ++ __array(unsigned char, addr, sizeof(struct sockaddr_in6)) ++ ), ++ TP_fast_assign( ++ const struct nfs4_client *clp = lo->lo_owner.so_client; ++ ++ __entry->cl_boot = clp->cl_clientid.cl_boot; ++ __entry->cl_id = clp->cl_clientid.cl_id; ++ __entry->fh_hash = knfsd_fh_hash(&nbl->nbl_fh); ++ memcpy(__entry->addr, &clp->cl_cb_conn.cb_addr, ++ sizeof(struct sockaddr_in6)); ++ ), ++ TP_printk("addr=%pISpc client %08x:%08x fh_hash=0x%08x", ++ __entry->addr, __entry->cl_boot, __entry->cl_id, ++ __entry->fh_hash) ++); ++ + #endif /* _NFSD_TRACE_H */ + + #undef TRACE_INCLUDE_PATH +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-an-nfsd_cb_offload-tracepoint.patch b/queue-5.10/nfsd-add-an-nfsd_cb_offload-tracepoint.patch new file mode 100644 index 00000000000..59b3f86d6b1 --- /dev/null +++ b/queue-5.10/nfsd-add-an-nfsd_cb_offload-tracepoint.patch @@ -0,0 +1,90 @@ +From 85c2087bc448c0baf1e3927503565d66252a7ff9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 14 May 2021 15:57:14 -0400 +Subject: NFSD: Add an nfsd_cb_offload tracepoint + +From: Chuck Lever + +[ Upstream commit 87512386e951ee28ba2e7ef32b843ac97621d371 ] + +Record the arguments of CB_OFFLOAD callbacks so we can better +observe asynchronous copy-offload behavior. For example: + +nfsd-995 [008] 7721.934222: nfsd_cb_offload: + addr=192.168.2.51:0 client 6092a47c:35a43fc1 fh_hash=0x8739113a + count=116528 status=0 + +Signed-off-by: Chuck Lever +Cc: Olga Kornievskaia +Cc: Dai Ngo +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 2 ++ + fs/nfsd/trace.h | 36 ++++++++++++++++++++++++++++++++++++ + 2 files changed, 38 insertions(+) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index f85958f81a266..dfce9c432a5ee 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -1489,6 +1489,8 @@ static int nfsd4_do_async_copy(void *data) + memcpy(&cb_copy->fh, ©->fh, sizeof(copy->fh)); + nfsd4_init_cb(&cb_copy->cp_cb, cb_copy->cp_clp, + &nfsd4_cb_offload_ops, NFSPROC4_CLNT_CB_OFFLOAD); ++ trace_nfsd_cb_offload(copy->cp_clp, ©->cp_res.cb_stateid, ++ ©->fh, copy->cp_count, copy->nfserr); + nfsd4_run_cb(&cb_copy->cp_cb); + out: + if (!copy->cp_intra) +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index bed7d5d49fee4..fe32dfe1e55af 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -1053,6 +1053,42 @@ TRACE_EVENT(nfsd_cb_notify_lock, + __entry->fh_hash) + ); + ++TRACE_EVENT(nfsd_cb_offload, ++ TP_PROTO( ++ const struct nfs4_client *clp, ++ const stateid_t *stp, ++ const struct knfsd_fh *fh, ++ u64 count, ++ __be32 status ++ ), ++ TP_ARGS(clp, stp, fh, count, status), ++ TP_STRUCT__entry( ++ __field(u32, cl_boot) ++ __field(u32, cl_id) ++ __field(u32, si_id) ++ __field(u32, si_generation) ++ __field(u32, fh_hash) ++ __field(int, status) ++ __field(u64, count) ++ __array(unsigned char, addr, sizeof(struct sockaddr_in6)) ++ ), ++ TP_fast_assign( ++ __entry->cl_boot = stp->si_opaque.so_clid.cl_boot; ++ __entry->cl_id = stp->si_opaque.so_clid.cl_id; ++ __entry->si_id = stp->si_opaque.so_id; ++ __entry->si_generation = stp->si_generation; ++ __entry->fh_hash = knfsd_fh_hash(fh); ++ __entry->status = be32_to_cpu(status); ++ __entry->count = count; ++ memcpy(__entry->addr, &clp->cl_cb_conn.cb_addr, ++ sizeof(struct sockaddr_in6)); ++ ), ++ TP_printk("addr=%pISpc client %08x:%08x stateid %08x:%08x fh_hash=0x%08x count=%llu status=%d", ++ __entry->addr, __entry->cl_boot, __entry->cl_id, ++ __entry->si_id, __entry->si_generation, ++ __entry->fh_hash, __entry->count, __entry->status) ++); ++ + #endif /* _NFSD_TRACE_H */ + + #undef TRACE_INCLUDE_PATH +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-an-nfsd_cb_probe-tracepoint.patch b/queue-5.10/nfsd-add-an-nfsd_cb_probe-tracepoint.patch new file mode 100644 index 00000000000..87899fce775 --- /dev/null +++ b/queue-5.10/nfsd-add-an-nfsd_cb_probe-tracepoint.patch @@ -0,0 +1,49 @@ +From cb8607c7839e1f042c3d4faee99c7aee00cac340 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 14 May 2021 15:57:26 -0400 +Subject: NFSD: Add an nfsd_cb_probe tracepoint + +From: Chuck Lever + +[ Upstream commit 4ade892ae1c35527584decb7fa026553d53cd03f ] + +Record a tracepoint event when the server performs a callback +probe. This event can be enabled as a group with other nfsd_cb +tracepoints. + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4callback.c | 1 + + fs/nfsd/trace.h | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c +index fe1f36b70fa03..453f60b127ebb 100644 +--- a/fs/nfsd/nfs4callback.c ++++ b/fs/nfsd/nfs4callback.c +@@ -1000,6 +1000,7 @@ static const struct rpc_call_ops nfsd4_cb_probe_ops = { + */ + void nfsd4_probe_callback(struct nfs4_client *clp) + { ++ trace_nfsd_cb_probe(clp); + nfsd4_mark_cb_state(clp, NFSD4_CB_UNKNOWN); + set_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_flags); + nfsd4_run_cb(&clp->cl_cb_null); +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index 9061fd28c996d..4361a0807f070 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -910,6 +910,7 @@ DEFINE_EVENT(nfsd_cb_class, nfsd_cb_##name, \ + TP_ARGS(clp)) + + DEFINE_NFSD_CB_EVENT(state); ++DEFINE_NFSD_CB_EVENT(probe); + DEFINE_NFSD_CB_EVENT(lost); + DEFINE_NFSD_CB_EVENT(shutdown); + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-an-nfsd_file_fsync-tracepoint.patch b/queue-5.10/nfsd-add-an-nfsd_file_fsync-tracepoint.patch new file mode 100644 index 00000000000..e5e0c3fe23a --- /dev/null +++ b/queue-5.10/nfsd-add-an-nfsd_file_fsync-tracepoint.patch @@ -0,0 +1,93 @@ +From 3a84f24ebc03067c3e24dcc9d48b1ca5fb5659be Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 3 Nov 2022 16:22:48 -0400 +Subject: NFSD: Add an nfsd_file_fsync tracepoint + +From: Chuck Lever + +[ Upstream commit d7064eaf688cfe454c50db9f59298463d80d403c ] + +Add a tracepoint to capture the number of filecache-triggered fsync +calls and which files needed it. Also, record when an fsync triggers +a write verifier reset. + +Examples: + +<...>-97 [007] 262.505611: nfsd_file_free: inode=0xffff888171e08140 ref=0 flags=GC may=WRITE nf_file=0xffff8881373d2400 +<...>-97 [007] 262.505612: nfsd_file_fsync: inode=0xffff888171e08140 ref=0 flags=GC may=WRITE nf_file=0xffff8881373d2400 ret=0 +<...>-97 [007] 262.505623: nfsd_file_free: inode=0xffff888171e08dc0 ref=0 flags=GC may=WRITE nf_file=0xffff8881373d1e00 +<...>-97 [007] 262.505624: nfsd_file_fsync: inode=0xffff888171e08dc0 ref=0 flags=GC may=WRITE nf_file=0xffff8881373d1e00 ret=0 + +Signed-off-by: Chuck Lever +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 5 ++++- + fs/nfsd/trace.h | 31 +++++++++++++++++++++++++++++++ + 2 files changed, 35 insertions(+), 1 deletion(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index 522e900a88605..6b8873b0c2c38 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -335,10 +335,13 @@ static void + nfsd_file_fsync(struct nfsd_file *nf) + { + struct file *file = nf->nf_file; ++ int ret; + + if (!file || !(file->f_mode & FMODE_WRITE)) + return; +- if (vfs_fsync(file, 1) != 0) ++ ret = vfs_fsync(file, 1); ++ trace_nfsd_file_fsync(nf, ret); ++ if (ret) + nfsd_reset_write_verifier(net_generic(nf->nf_net, nfsd_net_id)); + } + +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index 5faec08ac7cf7..235ea38da8644 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -1151,6 +1151,37 @@ DEFINE_EVENT(nfsd_file_lruwalk_class, name, \ + DEFINE_NFSD_FILE_LRUWALK_EVENT(nfsd_file_gc_removed); + DEFINE_NFSD_FILE_LRUWALK_EVENT(nfsd_file_shrinker_removed); + ++TRACE_EVENT(nfsd_file_fsync, ++ TP_PROTO( ++ const struct nfsd_file *nf, ++ int ret ++ ), ++ TP_ARGS(nf, ret), ++ TP_STRUCT__entry( ++ __field(void *, nf_inode) ++ __field(int, nf_ref) ++ __field(int, ret) ++ __field(unsigned long, nf_flags) ++ __field(unsigned char, nf_may) ++ __field(struct file *, nf_file) ++ ), ++ TP_fast_assign( ++ __entry->nf_inode = nf->nf_inode; ++ __entry->nf_ref = refcount_read(&nf->nf_ref); ++ __entry->ret = ret; ++ __entry->nf_flags = nf->nf_flags; ++ __entry->nf_may = nf->nf_may; ++ __entry->nf_file = nf->nf_file; ++ ), ++ TP_printk("inode=%p ref=%d flags=%s may=%s nf_file=%p ret=%d", ++ __entry->nf_inode, ++ __entry->nf_ref, ++ show_nf_flags(__entry->nf_flags), ++ show_nfsd_may_flags(__entry->nf_may), ++ __entry->nf_file, __entry->ret ++ ) ++); ++ + #include "cache.h" + + TRACE_DEFINE_ENUM(RC_DROPIT); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-an-nfsd_file_gc-flag-to-enable-nfsd_file-ga.patch b/queue-5.10/nfsd-add-an-nfsd_file_gc-flag-to-enable-nfsd_file-ga.patch new file mode 100644 index 00000000000..cc3aa87b76d --- /dev/null +++ b/queue-5.10/nfsd-add-an-nfsd_file_gc-flag-to-enable-nfsd_file-ga.patch @@ -0,0 +1,266 @@ +From ac5c66ac7558b46d69db02a10de8610a88417862 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Oct 2022 10:46:51 -0400 +Subject: NFSD: Add an NFSD_FILE_GC flag to enable nfsd_file garbage collection + +From: Chuck Lever + +[ Upstream commit 4d1ea8455716ca070e3cd85767e6f6a562a58b1b ] + +NFSv4 operations manage the lifetime of nfsd_file items they use by +means of NFSv4 OPEN and CLOSE. Hence there's no need for them to be +garbage collected. + +Introduce a mechanism to enable garbage collection for nfsd_file +items used only by NFSv2/3 callers. + +Note that the change in nfsd_file_put() ensures that both CLOSE and +DELEGRETURN will actually close out and free an nfsd_file on last +reference of a non-garbage-collected file. + +Link: https://bugzilla.linux-nfs.org/show_bug.cgi?id=394 +Suggested-by: Trond Myklebust +Signed-off-by: Chuck Lever +Tested-by: Jeff Layton +Reviewed-by: NeilBrown +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 63 +++++++++++++++++++++++++++++++++++++++------ + fs/nfsd/filecache.h | 3 +++ + fs/nfsd/nfs3proc.c | 4 +-- + fs/nfsd/trace.h | 3 ++- + fs/nfsd/vfs.c | 4 +-- + 5 files changed, 64 insertions(+), 13 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index e429fce894316..13a25503b80e1 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -62,6 +62,7 @@ struct nfsd_file_lookup_key { + struct net *net; + const struct cred *cred; + unsigned char need; ++ bool gc; + enum nfsd_file_lookup_type type; + }; + +@@ -161,6 +162,8 @@ static int nfsd_file_obj_cmpfn(struct rhashtable_compare_arg *arg, + return 1; + if (!nfsd_match_cred(nf->nf_cred, key->cred)) + return 1; ++ if (!!test_bit(NFSD_FILE_GC, &nf->nf_flags) != key->gc) ++ return 1; + if (test_bit(NFSD_FILE_HASHED, &nf->nf_flags) == 0) + return 1; + break; +@@ -296,6 +299,8 @@ nfsd_file_alloc(struct nfsd_file_lookup_key *key, unsigned int may) + nf->nf_flags = 0; + __set_bit(NFSD_FILE_HASHED, &nf->nf_flags); + __set_bit(NFSD_FILE_PENDING, &nf->nf_flags); ++ if (key->gc) ++ __set_bit(NFSD_FILE_GC, &nf->nf_flags); + nf->nf_inode = key->inode; + /* nf_ref is pre-incremented for hash table */ + refcount_set(&nf->nf_ref, 2); +@@ -427,16 +432,27 @@ nfsd_file_put_noref(struct nfsd_file *nf) + } + } + ++static void ++nfsd_file_unhash_and_put(struct nfsd_file *nf) ++{ ++ if (nfsd_file_unhash(nf)) ++ nfsd_file_put_noref(nf); ++} ++ + void + nfsd_file_put(struct nfsd_file *nf) + { + might_sleep(); + +- nfsd_file_lru_add(nf); +- if (test_bit(NFSD_FILE_HASHED, &nf->nf_flags) == 0) { ++ if (test_bit(NFSD_FILE_GC, &nf->nf_flags)) ++ nfsd_file_lru_add(nf); ++ else if (refcount_read(&nf->nf_ref) == 2) ++ nfsd_file_unhash_and_put(nf); ++ ++ if (!test_bit(NFSD_FILE_HASHED, &nf->nf_flags)) { + nfsd_file_flush(nf); + nfsd_file_put_noref(nf); +- } else if (nf->nf_file) { ++ } else if (nf->nf_file && test_bit(NFSD_FILE_GC, &nf->nf_flags)) { + nfsd_file_put_noref(nf); + nfsd_file_schedule_laundrette(); + } else +@@ -1015,12 +1031,14 @@ nfsd_file_is_cached(struct inode *inode) + + static __be32 + nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, +- unsigned int may_flags, struct nfsd_file **pnf, bool open) ++ unsigned int may_flags, struct nfsd_file **pnf, ++ bool open, bool want_gc) + { + struct nfsd_file_lookup_key key = { + .type = NFSD_FILE_KEY_FULL, + .need = may_flags & NFSD_FILE_MAY_MASK, + .net = SVC_NET(rqstp), ++ .gc = want_gc, + }; + bool open_retry = true; + struct nfsd_file *nf; +@@ -1116,14 +1134,35 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + * then unhash. + */ + if (status != nfs_ok || key.inode->i_nlink == 0) +- if (nfsd_file_unhash(nf)) +- nfsd_file_put_noref(nf); ++ nfsd_file_unhash_and_put(nf); + clear_bit_unlock(NFSD_FILE_PENDING, &nf->nf_flags); + smp_mb__after_atomic(); + wake_up_bit(&nf->nf_flags, NFSD_FILE_PENDING); + goto out; + } + ++/** ++ * nfsd_file_acquire_gc - Get a struct nfsd_file with an open file ++ * @rqstp: the RPC transaction being executed ++ * @fhp: the NFS filehandle of the file to be opened ++ * @may_flags: NFSD_MAY_ settings for the file ++ * @pnf: OUT: new or found "struct nfsd_file" object ++ * ++ * The nfsd_file object returned by this API is reference-counted ++ * and garbage-collected. The object is retained for a few ++ * seconds after the final nfsd_file_put() in case the caller ++ * wants to re-use it. ++ * ++ * Returns nfs_ok and sets @pnf on success; otherwise an nfsstat in ++ * network byte order is returned. ++ */ ++__be32 ++nfsd_file_acquire_gc(struct svc_rqst *rqstp, struct svc_fh *fhp, ++ unsigned int may_flags, struct nfsd_file **pnf) ++{ ++ return nfsd_file_do_acquire(rqstp, fhp, may_flags, pnf, true, true); ++} ++ + /** + * nfsd_file_acquire - Get a struct nfsd_file with an open file + * @rqstp: the RPC transaction being executed +@@ -1131,6 +1170,10 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + * @may_flags: NFSD_MAY_ settings for the file + * @pnf: OUT: new or found "struct nfsd_file" object + * ++ * The nfsd_file_object returned by this API is reference-counted ++ * but not garbage-collected. The object is unhashed after the ++ * final nfsd_file_put(). ++ * + * Returns nfs_ok and sets @pnf on success; otherwise an nfsstat in + * network byte order is returned. + */ +@@ -1138,7 +1181,7 @@ __be32 + nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + unsigned int may_flags, struct nfsd_file **pnf) + { +- return nfsd_file_do_acquire(rqstp, fhp, may_flags, pnf, true); ++ return nfsd_file_do_acquire(rqstp, fhp, may_flags, pnf, true, false); + } + + /** +@@ -1148,6 +1191,10 @@ nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + * @may_flags: NFSD_MAY_ settings for the file + * @pnf: OUT: new or found "struct nfsd_file" object + * ++ * The nfsd_file_object returned by this API is reference-counted ++ * but not garbage-collected. The object is released immediately ++ * one RCU grace period after the final nfsd_file_put(). ++ * + * Returns nfs_ok and sets @pnf on success; otherwise an nfsstat in + * network byte order is returned. + */ +@@ -1155,7 +1202,7 @@ __be32 + nfsd_file_create(struct svc_rqst *rqstp, struct svc_fh *fhp, + unsigned int may_flags, struct nfsd_file **pnf) + { +- return nfsd_file_do_acquire(rqstp, fhp, may_flags, pnf, false); ++ return nfsd_file_do_acquire(rqstp, fhp, may_flags, pnf, false, false); + } + + /* +diff --git a/fs/nfsd/filecache.h b/fs/nfsd/filecache.h +index 6b012ea4bd9da..b7efb2c3ddb18 100644 +--- a/fs/nfsd/filecache.h ++++ b/fs/nfsd/filecache.h +@@ -38,6 +38,7 @@ struct nfsd_file { + #define NFSD_FILE_HASHED (0) + #define NFSD_FILE_PENDING (1) + #define NFSD_FILE_REFERENCED (2) ++#define NFSD_FILE_GC (3) + unsigned long nf_flags; + struct inode *nf_inode; /* don't deref */ + refcount_t nf_ref; +@@ -55,6 +56,8 @@ void nfsd_file_put(struct nfsd_file *nf); + struct nfsd_file *nfsd_file_get(struct nfsd_file *nf); + void nfsd_file_close_inode_sync(struct inode *inode); + bool nfsd_file_is_cached(struct inode *inode); ++__be32 nfsd_file_acquire_gc(struct svc_rqst *rqstp, struct svc_fh *fhp, ++ unsigned int may_flags, struct nfsd_file **nfp); + __be32 nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + unsigned int may_flags, struct nfsd_file **nfp); + __be32 nfsd_file_create(struct svc_rqst *rqstp, struct svc_fh *fhp, +diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c +index a3a55b2be4f67..19cf583096d9c 100644 +--- a/fs/nfsd/nfs3proc.c ++++ b/fs/nfsd/nfs3proc.c +@@ -772,8 +772,8 @@ nfsd3_proc_commit(struct svc_rqst *rqstp) + (unsigned long long) argp->offset); + + fh_copy(&resp->fh, &argp->fh); +- resp->status = nfsd_file_acquire(rqstp, &resp->fh, NFSD_MAY_WRITE | +- NFSD_MAY_NOT_BREAK_LEASE, &nf); ++ resp->status = nfsd_file_acquire_gc(rqstp, &resp->fh, NFSD_MAY_WRITE | ++ NFSD_MAY_NOT_BREAK_LEASE, &nf); + if (resp->status) + goto out; + resp->status = nfsd_commit(rqstp, &resp->fh, nf, argp->offset, +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index 6803ac877ff70..03722414d6db8 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -730,7 +730,8 @@ DEFINE_CLID_EVENT(confirmed_r); + __print_flags(val, "|", \ + { 1 << NFSD_FILE_HASHED, "HASHED" }, \ + { 1 << NFSD_FILE_PENDING, "PENDING" }, \ +- { 1 << NFSD_FILE_REFERENCED, "REFERENCED"}) ++ { 1 << NFSD_FILE_REFERENCED, "REFERENCED"}, \ ++ { 1 << NFSD_FILE_GC, "GC"}) + + DECLARE_EVENT_CLASS(nfsd_file_class, + TP_PROTO(struct nfsd_file *nf), +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index 3278dddd11ba9..3d67dd7eab4b5 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -1165,7 +1165,7 @@ __be32 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, + __be32 err; + + trace_nfsd_read_start(rqstp, fhp, offset, *count); +- err = nfsd_file_acquire(rqstp, fhp, NFSD_MAY_READ, &nf); ++ err = nfsd_file_acquire_gc(rqstp, fhp, NFSD_MAY_READ, &nf); + if (err) + return err; + +@@ -1197,7 +1197,7 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, + + trace_nfsd_write_start(rqstp, fhp, offset, *cnt); + +- err = nfsd_file_acquire(rqstp, fhp, NFSD_MAY_WRITE, &nf); ++ err = nfsd_file_acquire_gc(rqstp, fhp, NFSD_MAY_WRITE, &nf); + if (err) + goto out; + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-an-rpc-authflavor-tracepoint-display-helper.patch b/queue-5.10/nfsd-add-an-rpc-authflavor-tracepoint-display-helper.patch new file mode 100644 index 00000000000..c0a74619837 --- /dev/null +++ b/queue-5.10/nfsd-add-an-rpc-authflavor-tracepoint-display-helper.patch @@ -0,0 +1,49 @@ +From 71a7d1c8b958363919322ed95d080d66f40f7d43 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 14 May 2021 15:55:23 -0400 +Subject: NFSD: Add an RPC authflavor tracepoint display helper + +From: Chuck Lever + +[ Upstream commit 87b2394d60c32c158ebb96ace4abee883baf1239 ] + +To be used in subsequent patches. + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/trace.h | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index d20ab767ba26a..3ec6d38fa5318 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -841,6 +841,22 @@ DEFINE_NFSD_CB_EVENT(setup); + DEFINE_NFSD_CB_EVENT(state); + DEFINE_NFSD_CB_EVENT(shutdown); + ++TRACE_DEFINE_ENUM(RPC_AUTH_NULL); ++TRACE_DEFINE_ENUM(RPC_AUTH_UNIX); ++TRACE_DEFINE_ENUM(RPC_AUTH_GSS); ++TRACE_DEFINE_ENUM(RPC_AUTH_GSS_KRB5); ++TRACE_DEFINE_ENUM(RPC_AUTH_GSS_KRB5I); ++TRACE_DEFINE_ENUM(RPC_AUTH_GSS_KRB5P); ++ ++#define show_nfsd_authflavor(val) \ ++ __print_symbolic(val, \ ++ { RPC_AUTH_NULL, "none" }, \ ++ { RPC_AUTH_UNIX, "sys" }, \ ++ { RPC_AUTH_GSS, "gss" }, \ ++ { RPC_AUTH_GSS_KRB5, "krb5" }, \ ++ { RPC_AUTH_GSS_KRB5I, "krb5i" }, \ ++ { RPC_AUTH_GSS_KRB5P, "krb5p" }) ++ + TRACE_EVENT(nfsd_cb_setup_err, + TP_PROTO( + const struct nfs4_client *clp, +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-an-xdr_stream-based-decoder-for-nfsv2-3-acl.patch b/queue-5.10/nfsd-add-an-xdr_stream-based-decoder-for-nfsv2-3-acl.patch new file mode 100644 index 00000000000..2ee7b3c9f09 --- /dev/null +++ b/queue-5.10/nfsd-add-an-xdr_stream-based-decoder-for-nfsv2-3-acl.patch @@ -0,0 +1,92 @@ +From 660fa5d8d9aaff044a7d534ca21dbe76e29b4949 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Nov 2020 10:38:46 -0500 +Subject: NFSD: Add an xdr_stream-based decoder for NFSv2/3 ACLs + +From: Chuck Lever + +[ Upstream commit 6bb844b4eb6e3b109a2fdaffb60e6da722dc4356 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfs_common/nfsacl.c | 52 ++++++++++++++++++++++++++++++++++++++++++ + include/linux/nfsacl.h | 3 +++ + 2 files changed, 55 insertions(+) + +diff --git a/fs/nfs_common/nfsacl.c b/fs/nfs_common/nfsacl.c +index d056ad2fdefd6..79c563c1a5e84 100644 +--- a/fs/nfs_common/nfsacl.c ++++ b/fs/nfs_common/nfsacl.c +@@ -295,3 +295,55 @@ int nfsacl_decode(struct xdr_buf *buf, unsigned int base, unsigned int *aclcnt, + nfsacl_desc.desc.array_len; + } + EXPORT_SYMBOL_GPL(nfsacl_decode); ++ ++/** ++ * nfs_stream_decode_acl - Decode an NFSv3 ACL ++ * ++ * @xdr: an xdr_stream positioned at an encoded ACL ++ * @aclcnt: OUT: count of ACEs in decoded posix_acl ++ * @pacl: OUT: a dynamically-allocated buffer containing the decoded posix_acl ++ * ++ * Return values: ++ * %false: The encoded ACL is not valid ++ * %true: @pacl contains a decoded ACL, and @xdr is advanced ++ * ++ * On a successful return, caller must release *pacl using posix_acl_release(). ++ */ ++bool nfs_stream_decode_acl(struct xdr_stream *xdr, unsigned int *aclcnt, ++ struct posix_acl **pacl) ++{ ++ const size_t elem_size = XDR_UNIT * 3; ++ struct nfsacl_decode_desc nfsacl_desc = { ++ .desc = { ++ .elem_size = elem_size, ++ .xcode = pacl ? xdr_nfsace_decode : NULL, ++ }, ++ }; ++ unsigned int base; ++ u32 entries; ++ ++ if (xdr_stream_decode_u32(xdr, &entries) < 0) ++ return false; ++ if (entries > NFS_ACL_MAX_ENTRIES) ++ return false; ++ ++ base = xdr_stream_pos(xdr); ++ if (!xdr_inline_decode(xdr, XDR_UNIT + elem_size * entries)) ++ return false; ++ nfsacl_desc.desc.array_maxlen = entries; ++ if (xdr_decode_array2(xdr->buf, base, &nfsacl_desc.desc)) ++ return false; ++ ++ if (pacl) { ++ if (entries != nfsacl_desc.desc.array_len || ++ posix_acl_from_nfsacl(nfsacl_desc.acl) != 0) { ++ posix_acl_release(nfsacl_desc.acl); ++ return false; ++ } ++ *pacl = nfsacl_desc.acl; ++ } ++ if (aclcnt) ++ *aclcnt = entries; ++ return true; ++} ++EXPORT_SYMBOL_GPL(nfs_stream_decode_acl); +diff --git a/include/linux/nfsacl.h b/include/linux/nfsacl.h +index 103d446953234..0ba99c5136491 100644 +--- a/include/linux/nfsacl.h ++++ b/include/linux/nfsacl.h +@@ -38,5 +38,8 @@ nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode, + extern int + nfsacl_decode(struct xdr_buf *buf, unsigned int base, unsigned int *aclcnt, + struct posix_acl **pacl); ++extern bool ++nfs_stream_decode_acl(struct xdr_stream *xdr, unsigned int *aclcnt, ++ struct posix_acl **pacl); + + #endif /* __LINUX_NFSACL_H */ +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-an-xdr_stream-based-encoder-for-nfsv2-3-acl.patch b/queue-5.10/nfsd-add-an-xdr_stream-based-encoder-for-nfsv2-3-acl.patch new file mode 100644 index 00000000000..14c575ac72d --- /dev/null +++ b/queue-5.10/nfsd-add-an-xdr_stream-based-encoder-for-nfsv2-3-acl.patch @@ -0,0 +1,114 @@ +From e28f5f448a22eee434c118710a7230c542fcae5f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Nov 2020 14:55:05 -0500 +Subject: NFSD: Add an xdr_stream-based encoder for NFSv2/3 ACLs + +From: Chuck Lever + +[ Upstream commit 8edc0648880a151026fe625fa1b76772b5766f68 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfs_common/nfsacl.c | 71 ++++++++++++++++++++++++++++++++++++++++++ + include/linux/nfsacl.h | 3 ++ + 2 files changed, 74 insertions(+) + +diff --git a/fs/nfs_common/nfsacl.c b/fs/nfs_common/nfsacl.c +index 79c563c1a5e84..5a5bd85d08f8c 100644 +--- a/fs/nfs_common/nfsacl.c ++++ b/fs/nfs_common/nfsacl.c +@@ -136,6 +136,77 @@ int nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode, + } + EXPORT_SYMBOL_GPL(nfsacl_encode); + ++/** ++ * nfs_stream_encode_acl - Encode an NFSv3 ACL ++ * ++ * @xdr: an xdr_stream positioned to receive an encoded ACL ++ * @inode: inode of file whose ACL this is ++ * @acl: posix_acl to encode ++ * @encode_entries: whether to encode ACEs as well ++ * @typeflag: ACL type: NFS_ACL_DEFAULT or zero ++ * ++ * Return values: ++ * %false: The ACL could not be encoded ++ * %true: @xdr is advanced to the next available position ++ */ ++bool nfs_stream_encode_acl(struct xdr_stream *xdr, struct inode *inode, ++ struct posix_acl *acl, int encode_entries, ++ int typeflag) ++{ ++ const size_t elem_size = XDR_UNIT * 3; ++ u32 entries = (acl && acl->a_count) ? max_t(int, acl->a_count, 4) : 0; ++ struct nfsacl_encode_desc nfsacl_desc = { ++ .desc = { ++ .elem_size = elem_size, ++ .array_len = encode_entries ? entries : 0, ++ .xcode = xdr_nfsace_encode, ++ }, ++ .acl = acl, ++ .typeflag = typeflag, ++ .uid = inode->i_uid, ++ .gid = inode->i_gid, ++ }; ++ struct nfsacl_simple_acl aclbuf; ++ unsigned int base; ++ int err; ++ ++ if (entries > NFS_ACL_MAX_ENTRIES) ++ return false; ++ if (xdr_stream_encode_u32(xdr, entries) < 0) ++ return false; ++ ++ if (encode_entries && acl && acl->a_count == 3) { ++ struct posix_acl *acl2 = &aclbuf.acl; ++ ++ /* Avoid the use of posix_acl_alloc(). nfsacl_encode() is ++ * invoked in contexts where a memory allocation failure is ++ * fatal. Fortunately this fake ACL is small enough to ++ * construct on the stack. */ ++ posix_acl_init(acl2, 4); ++ ++ /* Insert entries in canonical order: other orders seem ++ to confuse Solaris VxFS. */ ++ acl2->a_entries[0] = acl->a_entries[0]; /* ACL_USER_OBJ */ ++ acl2->a_entries[1] = acl->a_entries[1]; /* ACL_GROUP_OBJ */ ++ acl2->a_entries[2] = acl->a_entries[1]; /* ACL_MASK */ ++ acl2->a_entries[2].e_tag = ACL_MASK; ++ acl2->a_entries[3] = acl->a_entries[2]; /* ACL_OTHER */ ++ nfsacl_desc.acl = acl2; ++ } ++ ++ base = xdr_stream_pos(xdr); ++ if (!xdr_reserve_space(xdr, XDR_UNIT + ++ elem_size * nfsacl_desc.desc.array_len)) ++ return false; ++ err = xdr_encode_array2(xdr->buf, base, &nfsacl_desc.desc); ++ if (err) ++ return false; ++ ++ return true; ++} ++EXPORT_SYMBOL_GPL(nfs_stream_encode_acl); ++ ++ + struct nfsacl_decode_desc { + struct xdr_array2_desc desc; + unsigned int count; +diff --git a/include/linux/nfsacl.h b/include/linux/nfsacl.h +index 0ba99c5136491..8e76a79cdc6ae 100644 +--- a/include/linux/nfsacl.h ++++ b/include/linux/nfsacl.h +@@ -41,5 +41,8 @@ nfsacl_decode(struct xdr_buf *buf, unsigned int base, unsigned int *aclcnt, + extern bool + nfs_stream_decode_acl(struct xdr_stream *xdr, unsigned int *aclcnt, + struct posix_acl **pacl); ++extern bool ++nfs_stream_encode_acl(struct xdr_stream *xdr, struct inode *inode, ++ struct posix_acl *acl, int encode_entries, int typeflag); + + #endif /* __LINUX_NFSACL_H */ +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-cb_lost-tracepoint.patch b/queue-5.10/nfsd-add-cb_lost-tracepoint.patch new file mode 100644 index 00000000000..5c39d5a6ff5 --- /dev/null +++ b/queue-5.10/nfsd-add-cb_lost-tracepoint.patch @@ -0,0 +1,48 @@ +From 049acefdfa1b4f4ce76b9dd885c3664dae389485 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 14 May 2021 15:56:43 -0400 +Subject: NFSD: Add cb_lost tracepoint + +From: Chuck Lever + +[ Upstream commit 806d65b617d89be887fe68bfa051f78143669cd7 ] + +Provide more clarity about when the callback channel is in trouble. + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 2 ++ + fs/nfsd/trace.h | 1 + + 2 files changed, 3 insertions(+) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index adf476cbf36c3..a8aa3680605bb 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -1763,6 +1763,8 @@ static void nfsd4_conn_lost(struct svc_xpt_user *u) + struct nfsd4_conn *c = container_of(u, struct nfsd4_conn, cn_xpt_user); + struct nfs4_client *clp = c->cn_session->se_client; + ++ trace_nfsd_cb_lost(clp); ++ + spin_lock(&clp->cl_lock); + if (!list_empty(&c->cn_persession)) { + list_del(&c->cn_persession); +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index 3683076e0fcd3..afffb4912acbc 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -912,6 +912,7 @@ DEFINE_EVENT(nfsd_cb_class, nfsd_cb_##name, \ + + DEFINE_NFSD_CB_EVENT(setup); + DEFINE_NFSD_CB_EVENT(state); ++DEFINE_NFSD_CB_EVENT(lost); + DEFINE_NFSD_CB_EVENT(shutdown); + + TRACE_DEFINE_ENUM(RPC_AUTH_NULL); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-common-helpers-to-decode-void-args-and-enco.patch b/queue-5.10/nfsd-add-common-helpers-to-decode-void-args-and-enco.patch new file mode 100644 index 00000000000..8e7d370431b --- /dev/null +++ b/queue-5.10/nfsd-add-common-helpers-to-decode-void-args-and-enco.patch @@ -0,0 +1,406 @@ +From ddba6cce20db50d3fe9f17d6273ac84efb5fc86e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Nov 2020 14:48:29 -0500 +Subject: NFSD: Add common helpers to decode void args and encode void results + +From: Chuck Lever + +[ Upstream commit 788f7183fba86b46074c16e7d57ea09302badff4 ] + +Start off the conversion to xdr_stream by de-duplicating the functions +that decode void arguments and encode void results. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs2acl.c | 21 ++++----------------- + fs/nfsd/nfs3acl.c | 8 ++++---- + fs/nfsd/nfs3proc.c | 10 ++++------ + fs/nfsd/nfs3xdr.c | 11 ----------- + fs/nfsd/nfs4proc.c | 11 ++++------- + fs/nfsd/nfs4xdr.c | 12 ------------ + fs/nfsd/nfsd.h | 8 ++++++++ + fs/nfsd/nfsproc.c | 25 ++++++++++++------------- + fs/nfsd/nfssvc.c | 28 ++++++++++++++++++++++++++++ + fs/nfsd/nfsxdr.c | 10 ---------- + fs/nfsd/xdr.h | 2 -- + fs/nfsd/xdr3.h | 2 -- + fs/nfsd/xdr4.h | 2 -- + 13 files changed, 64 insertions(+), 86 deletions(-) + +diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c +index 6a900f770dd23..b0f66604532a5 100644 +--- a/fs/nfsd/nfs2acl.c ++++ b/fs/nfsd/nfs2acl.c +@@ -185,10 +185,6 @@ static __be32 nfsacld_proc_access(struct svc_rqst *rqstp) + /* + * XDR decode functions + */ +-static int nfsaclsvc_decode_voidarg(struct svc_rqst *rqstp, __be32 *p) +-{ +- return 1; +-} + + static int nfsaclsvc_decode_getaclargs(struct svc_rqst *rqstp, __be32 *p) + { +@@ -255,15 +251,6 @@ static int nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, __be32 *p) + * XDR encode functions + */ + +-/* +- * There must be an encoding function for void results so svc_process +- * will work properly. +- */ +-static int nfsaclsvc_encode_voidres(struct svc_rqst *rqstp, __be32 *p) +-{ +- return xdr_ressize_check(rqstp, p); +-} +- + /* GETACL */ + static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p) + { +@@ -378,10 +365,10 @@ struct nfsd3_voidargs { int dummy; }; + static const struct svc_procedure nfsd_acl_procedures2[5] = { + [ACLPROC2_NULL] = { + .pc_func = nfsacld_proc_null, +- .pc_decode = nfsaclsvc_decode_voidarg, +- .pc_encode = nfsaclsvc_encode_voidres, +- .pc_argsize = sizeof(struct nfsd3_voidargs), +- .pc_ressize = sizeof(struct nfsd3_voidargs), ++ .pc_decode = nfssvc_decode_voidarg, ++ .pc_encode = nfssvc_encode_voidres, ++ .pc_argsize = sizeof(struct nfsd_voidargs), ++ .pc_ressize = sizeof(struct nfsd_voidres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST, + }, +diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c +index 34a394e50e1d1..7c30876a31a1b 100644 +--- a/fs/nfsd/nfs3acl.c ++++ b/fs/nfsd/nfs3acl.c +@@ -245,10 +245,10 @@ struct nfsd3_voidargs { int dummy; }; + static const struct svc_procedure nfsd_acl_procedures3[3] = { + [ACLPROC3_NULL] = { + .pc_func = nfsd3_proc_null, +- .pc_decode = nfs3svc_decode_voidarg, +- .pc_encode = nfs3svc_encode_voidres, +- .pc_argsize = sizeof(struct nfsd3_voidargs), +- .pc_ressize = sizeof(struct nfsd3_voidargs), ++ .pc_decode = nfssvc_decode_voidarg, ++ .pc_encode = nfssvc_encode_voidres, ++ .pc_argsize = sizeof(struct nfsd_voidargs), ++ .pc_ressize = sizeof(struct nfsd_voidres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST, + }, +diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c +index eba84417406ca..3257233d1a655 100644 +--- a/fs/nfsd/nfs3proc.c ++++ b/fs/nfsd/nfs3proc.c +@@ -697,8 +697,6 @@ nfsd3_proc_commit(struct svc_rqst *rqstp) + #define nfsd3_attrstatres nfsd3_attrstat + #define nfsd3_wccstatres nfsd3_attrstat + #define nfsd3_createres nfsd3_diropres +-#define nfsd3_voidres nfsd3_voidargs +-struct nfsd3_voidargs { int dummy; }; + + #define ST 1 /* status*/ + #define FH 17 /* filehandle with length */ +@@ -709,10 +707,10 @@ struct nfsd3_voidargs { int dummy; }; + static const struct svc_procedure nfsd_procedures3[22] = { + [NFS3PROC_NULL] = { + .pc_func = nfsd3_proc_null, +- .pc_decode = nfs3svc_decode_voidarg, +- .pc_encode = nfs3svc_encode_voidres, +- .pc_argsize = sizeof(struct nfsd3_voidargs), +- .pc_ressize = sizeof(struct nfsd3_voidres), ++ .pc_decode = nfssvc_decode_voidarg, ++ .pc_encode = nfssvc_encode_voidres, ++ .pc_argsize = sizeof(struct nfsd_voidargs), ++ .pc_ressize = sizeof(struct nfsd_voidres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST, + }, +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index 27b24823f7c42..0d75d201db1b3 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -304,11 +304,6 @@ void fill_post_wcc(struct svc_fh *fhp) + /* + * XDR decode functions + */ +-int +-nfs3svc_decode_voidarg(struct svc_rqst *rqstp, __be32 *p) +-{ +- return 1; +-} + + int + nfs3svc_decode_fhandle(struct svc_rqst *rqstp, __be32 *p) +@@ -642,12 +637,6 @@ nfs3svc_decode_commitargs(struct svc_rqst *rqstp, __be32 *p) + * XDR encode functions + */ + +-int +-nfs3svc_encode_voidres(struct svc_rqst *rqstp, __be32 *p) +-{ +- return xdr_ressize_check(rqstp, p); +-} +- + /* GETATTR */ + int + nfs3svc_encode_attrstat(struct svc_rqst *rqstp, __be32 *p) +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index c01b6f7462fcb..55a46e7c152b9 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -3285,16 +3285,13 @@ static const char *nfsd4_op_name(unsigned opnum) + return "unknown_operation"; + } + +-#define nfsd4_voidres nfsd4_voidargs +-struct nfsd4_voidargs { int dummy; }; +- + static const struct svc_procedure nfsd_procedures4[2] = { + [NFSPROC4_NULL] = { + .pc_func = nfsd4_proc_null, +- .pc_decode = nfs4svc_decode_voidarg, +- .pc_encode = nfs4svc_encode_voidres, +- .pc_argsize = sizeof(struct nfsd4_voidargs), +- .pc_ressize = sizeof(struct nfsd4_voidres), ++ .pc_decode = nfssvc_decode_voidarg, ++ .pc_encode = nfssvc_encode_voidres, ++ .pc_argsize = sizeof(struct nfsd_voidargs), ++ .pc_ressize = sizeof(struct nfsd_voidres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = 1, + }, +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index fd9107332a20f..c176d0090f7c8 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -5288,12 +5288,6 @@ nfsd4_encode_replay(struct xdr_stream *xdr, struct nfsd4_op *op) + p = xdr_encode_opaque_fixed(p, rp->rp_buf, rp->rp_buflen); + } + +-int +-nfs4svc_encode_voidres(struct svc_rqst *rqstp, __be32 *p) +-{ +- return xdr_ressize_check(rqstp, p); +-} +- + void nfsd4_release_compoundargs(struct svc_rqst *rqstp) + { + struct nfsd4_compoundargs *args = rqstp->rq_argp; +@@ -5311,12 +5305,6 @@ void nfsd4_release_compoundargs(struct svc_rqst *rqstp) + } + } + +-int +-nfs4svc_decode_voidarg(struct svc_rqst *rqstp, __be32 *p) +-{ +- return 1; +-} +- + int + nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, __be32 *p) + { +diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h +index 4362d295ed340..3eaa81e001f9c 100644 +--- a/fs/nfsd/nfsd.h ++++ b/fs/nfsd/nfsd.h +@@ -73,6 +73,14 @@ extern unsigned long nfsd_drc_mem_used; + + extern const struct seq_operations nfs_exports_op; + ++/* ++ * Common void argument and result helpers ++ */ ++struct nfsd_voidargs { }; ++struct nfsd_voidres { }; ++int nfssvc_decode_voidarg(struct svc_rqst *rqstp, __be32 *p); ++int nfssvc_encode_voidres(struct svc_rqst *rqstp, __be32 *p); ++ + /* + * Function prototypes. + */ +diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c +index bbd01e8397f6e..dbd8d36046539 100644 +--- a/fs/nfsd/nfsproc.c ++++ b/fs/nfsd/nfsproc.c +@@ -609,7 +609,6 @@ nfsd_proc_statfs(struct svc_rqst *rqstp) + * NFSv2 Server procedures. + * Only the results of non-idempotent operations are cached. + */ +-struct nfsd_void { int dummy; }; + + #define ST 1 /* status */ + #define FH 8 /* filehandle */ +@@ -618,10 +617,10 @@ struct nfsd_void { int dummy; }; + static const struct svc_procedure nfsd_procedures2[18] = { + [NFSPROC_NULL] = { + .pc_func = nfsd_proc_null, +- .pc_decode = nfssvc_decode_void, +- .pc_encode = nfssvc_encode_void, +- .pc_argsize = sizeof(struct nfsd_void), +- .pc_ressize = sizeof(struct nfsd_void), ++ .pc_decode = nfssvc_decode_voidarg, ++ .pc_encode = nfssvc_encode_voidres, ++ .pc_argsize = sizeof(struct nfsd_voidargs), ++ .pc_ressize = sizeof(struct nfsd_voidres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = 0, + }, +@@ -647,10 +646,10 @@ static const struct svc_procedure nfsd_procedures2[18] = { + }, + [NFSPROC_ROOT] = { + .pc_func = nfsd_proc_root, +- .pc_decode = nfssvc_decode_void, +- .pc_encode = nfssvc_encode_void, +- .pc_argsize = sizeof(struct nfsd_void), +- .pc_ressize = sizeof(struct nfsd_void), ++ .pc_decode = nfssvc_decode_voidarg, ++ .pc_encode = nfssvc_encode_voidres, ++ .pc_argsize = sizeof(struct nfsd_voidargs), ++ .pc_ressize = sizeof(struct nfsd_voidres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = 0, + }, +@@ -685,10 +684,10 @@ static const struct svc_procedure nfsd_procedures2[18] = { + }, + [NFSPROC_WRITECACHE] = { + .pc_func = nfsd_proc_writecache, +- .pc_decode = nfssvc_decode_void, +- .pc_encode = nfssvc_encode_void, +- .pc_argsize = sizeof(struct nfsd_void), +- .pc_ressize = sizeof(struct nfsd_void), ++ .pc_decode = nfssvc_decode_voidarg, ++ .pc_encode = nfssvc_encode_voidres, ++ .pc_argsize = sizeof(struct nfsd_voidargs), ++ .pc_ressize = sizeof(struct nfsd_voidres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = 0, + }, +diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c +index 311b287c5024f..c81d49b07971c 100644 +--- a/fs/nfsd/nfssvc.c ++++ b/fs/nfsd/nfssvc.c +@@ -1107,6 +1107,34 @@ int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) + return 1; + } + ++/** ++ * nfssvc_decode_voidarg - Decode void arguments ++ * @rqstp: Server RPC transaction context ++ * @p: buffer containing arguments to decode ++ * ++ * Return values: ++ * %0: Arguments were not valid ++ * %1: Decoding was successful ++ */ ++int nfssvc_decode_voidarg(struct svc_rqst *rqstp, __be32 *p) ++{ ++ return 1; ++} ++ ++/** ++ * nfssvc_encode_voidres - Encode void results ++ * @rqstp: Server RPC transaction context ++ * @p: buffer in which to encode results ++ * ++ * Return values: ++ * %0: Local error while encoding ++ * %1: Encoding was successful ++ */ ++int nfssvc_encode_voidres(struct svc_rqst *rqstp, __be32 *p) ++{ ++ return xdr_ressize_check(rqstp, p); ++} ++ + int nfsd_pool_stats_open(struct inode *inode, struct file *file) + { + int ret; +diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c +index 9e00a902113e3..7aa6e8aca2c1a 100644 +--- a/fs/nfsd/nfsxdr.c ++++ b/fs/nfsd/nfsxdr.c +@@ -192,11 +192,6 @@ __be32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *f + /* + * XDR decode functions + */ +-int +-nfssvc_decode_void(struct svc_rqst *rqstp, __be32 *p) +-{ +- return xdr_argsize_check(rqstp, p); +-} + + int + nfssvc_decode_fhandle(struct svc_rqst *rqstp, __be32 *p) +@@ -423,11 +418,6 @@ nfssvc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p) + /* + * XDR encode functions + */ +-int +-nfssvc_encode_void(struct svc_rqst *rqstp, __be32 *p) +-{ +- return xdr_ressize_check(rqstp, p); +-} + + int + nfssvc_encode_stat(struct svc_rqst *rqstp, __be32 *p) +diff --git a/fs/nfsd/xdr.h b/fs/nfsd/xdr.h +index b8cc6a4b2e0ec..edd87688ff863 100644 +--- a/fs/nfsd/xdr.h ++++ b/fs/nfsd/xdr.h +@@ -144,7 +144,6 @@ union nfsd_xdrstore { + #define NFS2_SVC_XDRSIZE sizeof(union nfsd_xdrstore) + + +-int nfssvc_decode_void(struct svc_rqst *, __be32 *); + int nfssvc_decode_fhandle(struct svc_rqst *, __be32 *); + int nfssvc_decode_sattrargs(struct svc_rqst *, __be32 *); + int nfssvc_decode_diropargs(struct svc_rqst *, __be32 *); +@@ -156,7 +155,6 @@ int nfssvc_decode_readlinkargs(struct svc_rqst *, __be32 *); + int nfssvc_decode_linkargs(struct svc_rqst *, __be32 *); + int nfssvc_decode_symlinkargs(struct svc_rqst *, __be32 *); + int nfssvc_decode_readdirargs(struct svc_rqst *, __be32 *); +-int nfssvc_encode_void(struct svc_rqst *, __be32 *); + int nfssvc_encode_stat(struct svc_rqst *, __be32 *); + int nfssvc_encode_attrstat(struct svc_rqst *, __be32 *); + int nfssvc_encode_diropres(struct svc_rqst *, __be32 *); +diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h +index ae6fa6c9cb467..456fcd7a10383 100644 +--- a/fs/nfsd/xdr3.h ++++ b/fs/nfsd/xdr3.h +@@ -273,7 +273,6 @@ union nfsd3_xdrstore { + + #define NFS3_SVC_XDRSIZE sizeof(union nfsd3_xdrstore) + +-int nfs3svc_decode_voidarg(struct svc_rqst *, __be32 *); + int nfs3svc_decode_fhandle(struct svc_rqst *, __be32 *); + int nfs3svc_decode_sattrargs(struct svc_rqst *, __be32 *); + int nfs3svc_decode_diropargs(struct svc_rqst *, __be32 *); +@@ -290,7 +289,6 @@ int nfs3svc_decode_symlinkargs(struct svc_rqst *, __be32 *); + int nfs3svc_decode_readdirargs(struct svc_rqst *, __be32 *); + int nfs3svc_decode_readdirplusargs(struct svc_rqst *, __be32 *); + int nfs3svc_decode_commitargs(struct svc_rqst *, __be32 *); +-int nfs3svc_encode_voidres(struct svc_rqst *, __be32 *); + int nfs3svc_encode_attrstat(struct svc_rqst *, __be32 *); + int nfs3svc_encode_wccstat(struct svc_rqst *, __be32 *); + int nfs3svc_encode_diropres(struct svc_rqst *, __be32 *); +diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h +index 679d40af1bbb1..37f89ad5e9923 100644 +--- a/fs/nfsd/xdr4.h ++++ b/fs/nfsd/xdr4.h +@@ -781,8 +781,6 @@ set_change_info(struct nfsd4_change_info *cinfo, struct svc_fh *fhp) + + + bool nfsd4_mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp); +-int nfs4svc_decode_voidarg(struct svc_rqst *, __be32 *); +-int nfs4svc_encode_voidres(struct svc_rqst *, __be32 *); + int nfs4svc_decode_compoundargs(struct svc_rqst *, __be32 *); + int nfs4svc_encode_compoundres(struct svc_rqst *, __be32 *); + __be32 nfsd4_check_resp_size(struct nfsd4_compoundres *, u32); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-courteous-server-support-for-thread-with-on.patch b/queue-5.10/nfsd-add-courteous-server-support-for-thread-with-on.patch new file mode 100644 index 00000000000..37641f9370f --- /dev/null +++ b/queue-5.10/nfsd-add-courteous-server-support-for-thread-with-on.patch @@ -0,0 +1,278 @@ +From 455014ab9cabdd870f0e44b267646fe9fe0812a0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 May 2022 14:19:21 -0700 +Subject: NFSD: add courteous server support for thread with only delegation + +From: Dai Ngo + +[ Upstream commit 66af25799940b26efd41ea6e648f75c41a48a2c2 ] + +This patch provides courteous server support for delegation only. +Only expired client with delegation but no conflict and no open +or lock state is allowed to be in COURTESY state. + +Delegation conflict with COURTESY/EXPIRABLE client is resolved by +setting it to EXPIRABLE, queue work for the laundromat and return +delay to the caller. Conflict is resolved when the laudromat runs +and expires the EXIRABLE client while the NFS client retries the +OPEN request. Local thread request that gets conflict is doing the +retry in _break_lease. + +Client in COURTESY or EXPIRABLE state is allowed to reconnect and +continues to have access to its state. Access to the nfs4_client by +the reconnecting thread and the laundromat is serialized via the +client_lock. + +Reviewed-by: J. Bruce Fields +Signed-off-by: Dai Ngo +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 82 ++++++++++++++++++++++++++++++++++++--------- + fs/nfsd/nfsd.h | 1 + + fs/nfsd/state.h | 31 +++++++++++++++++ + 3 files changed, 99 insertions(+), 15 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 0170aaf318ea2..74c0a88904047 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -125,6 +125,8 @@ static void free_session(struct nfsd4_session *); + static const struct nfsd4_callback_ops nfsd4_cb_recall_ops; + static const struct nfsd4_callback_ops nfsd4_cb_notify_lock_ops; + ++static struct workqueue_struct *laundry_wq; ++ + static bool is_session_dead(struct nfsd4_session *ses) + { + return ses->se_flags & NFS4_SESSION_DEAD; +@@ -152,6 +154,7 @@ static __be32 get_client_locked(struct nfs4_client *clp) + if (is_client_expired(clp)) + return nfserr_expired; + atomic_inc(&clp->cl_rpc_users); ++ clp->cl_state = NFSD4_ACTIVE; + return nfs_ok; + } + +@@ -172,6 +175,7 @@ renew_client_locked(struct nfs4_client *clp) + + list_move_tail(&clp->cl_lru, &nn->client_lru); + clp->cl_time = ktime_get_boottime_seconds(); ++ clp->cl_state = NFSD4_ACTIVE; + } + + static void put_client_renew_locked(struct nfs4_client *clp) +@@ -1102,6 +1106,7 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_file *fp, + get_clnt_odstate(odstate); + dp->dl_type = NFS4_OPEN_DELEGATE_READ; + dp->dl_retries = 1; ++ dp->dl_recalled = false; + nfsd4_init_cb(&dp->dl_recall, dp->dl_stid.sc_client, + &nfsd4_cb_recall_ops, NFSPROC4_CLNT_CB_RECALL); + get_nfs4_file(fp); +@@ -2017,6 +2022,8 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name) + idr_init(&clp->cl_stateids); + atomic_set(&clp->cl_rpc_users, 0); + clp->cl_cb_state = NFSD4_CB_UNKNOWN; ++ clp->cl_state = NFSD4_ACTIVE; ++ atomic_set(&clp->cl_delegs_in_recall, 0); + INIT_LIST_HEAD(&clp->cl_idhash); + INIT_LIST_HEAD(&clp->cl_openowners); + INIT_LIST_HEAD(&clp->cl_delegations); +@@ -4711,9 +4718,18 @@ nfsd_break_deleg_cb(struct file_lock *fl) + bool ret = false; + struct nfs4_delegation *dp = (struct nfs4_delegation *)fl->fl_owner; + struct nfs4_file *fp = dp->dl_stid.sc_file; ++ struct nfs4_client *clp = dp->dl_stid.sc_client; ++ struct nfsd_net *nn; + + trace_nfsd_cb_recall(&dp->dl_stid); + ++ dp->dl_recalled = true; ++ atomic_inc(&clp->cl_delegs_in_recall); ++ if (try_to_expire_client(clp)) { ++ nn = net_generic(clp->net, nfsd_net_id); ++ mod_delayed_work(laundry_wq, &nn->laundromat_work, 0); ++ } ++ + /* + * We don't want the locks code to timeout the lease for us; + * we'll remove it ourself if a delegation isn't returned +@@ -4756,9 +4772,14 @@ static int + nfsd_change_deleg_cb(struct file_lock *onlist, int arg, + struct list_head *dispose) + { +- if (arg & F_UNLCK) ++ struct nfs4_delegation *dp = (struct nfs4_delegation *)onlist->fl_owner; ++ struct nfs4_client *clp = dp->dl_stid.sc_client; ++ ++ if (arg & F_UNLCK) { ++ if (dp->dl_recalled) ++ atomic_dec(&clp->cl_delegs_in_recall); + return lease_modify(onlist, arg, dispose); +- else ++ } else + return -EAGAIN; + } + +@@ -5622,6 +5643,49 @@ static void nfsd4_ssc_expire_umount(struct nfsd_net *nn) + } + #endif + ++/* ++ * place holder for now, no check for lock blockers yet ++ */ ++static bool ++nfs4_anylock_blockers(struct nfs4_client *clp) ++{ ++ if (atomic_read(&clp->cl_delegs_in_recall) || ++ client_has_openowners(clp) || ++ !list_empty(&clp->async_copies)) ++ return true; ++ return false; ++} ++ ++static void ++nfs4_get_client_reaplist(struct nfsd_net *nn, struct list_head *reaplist, ++ struct laundry_time *lt) ++{ ++ struct list_head *pos, *next; ++ struct nfs4_client *clp; ++ ++ INIT_LIST_HEAD(reaplist); ++ spin_lock(&nn->client_lock); ++ list_for_each_safe(pos, next, &nn->client_lru) { ++ clp = list_entry(pos, struct nfs4_client, cl_lru); ++ if (clp->cl_state == NFSD4_EXPIRABLE) ++ goto exp_client; ++ if (!state_expired(lt, clp->cl_time)) ++ break; ++ if (!atomic_read(&clp->cl_rpc_users)) ++ clp->cl_state = NFSD4_COURTESY; ++ if (!client_has_state(clp) || ++ ktime_get_boottime_seconds() >= ++ (clp->cl_time + NFSD_COURTESY_CLIENT_TIMEOUT)) ++ goto exp_client; ++ if (nfs4_anylock_blockers(clp)) { ++exp_client: ++ if (!mark_client_expired_locked(clp)) ++ list_add(&clp->cl_lru, reaplist); ++ } ++ } ++ spin_unlock(&nn->client_lock); ++} ++ + static time64_t + nfs4_laundromat(struct nfsd_net *nn) + { +@@ -5644,7 +5708,6 @@ nfs4_laundromat(struct nfsd_net *nn) + goto out; + } + nfsd4_end_grace(nn); +- INIT_LIST_HEAD(&reaplist); + + spin_lock(&nn->s2s_cp_lock); + idr_for_each_entry(&nn->s2s_cp_stateids, cps_t, i) { +@@ -5654,17 +5717,7 @@ nfs4_laundromat(struct nfsd_net *nn) + _free_cpntf_state_locked(nn, cps); + } + spin_unlock(&nn->s2s_cp_lock); +- +- spin_lock(&nn->client_lock); +- list_for_each_safe(pos, next, &nn->client_lru) { +- clp = list_entry(pos, struct nfs4_client, cl_lru); +- if (!state_expired(<, clp->cl_time)) +- break; +- if (mark_client_expired_locked(clp)) +- continue; +- list_add(&clp->cl_lru, &reaplist); +- } +- spin_unlock(&nn->client_lock); ++ nfs4_get_client_reaplist(nn, &reaplist, <); + list_for_each_safe(pos, next, &reaplist) { + clp = list_entry(pos, struct nfs4_client, cl_lru); + trace_nfsd_clid_purged(&clp->cl_clientid); +@@ -5739,7 +5792,6 @@ nfs4_laundromat(struct nfsd_net *nn) + return max_t(time64_t, lt.new_timeo, NFSD_LAUNDROMAT_MINTIMEOUT); + } + +-static struct workqueue_struct *laundry_wq; + static void laundromat_main(struct work_struct *); + + static void +diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h +index 4fc1fd639527a..23996c6ca75e3 100644 +--- a/fs/nfsd/nfsd.h ++++ b/fs/nfsd/nfsd.h +@@ -336,6 +336,7 @@ void nfsd_lockd_shutdown(void); + #define COMPOUND_ERR_SLACK_SPACE 16 /* OP_SETATTR */ + + #define NFSD_LAUNDROMAT_MINTIMEOUT 1 /* seconds */ ++#define NFSD_COURTESY_CLIENT_TIMEOUT (24 * 60 * 60) /* seconds */ + + /* + * The following attributes are currently not supported by the NFSv4 server: +diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h +index 95457cfd37fc0..f3d6313914ed0 100644 +--- a/fs/nfsd/state.h ++++ b/fs/nfsd/state.h +@@ -149,6 +149,7 @@ struct nfs4_delegation { + /* For recall: */ + int dl_retries; + struct nfsd4_callback dl_recall; ++ bool dl_recalled; + }; + + #define cb_to_delegation(cb) \ +@@ -282,6 +283,28 @@ struct nfsd4_sessionid { + + #define HEXDIR_LEN 33 /* hex version of 16 byte md5 of cl_name plus '\0' */ + ++/* ++ * State Meaning Where set ++ * -------------------------------------------------------------------------- ++ * | NFSD4_ACTIVE | Confirmed, active | Default | ++ * |------------------- ----------------------------------------------------| ++ * | NFSD4_COURTESY | Courtesy state. | nfs4_get_client_reaplist | ++ * | | Lease/lock/share | | ++ * | | reservation conflict | | ++ * | | can cause Courtesy | | ++ * | | client to be expired | | ++ * |------------------------------------------------------------------------| ++ * | NFSD4_EXPIRABLE | Courtesy client to be| nfs4_laundromat | ++ * | | expired by Laundromat| try_to_expire_client | ++ * | | due to conflict | | ++ * |------------------------------------------------------------------------| ++ */ ++enum { ++ NFSD4_ACTIVE = 0, ++ NFSD4_COURTESY, ++ NFSD4_EXPIRABLE, ++}; ++ + /* + * struct nfs4_client - one per client. Clientids live here. + * +@@ -385,6 +408,9 @@ struct nfs4_client { + struct list_head async_copies; /* list of async copies */ + spinlock_t async_lock; /* lock for async copies */ + atomic_t cl_cb_inflight; /* Outstanding callbacks */ ++ ++ unsigned int cl_state; ++ atomic_t cl_delegs_in_recall; + }; + + /* struct nfs4_client_reset +@@ -702,4 +728,9 @@ extern void nfsd4_client_record_remove(struct nfs4_client *clp); + extern int nfsd4_client_record_check(struct nfs4_client *clp); + extern void nfsd4_record_grace_done(struct nfsd_net *nn); + ++static inline bool try_to_expire_client(struct nfs4_client *clp) ++{ ++ cmpxchg(&clp->cl_state, NFSD4_COURTESY, NFSD4_EXPIRABLE); ++ return clp->cl_state == NFSD4_EXPIRABLE; ++} + #endif /* NFSD4_STATE_H */ +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-delegation-reaper-to-react-to-low-memory-co.patch b/queue-5.10/nfsd-add-delegation-reaper-to-react-to-low-memory-co.patch new file mode 100644 index 00000000000..e58b6d880b7 --- /dev/null +++ b/queue-5.10/nfsd-add-delegation-reaper-to-react-to-low-memory-co.patch @@ -0,0 +1,213 @@ +From 223703d1aeba6061a5686fa582f430d4b874617e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 16 Nov 2022 19:44:47 -0800 +Subject: NFSD: add delegation reaper to react to low memory condition + +From: Dai Ngo + +[ Upstream commit 44df6f439a1790a5f602e3842879efa88f346672 ] + +The delegation reaper is called by nfsd memory shrinker's on +the 'count' callback. It scans the client list and sends the +courtesy CB_RECALL_ANY to the clients that hold delegations. + +To avoid flooding the clients with CB_RECALL_ANY requests, the +delegation reaper sends only one CB_RECALL_ANY request to each +client per 5 seconds. + +Signed-off-by: Dai Ngo +[ cel: moved definition of RCA4_TYPE_MASK_RDATA_DLG ] +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 88 ++++++++++++++++++++++++++++++++++++++++++-- + fs/nfsd/state.h | 5 +++ + include/linux/nfs4.h | 13 +++++++ + 3 files changed, 102 insertions(+), 4 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 8fdf5ab5b9e47..4e05ad774c861 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -2144,6 +2144,7 @@ static void __free_client(struct kref *k) + kfree(clp->cl_nii_domain.data); + kfree(clp->cl_nii_name.data); + idr_destroy(&clp->cl_stateids); ++ kfree(clp->cl_ra); + kmem_cache_free(client_slab, clp); + } + +@@ -2871,6 +2872,36 @@ static const struct tree_descr client_files[] = { + [3] = {""}, + }; + ++static int ++nfsd4_cb_recall_any_done(struct nfsd4_callback *cb, ++ struct rpc_task *task) ++{ ++ switch (task->tk_status) { ++ case -NFS4ERR_DELAY: ++ rpc_delay(task, 2 * HZ); ++ return 0; ++ default: ++ return 1; ++ } ++} ++ ++static void ++nfsd4_cb_recall_any_release(struct nfsd4_callback *cb) ++{ ++ struct nfs4_client *clp = cb->cb_clp; ++ struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); ++ ++ spin_lock(&nn->client_lock); ++ clear_bit(NFSD4_CLIENT_CB_RECALL_ANY, &clp->cl_flags); ++ put_client_renew_locked(clp); ++ spin_unlock(&nn->client_lock); ++} ++ ++static const struct nfsd4_callback_ops nfsd4_cb_recall_any_ops = { ++ .done = nfsd4_cb_recall_any_done, ++ .release = nfsd4_cb_recall_any_release, ++}; ++ + static struct nfs4_client *create_client(struct xdr_netobj name, + struct svc_rqst *rqstp, nfs4_verifier *verf) + { +@@ -2908,6 +2939,14 @@ static struct nfs4_client *create_client(struct xdr_netobj name, + free_client(clp); + return NULL; + } ++ clp->cl_ra = kzalloc(sizeof(*clp->cl_ra), GFP_KERNEL); ++ if (!clp->cl_ra) { ++ free_client(clp); ++ return NULL; ++ } ++ clp->cl_ra_time = 0; ++ nfsd4_init_cb(&clp->cl_ra->ra_cb, clp, &nfsd4_cb_recall_any_ops, ++ NFSPROC4_CLNT_CB_RECALL_ANY); + return clp; + } + +@@ -4363,14 +4402,16 @@ nfsd4_init_slabs(void) + static unsigned long + nfsd4_state_shrinker_count(struct shrinker *shrink, struct shrink_control *sc) + { +- int cnt; ++ int count; + struct nfsd_net *nn = container_of(shrink, + struct nfsd_net, nfsd_client_shrinker); + +- cnt = atomic_read(&nn->nfsd_courtesy_clients); +- if (cnt > 0) ++ count = atomic_read(&nn->nfsd_courtesy_clients); ++ if (!count) ++ count = atomic_long_read(&num_delegations); ++ if (count) + mod_delayed_work(laundry_wq, &nn->nfsd_shrinker_work, 0); +- return (unsigned long)cnt; ++ return (unsigned long)count; + } + + static unsigned long +@@ -6159,6 +6200,44 @@ courtesy_client_reaper(struct nfsd_net *nn) + nfs4_process_client_reaplist(&reaplist); + } + ++static void ++deleg_reaper(struct nfsd_net *nn) ++{ ++ struct list_head *pos, *next; ++ struct nfs4_client *clp; ++ struct list_head cblist; ++ ++ INIT_LIST_HEAD(&cblist); ++ spin_lock(&nn->client_lock); ++ list_for_each_safe(pos, next, &nn->client_lru) { ++ clp = list_entry(pos, struct nfs4_client, cl_lru); ++ if (clp->cl_state != NFSD4_ACTIVE || ++ list_empty(&clp->cl_delegations) || ++ atomic_read(&clp->cl_delegs_in_recall) || ++ test_bit(NFSD4_CLIENT_CB_RECALL_ANY, &clp->cl_flags) || ++ (ktime_get_boottime_seconds() - ++ clp->cl_ra_time < 5)) { ++ continue; ++ } ++ list_add(&clp->cl_ra_cblist, &cblist); ++ ++ /* release in nfsd4_cb_recall_any_release */ ++ atomic_inc(&clp->cl_rpc_users); ++ set_bit(NFSD4_CLIENT_CB_RECALL_ANY, &clp->cl_flags); ++ clp->cl_ra_time = ktime_get_boottime_seconds(); ++ } ++ spin_unlock(&nn->client_lock); ++ ++ while (!list_empty(&cblist)) { ++ clp = list_first_entry(&cblist, struct nfs4_client, ++ cl_ra_cblist); ++ list_del_init(&clp->cl_ra_cblist); ++ clp->cl_ra->ra_keep = 0; ++ clp->cl_ra->ra_bmval[0] = BIT(RCA4_TYPE_MASK_RDATA_DLG); ++ nfsd4_run_cb(&clp->cl_ra->ra_cb); ++ } ++} ++ + static void + nfsd4_state_shrinker_worker(struct work_struct *work) + { +@@ -6167,6 +6246,7 @@ nfsd4_state_shrinker_worker(struct work_struct *work) + nfsd_shrinker_work); + + courtesy_client_reaper(nn); ++ deleg_reaper(nn); + } + + static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stid *stp) +diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h +index e30882f8b8516..e94634d305912 100644 +--- a/fs/nfsd/state.h ++++ b/fs/nfsd/state.h +@@ -368,6 +368,7 @@ struct nfs4_client { + #define NFSD4_CLIENT_UPCALL_LOCK (5) /* upcall serialization */ + #define NFSD4_CLIENT_CB_FLAG_MASK (1 << NFSD4_CLIENT_CB_UPDATE | \ + 1 << NFSD4_CLIENT_CB_KILL) ++#define NFSD4_CLIENT_CB_RECALL_ANY (6) + unsigned long cl_flags; + const struct cred *cl_cb_cred; + struct rpc_clnt *cl_cb_client; +@@ -411,6 +412,10 @@ struct nfs4_client { + + unsigned int cl_state; + atomic_t cl_delegs_in_recall; ++ ++ struct nfsd4_cb_recall_any *cl_ra; ++ time64_t cl_ra_time; ++ struct list_head cl_ra_cblist; + }; + + /* struct nfs4_client_reset +diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h +index 5b4c67c91f56a..ea88d0f462c9d 100644 +--- a/include/linux/nfs4.h ++++ b/include/linux/nfs4.h +@@ -717,4 +717,17 @@ enum nfs4_setxattr_options { + SETXATTR4_CREATE = 1, + SETXATTR4_REPLACE = 2, + }; ++ ++enum { ++ RCA4_TYPE_MASK_RDATA_DLG = 0, ++ RCA4_TYPE_MASK_WDATA_DLG = 1, ++ RCA4_TYPE_MASK_DIR_DLG = 2, ++ RCA4_TYPE_MASK_FILE_LAYOUT = 3, ++ RCA4_TYPE_MASK_BLK_LAYOUT = 4, ++ RCA4_TYPE_MASK_OBJ_LAYOUT_MIN = 8, ++ RCA4_TYPE_MASK_OBJ_LAYOUT_MAX = 9, ++ RCA4_TYPE_MASK_OTHER_LAYOUT_MIN = 12, ++ RCA4_TYPE_MASK_OTHER_LAYOUT_MAX = 15, ++}; ++ + #endif +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-documenting-comment-for-nfsd4_release_locko.patch b/queue-5.10/nfsd-add-documenting-comment-for-nfsd4_release_locko.patch new file mode 100644 index 00000000000..63568f3049b --- /dev/null +++ b/queue-5.10/nfsd-add-documenting-comment-for-nfsd4_release_locko.patch @@ -0,0 +1,72 @@ +From dabbfd526043bb9a5cf77d016545d270826c413c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 22 May 2022 12:34:38 -0400 +Subject: NFSD: Add documenting comment for nfsd4_release_lockowner() + +From: Chuck Lever + +[ Upstream commit 043862b09cc00273e35e6c3a6389957953a34207 ] + +And return explicit nfserr values that match what is documented in the +new comment / API contract. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 23 ++++++++++++++++++++--- + 1 file changed, 20 insertions(+), 3 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 1c32765e86b1f..76ec207f5e44d 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -7556,6 +7556,23 @@ check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner) + return status; + } + ++/** ++ * nfsd4_release_lockowner - process NFSv4.0 RELEASE_LOCKOWNER operations ++ * @rqstp: RPC transaction ++ * @cstate: NFSv4 COMPOUND state ++ * @u: RELEASE_LOCKOWNER arguments ++ * ++ * The lockowner's so_count is bumped when a lock record is added ++ * or when copying a conflicting lock. The latter case is brief, ++ * but can lead to fleeting false positives when looking for ++ * locks-in-use. ++ * ++ * Return values: ++ * %nfs_ok: lockowner released or not found ++ * %nfserr_locks_held: lockowner still in use ++ * %nfserr_stale_clientid: clientid no longer active ++ * %nfserr_expired: clientid not recognized ++ */ + __be32 + nfsd4_release_lockowner(struct svc_rqst *rqstp, + struct nfsd4_compound_state *cstate, +@@ -7582,7 +7599,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, + lo = find_lockowner_str_locked(clp, &rlockowner->rl_owner); + if (!lo) { + spin_unlock(&clp->cl_lock); +- return status; ++ return nfs_ok; + } + if (atomic_read(&lo->lo_owner.so_count) != 2) { + spin_unlock(&clp->cl_lock); +@@ -7598,11 +7615,11 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, + put_ol_stateid_locked(stp, &reaplist); + } + spin_unlock(&clp->cl_lock); ++ + free_ol_stateid_reaplist(&reaplist); + remove_blocked_locks(lo); + nfs4_put_stateowner(&lo->lo_owner); +- +- return status; ++ return nfs_ok; + } + + static inline struct nfs4_client_reclaim * +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-errno-mapping-for-eremoteio.patch b/queue-5.10/nfsd-add-errno-mapping-for-eremoteio.patch new file mode 100644 index 00000000000..6be0a1736de --- /dev/null +++ b/queue-5.10/nfsd-add-errno-mapping-for-eremoteio.patch @@ -0,0 +1,36 @@ +From df2e490423e12605cdb997df71080de1a56aa861 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 18 Dec 2021 20:37:55 -0500 +Subject: nfsd: Add errno mapping for EREMOTEIO + +From: Jeff Layton + +[ Upstream commit a2694e51f60c5a18c7e43d1a9feaa46d7f153e65 ] + +The NFS client can occasionally return EREMOTEIO when signalling issues +with the server. ...map to NFSERR_IO. + +Signed-off-by: Jeff Layton +Signed-off-by: Lance Shelton +Signed-off-by: Trond Myklebust +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsproc.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c +index de4b97cdbd2bc..6ed13754290a2 100644 +--- a/fs/nfsd/nfsproc.c ++++ b/fs/nfsd/nfsproc.c +@@ -874,6 +874,7 @@ nfserrno (int errno) + { nfserr_toosmall, -ETOOSMALL }, + { nfserr_serverfault, -ESERVERFAULT }, + { nfserr_serverfault, -ENFILE }, ++ { nfserr_io, -EREMOTEIO }, + { nfserr_io, -EUCLEAN }, + { nfserr_perm, -ENOKEY }, + { nfserr_no_grace, -ENOGRACE}, +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-helper-for-decoding-locker4.patch b/queue-5.10/nfsd-add-helper-for-decoding-locker4.patch new file mode 100644 index 00000000000..dfebec15062 --- /dev/null +++ b/queue-5.10/nfsd-add-helper-for-decoding-locker4.patch @@ -0,0 +1,135 @@ +From 07833d763d18bbf669382a63ed266d70daffd4c3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Nov 2020 17:16:52 -0500 +Subject: NFSD: Add helper for decoding locker4 + +From: Chuck Lever + +[ Upstream commit 8918cc0d2b72db9997390626010b182c4500d749 ] + +Refactor for clarity. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 64 +++++++++++++++++++++++++------------- + include/linux/sunrpc/xdr.h | 21 +++++++++++++ + 2 files changed, 64 insertions(+), 21 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 63140cd4c50e4..15ed5249e2c74 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -833,6 +833,48 @@ nfsd4_decode_link(struct nfsd4_compoundargs *argp, struct nfsd4_link *link) + return nfsd4_decode_component4(argp, &link->li_name, &link->li_namelen); + } + ++static __be32 ++nfsd4_decode_open_to_lock_owner4(struct nfsd4_compoundargs *argp, ++ struct nfsd4_lock *lock) ++{ ++ __be32 status; ++ ++ if (xdr_stream_decode_u32(argp->xdr, &lock->lk_new_open_seqid) < 0) ++ return nfserr_bad_xdr; ++ status = nfsd4_decode_stateid4(argp, &lock->lk_new_open_stateid); ++ if (status) ++ return status; ++ if (xdr_stream_decode_u32(argp->xdr, &lock->lk_new_lock_seqid) < 0) ++ return nfserr_bad_xdr; ++ return nfsd4_decode_state_owner4(argp, &lock->lk_new_clientid, ++ &lock->lk_new_owner); ++} ++ ++static __be32 ++nfsd4_decode_exist_lock_owner4(struct nfsd4_compoundargs *argp, ++ struct nfsd4_lock *lock) ++{ ++ __be32 status; ++ ++ status = nfsd4_decode_stateid4(argp, &lock->lk_old_lock_stateid); ++ if (status) ++ return status; ++ if (xdr_stream_decode_u32(argp->xdr, &lock->lk_old_lock_seqid) < 0) ++ return nfserr_bad_xdr; ++ ++ return nfs_ok; ++} ++ ++static __be32 ++nfsd4_decode_locker4(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock) ++{ ++ if (xdr_stream_decode_bool(argp->xdr, &lock->lk_is_new) < 0) ++ return nfserr_bad_xdr; ++ if (lock->lk_is_new) ++ return nfsd4_decode_open_to_lock_owner4(argp, lock); ++ return nfsd4_decode_exist_lock_owner4(argp, lock); ++} ++ + static __be32 + nfsd4_decode_lock(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock) + { +@@ -848,27 +890,7 @@ nfsd4_decode_lock(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock) + lock->lk_reclaim = be32_to_cpup(p++); + p = xdr_decode_hyper(p, &lock->lk_offset); + p = xdr_decode_hyper(p, &lock->lk_length); +- lock->lk_is_new = be32_to_cpup(p++); +- +- if (lock->lk_is_new) { +- READ_BUF(4); +- lock->lk_new_open_seqid = be32_to_cpup(p++); +- status = nfsd4_decode_stateid(argp, &lock->lk_new_open_stateid); +- if (status) +- return status; +- READ_BUF(4); +- lock->lk_new_lock_seqid = be32_to_cpup(p++); +- status = nfsd4_decode_state_owner4(argp, &lock->lk_new_clientid, +- &lock->lk_new_owner); +- if (status) +- return status; +- } else { +- status = nfsd4_decode_stateid(argp, &lock->lk_old_lock_stateid); +- if (status) +- return status; +- READ_BUF(4); +- lock->lk_old_lock_seqid = be32_to_cpup(p++); +- } ++ status = nfsd4_decode_locker4(argp, lock); + + DECODE_TAIL; + } +diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h +index 6b17575437474..f6569b620beab 100644 +--- a/include/linux/sunrpc/xdr.h ++++ b/include/linux/sunrpc/xdr.h +@@ -548,6 +548,27 @@ static inline bool xdr_item_is_present(const __be32 *p) + return *p != xdr_zero; + } + ++/** ++ * xdr_stream_decode_bool - Decode a boolean ++ * @xdr: pointer to xdr_stream ++ * @ptr: pointer to a u32 in which to store the result ++ * ++ * Return values: ++ * %0 on success ++ * %-EBADMSG on XDR buffer overflow ++ */ ++static inline ssize_t ++xdr_stream_decode_bool(struct xdr_stream *xdr, __u32 *ptr) ++{ ++ const size_t count = sizeof(*ptr); ++ __be32 *p = xdr_inline_decode(xdr, count); ++ ++ if (unlikely(!p)) ++ return -EBADMSG; ++ *ptr = (*p != xdr_zero); ++ return 0; ++} ++ + /** + * xdr_stream_decode_u32 - Decode a 32-bit integer + * @xdr: pointer to xdr_stream +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-helper-to-decode-nfsv4-verifiers.patch b/queue-5.10/nfsd-add-helper-to-decode-nfsv4-verifiers.patch new file mode 100644 index 00000000000..9d4068d48ad --- /dev/null +++ b/queue-5.10/nfsd-add-helper-to-decode-nfsv4-verifiers.patch @@ -0,0 +1,65 @@ +From 58ed7e4d3c98bac7205628cf05842f033eecd502 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Nov 2020 17:34:01 -0500 +Subject: NFSD: Add helper to decode NFSv4 verifiers + +From: Chuck Lever + +[ Upstream commit 796dd1c6b680959ac968b52aa507911b288b1749 ] + +This helper will be used to simplify decoders in subsequent +patches. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 22 ++++++++++++++++++---- + 1 file changed, 18 insertions(+), 4 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 431ab9d604be7..1a2dc52c4340b 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -284,6 +284,18 @@ nfsd4_decode_nfstime4(struct nfsd4_compoundargs *argp, struct timespec64 *tv) + return nfs_ok; + } + ++static __be32 ++nfsd4_decode_verifier4(struct nfsd4_compoundargs *argp, nfs4_verifier *verf) ++{ ++ __be32 *p; ++ ++ p = xdr_inline_decode(argp->xdr, NFS4_VERIFIER_SIZE); ++ if (!p) ++ return nfserr_bad_xdr; ++ memcpy(verf->data, p, sizeof(verf->data)); ++ return nfs_ok; ++} ++ + static __be32 + nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval) + { +@@ -1047,14 +1059,16 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) + goto out; + break; + case NFS4_CREATE_EXCLUSIVE: +- READ_BUF(NFS4_VERIFIER_SIZE); +- COPYMEM(open->op_verf.data, NFS4_VERIFIER_SIZE); ++ status = nfsd4_decode_verifier4(argp, &open->op_verf); ++ if (status) ++ return status; + break; + case NFS4_CREATE_EXCLUSIVE4_1: + if (argp->minorversion < 1) + goto xdr_error; +- READ_BUF(NFS4_VERIFIER_SIZE); +- COPYMEM(open->op_verf.data, NFS4_VERIFIER_SIZE); ++ status = nfsd4_decode_verifier4(argp, &open->op_verf); ++ if (status) ++ return status; + status = nfsd4_decode_fattr4(argp, open->op_bmval, + ARRAY_SIZE(open->op_bmval), + &open->op_iattr, &open->op_acl, +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-helper-to-decode-open-s-createhow4-argument.patch b/queue-5.10/nfsd-add-helper-to-decode-open-s-createhow4-argument.patch new file mode 100644 index 00000000000..5876266420b --- /dev/null +++ b/queue-5.10/nfsd-add-helper-to-decode-open-s-createhow4-argument.patch @@ -0,0 +1,116 @@ +From 5752268418d59189904ee46943091838abd4d42c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Nov 2020 17:37:42 -0500 +Subject: NFSD: Add helper to decode OPEN's createhow4 argument + +From: Chuck Lever + +[ Upstream commit bf33bab3c4182cdd795983f14de5606e82fab377 ] + +Refactor for clarity. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 78 +++++++++++++++++++++++++++-------------------- + 1 file changed, 45 insertions(+), 33 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 1a2dc52c4340b..62096b2a57b35 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -946,6 +946,48 @@ nfsd4_decode_lookup(struct nfsd4_compoundargs *argp, struct nfsd4_lookup *lookup + return nfsd4_decode_component4(argp, &lookup->lo_name, &lookup->lo_len); + } + ++static __be32 ++nfsd4_decode_createhow4(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) ++{ ++ __be32 status; ++ ++ if (xdr_stream_decode_u32(argp->xdr, &open->op_createmode) < 0) ++ return nfserr_bad_xdr; ++ switch (open->op_createmode) { ++ case NFS4_CREATE_UNCHECKED: ++ case NFS4_CREATE_GUARDED: ++ status = nfsd4_decode_fattr4(argp, open->op_bmval, ++ ARRAY_SIZE(open->op_bmval), ++ &open->op_iattr, &open->op_acl, ++ &open->op_label, &open->op_umask); ++ if (status) ++ return status; ++ break; ++ case NFS4_CREATE_EXCLUSIVE: ++ status = nfsd4_decode_verifier4(argp, &open->op_verf); ++ if (status) ++ return status; ++ break; ++ case NFS4_CREATE_EXCLUSIVE4_1: ++ if (argp->minorversion < 1) ++ return nfserr_bad_xdr; ++ status = nfsd4_decode_verifier4(argp, &open->op_verf); ++ if (status) ++ return status; ++ status = nfsd4_decode_fattr4(argp, open->op_bmval, ++ ARRAY_SIZE(open->op_bmval), ++ &open->op_iattr, &open->op_acl, ++ &open->op_label, &open->op_umask); ++ if (status) ++ return status; ++ break; ++ default: ++ return nfserr_bad_xdr; ++ } ++ ++ return nfs_ok; ++} ++ + static __be32 nfsd4_decode_share_access(struct nfsd4_compoundargs *argp, u32 *share_access, u32 *deleg_want, u32 *deleg_when) + { + __be32 *p; +@@ -1046,39 +1088,9 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) + case NFS4_OPEN_NOCREATE: + break; + case NFS4_OPEN_CREATE: +- READ_BUF(4); +- open->op_createmode = be32_to_cpup(p++); +- switch (open->op_createmode) { +- case NFS4_CREATE_UNCHECKED: +- case NFS4_CREATE_GUARDED: +- status = nfsd4_decode_fattr4(argp, open->op_bmval, +- ARRAY_SIZE(open->op_bmval), +- &open->op_iattr, &open->op_acl, +- &open->op_label, &open->op_umask); +- if (status) +- goto out; +- break; +- case NFS4_CREATE_EXCLUSIVE: +- status = nfsd4_decode_verifier4(argp, &open->op_verf); +- if (status) +- return status; +- break; +- case NFS4_CREATE_EXCLUSIVE4_1: +- if (argp->minorversion < 1) +- goto xdr_error; +- status = nfsd4_decode_verifier4(argp, &open->op_verf); +- if (status) +- return status; +- status = nfsd4_decode_fattr4(argp, open->op_bmval, +- ARRAY_SIZE(open->op_bmval), +- &open->op_iattr, &open->op_acl, +- &open->op_label, &open->op_umask); +- if (status) +- goto out; +- break; +- default: +- goto xdr_error; +- } ++ status = nfsd4_decode_createhow4(argp, open); ++ if (status) ++ return status; + break; + default: + goto xdr_error; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-helper-to-decode-open-s-open_claim4-argumen.patch b/queue-5.10/nfsd-add-helper-to-decode-open-s-open_claim4-argumen.patch new file mode 100644 index 00000000000..57afbced6ec --- /dev/null +++ b/queue-5.10/nfsd-add-helper-to-decode-open-s-open_claim4-argumen.patch @@ -0,0 +1,186 @@ +From 1994c026d87b06d9507a05d9862d4f07430fdb56 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Nov 2020 17:45:04 -0500 +Subject: NFSD: Add helper to decode OPEN's open_claim4 argument + +From: Chuck Lever + +[ Upstream commit 1708e50b0145f393acbec9e319bdf0e33f765d25 ] + +Refactor for clarity. + +Note that op_fname is the only instance of an NFSv4 filename stored +in a struct xdr_netobj. Convert it to a u32/char * pair so that the +new nfsd4_decode_filename() helper can be used. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 8 ++-- + fs/nfsd/nfs4xdr.c | 95 ++++++++++++++++++++++++---------------------- + fs/nfsd/xdr4.h | 3 +- + 3 files changed, 56 insertions(+), 50 deletions(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 95545a61bfc77..a038d1e182ff3 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -257,8 +257,8 @@ do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, stru + * in NFSv4 as in v3 except EXCLUSIVE4_1. + */ + current->fs->umask = open->op_umask; +- status = do_nfsd_create(rqstp, current_fh, open->op_fname.data, +- open->op_fname.len, &open->op_iattr, ++ status = do_nfsd_create(rqstp, current_fh, open->op_fname, ++ open->op_fnamelen, &open->op_iattr, + *resfh, open->op_createmode, + (u32 *)open->op_verf.data, + &open->op_truncate, &open->op_created); +@@ -283,7 +283,7 @@ do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, stru + * a chance to an acquire a delegation if appropriate. + */ + status = nfsd_lookup(rqstp, current_fh, +- open->op_fname.data, open->op_fname.len, *resfh); ++ open->op_fname, open->op_fnamelen, *resfh); + if (status) + goto out; + status = nfsd_check_obj_isreg(*resfh); +@@ -360,7 +360,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + bool reclaim = false; + + dprintk("NFSD: nfsd4_open filename %.*s op_openowner %p\n", +- (int)open->op_fname.len, open->op_fname.data, ++ (int)open->op_fnamelen, open->op_fname, + open->op_openowner); + + /* This check required by spec. */ +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index a9257ec9d151d..3e0fca521c39b 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -1072,6 +1072,55 @@ static __be32 nfsd4_decode_share_deny(struct nfsd4_compoundargs *argp, u32 *x) + return nfs_ok; + } + ++static __be32 ++nfsd4_decode_open_claim4(struct nfsd4_compoundargs *argp, ++ struct nfsd4_open *open) ++{ ++ __be32 status; ++ ++ if (xdr_stream_decode_u32(argp->xdr, &open->op_claim_type) < 0) ++ return nfserr_bad_xdr; ++ switch (open->op_claim_type) { ++ case NFS4_OPEN_CLAIM_NULL: ++ case NFS4_OPEN_CLAIM_DELEGATE_PREV: ++ status = nfsd4_decode_component4(argp, &open->op_fname, ++ &open->op_fnamelen); ++ if (status) ++ return status; ++ break; ++ case NFS4_OPEN_CLAIM_PREVIOUS: ++ if (xdr_stream_decode_u32(argp->xdr, &open->op_delegate_type) < 0) ++ return nfserr_bad_xdr; ++ break; ++ case NFS4_OPEN_CLAIM_DELEGATE_CUR: ++ status = nfsd4_decode_stateid4(argp, &open->op_delegate_stateid); ++ if (status) ++ return status; ++ status = nfsd4_decode_component4(argp, &open->op_fname, ++ &open->op_fnamelen); ++ if (status) ++ return status; ++ break; ++ case NFS4_OPEN_CLAIM_FH: ++ case NFS4_OPEN_CLAIM_DELEG_PREV_FH: ++ if (argp->minorversion < 1) ++ return nfserr_bad_xdr; ++ /* void */ ++ break; ++ case NFS4_OPEN_CLAIM_DELEG_CUR_FH: ++ if (argp->minorversion < 1) ++ return nfserr_bad_xdr; ++ status = nfsd4_decode_stateid4(argp, &open->op_delegate_stateid); ++ if (status) ++ return status; ++ break; ++ default: ++ return nfserr_bad_xdr; ++ } ++ ++ return nfs_ok; ++} ++ + static __be32 + nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) + { +@@ -1102,51 +1151,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) + status = nfsd4_decode_openflag4(argp, open); + if (status) + return status; +- +- /* open_claim */ +- READ_BUF(4); +- open->op_claim_type = be32_to_cpup(p++); +- switch (open->op_claim_type) { +- case NFS4_OPEN_CLAIM_NULL: +- case NFS4_OPEN_CLAIM_DELEGATE_PREV: +- READ_BUF(4); +- open->op_fname.len = be32_to_cpup(p++); +- READ_BUF(open->op_fname.len); +- SAVEMEM(open->op_fname.data, open->op_fname.len); +- if ((status = check_filename(open->op_fname.data, open->op_fname.len))) +- return status; +- break; +- case NFS4_OPEN_CLAIM_PREVIOUS: +- READ_BUF(4); +- open->op_delegate_type = be32_to_cpup(p++); +- break; +- case NFS4_OPEN_CLAIM_DELEGATE_CUR: +- status = nfsd4_decode_stateid(argp, &open->op_delegate_stateid); +- if (status) +- return status; +- READ_BUF(4); +- open->op_fname.len = be32_to_cpup(p++); +- READ_BUF(open->op_fname.len); +- SAVEMEM(open->op_fname.data, open->op_fname.len); +- if ((status = check_filename(open->op_fname.data, open->op_fname.len))) +- return status; +- break; +- case NFS4_OPEN_CLAIM_FH: +- case NFS4_OPEN_CLAIM_DELEG_PREV_FH: +- if (argp->minorversion < 1) +- goto xdr_error; +- /* void */ +- break; +- case NFS4_OPEN_CLAIM_DELEG_CUR_FH: +- if (argp->minorversion < 1) +- goto xdr_error; +- status = nfsd4_decode_stateid(argp, &open->op_delegate_stateid); +- if (status) +- return status; +- break; +- default: +- goto xdr_error; +- } ++ status = nfsd4_decode_open_claim4(argp, open); + + DECODE_TAIL; + } +diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h +index 0eb13bd603ea6..6245004a9993b 100644 +--- a/fs/nfsd/xdr4.h ++++ b/fs/nfsd/xdr4.h +@@ -252,7 +252,8 @@ struct nfsd4_listxattrs { + + struct nfsd4_open { + u32 op_claim_type; /* request */ +- struct xdr_netobj op_fname; /* request - everything but CLAIM_PREV */ ++ u32 op_fnamelen; ++ char * op_fname; /* request - everything but CLAIM_PREV */ + u32 op_delegate_type; /* request - CLAIM_PREV only */ + stateid_t op_delegate_stateid; /* request - response */ + u32 op_why_no_deleg; /* response - DELEG_NONE_EXT only */ +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-helper-to-decode-open-s-openflag4-argument.patch b/queue-5.10/nfsd-add-helper-to-decode-open-s-openflag4-argument.patch new file mode 100644 index 00000000000..22d50557c5e --- /dev/null +++ b/queue-5.10/nfsd-add-helper-to-decode-open-s-openflag4-argument.patch @@ -0,0 +1,76 @@ +From 0daee30812d7436847b4ff4c26907df029698101 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Nov 2020 17:41:21 -0500 +Subject: NFSD: Add helper to decode OPEN's openflag4 argument + +From: Chuck Lever + +[ Upstream commit e6ec04b27bfb4869c0e35fbcf24333d379f101d5 ] + +Refactor for clarity. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 38 +++++++++++++++++++++++++------------- + 1 file changed, 25 insertions(+), 13 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 62096b2a57b35..76715d1935ade 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -988,6 +988,28 @@ nfsd4_decode_createhow4(struct nfsd4_compoundargs *argp, struct nfsd4_open *open + return nfs_ok; + } + ++static __be32 ++nfsd4_decode_openflag4(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) ++{ ++ __be32 status; ++ ++ if (xdr_stream_decode_u32(argp->xdr, &open->op_create) < 0) ++ return nfserr_bad_xdr; ++ switch (open->op_create) { ++ case NFS4_OPEN_NOCREATE: ++ break; ++ case NFS4_OPEN_CREATE: ++ status = nfsd4_decode_createhow4(argp, open); ++ if (status) ++ return status; ++ break; ++ default: ++ return nfserr_bad_xdr; ++ } ++ ++ return nfs_ok; ++} ++ + static __be32 nfsd4_decode_share_access(struct nfsd4_compoundargs *argp, u32 *share_access, u32 *deleg_want, u32 *deleg_when) + { + __be32 *p; +@@ -1082,19 +1104,9 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) + status = nfsd4_decode_opaque(argp, &open->op_owner); + if (status) + goto xdr_error; +- READ_BUF(4); +- open->op_create = be32_to_cpup(p++); +- switch (open->op_create) { +- case NFS4_OPEN_NOCREATE: +- break; +- case NFS4_OPEN_CREATE: +- status = nfsd4_decode_createhow4(argp, open); +- if (status) +- return status; +- break; +- default: +- goto xdr_error; +- } ++ status = nfsd4_decode_openflag4(argp, open); ++ if (status) ++ return status; + + /* open_claim */ + READ_BUF(4); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-helper-to-set-up-the-pages-where-the-dirlis.patch b/queue-5.10/nfsd-add-helper-to-set-up-the-pages-where-the-dirlis.patch new file mode 100644 index 00000000000..9f0af6005cc --- /dev/null +++ b/queue-5.10/nfsd-add-helper-to-set-up-the-pages-where-the-dirlis.patch @@ -0,0 +1,152 @@ +From 78d43d0c5be2917acac21bfb76b67c0aee367d87 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Nov 2020 09:50:23 -0500 +Subject: NFSD: Add helper to set up the pages where the dirlist is encoded + +From: Chuck Lever + +[ Upstream commit 40116ebd0934cca7e46423bdb3397d3d27eb9fb9 ] + +De-duplicate some code that is used by both READDIR and READDIRPLUS +to build the dirlist in the Reply. Because this code is not related +to decoding READ arguments, it is moved to a more appropriate spot. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3proc.c | 29 +++++++++++++++++++---------- + fs/nfsd/nfs3xdr.c | 20 -------------------- + fs/nfsd/xdr3.h | 1 - + 3 files changed, 19 insertions(+), 31 deletions(-) + +diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c +index 8cffd9852ef04..25f31a03c4f1b 100644 +--- a/fs/nfsd/nfs3proc.c ++++ b/fs/nfsd/nfs3proc.c +@@ -440,6 +440,23 @@ nfsd3_proc_link(struct svc_rqst *rqstp) + return rpc_success; + } + ++static void nfsd3_init_dirlist_pages(struct svc_rqst *rqstp, ++ struct nfsd3_readdirres *resp, ++ int count) ++{ ++ count = min_t(u32, count, svc_max_payload(rqstp)); ++ ++ /* Convert byte count to number of words (i.e. >> 2), ++ * and reserve room for the NULL ptr & eof flag (-2 words) */ ++ resp->buflen = (count >> 2) - 2; ++ ++ resp->buffer = page_address(*rqstp->rq_next_page); ++ while (count > 0) { ++ rqstp->rq_next_page++; ++ count -= PAGE_SIZE; ++ } ++} ++ + /* + * Read a portion of a directory. + */ +@@ -457,16 +474,12 @@ nfsd3_proc_readdir(struct svc_rqst *rqstp) + SVCFH_fmt(&argp->fh), + argp->count, (u32) argp->cookie); + +- /* Make sure we've room for the NULL ptr & eof flag, and shrink to +- * client read size */ +- count = (argp->count >> 2) - 2; ++ nfsd3_init_dirlist_pages(rqstp, resp, argp->count); + + /* Read directory and encode entries on the fly */ + fh_copy(&resp->fh, &argp->fh); + +- resp->buflen = count; + resp->common.err = nfs_ok; +- resp->buffer = argp->buffer; + resp->rqstp = rqstp; + offset = argp->cookie; + +@@ -518,16 +531,12 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp) + SVCFH_fmt(&argp->fh), + argp->count, (u32) argp->cookie); + +- /* Convert byte count to number of words (i.e. >> 2), +- * and reserve room for the NULL ptr & eof flag (-2 words) */ +- resp->count = (argp->count >> 2) - 2; ++ nfsd3_init_dirlist_pages(rqstp, resp, argp->count); + + /* Read directory and encode entries on the fly */ + fh_copy(&resp->fh, &argp->fh); + + resp->common.err = nfs_ok; +- resp->buffer = argp->buffer; +- resp->buflen = resp->count; + resp->rqstp = rqstp; + offset = argp->cookie; + +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index 6b6a839c1fc8c..8394aeb8381e6 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -560,8 +560,6 @@ int + nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p) + { + struct nfsd3_readdirargs *args = rqstp->rq_argp; +- int len; +- u32 max_blocksize = svc_max_payload(rqstp); + + p = decode_fh(p, &args->fh); + if (!p) +@@ -570,14 +568,6 @@ nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p) + args->verf = p; p += 2; + args->dircount = ~0; + args->count = ntohl(*p++); +- len = args->count = min_t(u32, args->count, max_blocksize); +- +- while (len > 0) { +- struct page *p = *(rqstp->rq_next_page++); +- if (!args->buffer) +- args->buffer = page_address(p); +- len -= PAGE_SIZE; +- } + + return xdr_argsize_check(rqstp, p); + } +@@ -586,8 +576,6 @@ int + nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, __be32 *p) + { + struct nfsd3_readdirargs *args = rqstp->rq_argp; +- int len; +- u32 max_blocksize = svc_max_payload(rqstp); + + p = decode_fh(p, &args->fh); + if (!p) +@@ -597,14 +585,6 @@ nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, __be32 *p) + args->dircount = ntohl(*p++); + args->count = ntohl(*p++); + +- len = args->count = min(args->count, max_blocksize); +- while (len > 0) { +- struct page *p = *(rqstp->rq_next_page++); +- if (!args->buffer) +- args->buffer = page_address(p); +- len -= PAGE_SIZE; +- } +- + return xdr_argsize_check(rqstp, p); + } + +diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h +index 08f909142ddf7..789a364d5e69d 100644 +--- a/fs/nfsd/xdr3.h ++++ b/fs/nfsd/xdr3.h +@@ -93,7 +93,6 @@ struct nfsd3_readdirargs { + __u32 dircount; + __u32 count; + __be32 * verf; +- __be32 * buffer; + }; + + struct nfsd3_commitargs { +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-helper-to-set-up-the-pages-where-the-dirlis.patch-28629 b/queue-5.10/nfsd-add-helper-to-set-up-the-pages-where-the-dirlis.patch-28629 new file mode 100644 index 00000000000..c8fb96397e3 --- /dev/null +++ b/queue-5.10/nfsd-add-helper-to-set-up-the-pages-where-the-dirlis.patch-28629 @@ -0,0 +1,108 @@ +From b5e3c3916966826285520325854a877eff6679cf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Nov 2020 17:03:49 -0500 +Subject: NFSD: Add helper to set up the pages where the dirlist is encoded + +From: Chuck Lever + +[ Upstream commit 788cd46ecf83ee2d561cb4e754e276dc8089b787 ] + +Add a helper similar to nfsd3_init_dirlist_pages(). + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsproc.c | 29 ++++++++++++++++++----------- + fs/nfsd/nfsxdr.c | 2 -- + fs/nfsd/xdr.h | 1 - + 3 files changed, 18 insertions(+), 14 deletions(-) + +diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c +index 6352da0168e04..a628ea4d66ead 100644 +--- a/fs/nfsd/nfsproc.c ++++ b/fs/nfsd/nfsproc.c +@@ -553,6 +553,20 @@ nfsd_proc_rmdir(struct svc_rqst *rqstp) + return rpc_success; + } + ++static void nfsd_init_dirlist_pages(struct svc_rqst *rqstp, ++ struct nfsd_readdirres *resp, ++ int count) ++{ ++ count = min_t(u32, count, PAGE_SIZE); ++ ++ /* Convert byte count to number of words (i.e. >> 2), ++ * and reserve room for the NULL ptr & eof flag (-2 words) */ ++ resp->buflen = (count >> 2) - 2; ++ ++ resp->buffer = page_address(*rqstp->rq_next_page); ++ rqstp->rq_next_page++; ++} ++ + /* + * Read a portion of a directory. + */ +@@ -561,31 +575,24 @@ nfsd_proc_readdir(struct svc_rqst *rqstp) + { + struct nfsd_readdirargs *argp = rqstp->rq_argp; + struct nfsd_readdirres *resp = rqstp->rq_resp; +- int count; + loff_t offset; ++ __be32 *buffer; + + dprintk("nfsd: READDIR %s %d bytes at %d\n", + SVCFH_fmt(&argp->fh), + argp->count, argp->cookie); + +- /* Shrink to the client read size */ +- count = (argp->count >> 2) - 2; +- +- /* Make sure we've room for the NULL ptr & eof flag */ +- count -= 2; +- if (count < 0) +- count = 0; ++ nfsd_init_dirlist_pages(rqstp, resp, argp->count); ++ buffer = resp->buffer; + +- resp->buffer = argp->buffer; + resp->offset = NULL; +- resp->buflen = count; + resp->common.err = nfs_ok; + /* Read directory and encode entries on the fly */ + offset = argp->cookie; + resp->status = nfsd_readdir(rqstp, &argp->fh, &offset, + &resp->common, nfssvc_encode_entry); + +- resp->count = resp->buffer - argp->buffer; ++ resp->count = resp->buffer - buffer; + if (resp->offset) + *resp->offset = htonl(offset); + +diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c +index 02dd9888d93b2..3d72334e16733 100644 +--- a/fs/nfsd/nfsxdr.c ++++ b/fs/nfsd/nfsxdr.c +@@ -388,8 +388,6 @@ nfssvc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p) + return 0; + args->cookie = ntohl(*p++); + args->count = ntohl(*p++); +- args->count = min_t(u32, args->count, PAGE_SIZE); +- args->buffer = page_address(*(rqstp->rq_next_page++)); + + return xdr_argsize_check(rqstp, p); + } +diff --git a/fs/nfsd/xdr.h b/fs/nfsd/xdr.h +index 1338551de828e..ff68643504c3c 100644 +--- a/fs/nfsd/xdr.h ++++ b/fs/nfsd/xdr.h +@@ -73,7 +73,6 @@ struct nfsd_readdirargs { + struct svc_fh fh; + __u32 cookie; + __u32 count; +- __be32 * buffer; + }; + + struct nfsd_stat { +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-helpers-to-decode-a-clientid4-and-an-nfsv4-.patch b/queue-5.10/nfsd-add-helpers-to-decode-a-clientid4-and-an-nfsv4-.patch new file mode 100644 index 00000000000..707f98972a5 --- /dev/null +++ b/queue-5.10/nfsd-add-helpers-to-decode-a-clientid4-and-an-nfsv4-.patch @@ -0,0 +1,74 @@ +From 324a97aa74b68574d76c03ec1db3cf9ea8b39ec6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Nov 2020 17:25:02 -0500 +Subject: NFSD: Add helpers to decode a clientid4 and an NFSv4 state owner + +From: Chuck Lever + +[ Upstream commit 144e82694092ff80b5e64749d6822cd8947587f2 ] + +These helpers will also be used to simplify decoders in subsequent +patches. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 34 +++++++++++++++++++++++++++++----- + 1 file changed, 29 insertions(+), 5 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index b3459059cec1b..63140cd4c50e4 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -609,6 +609,30 @@ nfsd4_decode_stateid4(struct nfsd4_compoundargs *argp, stateid_t *sid) + return nfs_ok; + } + ++static __be32 ++nfsd4_decode_clientid4(struct nfsd4_compoundargs *argp, clientid_t *clientid) ++{ ++ __be32 *p; ++ ++ p = xdr_inline_decode(argp->xdr, sizeof(__be64)); ++ if (!p) ++ return nfserr_bad_xdr; ++ memcpy(clientid, p, sizeof(*clientid)); ++ return nfs_ok; ++} ++ ++static __be32 ++nfsd4_decode_state_owner4(struct nfsd4_compoundargs *argp, ++ clientid_t *clientid, struct xdr_netobj *owner) ++{ ++ __be32 status; ++ ++ status = nfsd4_decode_clientid4(argp, clientid); ++ if (status) ++ return status; ++ return nfsd4_decode_opaque(argp, owner); ++} ++ + static __be32 nfsd4_decode_cb_sec(struct nfsd4_compoundargs *argp, struct nfsd4_cb_sec *cbs) + { + DECODE_HEAD; +@@ -832,12 +856,12 @@ nfsd4_decode_lock(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock) + status = nfsd4_decode_stateid(argp, &lock->lk_new_open_stateid); + if (status) + return status; +- READ_BUF(8 + sizeof(clientid_t)); ++ READ_BUF(4); + lock->lk_new_lock_seqid = be32_to_cpup(p++); +- COPYMEM(&lock->lk_new_clientid, sizeof(clientid_t)); +- lock->lk_new_owner.len = be32_to_cpup(p++); +- READ_BUF(lock->lk_new_owner.len); +- READMEM(lock->lk_new_owner.data, lock->lk_new_owner.len); ++ status = nfsd4_decode_state_owner4(argp, &lock->lk_new_clientid, ++ &lock->lk_new_owner); ++ if (status) ++ return status; + } else { + status = nfsd4_decode_stateid(argp, &lock->lk_old_lock_stateid); + if (status) +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-nfsd4_send_cb_offload.patch b/queue-5.10/nfsd-add-nfsd4_send_cb_offload.patch new file mode 100644 index 00000000000..0f0af36269d --- /dev/null +++ b/queue-5.10/nfsd-add-nfsd4_send_cb_offload.patch @@ -0,0 +1,82 @@ +From ea7c2e2c84fabff93a8f6f52a87b1780b9b8c641 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 Jul 2022 14:41:12 -0400 +Subject: NFSD: Add nfsd4_send_cb_offload() + +From: Chuck Lever + +[ Upstream commit e72f9bc006c08841c46d27747a4debc747a8fe13 ] + +Refactor for legibility. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 37 ++++++++++++++++++++++--------------- + 1 file changed, 22 insertions(+), 15 deletions(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index dbc507c9aa11b..332fd1d0b188d 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -1753,6 +1753,27 @@ static void cleanup_async_copy(struct nfsd4_copy *copy) + nfs4_put_copy(copy); + } + ++static void nfsd4_send_cb_offload(struct nfsd4_copy *copy) ++{ ++ struct nfsd4_copy *cb_copy; ++ ++ cb_copy = kzalloc(sizeof(struct nfsd4_copy), GFP_KERNEL); ++ if (!cb_copy) ++ return; ++ ++ refcount_set(&cb_copy->refcount, 1); ++ memcpy(&cb_copy->cp_res, ©->cp_res, sizeof(copy->cp_res)); ++ cb_copy->cp_clp = copy->cp_clp; ++ cb_copy->nfserr = copy->nfserr; ++ memcpy(&cb_copy->fh, ©->fh, sizeof(copy->fh)); ++ ++ nfsd4_init_cb(&cb_copy->cp_cb, cb_copy->cp_clp, ++ &nfsd4_cb_offload_ops, NFSPROC4_CLNT_CB_OFFLOAD); ++ trace_nfsd_cb_offload(copy->cp_clp, ©->cp_res.cb_stateid, ++ ©->fh, copy->cp_count, copy->nfserr); ++ nfsd4_run_cb(&cb_copy->cp_cb); ++} ++ + /** + * nfsd4_do_async_copy - kthread function for background server-side COPY + * @data: arguments for COPY operation +@@ -1763,7 +1784,6 @@ static void cleanup_async_copy(struct nfsd4_copy *copy) + static int nfsd4_do_async_copy(void *data) + { + struct nfsd4_copy *copy = (struct nfsd4_copy *)data; +- struct nfsd4_copy *cb_copy; + + if (nfsd4_ssc_is_inter(copy)) { + struct file *filp; +@@ -1785,20 +1805,7 @@ static int nfsd4_do_async_copy(void *data) + } + + do_callback: +- cb_copy = kzalloc(sizeof(struct nfsd4_copy), GFP_KERNEL); +- if (!cb_copy) +- goto out; +- refcount_set(&cb_copy->refcount, 1); +- memcpy(&cb_copy->cp_res, ©->cp_res, sizeof(copy->cp_res)); +- cb_copy->cp_clp = copy->cp_clp; +- cb_copy->nfserr = copy->nfserr; +- memcpy(&cb_copy->fh, ©->fh, sizeof(copy->fh)); +- nfsd4_init_cb(&cb_copy->cp_cb, cb_copy->cp_clp, +- &nfsd4_cb_offload_ops, NFSPROC4_CLNT_CB_OFFLOAD); +- trace_nfsd_cb_offload(copy->cp_clp, ©->cp_res.cb_stateid, +- ©->fh, copy->cp_count, copy->nfserr); +- nfsd4_run_cb(&cb_copy->cp_cb); +-out: ++ nfsd4_send_cb_offload(copy); + cleanup_async_copy(copy); + return 0; + } +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-nfsd_clid_confirmed-tracepoint.patch b/queue-5.10/nfsd-add-nfsd_clid_confirmed-tracepoint.patch new file mode 100644 index 00000000000..d9fcb0469dc --- /dev/null +++ b/queue-5.10/nfsd-add-nfsd_clid_confirmed-tracepoint.patch @@ -0,0 +1,68 @@ +From 788a0dd9be531a33b5ec5a906de17445f913b11c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 14 May 2021 15:55:48 -0400 +Subject: NFSD: Add nfsd_clid_confirmed tracepoint + +From: Chuck Lever + +[ Upstream commit 7e3b32ace6094aadfa2e1e54ca4c6bbfd07646af ] + +This replaces a dprintk call site in order to get greater visibility +on when client IDs are confirmed or re-used. Simple example: + + nfsd-995 [000] 126.622975: nfsd_compound: xid=0x3a34e2b1 opcnt=1 + nfsd-995 [000] 126.623005: nfsd_cb_args: addr=192.168.2.51:45901 client 60958e3b:9213ef0e prog=1073741824 ident=1 + nfsd-995 [000] 126.623007: nfsd_compound_status: op=1/1 OP_SETCLIENTID status=0 + nfsd-996 [001] 126.623142: nfsd_compound: xid=0x3b34e2b1 opcnt=1 + >>>> nfsd-996 [001] 126.623146: nfsd_clid_confirmed: client 60958e3b:9213ef0e + nfsd-996 [001] 126.623148: nfsd_cb_probe: addr=192.168.2.51:45901 client 60958e3b:9213ef0e state=UNKNOWN + nfsd-996 [001] 126.623154: nfsd_compound_status: op=1/1 OP_SETCLIENTID_CONFIRM status=0 + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 10 +++++----- + fs/nfsd/trace.h | 1 + + 2 files changed, 6 insertions(+), 5 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 8169625fdd233..b10593079e380 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -2838,14 +2838,14 @@ move_to_confirmed(struct nfs4_client *clp) + + lockdep_assert_held(&nn->client_lock); + +- dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp); + list_move(&clp->cl_idhash, &nn->conf_id_hashtbl[idhashval]); + rb_erase(&clp->cl_namenode, &nn->unconf_name_tree); + add_clp_to_name_tree(clp, &nn->conf_name_tree); +- if (!test_and_set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags) && +- clp->cl_nfsd_dentry && +- clp->cl_nfsd_info_dentry) +- fsnotify_dentry(clp->cl_nfsd_info_dentry, FS_MODIFY); ++ if (!test_and_set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags)) { ++ trace_nfsd_clid_confirmed(&clp->cl_clientid); ++ if (clp->cl_nfsd_dentry && clp->cl_nfsd_info_dentry) ++ fsnotify_dentry(clp->cl_nfsd_info_dentry, FS_MODIFY); ++ } + renew_client_locked(clp); + } + +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index 2fac89e29f515..2c0f0057f60c9 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -511,6 +511,7 @@ DEFINE_EVENT(nfsd_clientid_class, nfsd_clid_##name, \ + TP_PROTO(const clientid_t *clid), \ + TP_ARGS(clid)) + ++DEFINE_CLIENTID_EVENT(confirmed); + DEFINE_CLIENTID_EVENT(expired); + DEFINE_CLIENTID_EVENT(purged); + DEFINE_CLIENTID_EVENT(renew); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-nfsd_clid_cred_mismatch-tracepoint.patch b/queue-5.10/nfsd-add-nfsd_clid_cred_mismatch-tracepoint.patch new file mode 100644 index 00000000000..911892004c8 --- /dev/null +++ b/queue-5.10/nfsd-add-nfsd_clid_cred_mismatch-tracepoint.patch @@ -0,0 +1,114 @@ +From d05600a3331d475fcfc48583c985335204e1cf9b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 14 May 2021 15:55:29 -0400 +Subject: NFSD: Add nfsd_clid_cred_mismatch tracepoint + +From: Chuck Lever + +[ Upstream commit 27787733ef44332fce749aa853f2749d141982b0 ] + +Record when a client tries to establish a lease record but uses an +unexpected credential. This is often a sign of a configuration +problem. + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 14 ++++++++++---- + fs/nfsd/trace.h | 28 ++++++++++++++++++++++++++++ + 2 files changed, 38 insertions(+), 4 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index ea68dc157ada1..2e18b1ad889d7 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -3203,6 +3203,7 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + if (!creds_match) { /* case 3 */ + if (client_has_state(conf)) { + status = nfserr_clid_inuse; ++ trace_nfsd_clid_cred_mismatch(conf, rqstp); + goto out; + } + goto out_new; +@@ -3447,9 +3448,10 @@ nfsd4_create_session(struct svc_rqst *rqstp, + goto out_free_conn; + } + } else if (unconf) { ++ status = nfserr_clid_inuse; + if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) || + !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) { +- status = nfserr_clid_inuse; ++ trace_nfsd_clid_cred_mismatch(unconf, rqstp); + goto out_free_conn; + } + status = nfserr_wrong_cred; +@@ -4008,7 +4010,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + if (clp_used_exchangeid(conf)) + goto out; + if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) { +- trace_nfsd_clid_inuse_err(conf); ++ trace_nfsd_clid_cred_mismatch(conf, rqstp); + goto out; + } + } +@@ -4066,10 +4068,14 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, + * Nevertheless, RFC 7530 recommends INUSE for this case: + */ + status = nfserr_clid_inuse; +- if (unconf && !same_creds(&unconf->cl_cred, &rqstp->rq_cred)) ++ if (unconf && !same_creds(&unconf->cl_cred, &rqstp->rq_cred)) { ++ trace_nfsd_clid_cred_mismatch(unconf, rqstp); + goto out; +- if (conf && !same_creds(&conf->cl_cred, &rqstp->rq_cred)) ++ } ++ if (conf && !same_creds(&conf->cl_cred, &rqstp->rq_cred)) { ++ trace_nfsd_clid_cred_mismatch(conf, rqstp); + goto out; ++ } + /* cases below refer to rfc 3530 section 14.2.34: */ + if (!unconf || !same_verf(&confirm, &unconf->cl_confirm)) { + if (conf && same_verf(&confirm, &conf->cl_confirm)) { +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index 3ec6d38fa5318..bec85fc8be01a 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -536,6 +536,34 @@ DEFINE_EVENT(nfsd_net_class, nfsd_##name, \ + DEFINE_NET_EVENT(grace_start); + DEFINE_NET_EVENT(grace_complete); + ++TRACE_EVENT(nfsd_clid_cred_mismatch, ++ TP_PROTO( ++ const struct nfs4_client *clp, ++ const struct svc_rqst *rqstp ++ ), ++ TP_ARGS(clp, rqstp), ++ TP_STRUCT__entry( ++ __field(u32, cl_boot) ++ __field(u32, cl_id) ++ __field(unsigned long, cl_flavor) ++ __field(unsigned long, new_flavor) ++ __array(unsigned char, addr, sizeof(struct sockaddr_in6)) ++ ), ++ TP_fast_assign( ++ __entry->cl_boot = clp->cl_clientid.cl_boot; ++ __entry->cl_id = clp->cl_clientid.cl_id; ++ __entry->cl_flavor = clp->cl_cred.cr_flavor; ++ __entry->new_flavor = rqstp->rq_cred.cr_flavor; ++ memcpy(__entry->addr, &rqstp->rq_xprt->xpt_remote, ++ sizeof(struct sockaddr_in6)); ++ ), ++ TP_printk("client %08x:%08x flavor=%s, conflict=%s from addr=%pISpc", ++ __entry->cl_boot, __entry->cl_id, ++ show_nfsd_authflavor(__entry->cl_flavor), ++ show_nfsd_authflavor(__entry->new_flavor), __entry->addr ++ ) ++) ++ + TRACE_EVENT(nfsd_clid_inuse_err, + TP_PROTO(const struct nfs4_client *clp), + TP_ARGS(clp), +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-nfsd_clid_destroyed-tracepoint.patch b/queue-5.10/nfsd-add-nfsd_clid_destroyed-tracepoint.patch new file mode 100644 index 00000000000..b40942839ec --- /dev/null +++ b/queue-5.10/nfsd-add-nfsd_clid_destroyed-tracepoint.patch @@ -0,0 +1,47 @@ +From bf4deba43b3043e616d0862ac968c13e21e3886a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 14 May 2021 15:56:00 -0400 +Subject: NFSD: Add nfsd_clid_destroyed tracepoint + +From: Chuck Lever + +[ Upstream commit c41a9b7a906fb872f8b2b1a34d2a1d5ef7f94adb ] + +Record client-requested termination of client IDs. + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 1 + + fs/nfsd/trace.h | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index da5b9b88b0cd4..6f04a84f76c0e 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -3939,6 +3939,7 @@ nfsd4_destroy_clientid(struct svc_rqst *rqstp, + status = nfserr_wrong_cred; + goto out; + } ++ trace_nfsd_clid_destroyed(&clp->cl_clientid); + unhash_client_locked(clp); + out: + spin_unlock(&nn->client_lock); +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index 6c787f4ef5633..3aca6dcba90a5 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -513,6 +513,7 @@ DEFINE_EVENT(nfsd_clientid_class, nfsd_clid_##name, \ + + DEFINE_CLIENTID_EVENT(reclaim_complete); + DEFINE_CLIENTID_EVENT(confirmed); ++DEFINE_CLIENTID_EVENT(destroyed); + DEFINE_CLIENTID_EVENT(expired); + DEFINE_CLIENTID_EVENT(purged); + DEFINE_CLIENTID_EVENT(renew); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-nfsd_clid_reclaim_complete-tracepoint.patch b/queue-5.10/nfsd-add-nfsd_clid_reclaim_complete-tracepoint.patch new file mode 100644 index 00000000000..ea398760b2c --- /dev/null +++ b/queue-5.10/nfsd-add-nfsd_clid_reclaim_complete-tracepoint.patch @@ -0,0 +1,45 @@ +From a4b06b22c43997d1c82169fe806f9f0f462f076a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 14 May 2021 15:55:54 -0400 +Subject: NFSD: Add nfsd_clid_reclaim_complete tracepoint + +From: Chuck Lever + +[ Upstream commit cee8aa074281e5269d8404be2b6388bb29ea8efc ] + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 1 + + fs/nfsd/trace.h | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index b10593079e380..da5b9b88b0cd4 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -3981,6 +3981,7 @@ nfsd4_reclaim_complete(struct svc_rqst *rqstp, + goto out; + + status = nfs_ok; ++ trace_nfsd_clid_reclaim_complete(&clp->cl_clientid); + nfsd4_client_record_create(clp); + inc_reclaim_complete(clp); + out: +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index 2c0f0057f60c9..6c787f4ef5633 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -511,6 +511,7 @@ DEFINE_EVENT(nfsd_clientid_class, nfsd_clid_##name, \ + TP_PROTO(const clientid_t *clid), \ + TP_ARGS(clid)) + ++DEFINE_CLIENTID_EVENT(reclaim_complete); + DEFINE_CLIENTID_EVENT(confirmed); + DEFINE_CLIENTID_EVENT(expired); + DEFINE_CLIENTID_EVENT(purged); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-nfsd_clid_verf_mismatch-tracepoint.patch b/queue-5.10/nfsd-add-nfsd_clid_verf_mismatch-tracepoint.patch new file mode 100644 index 00000000000..d80f17b8f10 --- /dev/null +++ b/queue-5.10/nfsd-add-nfsd_clid_verf_mismatch-tracepoint.patch @@ -0,0 +1,98 @@ +From 94c0d488baed96bcc26c3e5c3c9827c4e7bff1ae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 14 May 2021 15:55:36 -0400 +Subject: NFSD: Add nfsd_clid_verf_mismatch tracepoint + +From: Chuck Lever + +[ Upstream commit 744ea54c869cebe41fbad5f53f8a8ca5d93a5c97 ] + +Record when a client presents a different boot verifier than the +one we know about. Typically this is a sign the client has +rebooted, but sometimes it signals a conflicting client ID, which +the client's administrator will need to address. + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 11 ++++++++--- + fs/nfsd/trace.h | 32 ++++++++++++++++++++++++++++++++ + 2 files changed, 40 insertions(+), 3 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 2e18b1ad889d7..8169625fdd233 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -3213,6 +3213,7 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + goto out_copy; + } + /* case 5, client reboot */ ++ trace_nfsd_clid_verf_mismatch(conf, rqstp, &verf); + conf = NULL; + goto out_new; + } +@@ -4018,9 +4019,13 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + if (unconf) + unhash_client_locked(unconf); + /* We need to handle only case 1: probable callback update */ +- if (conf && same_verf(&conf->cl_verifier, &clverifier)) { +- copy_clid(new, conf); +- gen_confirm(new, nn); ++ if (conf) { ++ if (same_verf(&conf->cl_verifier, &clverifier)) { ++ copy_clid(new, conf); ++ gen_confirm(new, nn); ++ } else ++ trace_nfsd_clid_verf_mismatch(conf, rqstp, ++ &clverifier); + } + new->cl_minorversion = 0; + gen_callback(new, setclid, rqstp); +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index bec85fc8be01a..0ab46a0c911d2 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -564,6 +564,38 @@ TRACE_EVENT(nfsd_clid_cred_mismatch, + ) + ) + ++TRACE_EVENT(nfsd_clid_verf_mismatch, ++ TP_PROTO( ++ const struct nfs4_client *clp, ++ const struct svc_rqst *rqstp, ++ const nfs4_verifier *verf ++ ), ++ TP_ARGS(clp, rqstp, verf), ++ TP_STRUCT__entry( ++ __field(u32, cl_boot) ++ __field(u32, cl_id) ++ __array(unsigned char, cl_verifier, NFS4_VERIFIER_SIZE) ++ __array(unsigned char, new_verifier, NFS4_VERIFIER_SIZE) ++ __array(unsigned char, addr, sizeof(struct sockaddr_in6)) ++ ), ++ TP_fast_assign( ++ __entry->cl_boot = clp->cl_clientid.cl_boot; ++ __entry->cl_id = clp->cl_clientid.cl_id; ++ memcpy(__entry->cl_verifier, (void *)&clp->cl_verifier, ++ NFS4_VERIFIER_SIZE); ++ memcpy(__entry->new_verifier, (void *)verf, ++ NFS4_VERIFIER_SIZE); ++ memcpy(__entry->addr, &rqstp->rq_xprt->xpt_remote, ++ sizeof(struct sockaddr_in6)); ++ ), ++ TP_printk("client %08x:%08x verf=0x%s, updated=0x%s from addr=%pISpc", ++ __entry->cl_boot, __entry->cl_id, ++ __print_hex_str(__entry->cl_verifier, NFS4_VERIFIER_SIZE), ++ __print_hex_str(__entry->new_verifier, NFS4_VERIFIER_SIZE), ++ __entry->addr ++ ) ++); ++ + TRACE_EVENT(nfsd_clid_inuse_err, + TP_PROTO(const struct nfs4_client *clp), + TP_ARGS(clp), +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-nfsd_file_lru_dispose_list-helper.patch b/queue-5.10/nfsd-add-nfsd_file_lru_dispose_list-helper.patch new file mode 100644 index 00000000000..d896cdc575c --- /dev/null +++ b/queue-5.10/nfsd-add-nfsd_file_lru_dispose_list-helper.patch @@ -0,0 +1,73 @@ +From ba72e2f916a00245939ce190f41f07baddbc62fb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 Jul 2022 14:24:18 -0400 +Subject: NFSD: Add nfsd_file_lru_dispose_list() helper + +From: Chuck Lever + +[ Upstream commit 0bac5a264d9a923f5b01f3521e1519a8d0358342 ] + +Refactor the invariant part of nfsd_file_lru_walk_list() into a +separate helper function. + +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 29 ++++++++++++++++++++++------- + 1 file changed, 22 insertions(+), 7 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index 0cd72c20fc12d..ffe46f3f33495 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -450,11 +450,31 @@ nfsd_file_lru_cb(struct list_head *item, struct list_lru_one *lru, + return LRU_SKIP; + } + ++/* ++ * Unhash items on @dispose immediately, then queue them on the ++ * disposal workqueue to finish releasing them in the background. ++ * ++ * cel: Note that between the time list_lru_shrink_walk runs and ++ * now, these items are in the hash table but marked unhashed. ++ * Why release these outside of lru_cb ? There's no lock ordering ++ * problem since lru_cb currently takes no lock. ++ */ ++static void nfsd_file_gc_dispose_list(struct list_head *dispose) ++{ ++ struct nfsd_file *nf; ++ ++ list_for_each_entry(nf, dispose, nf_lru) { ++ spin_lock(&nfsd_file_hashtbl[nf->nf_hashval].nfb_lock); ++ nfsd_file_do_unhash(nf); ++ spin_unlock(&nfsd_file_hashtbl[nf->nf_hashval].nfb_lock); ++ } ++ nfsd_file_dispose_list_delayed(dispose); ++} ++ + static unsigned long + nfsd_file_lru_walk_list(struct shrink_control *sc) + { + LIST_HEAD(head); +- struct nfsd_file *nf; + unsigned long ret; + + if (sc) +@@ -464,12 +484,7 @@ nfsd_file_lru_walk_list(struct shrink_control *sc) + ret = list_lru_walk(&nfsd_file_lru, + nfsd_file_lru_cb, + &head, LONG_MAX); +- list_for_each_entry(nf, &head, nf_lru) { +- spin_lock(&nfsd_file_hashtbl[nf->nf_hashval].nfb_lock); +- nfsd_file_do_unhash(nf); +- spin_unlock(&nfsd_file_hashtbl[nf->nf_hashval].nfb_lock); +- } +- nfsd_file_dispose_list_delayed(&head); ++ nfsd_file_gc_dispose_list(&head); + return ret; + } + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-posix-acls-to-struct-nfsd_attrs.patch b/queue-5.10/nfsd-add-posix-acls-to-struct-nfsd_attrs.patch new file mode 100644 index 00000000000..518ca2c25ef --- /dev/null +++ b/queue-5.10/nfsd-add-posix-acls-to-struct-nfsd_attrs.patch @@ -0,0 +1,298 @@ +From 9c4a809a47b9f3434c4367b52f82085240f4385c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 Jul 2022 16:45:30 +1000 +Subject: NFSD: add posix ACLs to struct nfsd_attrs + +From: NeilBrown + +[ Upstream commit c0cbe70742f4a70893cd6e5f6b10b6e89b6db95b ] + +pacl and dpacl pointers are added to struct nfsd_attrs, which requires +that we have an nfsd_attrs_free() function to free them. +Those nfsv4 functions that can set ACLs now set up these pointers +based on the passed in NFSv4 ACL. + +nfsd_setattr() sets the acls as appropriate. + +Errors are handled as with security labels. + +Signed-off-by: NeilBrown +[ cel: backported to 5.10.y, prior to idmapped mounts ] +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/acl.h | 6 ++++-- + fs/nfsd/nfs4acl.c | 45 +++++++-------------------------------------- + fs/nfsd/nfs4proc.c | 46 ++++++++++++++++------------------------------ + fs/nfsd/vfs.c | 7 +++++++ + fs/nfsd/vfs.h | 11 +++++++++++ + 5 files changed, 45 insertions(+), 70 deletions(-) + +diff --git a/fs/nfsd/acl.h b/fs/nfsd/acl.h +index ba14d2f4b64f4..4b7324458a94e 100644 +--- a/fs/nfsd/acl.h ++++ b/fs/nfsd/acl.h +@@ -38,6 +38,8 @@ + struct nfs4_acl; + struct svc_fh; + struct svc_rqst; ++struct nfsd_attrs; ++enum nfs_ftype4; + + int nfs4_acl_bytes(int entries); + int nfs4_acl_get_whotype(char *, u32); +@@ -45,7 +47,7 @@ __be32 nfs4_acl_write_who(struct xdr_stream *xdr, int who); + + int nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, + struct nfs4_acl **acl); +-__be32 nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, +- struct nfs4_acl *acl); ++__be32 nfsd4_acl_to_attr(enum nfs_ftype4 type, struct nfs4_acl *acl, ++ struct nfsd_attrs *attr); + + #endif /* LINUX_NFS4_ACL_H */ +diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c +index 71292a0d6f092..bb8e2f6d7d03c 100644 +--- a/fs/nfsd/nfs4acl.c ++++ b/fs/nfsd/nfs4acl.c +@@ -751,57 +751,26 @@ static int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, + return ret; + } + +-__be32 +-nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, +- struct nfs4_acl *acl) ++__be32 nfsd4_acl_to_attr(enum nfs_ftype4 type, struct nfs4_acl *acl, ++ struct nfsd_attrs *attr) + { +- __be32 error; + int host_error; +- struct dentry *dentry; +- struct inode *inode; +- struct posix_acl *pacl = NULL, *dpacl = NULL; + unsigned int flags = 0; + +- /* Get inode */ +- error = fh_verify(rqstp, fhp, 0, NFSD_MAY_SATTR); +- if (error) +- return error; +- +- dentry = fhp->fh_dentry; +- inode = d_inode(dentry); ++ if (!acl) ++ return nfs_ok; + +- if (S_ISDIR(inode->i_mode)) ++ if (type == NF4DIR) + flags = NFS4_ACL_DIR; + +- host_error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags); ++ host_error = nfs4_acl_nfsv4_to_posix(acl, &attr->na_pacl, ++ &attr->na_dpacl, flags); + if (host_error == -EINVAL) + return nfserr_attrnotsupp; +- if (host_error < 0) +- goto out_nfserr; +- +- fh_lock(fhp); +- +- host_error = set_posix_acl(inode, ACL_TYPE_ACCESS, pacl); +- if (host_error < 0) +- goto out_drop_lock; +- +- if (S_ISDIR(inode->i_mode)) { +- host_error = set_posix_acl(inode, ACL_TYPE_DEFAULT, dpacl); +- } +- +-out_drop_lock: +- fh_unlock(fhp); +- +- posix_acl_release(pacl); +- posix_acl_release(dpacl); +-out_nfserr: +- if (host_error == -EOPNOTSUPP) +- return nfserr_attrnotsupp; + else + return nfserrno(host_error); + } + +- + static short + ace2type(struct nfs4_ace *ace) + { +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index cfcc463968b70..507a2aa967133 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -128,26 +128,6 @@ is_create_with_attrs(struct nfsd4_open *open) + || open->op_createmode == NFS4_CREATE_EXCLUSIVE4_1); + } + +-/* +- * if error occurs when setting the acl, just clear the acl bit +- * in the returned attr bitmap. +- */ +-static void +-do_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp, +- struct nfs4_acl *acl, u32 *bmval) +-{ +- __be32 status; +- +- status = nfsd4_set_nfs4_acl(rqstp, fhp, acl); +- if (status) +- /* +- * We should probably fail the whole open at this point, +- * but we've already created the file, so it's too late; +- * So this seems the least of evils: +- */ +- bmval[0] &= ~FATTR4_WORD0_ACL; +-} +- + static inline void + fh_dup2(struct svc_fh *dst, struct svc_fh *src) + { +@@ -281,6 +261,9 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp, + if (host_err) + return nfserrno(host_err); + ++ if (is_create_with_attrs(open)) ++ nfsd4_acl_to_attr(NF4REG, open->op_acl, &attrs); ++ + fh_lock_nested(fhp, I_MUTEX_PARENT); + + child = lookup_one_len(open->op_fname, parent, open->op_fnamelen); +@@ -382,8 +365,11 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp, + + if (attrs.na_labelerr) + open->op_bmval[2] &= ~FATTR4_WORD2_SECURITY_LABEL; ++ if (attrs.na_aclerr) ++ open->op_bmval[0] &= ~FATTR4_WORD0_ACL; + out: + fh_unlock(fhp); ++ nfsd_attrs_free(&attrs); + if (child && !IS_ERR(child)) + dput(child); + fh_drop_write(fhp); +@@ -446,9 +432,6 @@ do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, stru + if (status) + goto out; + +- if (is_create_with_attrs(open) && open->op_acl != NULL) +- do_set_nfs4_acl(rqstp, *resfh, open->op_acl, open->op_bmval); +- + nfsd4_set_open_owner_reply_cache(cstate, open, *resfh); + accmode = NFSD_MAY_NOP; + if (open->op_created || +@@ -779,6 +762,7 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + if (status) + return status; + ++ status = nfsd4_acl_to_attr(create->cr_type, create->cr_acl, &attrs); + current->fs->umask = create->cr_umask; + switch (create->cr_type) { + case NF4LNK: +@@ -837,10 +821,8 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + + if (attrs.na_labelerr) + create->cr_bmval[2] &= ~FATTR4_WORD2_SECURITY_LABEL; +- +- if (create->cr_acl != NULL) +- do_set_nfs4_acl(rqstp, &resfh, create->cr_acl, +- create->cr_bmval); ++ if (attrs.na_aclerr) ++ create->cr_bmval[0] &= ~FATTR4_WORD0_ACL; + + fh_unlock(&cstate->current_fh); + set_change_info(&create->cr_cinfo, &cstate->current_fh); +@@ -849,6 +831,7 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + fh_put(&resfh); + out_umask: + current->fs->umask = 0; ++ nfsd_attrs_free(&attrs); + return status; + } + +@@ -1123,6 +1106,7 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + .na_iattr = &setattr->sa_iattr, + .na_seclabel = &setattr->sa_label, + }; ++ struct inode *inode; + __be32 status = nfs_ok; + int err; + +@@ -1145,9 +1129,10 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + if (status) + goto out; + +- if (setattr->sa_acl != NULL) +- status = nfsd4_set_nfs4_acl(rqstp, &cstate->current_fh, +- setattr->sa_acl); ++ inode = cstate->current_fh.fh_dentry->d_inode; ++ status = nfsd4_acl_to_attr(S_ISDIR(inode->i_mode) ? NF4DIR : NF4REG, ++ setattr->sa_acl, &attrs); ++ + if (status) + goto out; + status = nfsd_setattr(rqstp, &cstate->current_fh, &attrs, +@@ -1155,6 +1140,7 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + if (!status) + status = nfserrno(attrs.na_labelerr); + out: ++ nfsd_attrs_free(&attrs); + fh_drop_write(&cstate->current_fh); + return status; + } +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index 01c431ed90ecf..bed542ba8ad8e 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -474,6 +474,13 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, + if (attr->na_seclabel && attr->na_seclabel->len) + attr->na_labelerr = security_inode_setsecctx(dentry, + attr->na_seclabel->data, attr->na_seclabel->len); ++ if (IS_ENABLED(CONFIG_FS_POSIX_ACL) && attr->na_pacl) ++ attr->na_aclerr = set_posix_acl(inode, ACL_TYPE_ACCESS, ++ attr->na_pacl); ++ if (IS_ENABLED(CONFIG_FS_POSIX_ACL) && ++ !attr->na_aclerr && attr->na_dpacl && S_ISDIR(inode->i_mode)) ++ attr->na_aclerr = set_posix_acl(inode, ACL_TYPE_DEFAULT, ++ attr->na_dpacl); + fh_unlock(fhp); + if (size_change) + put_write_access(inode); +diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h +index d5d4cfe37c933..c95cd414b4bb0 100644 +--- a/fs/nfsd/vfs.h ++++ b/fs/nfsd/vfs.h +@@ -6,6 +6,8 @@ + #ifndef LINUX_NFSD_VFS_H + #define LINUX_NFSD_VFS_H + ++#include ++#include + #include "nfsfh.h" + #include "nfsd.h" + +@@ -45,10 +47,19 @@ typedef int (*nfsd_filldir_t)(void *, const char *, int, loff_t, u64, unsigned); + struct nfsd_attrs { + struct iattr *na_iattr; /* input */ + struct xdr_netobj *na_seclabel; /* input */ ++ struct posix_acl *na_pacl; /* input */ ++ struct posix_acl *na_dpacl; /* input */ + + int na_labelerr; /* output */ ++ int na_aclerr; /* output */ + }; + ++static inline void nfsd_attrs_free(struct nfsd_attrs *attrs) ++{ ++ posix_acl_release(attrs->na_pacl); ++ posix_acl_release(attrs->na_dpacl); ++} ++ + int nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp, + struct svc_export **expp); + __be32 nfsd_lookup(struct svc_rqst *, struct svc_fh *, +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-security-label-to-struct-nfsd_attrs.patch b/queue-5.10/nfsd-add-security-label-to-struct-nfsd_attrs.patch new file mode 100644 index 00000000000..31940a593e4 --- /dev/null +++ b/queue-5.10/nfsd-add-security-label-to-struct-nfsd_attrs.patch @@ -0,0 +1,210 @@ +From 1a859bd80e3a5c819fa5b62fe5744f2a10018221 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 Jul 2022 16:45:30 +1000 +Subject: NFSD: add security label to struct nfsd_attrs + +From: NeilBrown + +[ Upstream commit d6a97d3f589a3a46a16183e03f3774daee251317 ] + +nfsd_setattr() now sets a security label if provided, and nfsv4 provides +it in the 'open' and 'create' paths and the 'setattr' path. +If setting the label failed (including because the kernel doesn't +support labels), an error field in 'struct nfsd_attrs' is set, and the +caller can respond. The open/create callers clear +FATTR4_WORD2_SECURITY_LABEL in the returned attr set in this case. +The setattr caller returns the error. + +Signed-off-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 49 +++++++++------------------------------------- + fs/nfsd/vfs.c | 29 +++------------------------ + fs/nfsd/vfs.h | 5 +++-- + 3 files changed, 15 insertions(+), 68 deletions(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 43387a8f10d06..cfcc463968b70 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -64,36 +64,6 @@ MODULE_PARM_DESC(nfsd4_ssc_umount_timeout, + "idle msecs before unmount export from source server"); + #endif + +-#ifdef CONFIG_NFSD_V4_SECURITY_LABEL +-#include +- +-static inline void +-nfsd4_security_inode_setsecctx(struct svc_fh *resfh, struct xdr_netobj *label, u32 *bmval) +-{ +- struct inode *inode = d_inode(resfh->fh_dentry); +- int status; +- +- inode_lock(inode); +- status = security_inode_setsecctx(resfh->fh_dentry, +- label->data, label->len); +- inode_unlock(inode); +- +- if (status) +- /* +- * XXX: We should really fail the whole open, but we may +- * already have created a new file, so it may be too +- * late. For now this seems the least of evils: +- */ +- bmval[2] &= ~FATTR4_WORD2_SECURITY_LABEL; +- +- return; +-} +-#else +-static inline void +-nfsd4_security_inode_setsecctx(struct svc_fh *resfh, struct xdr_netobj *label, u32 *bmval) +-{ } +-#endif +- + #define NFSDDBG_FACILITY NFSDDBG_PROC + + static u32 nfsd_attrmask[] = { +@@ -288,6 +258,7 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp, + struct iattr *iap = &open->op_iattr; + struct nfsd_attrs attrs = { + .na_iattr = iap, ++ .na_seclabel = &open->op_label, + }; + struct dentry *parent, *child; + __u32 v_mtime, v_atime; +@@ -409,6 +380,8 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp, + set_attr: + status = nfsd_create_setattr(rqstp, fhp, resfhp, &attrs); + ++ if (attrs.na_labelerr) ++ open->op_bmval[2] &= ~FATTR4_WORD2_SECURITY_LABEL; + out: + fh_unlock(fhp); + if (child && !IS_ERR(child)) +@@ -450,9 +423,6 @@ do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, stru + status = nfsd4_create_file(rqstp, current_fh, *resfh, open); + current->fs->umask = 0; + +- if (!status && open->op_label.len) +- nfsd4_security_inode_setsecctx(*resfh, &open->op_label, open->op_bmval); +- + /* + * Following rfc 3530 14.2.16, and rfc 5661 18.16.4 + * use the returned bitmask to indicate which attributes +@@ -792,6 +762,7 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + struct nfsd4_create *create = &u->create; + struct nfsd_attrs attrs = { + .na_iattr = &create->cr_iattr, ++ .na_seclabel = &create->cr_label, + }; + struct svc_fh resfh; + __be32 status; +@@ -864,8 +835,8 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + if (status) + goto out; + +- if (create->cr_label.len) +- nfsd4_security_inode_setsecctx(&resfh, &create->cr_label, create->cr_bmval); ++ if (attrs.na_labelerr) ++ create->cr_bmval[2] &= ~FATTR4_WORD2_SECURITY_LABEL; + + if (create->cr_acl != NULL) + do_set_nfs4_acl(rqstp, &resfh, create->cr_acl, +@@ -1150,6 +1121,7 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + struct nfsd4_setattr *setattr = &u->setattr; + struct nfsd_attrs attrs = { + .na_iattr = &setattr->sa_iattr, ++ .na_seclabel = &setattr->sa_label, + }; + __be32 status = nfs_ok; + int err; +@@ -1178,13 +1150,10 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + setattr->sa_acl); + if (status) + goto out; +- if (setattr->sa_label.len) +- status = nfsd4_set_nfs4_label(rqstp, &cstate->current_fh, +- &setattr->sa_label); +- if (status) +- goto out; + status = nfsd_setattr(rqstp, &cstate->current_fh, &attrs, + 0, (time64_t)0); ++ if (!status) ++ status = nfserrno(attrs.na_labelerr); + out: + fh_drop_write(&cstate->current_fh); + return status; +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index f5a1f41cddfff..01c431ed90ecf 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -471,6 +471,9 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, + host_err = notify_change(dentry, iap, NULL); + + out_unlock: ++ if (attr->na_seclabel && attr->na_seclabel->len) ++ attr->na_labelerr = security_inode_setsecctx(dentry, ++ attr->na_seclabel->data, attr->na_seclabel->len); + fh_unlock(fhp); + if (size_change) + put_write_access(inode); +@@ -508,32 +511,6 @@ int nfsd4_is_junction(struct dentry *dentry) + return 0; + return 1; + } +-#ifdef CONFIG_NFSD_V4_SECURITY_LABEL +-__be32 nfsd4_set_nfs4_label(struct svc_rqst *rqstp, struct svc_fh *fhp, +- struct xdr_netobj *label) +-{ +- __be32 error; +- int host_error; +- struct dentry *dentry; +- +- error = fh_verify(rqstp, fhp, 0 /* S_IFREG */, NFSD_MAY_SATTR); +- if (error) +- return error; +- +- dentry = fhp->fh_dentry; +- +- inode_lock(d_inode(dentry)); +- host_error = security_inode_setsecctx(dentry, label->data, label->len); +- inode_unlock(d_inode(dentry)); +- return nfserrno(host_error); +-} +-#else +-__be32 nfsd4_set_nfs4_label(struct svc_rqst *rqstp, struct svc_fh *fhp, +- struct xdr_netobj *label) +-{ +- return nfserr_notsupp; +-} +-#endif + + static struct nfsd4_compound_state *nfsd4_get_cstate(struct svc_rqst *rqstp) + { +diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h +index 5047cec4c423c..d5d4cfe37c933 100644 +--- a/fs/nfsd/vfs.h ++++ b/fs/nfsd/vfs.h +@@ -44,6 +44,9 @@ typedef int (*nfsd_filldir_t)(void *, const char *, int, loff_t, u64, unsigned); + /* nfsd/vfs.c */ + struct nfsd_attrs { + struct iattr *na_iattr; /* input */ ++ struct xdr_netobj *na_seclabel; /* input */ ++ ++ int na_labelerr; /* output */ + }; + + int nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp, +@@ -57,8 +60,6 @@ __be32 nfsd_setattr(struct svc_rqst *, struct svc_fh *, + struct nfsd_attrs *, int, time64_t); + int nfsd_mountpoint(struct dentry *, struct svc_export *); + #ifdef CONFIG_NFSD_V4 +-__be32 nfsd4_set_nfs4_label(struct svc_rqst *, struct svc_fh *, +- struct xdr_netobj *); + __be32 nfsd4_vfs_fallocate(struct svc_rqst *, struct svc_fh *, + struct file *, loff_t, loff_t, int); + __be32 nfsd4_clone_file_range(struct svc_rqst *rqstp, +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-shrinker-to-reap-courtesy-clients-on-low-me.patch b/queue-5.10/nfsd-add-shrinker-to-reap-courtesy-clients-on-low-me.patch new file mode 100644 index 00000000000..9c7c10b7c62 --- /dev/null +++ b/queue-5.10/nfsd-add-shrinker-to-reap-courtesy-clients-on-low-me.patch @@ -0,0 +1,239 @@ +From b5e7c8b3931467061a7e9b035b4a1ba0a5029e80 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Sep 2022 08:54:26 -0700 +Subject: NFSD: add shrinker to reap courtesy clients on low memory condition + +From: Dai Ngo + +[ Upstream commit 7746b32f467b3813fb61faaab3258de35806a7ac ] + +Add courtesy_client_reaper to react to low memory condition triggered +by the system memory shrinker. + +The delayed_work for the courtesy_client_reaper is scheduled on +the shrinker's count callback using the laundry_wq. + +The shrinker's scan callback is not used for expiring the courtesy +clients due to potential deadlocks. + +Signed-off-by: Dai Ngo +[ cel: adjusted to apply without e33c267ab70d ] +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/netns.h | 2 + + fs/nfsd/nfs4state.c | 94 +++++++++++++++++++++++++++++++++++++++++---- + fs/nfsd/nfsctl.c | 6 ++- + fs/nfsd/nfsd.h | 6 ++- + 4 files changed, 96 insertions(+), 12 deletions(-) + +diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h +index 55c7006d6109a..8c854ba3285bb 100644 +--- a/fs/nfsd/netns.h ++++ b/fs/nfsd/netns.h +@@ -194,6 +194,8 @@ struct nfsd_net { + int nfs4_max_clients; + + atomic_t nfsd_courtesy_clients; ++ struct shrinker nfsd_client_shrinker; ++ struct delayed_work nfsd_shrinker_work; + }; + + /* Simple check to find out if a given net was properly initialized */ +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 9930c5f9440c7..d2468a408328d 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -4366,7 +4366,27 @@ nfsd4_init_slabs(void) + return -ENOMEM; + } + +-void nfsd4_init_leases_net(struct nfsd_net *nn) ++static unsigned long ++nfsd_courtesy_client_count(struct shrinker *shrink, struct shrink_control *sc) ++{ ++ int cnt; ++ struct nfsd_net *nn = container_of(shrink, ++ struct nfsd_net, nfsd_client_shrinker); ++ ++ cnt = atomic_read(&nn->nfsd_courtesy_clients); ++ if (cnt > 0) ++ mod_delayed_work(laundry_wq, &nn->nfsd_shrinker_work, 0); ++ return (unsigned long)cnt; ++} ++ ++static unsigned long ++nfsd_courtesy_client_scan(struct shrinker *shrink, struct shrink_control *sc) ++{ ++ return SHRINK_STOP; ++} ++ ++int ++nfsd4_init_leases_net(struct nfsd_net *nn) + { + struct sysinfo si; + u64 max_clients; +@@ -4387,6 +4407,16 @@ void nfsd4_init_leases_net(struct nfsd_net *nn) + nn->nfs4_max_clients = max_t(int, max_clients, NFS4_CLIENTS_PER_GB); + + atomic_set(&nn->nfsd_courtesy_clients, 0); ++ nn->nfsd_client_shrinker.scan_objects = nfsd_courtesy_client_scan; ++ nn->nfsd_client_shrinker.count_objects = nfsd_courtesy_client_count; ++ nn->nfsd_client_shrinker.seeks = DEFAULT_SEEKS; ++ return register_shrinker(&nn->nfsd_client_shrinker); ++} ++ ++void ++nfsd4_leases_net_shutdown(struct nfsd_net *nn) ++{ ++ unregister_shrinker(&nn->nfsd_client_shrinker); + } + + static void init_nfs4_replay(struct nfs4_replay *rp) +@@ -5959,10 +5989,49 @@ nfs4_get_client_reaplist(struct nfsd_net *nn, struct list_head *reaplist, + spin_unlock(&nn->client_lock); + } + ++static void ++nfs4_get_courtesy_client_reaplist(struct nfsd_net *nn, ++ struct list_head *reaplist) ++{ ++ unsigned int maxreap = 0, reapcnt = 0; ++ struct list_head *pos, *next; ++ struct nfs4_client *clp; ++ ++ maxreap = NFSD_CLIENT_MAX_TRIM_PER_RUN; ++ INIT_LIST_HEAD(reaplist); ++ ++ spin_lock(&nn->client_lock); ++ list_for_each_safe(pos, next, &nn->client_lru) { ++ clp = list_entry(pos, struct nfs4_client, cl_lru); ++ if (clp->cl_state == NFSD4_ACTIVE) ++ break; ++ if (reapcnt >= maxreap) ++ break; ++ if (!mark_client_expired_locked(clp)) { ++ list_add(&clp->cl_lru, reaplist); ++ reapcnt++; ++ } ++ } ++ spin_unlock(&nn->client_lock); ++} ++ ++static void ++nfs4_process_client_reaplist(struct list_head *reaplist) ++{ ++ struct list_head *pos, *next; ++ struct nfs4_client *clp; ++ ++ list_for_each_safe(pos, next, reaplist) { ++ clp = list_entry(pos, struct nfs4_client, cl_lru); ++ trace_nfsd_clid_purged(&clp->cl_clientid); ++ list_del_init(&clp->cl_lru); ++ expire_client(clp); ++ } ++} ++ + static time64_t + nfs4_laundromat(struct nfsd_net *nn) + { +- struct nfs4_client *clp; + struct nfs4_openowner *oo; + struct nfs4_delegation *dp; + struct nfs4_ol_stateid *stp; +@@ -5991,12 +6060,8 @@ nfs4_laundromat(struct nfsd_net *nn) + } + spin_unlock(&nn->s2s_cp_lock); + nfs4_get_client_reaplist(nn, &reaplist, <); +- list_for_each_safe(pos, next, &reaplist) { +- clp = list_entry(pos, struct nfs4_client, cl_lru); +- trace_nfsd_clid_purged(&clp->cl_clientid); +- list_del_init(&clp->cl_lru); +- expire_client(clp); +- } ++ nfs4_process_client_reaplist(&reaplist); ++ + spin_lock(&state_lock); + list_for_each_safe(pos, next, &nn->del_recall_lru) { + dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); +@@ -6079,6 +6144,18 @@ laundromat_main(struct work_struct *laundry) + queue_delayed_work(laundry_wq, &nn->laundromat_work, t*HZ); + } + ++static void ++courtesy_client_reaper(struct work_struct *reaper) ++{ ++ struct list_head reaplist; ++ struct delayed_work *dwork = to_delayed_work(reaper); ++ struct nfsd_net *nn = container_of(dwork, struct nfsd_net, ++ nfsd_shrinker_work); ++ ++ nfs4_get_courtesy_client_reaplist(nn, &reaplist); ++ nfs4_process_client_reaplist(&reaplist); ++} ++ + static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stid *stp) + { + if (!fh_match(&fhp->fh_handle, &stp->sc_file->fi_fhandle)) +@@ -7911,6 +7988,7 @@ static int nfs4_state_create_net(struct net *net) + INIT_LIST_HEAD(&nn->blocked_locks_lru); + + INIT_DELAYED_WORK(&nn->laundromat_work, laundromat_main); ++ INIT_DELAYED_WORK(&nn->nfsd_shrinker_work, courtesy_client_reaper); + get_net(net); + + return 0; +diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c +index 917fa1892fd2d..597a26ad4183f 100644 +--- a/fs/nfsd/nfsctl.c ++++ b/fs/nfsd/nfsctl.c +@@ -1481,11 +1481,12 @@ static __net_init int nfsd_init_net(struct net *net) + goto out_idmap_error; + nn->nfsd_versions = NULL; + nn->nfsd4_minorversions = NULL; ++ retval = nfsd4_init_leases_net(nn); ++ if (retval) ++ goto out_drc_error; + retval = nfsd_reply_cache_init(nn); + if (retval) + goto out_drc_error; +- nfsd4_init_leases_net(nn); +- + get_random_bytes(&nn->siphash_key, sizeof(nn->siphash_key)); + seqlock_init(&nn->writeverf_lock); + +@@ -1507,6 +1508,7 @@ static __net_exit void nfsd_exit_net(struct net *net) + nfsd_idmap_shutdown(net); + nfsd_export_shutdown(net); + nfsd_netns_free_versions(net_generic(net, nfsd_net_id)); ++ nfsd4_leases_net_shutdown(nn); + } + + static struct pernet_operations nfsd_net_ops = { +diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h +index 6ab4ad41ae84e..09726c5b9a317 100644 +--- a/fs/nfsd/nfsd.h ++++ b/fs/nfsd/nfsd.h +@@ -505,7 +505,8 @@ extern void unregister_cld_notifier(void); + extern void nfsd4_ssc_init_umount_work(struct nfsd_net *nn); + #endif + +-extern void nfsd4_init_leases_net(struct nfsd_net *nn); ++extern int nfsd4_init_leases_net(struct nfsd_net *nn); ++extern void nfsd4_leases_net_shutdown(struct nfsd_net *nn); + + #else /* CONFIG_NFSD_V4 */ + static inline int nfsd4_is_junction(struct dentry *dentry) +@@ -513,7 +514,8 @@ static inline int nfsd4_is_junction(struct dentry *dentry) + return 0; + } + +-static inline void nfsd4_init_leases_net(struct nfsd_net *nn) {}; ++static inline int nfsd4_init_leases_net(struct nfsd_net *nn) { return 0; }; ++static inline void nfsd4_leases_net_shutdown(struct nfsd_net *nn) {}; + + #define register_cld_notifier() 0 + #define unregister_cld_notifier() do { } while(0) +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-some-comments-to-nfsd_file_do_acquire.patch b/queue-5.10/nfsd-add-some-comments-to-nfsd_file_do_acquire.patch new file mode 100644 index 00000000000..fe1ebad65e4 --- /dev/null +++ b/queue-5.10/nfsd-add-some-comments-to-nfsd_file_do_acquire.patch @@ -0,0 +1,39 @@ +From 10f6193e232c67ccd4fb1887693d109fc859aae0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Jan 2023 07:15:12 -0500 +Subject: nfsd: add some comments to nfsd_file_do_acquire + +From: Jeff Layton + +[ Upstream commit b680cb9b737331aad271feebbedafb865504e234 ] + +David Howells mentioned that he found this bit of code confusing, so +sprinkle in some comments to clarify. + +Reported-by: David Howells +Signed-off-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index 43bb2fd47cf58..faa0c7d0253eb 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -1093,6 +1093,11 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + rcu_read_unlock(); + + if (nf) { ++ /* ++ * If the nf is on the LRU then it holds an extra reference ++ * that must be put if it's removed. It had better not be ++ * the last one however, since we should hold another. ++ */ + if (nfsd_file_lru_remove(nf)) + WARN_ON_ONCE(refcount_dec_and_test(&nf->nf_ref)); + goto wait_for_construction; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-spdx-header-for-fs-nfsd-trace.c.patch b/queue-5.10/nfsd-add-spdx-header-for-fs-nfsd-trace.c.patch new file mode 100644 index 00000000000..52e3ed1ae7f --- /dev/null +++ b/queue-5.10/nfsd-add-spdx-header-for-fs-nfsd-trace.c.patch @@ -0,0 +1,32 @@ +From 657d26a5ae066b63f7d03e2e5b16bc1d17e19585 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 27 Aug 2020 16:09:53 -0400 +Subject: NFSD: Add SPDX header for fs/nfsd/trace.c + +From: Chuck Lever + +[ Upstream commit f45a444cfe582b85af937a30d35d68d9a84399dd ] + +Clean up. + +The file was contributed in 2014 by Christoph Hellwig in commit +31ef83dc0538 ("nfsd: add trace events"). + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/trace.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/nfsd/trace.c b/fs/nfsd/trace.c +index 90967466a1e56..f008b95ceec2e 100644 +--- a/fs/nfsd/trace.c ++++ b/fs/nfsd/trace.c +@@ -1,3 +1,4 @@ ++// SPDX-License-Identifier: GPL-2.0 + + #define CREATE_TRACE_POINTS + #include "trace.h" +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-support-for-lock-conflict-to-courteous-serv.patch b/queue-5.10/nfsd-add-support-for-lock-conflict-to-courteous-serv.patch new file mode 100644 index 00000000000..5ffccd64f2f --- /dev/null +++ b/queue-5.10/nfsd-add-support-for-lock-conflict-to-courteous-serv.patch @@ -0,0 +1,145 @@ +From 3fa19e4a0d72d1dde4639fef65d33bd65247432f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 May 2022 14:19:26 -0700 +Subject: NFSD: add support for lock conflict to courteous server + +From: Dai Ngo + +[ Upstream commit 27431affb0dbc259ac6ffe6071243a576c8f38f1 ] + +This patch allows expired client with lock state to be in COURTESY +state. Lock conflict with COURTESY client is resolved by the fs/lock +code using the lm_lock_expirable and lm_expire_lock callback in the +struct lock_manager_operations. + +If conflict client is in COURTESY state, set it to EXPIRABLE and +schedule the laundromat to run immediately to expire the client. The +callback lm_expire_lock waits for the laundromat to flush its work +queue before returning to caller. + +Reviewed-by: J. Bruce Fields +Signed-off-by: Dai Ngo +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 70 ++++++++++++++++++++++++++++++++++----------- + 1 file changed, 54 insertions(+), 16 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 30ea1c7b6b9fd..6851fece3a760 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -5731,39 +5731,51 @@ static void nfsd4_ssc_expire_umount(struct nfsd_net *nn) + } + #endif + ++/* Check if any lock belonging to this lockowner has any blockers */ + static bool +-nfs4_has_any_locks(struct nfs4_client *clp) ++nfs4_lockowner_has_blockers(struct nfs4_lockowner *lo) ++{ ++ struct file_lock_context *ctx; ++ struct nfs4_ol_stateid *stp; ++ struct nfs4_file *nf; ++ ++ list_for_each_entry(stp, &lo->lo_owner.so_stateids, st_perstateowner) { ++ nf = stp->st_stid.sc_file; ++ ctx = nf->fi_inode->i_flctx; ++ if (!ctx) ++ continue; ++ if (locks_owner_has_blockers(ctx, lo)) ++ return true; ++ } ++ return false; ++} ++ ++static bool ++nfs4_anylock_blockers(struct nfs4_client *clp) + { + int i; + struct nfs4_stateowner *so; ++ struct nfs4_lockowner *lo; + ++ if (atomic_read(&clp->cl_delegs_in_recall)) ++ return true; + spin_lock(&clp->cl_lock); + for (i = 0; i < OWNER_HASH_SIZE; i++) { + list_for_each_entry(so, &clp->cl_ownerstr_hashtbl[i], + so_strhash) { + if (so->so_is_open_owner) + continue; +- spin_unlock(&clp->cl_lock); +- return true; ++ lo = lockowner(so); ++ if (nfs4_lockowner_has_blockers(lo)) { ++ spin_unlock(&clp->cl_lock); ++ return true; ++ } + } + } + spin_unlock(&clp->cl_lock); + return false; + } + +-/* +- * place holder for now, no check for lock blockers yet +- */ +-static bool +-nfs4_anylock_blockers(struct nfs4_client *clp) +-{ +- if (atomic_read(&clp->cl_delegs_in_recall) || +- !list_empty(&clp->async_copies) || +- nfs4_has_any_locks(clp)) +- return true; +- return false; +-} +- + static void + nfs4_get_client_reaplist(struct nfsd_net *nn, struct list_head *reaplist, + struct laundry_time *lt) +@@ -6743,6 +6755,29 @@ nfsd4_lm_put_owner(fl_owner_t owner) + nfs4_put_stateowner(&lo->lo_owner); + } + ++/* return pointer to struct nfs4_client if client is expirable */ ++static bool ++nfsd4_lm_lock_expirable(struct file_lock *cfl) ++{ ++ struct nfs4_lockowner *lo = (struct nfs4_lockowner *)cfl->fl_owner; ++ struct nfs4_client *clp = lo->lo_owner.so_client; ++ struct nfsd_net *nn; ++ ++ if (try_to_expire_client(clp)) { ++ nn = net_generic(clp->net, nfsd_net_id); ++ mod_delayed_work(laundry_wq, &nn->laundromat_work, 0); ++ return true; ++ } ++ return false; ++} ++ ++/* schedule laundromat to run immediately and wait for it to complete */ ++static void ++nfsd4_lm_expire_lock(void) ++{ ++ flush_workqueue(laundry_wq); ++} ++ + static void + nfsd4_lm_notify(struct file_lock *fl) + { +@@ -6769,9 +6804,12 @@ nfsd4_lm_notify(struct file_lock *fl) + } + + static const struct lock_manager_operations nfsd_posix_mng_ops = { ++ .lm_mod_owner = THIS_MODULE, + .lm_notify = nfsd4_lm_notify, + .lm_get_owner = nfsd4_lm_get_owner, + .lm_put_owner = nfsd4_lm_put_owner, ++ .lm_lock_expirable = nfsd4_lm_lock_expirable, ++ .lm_expire_lock = nfsd4_lm_expire_lock, + }; + + static inline void +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-support-for-sending-cb_recall_any.patch b/queue-5.10/nfsd-add-support-for-sending-cb_recall_any.patch new file mode 100644 index 00000000000..bdf5c9e2c65 --- /dev/null +++ b/queue-5.10/nfsd-add-support-for-sending-cb_recall_any.patch @@ -0,0 +1,177 @@ +From 50c5a1561714499f4196c3b391385ae1236fdd17 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 16 Nov 2022 19:44:46 -0800 +Subject: NFSD: add support for sending CB_RECALL_ANY + +From: Dai Ngo + +[ Upstream commit 3959066b697b5dfbb7141124ae9665337d4bc638 ] + +Add XDR encode and decode function for CB_RECALL_ANY. + +Signed-off-by: Dai Ngo +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4callback.c | 72 ++++++++++++++++++++++++++++++++++++++++++ + fs/nfsd/state.h | 1 + + fs/nfsd/xdr4.h | 5 +++ + fs/nfsd/xdr4cb.h | 6 ++++ + 4 files changed, 84 insertions(+) + +diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c +index 39989c14c8a1e..4eae2c5af2edf 100644 +--- a/fs/nfsd/nfs4callback.c ++++ b/fs/nfsd/nfs4callback.c +@@ -76,6 +76,17 @@ static __be32 *xdr_encode_empty_array(__be32 *p) + * 1 Protocol" + */ + ++static void encode_uint32(struct xdr_stream *xdr, u32 n) ++{ ++ WARN_ON_ONCE(xdr_stream_encode_u32(xdr, n) < 0); ++} ++ ++static void encode_bitmap4(struct xdr_stream *xdr, const __u32 *bitmap, ++ size_t len) ++{ ++ WARN_ON_ONCE(xdr_stream_encode_uint32_array(xdr, bitmap, len) < 0); ++} ++ + /* + * nfs_cb_opnum4 + * +@@ -328,6 +339,24 @@ static void encode_cb_recall4args(struct xdr_stream *xdr, + hdr->nops++; + } + ++/* ++ * CB_RECALLANY4args ++ * ++ * struct CB_RECALLANY4args { ++ * uint32_t craa_objects_to_keep; ++ * bitmap4 craa_type_mask; ++ * }; ++ */ ++static void ++encode_cb_recallany4args(struct xdr_stream *xdr, ++ struct nfs4_cb_compound_hdr *hdr, struct nfsd4_cb_recall_any *ra) ++{ ++ encode_nfs_cb_opnum4(xdr, OP_CB_RECALL_ANY); ++ encode_uint32(xdr, ra->ra_keep); ++ encode_bitmap4(xdr, ra->ra_bmval, ARRAY_SIZE(ra->ra_bmval)); ++ hdr->nops++; ++} ++ + /* + * CB_SEQUENCE4args + * +@@ -482,6 +511,26 @@ static void nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, struct xdr_stream *xdr, + encode_cb_nops(&hdr); + } + ++/* ++ * 20.6. Operation 8: CB_RECALL_ANY - Keep Any N Recallable Objects ++ */ ++static void ++nfs4_xdr_enc_cb_recall_any(struct rpc_rqst *req, ++ struct xdr_stream *xdr, const void *data) ++{ ++ const struct nfsd4_callback *cb = data; ++ struct nfsd4_cb_recall_any *ra; ++ struct nfs4_cb_compound_hdr hdr = { ++ .ident = cb->cb_clp->cl_cb_ident, ++ .minorversion = cb->cb_clp->cl_minorversion, ++ }; ++ ++ ra = container_of(cb, struct nfsd4_cb_recall_any, ra_cb); ++ encode_cb_compound4args(xdr, &hdr); ++ encode_cb_sequence4args(xdr, cb, &hdr); ++ encode_cb_recallany4args(xdr, &hdr, ra); ++ encode_cb_nops(&hdr); ++} + + /* + * NFSv4.0 and NFSv4.1 XDR decode functions +@@ -520,6 +569,28 @@ static int nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp, + return decode_cb_op_status(xdr, OP_CB_RECALL, &cb->cb_status); + } + ++/* ++ * 20.6. Operation 8: CB_RECALL_ANY - Keep Any N Recallable Objects ++ */ ++static int ++nfs4_xdr_dec_cb_recall_any(struct rpc_rqst *rqstp, ++ struct xdr_stream *xdr, ++ void *data) ++{ ++ struct nfsd4_callback *cb = data; ++ struct nfs4_cb_compound_hdr hdr; ++ int status; ++ ++ status = decode_cb_compound4res(xdr, &hdr); ++ if (unlikely(status)) ++ return status; ++ status = decode_cb_sequence4res(xdr, cb); ++ if (unlikely(status || cb->cb_seq_status)) ++ return status; ++ status = decode_cb_op_status(xdr, OP_CB_RECALL_ANY, &cb->cb_status); ++ return status; ++} ++ + #ifdef CONFIG_NFSD_PNFS + /* + * CB_LAYOUTRECALL4args +@@ -783,6 +854,7 @@ static const struct rpc_procinfo nfs4_cb_procedures[] = { + #endif + PROC(CB_NOTIFY_LOCK, COMPOUND, cb_notify_lock, cb_notify_lock), + PROC(CB_OFFLOAD, COMPOUND, cb_offload, cb_offload), ++ PROC(CB_RECALL_ANY, COMPOUND, cb_recall_any, cb_recall_any), + }; + + static unsigned int nfs4_cb_counts[ARRAY_SIZE(nfs4_cb_procedures)]; +diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h +index eadd7f465bf52..e30882f8b8516 100644 +--- a/fs/nfsd/state.h ++++ b/fs/nfsd/state.h +@@ -636,6 +636,7 @@ enum nfsd4_cb_op { + NFSPROC4_CLNT_CB_OFFLOAD, + NFSPROC4_CLNT_CB_SEQUENCE, + NFSPROC4_CLNT_CB_NOTIFY_LOCK, ++ NFSPROC4_CLNT_CB_RECALL_ANY, + }; + + /* Returns true iff a is later than b: */ +diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h +index 8f323d9071f06..24934cf90a84f 100644 +--- a/fs/nfsd/xdr4.h ++++ b/fs/nfsd/xdr4.h +@@ -896,6 +896,11 @@ struct nfsd4_operation { + union nfsd4_op_u *); + }; + ++struct nfsd4_cb_recall_any { ++ struct nfsd4_callback ra_cb; ++ u32 ra_keep; ++ u32 ra_bmval[1]; ++}; + + #endif + +diff --git a/fs/nfsd/xdr4cb.h b/fs/nfsd/xdr4cb.h +index 547cf07cf4e08..0d39af1b00a0f 100644 +--- a/fs/nfsd/xdr4cb.h ++++ b/fs/nfsd/xdr4cb.h +@@ -48,3 +48,9 @@ + #define NFS4_dec_cb_offload_sz (cb_compound_dec_hdr_sz + \ + cb_sequence_dec_sz + \ + op_dec_sz) ++#define NFS4_enc_cb_recall_any_sz (cb_compound_enc_hdr_sz + \ ++ cb_sequence_enc_sz + \ ++ 1 + 1 + 1) ++#define NFS4_dec_cb_recall_any_sz (cb_compound_dec_hdr_sz + \ ++ cb_sequence_dec_sz + \ ++ op_dec_sz) +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-support-for-share-reservation-conflict-to-c.patch b/queue-5.10/nfsd-add-support-for-share-reservation-conflict-to-c.patch new file mode 100644 index 00000000000..a5a28b0d52e --- /dev/null +++ b/queue-5.10/nfsd-add-support-for-share-reservation-conflict-to-c.patch @@ -0,0 +1,205 @@ +From aa41cb7955548a9bbd10ca15779a1b3942d3593e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 May 2022 14:19:22 -0700 +Subject: NFSD: add support for share reservation conflict to courteous server + +From: Dai Ngo + +[ Upstream commit 3d69427151806656abf129342028f3f4e5e1fee0 ] + +This patch allows expired client with open state to be in COURTESY +state. Share/access conflict with COURTESY client is resolved by +setting COURTESY client to EXPIRABLE state, schedule laundromat +to run and returning nfserr_jukebox to the request client. + +Reviewed-by: J. Bruce Fields +Signed-off-by: Dai Ngo +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 109 ++++++++++++++++++++++++++++++++++++++++---- + 1 file changed, 101 insertions(+), 8 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 74c0a88904047..4ba0a70d8990f 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -705,6 +705,57 @@ static unsigned int file_hashval(struct svc_fh *fh) + + static struct hlist_head file_hashtbl[FILE_HASH_SIZE]; + ++/* ++ * Check if courtesy clients have conflicting access and resolve it if possible ++ * ++ * access: is op_share_access if share_access is true. ++ * Check if access mode, op_share_access, would conflict with ++ * the current deny mode of the file 'fp'. ++ * access: is op_share_deny if share_access is false. ++ * Check if the deny mode, op_share_deny, would conflict with ++ * current access of the file 'fp'. ++ * stp: skip checking this entry. ++ * new_stp: normal open, not open upgrade. ++ * ++ * Function returns: ++ * false - access/deny mode conflict with normal client. ++ * true - no conflict or conflict with courtesy client(s) is resolved. ++ */ ++static bool ++nfs4_resolve_deny_conflicts_locked(struct nfs4_file *fp, bool new_stp, ++ struct nfs4_ol_stateid *stp, u32 access, bool share_access) ++{ ++ struct nfs4_ol_stateid *st; ++ bool resolvable = true; ++ unsigned char bmap; ++ struct nfsd_net *nn; ++ struct nfs4_client *clp; ++ ++ lockdep_assert_held(&fp->fi_lock); ++ list_for_each_entry(st, &fp->fi_stateids, st_perfile) { ++ /* ignore lock stateid */ ++ if (st->st_openstp) ++ continue; ++ if (st == stp && new_stp) ++ continue; ++ /* check file access against deny mode or vice versa */ ++ bmap = share_access ? st->st_deny_bmap : st->st_access_bmap; ++ if (!(access & bmap_to_share_mode(bmap))) ++ continue; ++ clp = st->st_stid.sc_client; ++ if (try_to_expire_client(clp)) ++ continue; ++ resolvable = false; ++ break; ++ } ++ if (resolvable) { ++ clp = stp->st_stid.sc_client; ++ nn = net_generic(clp->net, nfsd_net_id); ++ mod_delayed_work(laundry_wq, &nn->laundromat_work, 0); ++ } ++ return resolvable; ++} ++ + static void + __nfs4_file_get_access(struct nfs4_file *fp, u32 access) + { +@@ -4985,7 +5036,7 @@ nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh, + + static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp, + struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp, +- struct nfsd4_open *open) ++ struct nfsd4_open *open, bool new_stp) + { + struct nfsd_file *nf = NULL; + __be32 status; +@@ -5001,6 +5052,13 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp, + */ + status = nfs4_file_check_deny(fp, open->op_share_deny); + if (status != nfs_ok) { ++ if (status != nfserr_share_denied) { ++ spin_unlock(&fp->fi_lock); ++ goto out; ++ } ++ if (nfs4_resolve_deny_conflicts_locked(fp, new_stp, ++ stp, open->op_share_deny, false)) ++ status = nfserr_jukebox; + spin_unlock(&fp->fi_lock); + goto out; + } +@@ -5008,6 +5066,13 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp, + /* set access to the file */ + status = nfs4_file_get_access(fp, open->op_share_access); + if (status != nfs_ok) { ++ if (status != nfserr_share_denied) { ++ spin_unlock(&fp->fi_lock); ++ goto out; ++ } ++ if (nfs4_resolve_deny_conflicts_locked(fp, new_stp, ++ stp, open->op_share_access, true)) ++ status = nfserr_jukebox; + spin_unlock(&fp->fi_lock); + goto out; + } +@@ -5054,21 +5119,29 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp, + } + + static __be32 +-nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp, struct nfsd4_open *open) ++nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, ++ struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp, ++ struct nfsd4_open *open) + { + __be32 status; + unsigned char old_deny_bmap = stp->st_deny_bmap; + + if (!test_access(open->op_share_access, stp)) +- return nfs4_get_vfs_file(rqstp, fp, cur_fh, stp, open); ++ return nfs4_get_vfs_file(rqstp, fp, cur_fh, stp, open, false); + + /* test and set deny mode */ + spin_lock(&fp->fi_lock); + status = nfs4_file_check_deny(fp, open->op_share_deny); + if (status == nfs_ok) { +- set_deny(open->op_share_deny, stp); +- fp->fi_share_deny |= ++ if (status != nfserr_share_denied) { ++ set_deny(open->op_share_deny, stp); ++ fp->fi_share_deny |= + (open->op_share_deny & NFS4_SHARE_DENY_BOTH); ++ } else { ++ if (nfs4_resolve_deny_conflicts_locked(fp, false, ++ stp, open->op_share_deny, false)) ++ status = nfserr_jukebox; ++ } + } + spin_unlock(&fp->fi_lock); + +@@ -5409,7 +5482,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf + goto out; + } + } else { +- status = nfs4_get_vfs_file(rqstp, fp, current_fh, stp, open); ++ status = nfs4_get_vfs_file(rqstp, fp, current_fh, stp, open, true); + if (status) { + stp->st_stid.sc_type = NFS4_CLOSED_STID; + release_open_stateid(stp); +@@ -5643,6 +5716,26 @@ static void nfsd4_ssc_expire_umount(struct nfsd_net *nn) + } + #endif + ++static bool ++nfs4_has_any_locks(struct nfs4_client *clp) ++{ ++ int i; ++ struct nfs4_stateowner *so; ++ ++ spin_lock(&clp->cl_lock); ++ for (i = 0; i < OWNER_HASH_SIZE; i++) { ++ list_for_each_entry(so, &clp->cl_ownerstr_hashtbl[i], ++ so_strhash) { ++ if (so->so_is_open_owner) ++ continue; ++ spin_unlock(&clp->cl_lock); ++ return true; ++ } ++ } ++ spin_unlock(&clp->cl_lock); ++ return false; ++} ++ + /* + * place holder for now, no check for lock blockers yet + */ +@@ -5650,8 +5743,8 @@ static bool + nfs4_anylock_blockers(struct nfs4_client *clp) + { + if (atomic_read(&clp->cl_delegs_in_recall) || +- client_has_openowners(clp) || +- !list_empty(&clp->async_copies)) ++ !list_empty(&clp->async_copies) || ++ nfs4_has_any_locks(clp)) + return true; + return false; + } +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-support-for-the-birth-time-attribute.patch b/queue-5.10/nfsd-add-support-for-the-birth-time-attribute.patch new file mode 100644 index 00000000000..bc8ded27774 --- /dev/null +++ b/queue-5.10/nfsd-add-support-for-the-birth-time-attribute.patch @@ -0,0 +1,67 @@ +From 8b6d3a1849d9c1828185822821bf746809bfb154 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 11 Jan 2022 13:08:42 +0100 +Subject: nfsd: Add support for the birth time attribute + +From: Ondrej Valousek + +[ Upstream commit e377a3e698fb56cb63f6bddbebe7da76dc37e316 ] + +For filesystems that supports "btime" timestamp (i.e. most modern +filesystems do) we share it via kernel nfsd. Btime support for NFS +client has already been added by Trond recently. + +Suggested-by: Bruce Fields +Signed-off-by: Ondrej Valousek +[ cel: addressed some whitespace/checkpatch nits ] +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 10 ++++++++++ + fs/nfsd/nfsd.h | 2 +- + 2 files changed, 11 insertions(+), 1 deletion(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index a7b9c3faf7a79..a9f6c7eeb756e 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -2854,6 +2854,9 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, + err = vfs_getattr(&path, &stat, STATX_BASIC_STATS, AT_STATX_SYNC_AS_STAT); + if (err) + goto out_nfserr; ++ if (!(stat.result_mask & STATX_BTIME)) ++ /* underlying FS does not offer btime so we can't share it */ ++ bmval1 &= ~FATTR4_WORD1_TIME_CREATE; + if ((bmval0 & (FATTR4_WORD0_FILES_AVAIL | FATTR4_WORD0_FILES_FREE | + FATTR4_WORD0_FILES_TOTAL | FATTR4_WORD0_MAXNAME)) || + (bmval1 & (FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE | +@@ -3254,6 +3257,13 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, + p = xdr_encode_hyper(p, (s64)stat.mtime.tv_sec); + *p++ = cpu_to_be32(stat.mtime.tv_nsec); + } ++ if (bmval1 & FATTR4_WORD1_TIME_CREATE) { ++ p = xdr_reserve_space(xdr, 12); ++ if (!p) ++ goto out_resource; ++ p = xdr_encode_hyper(p, (s64)stat.btime.tv_sec); ++ *p++ = cpu_to_be32(stat.btime.tv_nsec); ++ } + if (bmval1 & FATTR4_WORD1_MOUNTED_ON_FILEID) { + struct kstat parent_stat; + u64 ino = stat.ino; +diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h +index 3e5008b475ff0..4fc1fd639527a 100644 +--- a/fs/nfsd/nfsd.h ++++ b/fs/nfsd/nfsd.h +@@ -364,7 +364,7 @@ void nfsd_lockd_shutdown(void); + | FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP | FATTR4_WORD1_RAWDEV \ + | FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE | FATTR4_WORD1_SPACE_TOTAL \ + | FATTR4_WORD1_SPACE_USED | FATTR4_WORD1_TIME_ACCESS | FATTR4_WORD1_TIME_ACCESS_SET \ +- | FATTR4_WORD1_TIME_DELTA | FATTR4_WORD1_TIME_METADATA \ ++ | FATTR4_WORD1_TIME_DELTA | FATTR4_WORD1_TIME_METADATA | FATTR4_WORD1_TIME_CREATE \ + | FATTR4_WORD1_TIME_MODIFY | FATTR4_WORD1_TIME_MODIFY_SET | FATTR4_WORD1_MOUNTED_ON_FILEID) + + #define NFSD4_SUPPORTED_ATTRS_WORD2 0 +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-tracepoints-for-exchangeid-edge-cases.patch b/queue-5.10/nfsd-add-tracepoints-for-exchangeid-edge-cases.patch new file mode 100644 index 00000000000..22b62a961fd --- /dev/null +++ b/queue-5.10/nfsd-add-tracepoints-for-exchangeid-edge-cases.patch @@ -0,0 +1,84 @@ +From 265f38b86df10bacfbc739ffd33db0301aaee1f8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 14 May 2021 15:56:19 -0400 +Subject: NFSD: Add tracepoints for EXCHANGEID edge cases + +From: Chuck Lever + +[ Upstream commit e8f80c5545ec5794644b48537449e48b009d608d ] + +Some of the most common cases are traced. Enough infrastructure is +now in place that more can be added later, as needed. + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 12 +++++++++--- + fs/nfsd/trace.h | 1 + + 2 files changed, 10 insertions(+), 3 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 31310dbe9c1e2..adf476cbf36c3 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -3200,6 +3200,7 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + } + /* case 6 */ + exid->flags |= EXCHGID4_FLAG_CONFIRMED_R; ++ trace_nfsd_clid_confirmed_r(conf); + goto out_copy; + } + if (!creds_match) { /* case 3 */ +@@ -3212,6 +3213,7 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + } + if (verfs_match) { /* case 2 */ + conf->cl_exchange_flags |= EXCHGID4_FLAG_CONFIRMED_R; ++ trace_nfsd_clid_confirmed_r(conf); + goto out_copy; + } + /* case 5, client reboot */ +@@ -3225,11 +3227,13 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + goto out; + } + +- unconf = find_unconfirmed_client_by_name(&exid->clname, nn); ++ unconf = find_unconfirmed_client_by_name(&exid->clname, nn); + if (unconf) /* case 4, possible retry or client restart */ + unhash_client_locked(unconf); + +- /* case 1 (normal case) */ ++ /* case 1, new owner ID */ ++ trace_nfsd_clid_fresh(new); ++ + out_new: + if (conf) { + status = mark_client_expired_locked(conf); +@@ -3259,8 +3263,10 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + out_nolock: + if (new) + expire_client(new); +- if (unconf) ++ if (unconf) { ++ trace_nfsd_clid_expire_unconf(&unconf->cl_clientid); + expire_client(unconf); ++ } + return status; + } + +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index aa42d31cdfac1..de461c82dbf40 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -636,6 +636,7 @@ DEFINE_EVENT(nfsd_clid_class, nfsd_clid_##name, \ + TP_ARGS(clp)) + + DEFINE_CLID_EVENT(fresh); ++DEFINE_CLID_EVENT(confirmed_r); + + /* + * from fs/nfsd/filecache.h +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-tracepoints-for-setclientid-edge-cases.patch b/queue-5.10/nfsd-add-tracepoints-for-setclientid-edge-cases.patch new file mode 100644 index 00000000000..c8f75f01555 --- /dev/null +++ b/queue-5.10/nfsd-add-tracepoints-for-setclientid-edge-cases.patch @@ -0,0 +1,151 @@ +From c255c3c8458a7e254665751b15c6c5cac9767d5b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 14 May 2021 15:56:13 -0400 +Subject: NFSD: Add tracepoints for SETCLIENTID edge cases + +From: Chuck Lever + +[ Upstream commit 237f91c85acef206a33bc02f3c4e856128fd7994 ] + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 19 ++++++++----------- + fs/nfsd/trace.h | 37 +++++++++++++++++++++++++++++++++++++ + 2 files changed, 45 insertions(+), 11 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 7e8752f4affda..31310dbe9c1e2 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -4008,11 +4008,9 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + new = create_client(clname, rqstp, &clverifier); + if (new == NULL) + return nfserr_jukebox; +- /* Cases below refer to rfc 3530 section 14.2.33: */ + spin_lock(&nn->client_lock); + conf = find_confirmed_client_by_name(&clname, nn); + if (conf && client_has_state(conf)) { +- /* case 0: */ + status = nfserr_clid_inuse; + if (clp_used_exchangeid(conf)) + goto out; +@@ -4024,7 +4022,6 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + unconf = find_unconfirmed_client_by_name(&clname, nn); + if (unconf) + unhash_client_locked(unconf); +- /* We need to handle only case 1: probable callback update */ + if (conf) { + if (same_verf(&conf->cl_verifier, &clverifier)) { + copy_clid(new, conf); +@@ -4032,7 +4029,8 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + } else + trace_nfsd_clid_verf_mismatch(conf, rqstp, + &clverifier); +- } ++ } else ++ trace_nfsd_clid_fresh(new); + new->cl_minorversion = 0; + gen_callback(new, setclid, rqstp); + add_to_unconfirmed(new); +@@ -4045,12 +4043,13 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + spin_unlock(&nn->client_lock); + if (new) + free_client(new); +- if (unconf) ++ if (unconf) { ++ trace_nfsd_clid_expire_unconf(&unconf->cl_clientid); + expire_client(unconf); ++ } + return status; + } + +- + __be32 + nfsd4_setclientid_confirm(struct svc_rqst *rqstp, + struct nfsd4_compound_state *cstate, +@@ -4087,21 +4086,19 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, + trace_nfsd_clid_cred_mismatch(conf, rqstp); + goto out; + } +- /* cases below refer to rfc 3530 section 14.2.34: */ + if (!unconf || !same_verf(&confirm, &unconf->cl_confirm)) { + if (conf && same_verf(&confirm, &conf->cl_confirm)) { +- /* case 2: probable retransmit */ + status = nfs_ok; +- } else /* case 4: client hasn't noticed we rebooted yet? */ ++ } else + status = nfserr_stale_clientid; + goto out; + } + status = nfs_ok; +- if (conf) { /* case 1: callback update */ ++ if (conf) { + old = unconf; + unhash_client_locked(old); + nfsd4_change_callback(conf, &unconf->cl_cb_conn); +- } else { /* case 3: normal case; new or rebooted client */ ++ } else { + old = find_confirmed_client_by_name(&unconf->cl_name, nn); + if (old) { + status = nfserr_clid_inuse; +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index 3271d925abf2e..aa42d31cdfac1 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -511,6 +511,7 @@ DEFINE_EVENT(nfsd_clientid_class, nfsd_clid_##name, \ + TP_PROTO(const clientid_t *clid), \ + TP_ARGS(clid)) + ++DEFINE_CLIENTID_EVENT(expire_unconf); + DEFINE_CLIENTID_EVENT(reclaim_complete); + DEFINE_CLIENTID_EVENT(confirmed); + DEFINE_CLIENTID_EVENT(destroyed); +@@ -600,6 +601,42 @@ TRACE_EVENT(nfsd_clid_verf_mismatch, + ) + ); + ++DECLARE_EVENT_CLASS(nfsd_clid_class, ++ TP_PROTO(const struct nfs4_client *clp), ++ TP_ARGS(clp), ++ TP_STRUCT__entry( ++ __field(u32, cl_boot) ++ __field(u32, cl_id) ++ __array(unsigned char, addr, sizeof(struct sockaddr_in6)) ++ __field(unsigned long, flavor) ++ __array(unsigned char, verifier, NFS4_VERIFIER_SIZE) ++ __dynamic_array(char, name, clp->cl_name.len + 1) ++ ), ++ TP_fast_assign( ++ __entry->cl_boot = clp->cl_clientid.cl_boot; ++ __entry->cl_id = clp->cl_clientid.cl_id; ++ memcpy(__entry->addr, &clp->cl_addr, ++ sizeof(struct sockaddr_in6)); ++ __entry->flavor = clp->cl_cred.cr_flavor; ++ memcpy(__entry->verifier, (void *)&clp->cl_verifier, ++ NFS4_VERIFIER_SIZE); ++ memcpy(__get_str(name), clp->cl_name.data, clp->cl_name.len); ++ __get_str(name)[clp->cl_name.len] = '\0'; ++ ), ++ TP_printk("addr=%pISpc name='%s' verifier=0x%s flavor=%s client=%08x:%08x", ++ __entry->addr, __get_str(name), ++ __print_hex_str(__entry->verifier, NFS4_VERIFIER_SIZE), ++ show_nfsd_authflavor(__entry->flavor), ++ __entry->cl_boot, __entry->cl_id) ++); ++ ++#define DEFINE_CLID_EVENT(name) \ ++DEFINE_EVENT(nfsd_clid_class, nfsd_clid_##name, \ ++ TP_PROTO(const struct nfs4_client *clp), \ ++ TP_ARGS(clp)) ++ ++DEFINE_CLID_EVENT(fresh); ++ + /* + * from fs/nfsd/filecache.h + */ +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-tracepoints-in-nfsd4_decode-encode_compound.patch b/queue-5.10/nfsd-add-tracepoints-in-nfsd4_decode-encode_compound.patch new file mode 100644 index 00000000000..8745ee849b4 --- /dev/null +++ b/queue-5.10/nfsd-add-tracepoints-in-nfsd4_decode-encode_compound.patch @@ -0,0 +1,150 @@ +From fcaabeb3a0366b474d07e28d094ee574f39215ae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 21 Nov 2020 11:36:42 -0500 +Subject: NFSD: Add tracepoints in nfsd4_decode/encode_compound() + +From: Chuck Lever + +[ Upstream commit 08281341be8ebc97ee47999812bcf411942baa1e ] + +For troubleshooting purposes, record failures to decode NFSv4 +operation arguments and encode operation results. + +trace_nfsd_compound_decode_err() replaces the dprintk() call sites +that are embedded in READ_* macros that are about to be removed. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 13 +++++++-- + fs/nfsd/trace.h | 68 +++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 79 insertions(+), 2 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index c176d0090f7c8..101ada3636b78 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -54,6 +54,8 @@ + #include "pnfs.h" + #include "filecache.h" + ++#include "trace.h" ++ + #ifdef CONFIG_NFSD_V4_SECURITY_LABEL + #include + #endif +@@ -2248,9 +2250,14 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) + READ_BUF(4); + op->opnum = be32_to_cpup(p++); + +- if (nfsd4_opnum_in_range(argp, op)) ++ if (nfsd4_opnum_in_range(argp, op)) { + op->status = nfsd4_dec_ops[op->opnum](argp, &op->u); +- else { ++ if (op->status != nfs_ok) ++ trace_nfsd_compound_decode_err(argp->rqstp, ++ argp->opcnt, i, ++ op->opnum, ++ op->status); ++ } else { + op->opnum = OP_ILLEGAL; + op->status = nfserr_op_illegal; + } +@@ -5220,6 +5227,8 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) + !nfsd4_enc_ops[op->opnum]); + encoder = nfsd4_enc_ops[op->opnum]; + op->status = encoder(resp, op->status, &op->u); ++ if (op->status) ++ trace_nfsd_compound_encode_err(rqstp, op->opnum, op->status); + if (opdesc && opdesc->op_release) + opdesc->op_release(&op->u); + xdr_commit_encode(xdr); +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index dbbda3e09eedd..2bc2a888f7fa8 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -28,6 +28,24 @@ + rqstp->rq_xprt->xpt_remotelen); \ + } while (0); + ++#define NFSD_TRACE_PROC_RES_FIELDS \ ++ __field(unsigned int, netns_ino) \ ++ __field(u32, xid) \ ++ __field(unsigned long, status) \ ++ __array(unsigned char, server, sizeof(struct sockaddr_in6)) \ ++ __array(unsigned char, client, sizeof(struct sockaddr_in6)) ++ ++#define NFSD_TRACE_PROC_RES_ASSIGNMENTS(error) \ ++ do { \ ++ __entry->netns_ino = SVC_NET(rqstp)->ns.inum; \ ++ __entry->xid = be32_to_cpu(rqstp->rq_xid); \ ++ __entry->status = be32_to_cpu(error); \ ++ memcpy(__entry->server, &rqstp->rq_xprt->xpt_local, \ ++ rqstp->rq_xprt->xpt_locallen); \ ++ memcpy(__entry->client, &rqstp->rq_xprt->xpt_remote, \ ++ rqstp->rq_xprt->xpt_remotelen); \ ++ } while (0); ++ + TRACE_EVENT(nfsd_garbage_args_err, + TP_PROTO( + const struct svc_rqst *rqstp +@@ -127,6 +145,56 @@ TRACE_EVENT(nfsd_compound_status, + __get_str(name), __entry->status) + ) + ++TRACE_EVENT(nfsd_compound_decode_err, ++ TP_PROTO( ++ const struct svc_rqst *rqstp, ++ u32 args_opcnt, ++ u32 resp_opcnt, ++ u32 opnum, ++ __be32 status ++ ), ++ TP_ARGS(rqstp, args_opcnt, resp_opcnt, opnum, status), ++ TP_STRUCT__entry( ++ NFSD_TRACE_PROC_RES_FIELDS ++ ++ __field(u32, args_opcnt) ++ __field(u32, resp_opcnt) ++ __field(u32, opnum) ++ ), ++ TP_fast_assign( ++ NFSD_TRACE_PROC_RES_ASSIGNMENTS(status) ++ ++ __entry->args_opcnt = args_opcnt; ++ __entry->resp_opcnt = resp_opcnt; ++ __entry->opnum = opnum; ++ ), ++ TP_printk("op=%u/%u opnum=%u status=%lu", ++ __entry->resp_opcnt, __entry->args_opcnt, ++ __entry->opnum, __entry->status) ++); ++ ++TRACE_EVENT(nfsd_compound_encode_err, ++ TP_PROTO( ++ const struct svc_rqst *rqstp, ++ u32 opnum, ++ __be32 status ++ ), ++ TP_ARGS(rqstp, opnum, status), ++ TP_STRUCT__entry( ++ NFSD_TRACE_PROC_RES_FIELDS ++ ++ __field(u32, opnum) ++ ), ++ TP_fast_assign( ++ NFSD_TRACE_PROC_RES_ASSIGNMENTS(status) ++ ++ __entry->opnum = opnum; ++ ), ++ TP_printk("opnum=%u status=%lu", ++ __entry->opnum, __entry->status) ++); ++ ++ + DECLARE_EVENT_CLASS(nfsd_fh_err_class, + TP_PROTO(struct svc_rqst *rqstp, + struct svc_fh *fhp, +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-tracepoints-in-nfsd_dispatch.patch b/queue-5.10/nfsd-add-tracepoints-in-nfsd_dispatch.patch new file mode 100644 index 00000000000..d3874bfb571 --- /dev/null +++ b/queue-5.10/nfsd-add-tracepoints-in-nfsd_dispatch.patch @@ -0,0 +1,146 @@ +From c7d3fd127d8321ade4da8f377c48032accae03df Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Oct 2020 13:00:29 -0400 +Subject: NFSD: Add tracepoints in nfsd_dispatch() + +From: Chuck Lever + +[ Upstream commit 0dfdad1c1d1b77b9b085f4da390464dd0ac5647a ] + +For troubleshooting purposes, record GARBAGE_ARGS and CANT_ENCODE +failures. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfssvc.c | 17 ++++---------- + fs/nfsd/trace.h | 60 ++++++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 65 insertions(+), 12 deletions(-) + +diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c +index c81d49b07971c..3fb9607d67a37 100644 +--- a/fs/nfsd/nfssvc.c ++++ b/fs/nfsd/nfssvc.c +@@ -29,6 +29,8 @@ + #include "netns.h" + #include "filecache.h" + ++#include "trace.h" ++ + #define NFSDDBG_FACILITY NFSDDBG_SVC + + bool inter_copy_offload_enable; +@@ -1041,11 +1043,8 @@ int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) + struct kvec *resv = &rqstp->rq_res.head[0]; + __be32 *p; + +- dprintk("nfsd_dispatch: vers %d proc %d\n", +- rqstp->rq_vers, rqstp->rq_proc); +- + if (nfs_request_too_big(rqstp, proc)) +- goto out_too_large; ++ goto out_decode_err; + + /* + * Give the xdr decoder a chance to change this if it wants +@@ -1084,24 +1083,18 @@ int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) + out_cached_reply: + return 1; + +-out_too_large: +- dprintk("nfsd: NFSv%d argument too large\n", rqstp->rq_vers); +- *statp = rpc_garbage_args; +- return 1; +- + out_decode_err: +- dprintk("nfsd: failed to decode arguments!\n"); ++ trace_nfsd_garbage_args_err(rqstp); + *statp = rpc_garbage_args; + return 1; + + out_update_drop: +- dprintk("nfsd: Dropping request; may be revisited later\n"); + nfsd_cache_update(rqstp, RC_NOCACHE, NULL); + out_dropit: + return 0; + + out_encode_err: +- dprintk("nfsd: failed to encode result!\n"); ++ trace_nfsd_cant_encode_err(rqstp); + nfsd_cache_update(rqstp, RC_NOCACHE, NULL); + *statp = rpc_system_err; + return 1; +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index 9239d97b682c7..dbbda3e09eedd 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -12,6 +12,66 @@ + #include "export.h" + #include "nfsfh.h" + ++#define NFSD_TRACE_PROC_ARG_FIELDS \ ++ __field(unsigned int, netns_ino) \ ++ __field(u32, xid) \ ++ __array(unsigned char, server, sizeof(struct sockaddr_in6)) \ ++ __array(unsigned char, client, sizeof(struct sockaddr_in6)) ++ ++#define NFSD_TRACE_PROC_ARG_ASSIGNMENTS \ ++ do { \ ++ __entry->netns_ino = SVC_NET(rqstp)->ns.inum; \ ++ __entry->xid = be32_to_cpu(rqstp->rq_xid); \ ++ memcpy(__entry->server, &rqstp->rq_xprt->xpt_local, \ ++ rqstp->rq_xprt->xpt_locallen); \ ++ memcpy(__entry->client, &rqstp->rq_xprt->xpt_remote, \ ++ rqstp->rq_xprt->xpt_remotelen); \ ++ } while (0); ++ ++TRACE_EVENT(nfsd_garbage_args_err, ++ TP_PROTO( ++ const struct svc_rqst *rqstp ++ ), ++ TP_ARGS(rqstp), ++ TP_STRUCT__entry( ++ NFSD_TRACE_PROC_ARG_FIELDS ++ ++ __field(u32, vers) ++ __field(u32, proc) ++ ), ++ TP_fast_assign( ++ NFSD_TRACE_PROC_ARG_ASSIGNMENTS ++ ++ __entry->vers = rqstp->rq_vers; ++ __entry->proc = rqstp->rq_proc; ++ ), ++ TP_printk("xid=0x%08x vers=%u proc=%u", ++ __entry->xid, __entry->vers, __entry->proc ++ ) ++); ++ ++TRACE_EVENT(nfsd_cant_encode_err, ++ TP_PROTO( ++ const struct svc_rqst *rqstp ++ ), ++ TP_ARGS(rqstp), ++ TP_STRUCT__entry( ++ NFSD_TRACE_PROC_ARG_FIELDS ++ ++ __field(u32, vers) ++ __field(u32, proc) ++ ), ++ TP_fast_assign( ++ NFSD_TRACE_PROC_ARG_ASSIGNMENTS ++ ++ __entry->vers = rqstp->rq_vers; ++ __entry->proc = rqstp->rq_proc; ++ ), ++ TP_printk("xid=0x%08x vers=%u proc=%u", ++ __entry->xid, __entry->vers, __entry->proc ++ ) ++); ++ + #define show_nfsd_may_flags(x) \ + __print_flags(x, "|", \ + { NFSD_MAY_EXEC, "EXEC" }, \ +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-tracepoints-to-report-nfsv4-callback-comple.patch b/queue-5.10/nfsd-add-tracepoints-to-report-nfsv4-callback-comple.patch new file mode 100644 index 00000000000..1ec54bfcf66 --- /dev/null +++ b/queue-5.10/nfsd-add-tracepoints-to-report-nfsv4-callback-comple.patch @@ -0,0 +1,139 @@ +From 8f076dd9dc3620492b7092226f58255737e1ce0d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Sep 2022 18:13:54 -0400 +Subject: NFSD: Add tracepoints to report NFSv4 callback completions + +From: Chuck Lever + +[ Upstream commit 1035d65446a018ca2dd179e29a2fcd6d29057781 ] + +Wireshark has always been lousy about dissecting NFSv4 callbacks, +especially NFSv4.0 backchannel requests. Add tracepoints so we +can surgically capture these events in the trace log. + +Tracepoints are time-stamped and ordered so that we can now observe +the timing relationship between a CB_RECALL Reply and the client's +DELEGRETURN Call. Example: + + nfsd-1153 [002] 211.986391: nfsd_cb_recall: addr=192.168.1.67:45767 client 62ea82e4:fee7492a stateid 00000003:00000001 + + nfsd-1153 [002] 212.095634: nfsd_compound: xid=0x0000002c opcnt=2 + nfsd-1153 [002] 212.095647: nfsd_compound_status: op=1/2 OP_PUTFH status=0 + nfsd-1153 [002] 212.095658: nfsd_file_put: hash=0xf72 inode=0xffff9291148c7410 ref=3 flags=HASHED|REFERENCED may=READ file=0xffff929103b3ea00 + nfsd-1153 [002] 212.095661: nfsd_compound_status: op=2/2 OP_DELEGRETURN status=0 + kworker/u25:8-148 [002] 212.096713: nfsd_cb_recall_done: client 62ea82e4:fee7492a stateid 00000003:00000001 status=0 + +Signed-off-by: Chuck Lever +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4layouts.c | 2 +- + fs/nfsd/nfs4proc.c | 4 ++++ + fs/nfsd/nfs4state.c | 4 ++++ + fs/nfsd/trace.h | 39 +++++++++++++++++++++++++++++++++++++++ + 4 files changed, 48 insertions(+), 1 deletion(-) + +diff --git a/fs/nfsd/nfs4layouts.c b/fs/nfsd/nfs4layouts.c +index 7018d209b784a..e4e23b2a3e655 100644 +--- a/fs/nfsd/nfs4layouts.c ++++ b/fs/nfsd/nfs4layouts.c +@@ -657,7 +657,7 @@ nfsd4_cb_layout_done(struct nfsd4_callback *cb, struct rpc_task *task) + ktime_t now, cutoff; + const struct nfsd4_layout_ops *ops; + +- ++ trace_nfsd_cb_layout_done(&ls->ls_stid.sc_stateid, task); + switch (task->tk_status) { + case 0: + case -NFS4ERR_DELAY: +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index c40795d1d98df..38d60964d8b2d 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -1603,6 +1603,10 @@ static void nfsd4_cb_offload_release(struct nfsd4_callback *cb) + static int nfsd4_cb_offload_done(struct nfsd4_callback *cb, + struct rpc_task *task) + { ++ struct nfsd4_cb_offload *cbo = ++ container_of(cb, struct nfsd4_cb_offload, co_cb); ++ ++ trace_nfsd_cb_offload_done(&cbo->co_res.cb_stateid, task); + return 1; + } + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 7a4baa41b5362..8bbff388e4f03 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -357,6 +357,8 @@ nfsd4_cb_notify_lock_prepare(struct nfsd4_callback *cb) + static int + nfsd4_cb_notify_lock_done(struct nfsd4_callback *cb, struct rpc_task *task) + { ++ trace_nfsd_cb_notify_lock_done(&zero_stateid, task); ++ + /* + * Since this is just an optimization, we don't try very hard if it + * turns out not to succeed. We'll requeue it on NFS4ERR_DELAY, and +@@ -4760,6 +4762,8 @@ static int nfsd4_cb_recall_done(struct nfsd4_callback *cb, + { + struct nfs4_delegation *dp = cb_to_delegation(cb); + ++ trace_nfsd_cb_recall_done(&dp->dl_stid.sc_stateid, task); ++ + if (dp->dl_stid.sc_type == NFS4_CLOSED_DELEG_STID || + dp->dl_stid.sc_type == NFS4_REVOKED_DELEG_STID) + return 1; +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index 22c1fb735f1a7..0ee4220a289a0 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -1366,6 +1366,45 @@ TRACE_EVENT(nfsd_cb_offload, + __entry->fh_hash, __entry->count, __entry->status) + ); + ++DECLARE_EVENT_CLASS(nfsd_cb_done_class, ++ TP_PROTO( ++ const stateid_t *stp, ++ const struct rpc_task *task ++ ), ++ TP_ARGS(stp, task), ++ TP_STRUCT__entry( ++ __field(u32, cl_boot) ++ __field(u32, cl_id) ++ __field(u32, si_id) ++ __field(u32, si_generation) ++ __field(int, status) ++ ), ++ TP_fast_assign( ++ __entry->cl_boot = stp->si_opaque.so_clid.cl_boot; ++ __entry->cl_id = stp->si_opaque.so_clid.cl_id; ++ __entry->si_id = stp->si_opaque.so_id; ++ __entry->si_generation = stp->si_generation; ++ __entry->status = task->tk_status; ++ ), ++ TP_printk("client %08x:%08x stateid %08x:%08x status=%d", ++ __entry->cl_boot, __entry->cl_id, __entry->si_id, ++ __entry->si_generation, __entry->status ++ ) ++); ++ ++#define DEFINE_NFSD_CB_DONE_EVENT(name) \ ++DEFINE_EVENT(nfsd_cb_done_class, name, \ ++ TP_PROTO( \ ++ const stateid_t *stp, \ ++ const struct rpc_task *task \ ++ ), \ ++ TP_ARGS(stp, task)) ++ ++DEFINE_NFSD_CB_DONE_EVENT(nfsd_cb_recall_done); ++DEFINE_NFSD_CB_DONE_EVENT(nfsd_cb_notify_lock_done); ++DEFINE_NFSD_CB_DONE_EVENT(nfsd_cb_layout_done); ++DEFINE_NFSD_CB_DONE_EVENT(nfsd_cb_offload_done); ++ + #endif /* _NFSD_TRACE_H */ + + #undef TRACE_INCLUDE_PATH +-- +2.43.0 + diff --git a/queue-5.10/nfsd-add-vfs_fsync-after-async-copy-is-done.patch b/queue-5.10/nfsd-add-vfs_fsync-after-async-copy-is-done.patch new file mode 100644 index 00000000000..72723318a2e --- /dev/null +++ b/queue-5.10/nfsd-add-vfs_fsync-after-async-copy-is-done.patch @@ -0,0 +1,87 @@ +From d5a9486238386f9cd9dcbef7ad9f2556ba9e894b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 19 May 2021 14:48:27 -0400 +Subject: NFSD add vfs_fsync after async copy is done + +From: Olga Kornievskaia + +[ Upstream commit eac0b17a77fbd763d305a5eaa4fd1119e5a0fe0d ] + +Currently, the server does all copies as NFS_UNSTABLE. For synchronous +copies linux client will append a COMMIT to the COPY compound but for +async copies it does not (because COMMIT needs to be done after all +bytes are copied and not as a reply to the COPY operation). + +However, in order to save the client doing a COMMIT as a separate +rpc, the server can reply back with NFS_FILE_SYNC copy. This patch +proposed to add vfs_fsync() call at the end of the async copy. + +Signed-off-by: Olga Kornievskaia +Signed-off-by: J. Bruce Fields +[ cel: adjusted to apply to v5.10.y ] +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 15 ++++++++++++++- + fs/nfsd/xdr4.h | 1 + + 2 files changed, 15 insertions(+), 1 deletion(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index dfce9c432a5ee..aa0da0737a3ff 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -1366,7 +1366,8 @@ static const struct nfsd4_callback_ops nfsd4_cb_offload_ops = { + + static void nfsd4_init_copy_res(struct nfsd4_copy *copy, bool sync) + { +- copy->cp_res.wr_stable_how = NFS_UNSTABLE; ++ copy->cp_res.wr_stable_how = ++ copy->committed ? NFS_FILE_SYNC : NFS_UNSTABLE; + copy->cp_synchronous = sync; + gen_boot_verifier(©->cp_res.wr_verifier, copy->cp_clp->net); + } +@@ -1375,10 +1376,12 @@ static ssize_t _nfsd_copy_file_range(struct nfsd4_copy *copy) + { + struct file *dst = copy->nf_dst->nf_file; + struct file *src = copy->nf_src->nf_file; ++ errseq_t since; + ssize_t bytes_copied = 0; + u64 bytes_total = copy->cp_count; + u64 src_pos = copy->cp_src_pos; + u64 dst_pos = copy->cp_dst_pos; ++ __be32 status; + + /* See RFC 7862 p.67: */ + if (bytes_total == 0) +@@ -1395,6 +1398,16 @@ static ssize_t _nfsd_copy_file_range(struct nfsd4_copy *copy) + src_pos += bytes_copied; + dst_pos += bytes_copied; + } while (bytes_total > 0 && !copy->cp_synchronous); ++ /* for a non-zero asynchronous copy do a commit of data */ ++ if (!copy->cp_synchronous && copy->cp_res.wr_bytes_written > 0) { ++ since = READ_ONCE(dst->f_wb_err); ++ status = vfs_fsync_range(dst, copy->cp_dst_pos, ++ copy->cp_res.wr_bytes_written, 0); ++ if (!status) ++ status = filemap_check_wb_err(dst->f_mapping, since); ++ if (!status) ++ copy->committed = true; ++ } + return bytes_copied; + } + +diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h +index fe540a3415c6a..37af86e370cb3 100644 +--- a/fs/nfsd/xdr4.h ++++ b/fs/nfsd/xdr4.h +@@ -567,6 +567,7 @@ struct nfsd4_copy { + struct vfsmount *ss_mnt; + struct nfs_fh c_fh; + nfs4_stateid stateid; ++ bool committed; + }; + + struct nfsd4_seek { +-- +2.43.0 + diff --git a/queue-5.10/nfsd-adjust-cb_shutdown-tracepoint.patch b/queue-5.10/nfsd-adjust-cb_shutdown-tracepoint.patch new file mode 100644 index 00000000000..485fc94f061 --- /dev/null +++ b/queue-5.10/nfsd-adjust-cb_shutdown-tracepoint.patch @@ -0,0 +1,45 @@ +From 120633129172bff4f00c9ac59e3d8cb329a1eebe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 14 May 2021 15:56:49 -0400 +Subject: NFSD: Adjust cb_shutdown tracepoint + +From: Chuck Lever + +[ Upstream commit b200f0e35338b052976b6c5759e4f77a3013e6f6 ] + +Show when the upper layer requested a shutdown. RPC tracepoints can +already show when rpc_shutdown_client() is called. + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4callback.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c +index 2e6a4a9e59ca1..2a2eb6184bdae 100644 +--- a/fs/nfsd/nfs4callback.c ++++ b/fs/nfsd/nfs4callback.c +@@ -1233,6 +1233,9 @@ void nfsd4_destroy_callback_queue(void) + /* must be called under the state lock */ + void nfsd4_shutdown_callback(struct nfs4_client *clp) + { ++ if (clp->cl_cb_state != NFSD4_CB_UNKNOWN) ++ trace_nfsd_cb_shutdown(clp); ++ + set_bit(NFSD4_CLIENT_CB_KILL, &clp->cl_flags); + /* + * Note this won't actually result in a null callback; +@@ -1278,7 +1281,6 @@ static void nfsd4_process_cb_update(struct nfsd4_callback *cb) + * kill the old client: + */ + if (clp->cl_cb_client) { +- trace_nfsd_cb_shutdown(clp); + rpc_shutdown_client(clp->cl_cb_client); + clp->cl_cb_client = NULL; + put_cred(clp->cl_cb_cred); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-allow-disabling-nfsv2-at-compile-time.patch b/queue-5.10/nfsd-allow-disabling-nfsv2-at-compile-time.patch new file mode 100644 index 00000000000..095d0e1c77d --- /dev/null +++ b/queue-5.10/nfsd-allow-disabling-nfsv2-at-compile-time.patch @@ -0,0 +1,156 @@ +From bdda8d5409c511e280d9dc43eb1c52c1fffa6707 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 18 Oct 2022 07:47:56 -0400 +Subject: nfsd: allow disabling NFSv2 at compile time + +From: Jeff Layton + +[ Upstream commit 2f3a4b2ac2f28b9be78ad21f401f31e263845214 ] + +rpc.nfsd stopped supporting NFSv2 a year ago. Take the next logical +step toward deprecating it and allow NFSv2 support to be compiled out. + +Add a new CONFIG_NFSD_V2 option that can be turned off and rework the +CONFIG_NFSD_V?_ACL option dependencies. Add a description that +discourages enabling it. + +Also, change the description of CONFIG_NFSD to state that the always-on +version is now 3 instead of 2. + +Finally, add an #ifdef around "case 2:" in __write_versions. When NFSv2 +is disabled at compile time, this should make the kernel ignore attempts +to disable it at runtime, but still error out when trying to enable it. + +Signed-off-by: Jeff Layton +Reviewed-by: Tom Talpey +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/Kconfig | 19 +++++++++++++++---- + fs/nfsd/Makefile | 5 +++-- + fs/nfsd/nfsctl.c | 2 ++ + fs/nfsd/nfsd.h | 3 +-- + fs/nfsd/nfssvc.c | 6 ++++++ + 5 files changed, 27 insertions(+), 8 deletions(-) + +diff --git a/fs/nfsd/Kconfig b/fs/nfsd/Kconfig +index 887af7966b032..6d2d498a59573 100644 +--- a/fs/nfsd/Kconfig ++++ b/fs/nfsd/Kconfig +@@ -8,6 +8,7 @@ config NFSD + select SUNRPC + select EXPORTFS + select NFS_ACL_SUPPORT if NFSD_V2_ACL ++ select NFS_ACL_SUPPORT if NFSD_V3_ACL + depends on MULTIUSER + help + Choose Y here if you want to allow other computers to access +@@ -26,19 +27,29 @@ config NFSD + + Below you can choose which versions of the NFS protocol are + available to clients mounting the NFS server on this system. +- Support for NFS version 2 (RFC 1094) is always available when ++ Support for NFS version 3 (RFC 1813) is always available when + CONFIG_NFSD is selected. + + If unsure, say N. + +-config NFSD_V2_ACL +- bool ++config NFSD_V2 ++ bool "NFS server support for NFS version 2 (DEPRECATED)" + depends on NFSD ++ default n ++ help ++ NFSv2 (RFC 1094) was the first publicly-released version of NFS. ++ Unless you are hosting ancient (1990's era) NFS clients, you don't ++ need this. ++ ++ If unsure, say N. ++ ++config NFSD_V2_ACL ++ bool "NFS server support for the NFSv2 ACL protocol extension" ++ depends on NFSD_V2 + + config NFSD_V3_ACL + bool "NFS server support for the NFSv3 ACL protocol extension" + depends on NFSD +- select NFSD_V2_ACL + help + Solaris NFS servers support an auxiliary NFSv3 ACL protocol that + never became an official part of the NFS version 3 protocol. +diff --git a/fs/nfsd/Makefile b/fs/nfsd/Makefile +index 805c06d5f1b4b..6fffc8f03f740 100644 +--- a/fs/nfsd/Makefile ++++ b/fs/nfsd/Makefile +@@ -10,9 +10,10 @@ obj-$(CONFIG_NFSD) += nfsd.o + # this one should be compiled first, as the tracing macros can easily blow up + nfsd-y += trace.o + +-nfsd-y += nfssvc.o nfsctl.o nfsproc.o nfsfh.o vfs.o \ +- export.o auth.o lockd.o nfscache.o nfsxdr.o \ ++nfsd-y += nfssvc.o nfsctl.o nfsfh.o vfs.o \ ++ export.o auth.o lockd.o nfscache.o \ + stats.o filecache.o nfs3proc.o nfs3xdr.o ++nfsd-$(CONFIG_NFSD_V2) += nfsproc.o nfsxdr.o + nfsd-$(CONFIG_NFSD_V2_ACL) += nfs2acl.o + nfsd-$(CONFIG_NFSD_V3_ACL) += nfs3acl.o + nfsd-$(CONFIG_NFSD_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4idmap.o \ +diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c +index 68ed42fd29fc8..d1e581a60480c 100644 +--- a/fs/nfsd/nfsctl.c ++++ b/fs/nfsd/nfsctl.c +@@ -581,7 +581,9 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size) + + cmd = sign == '-' ? NFSD_CLEAR : NFSD_SET; + switch(num) { ++#ifdef CONFIG_NFSD_V2 + case 2: ++#endif + case 3: + nfsd_vers(nn, num, cmd); + break; +diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h +index 09726c5b9a317..93b42ef9ed91b 100644 +--- a/fs/nfsd/nfsd.h ++++ b/fs/nfsd/nfsd.h +@@ -64,8 +64,7 @@ struct readdir_cd { + + + extern struct svc_program nfsd_program; +-extern const struct svc_version nfsd_version2, nfsd_version3, +- nfsd_version4; ++extern const struct svc_version nfsd_version2, nfsd_version3, nfsd_version4; + extern struct mutex nfsd_mutex; + extern spinlock_t nfsd_drc_lock; + extern unsigned long nfsd_drc_max_mem; +diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c +index 8b1afde192118..429f38c986280 100644 +--- a/fs/nfsd/nfssvc.c ++++ b/fs/nfsd/nfssvc.c +@@ -91,8 +91,12 @@ unsigned long nfsd_drc_mem_used; + #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) + static struct svc_stat nfsd_acl_svcstats; + static const struct svc_version *nfsd_acl_version[] = { ++# if defined(CONFIG_NFSD_V2_ACL) + [2] = &nfsd_acl_version2, ++# endif ++# if defined(CONFIG_NFSD_V3_ACL) + [3] = &nfsd_acl_version3, ++# endif + }; + + #define NFSD_ACL_MINVERS 2 +@@ -116,7 +120,9 @@ static struct svc_stat nfsd_acl_svcstats = { + #endif /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */ + + static const struct svc_version *nfsd_version[] = { ++#if defined(CONFIG_NFSD_V2) + [2] = &nfsd_version2, ++#endif + [3] = &nfsd_version3, + #if defined(CONFIG_NFSD_V4) + [4] = &nfsd_version4, +-- +2.43.0 + diff --git a/queue-5.10/nfsd-allow-filesystems-to-opt-out-of-subtree-checkin.patch b/queue-5.10/nfsd-allow-filesystems-to-opt-out-of-subtree-checkin.patch new file mode 100644 index 00000000000..8c33515aee1 --- /dev/null +++ b/queue-5.10/nfsd-allow-filesystems-to-opt-out-of-subtree-checkin.patch @@ -0,0 +1,92 @@ +From 41ca6bdf3f88a29507615532fb395d2fdf17305f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Nov 2020 17:03:15 -0500 +Subject: nfsd: allow filesystems to opt out of subtree checking + +From: Jeff Layton + +[ Upstream commit ba5e8187c55555519ae0b63c0fb681391bc42af9 ] + +When we start allowing NFS to be reexported, then we have some problems +when it comes to subtree checking. In principle, we could allow it, but +it would mean encoding parent info in the filehandles and there may not +be enough space for that in a NFSv3 filehandle. + +To enforce this at export upcall time, we add a new export_ops flag +that declares the filesystem ineligible for subtree checking. + +Signed-off-by: Jeff Layton +Signed-off-by: Lance Shelton +Signed-off-by: Trond Myklebust +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + Documentation/filesystems/nfs/exporting.rst | 12 ++++++++++++ + fs/nfs/export.c | 2 +- + fs/nfsd/export.c | 6 ++++++ + include/linux/exportfs.h | 1 + + 4 files changed, 20 insertions(+), 1 deletion(-) + +diff --git a/Documentation/filesystems/nfs/exporting.rst b/Documentation/filesystems/nfs/exporting.rst +index cbe542ad52333..960be64446cb9 100644 +--- a/Documentation/filesystems/nfs/exporting.rst ++++ b/Documentation/filesystems/nfs/exporting.rst +@@ -190,3 +190,15 @@ following flags are defined: + this on filesystems that have an expensive ->getattr inode operation, + or when atomicity between pre and post operation attribute collection + is impossible to guarantee. ++ ++ EXPORT_OP_NOSUBTREECHK - disallow subtree checking on this fs ++ Many NFS operations deal with filehandles, which the server must then ++ vet to ensure that they live inside of an exported tree. When the ++ export consists of an entire filesystem, this is trivial. nfsd can just ++ ensure that the filehandle live on the filesystem. When only part of a ++ filesystem is exported however, then nfsd must walk the ancestors of the ++ inode to ensure that it's within an exported subtree. This is an ++ expensive operation and not all filesystems can support it properly. ++ This flag exempts the filesystem from subtree checking and causes ++ exportfs to get back an error if it tries to enable subtree checking ++ on it. +diff --git a/fs/nfs/export.c b/fs/nfs/export.c +index 8f4c528865c57..b9ba306bf9120 100644 +--- a/fs/nfs/export.c ++++ b/fs/nfs/export.c +@@ -171,5 +171,5 @@ const struct export_operations nfs_export_ops = { + .encode_fh = nfs_encode_fh, + .fh_to_dentry = nfs_fh_to_dentry, + .get_parent = nfs_get_parent, +- .flags = EXPORT_OP_NOWCC, ++ .flags = EXPORT_OP_NOWCC|EXPORT_OP_NOSUBTREECHK, + }; +diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c +index 21e404e7cb68c..81e7bb12aca69 100644 +--- a/fs/nfsd/export.c ++++ b/fs/nfsd/export.c +@@ -408,6 +408,12 @@ static int check_export(struct inode *inode, int *flags, unsigned char *uuid) + return -EINVAL; + } + ++ if (inode->i_sb->s_export_op->flags & EXPORT_OP_NOSUBTREECHK && ++ !(*flags & NFSEXP_NOSUBTREECHECK)) { ++ dprintk("%s: %s does not support subtree checking!\n", ++ __func__, inode->i_sb->s_type->name); ++ return -EINVAL; ++ } + return 0; + + } +diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h +index e7de0103a32e8..2fcbab0f6b612 100644 +--- a/include/linux/exportfs.h ++++ b/include/linux/exportfs.h +@@ -214,6 +214,7 @@ struct export_operations { + int (*commit_blocks)(struct inode *inode, struct iomap *iomaps, + int nr_iomaps, struct iattr *iattr); + #define EXPORT_OP_NOWCC (0x1) /* Don't collect wcc data for NFSv3 replies */ ++#define EXPORT_OP_NOSUBTREECHK (0x2) /* Subtree checking is not supported! */ + unsigned long flags; + }; + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-allow-nfsd_file_get-to-sanely-handle-a-null-poi.patch b/queue-5.10/nfsd-allow-nfsd_file_get-to-sanely-handle-a-null-poi.patch new file mode 100644 index 00000000000..10dfd4a7614 --- /dev/null +++ b/queue-5.10/nfsd-allow-nfsd_file_get-to-sanely-handle-a-null-poi.patch @@ -0,0 +1,61 @@ +From 5397b11b971ef015dbd45ea27b90568406d0ab54 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Jan 2023 10:33:47 -0500 +Subject: nfsd: allow nfsd_file_get to sanely handle a NULL pointer + +From: Jeff Layton + +[ Upstream commit 70f62231cdfd52357836733dd31db787e0412ab2 ] + +...and remove some now-useless NULL pointer checks in its callers. + +Suggested-by: NeilBrown +Signed-off-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 5 ++--- + fs/nfsd/nfs4state.c | 4 +--- + 2 files changed, 3 insertions(+), 6 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index 68c7c82f8b3bb..206742bbbd682 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -451,7 +451,7 @@ static bool nfsd_file_lru_remove(struct nfsd_file *nf) + struct nfsd_file * + nfsd_file_get(struct nfsd_file *nf) + { +- if (likely(refcount_inc_not_zero(&nf->nf_ref))) ++ if (nf && refcount_inc_not_zero(&nf->nf_ref)) + return nf; + return NULL; + } +@@ -1106,8 +1106,7 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + rcu_read_lock(); + nf = rhashtable_lookup(&nfsd_file_rhash_tbl, &key, + nfsd_file_rhash_params); +- if (nf) +- nf = nfsd_file_get(nf); ++ nf = nfsd_file_get(nf); + rcu_read_unlock(); + + if (nf) { +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 6c11f2701af88..2733eb33d5df2 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -602,9 +602,7 @@ put_nfs4_file(struct nfs4_file *fi) + static struct nfsd_file * + __nfs4_get_fd(struct nfs4_file *f, int oflag) + { +- if (f->fi_fds[oflag]) +- return nfsd_file_get(f->fi_fds[oflag]); +- return NULL; ++ return nfsd_file_get(f->fi_fds[oflag]); + } + + static struct nfsd_file * +-- +2.43.0 + diff --git a/queue-5.10/nfsd-allow-reaping-files-still-under-writeback.patch b/queue-5.10/nfsd-allow-reaping-files-still-under-writeback.patch new file mode 100644 index 00000000000..ac65c94757b --- /dev/null +++ b/queue-5.10/nfsd-allow-reaping-files-still-under-writeback.patch @@ -0,0 +1,95 @@ +From 38c52367363037c9ac1aeb468ca79fc306b6a779 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 15 Feb 2023 06:53:54 -0500 +Subject: nfsd: allow reaping files still under writeback + +From: Jeff Layton + +[ Upstream commit dcb779fcd4ed5984ad15991d574943d12a8693d1 ] + +On most filesystems, there is no reason to delay reaping an nfsd_file +just because its underlying inode is still under writeback. nfsd just +relies on client activity or the local flusher threads to do writeback. + +The main exception is NFS, which flushes all of its dirty data on last +close. Add a new EXPORT_OP_FLUSH_ON_CLOSE flag to allow filesystems to +signal that they do this, and only skip closing files under writeback on +such filesystems. + +Also, remove a redundant NULL file pointer check in +nfsd_file_check_writeback, and clean up nfs's export op flag +definitions. + +Signed-off-by: Jeff Layton +Acked-by: Anna Schumaker +[ cel: adjusted to apply to v5.10.y ] +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfs/export.c | 9 ++++++--- + fs/nfsd/filecache.c | 12 +++++++++++- + include/linux/exportfs.h | 1 + + 3 files changed, 18 insertions(+), 4 deletions(-) + +diff --git a/fs/nfs/export.c b/fs/nfs/export.c +index b347e3ce0cc8e..993be63ab3015 100644 +--- a/fs/nfs/export.c ++++ b/fs/nfs/export.c +@@ -182,7 +182,10 @@ const struct export_operations nfs_export_ops = { + .fh_to_dentry = nfs_fh_to_dentry, + .get_parent = nfs_get_parent, + .fetch_iversion = nfs_fetch_iversion, +- .flags = EXPORT_OP_NOWCC|EXPORT_OP_NOSUBTREECHK| +- EXPORT_OP_CLOSE_BEFORE_UNLINK|EXPORT_OP_REMOTE_FS| +- EXPORT_OP_NOATOMIC_ATTR, ++ .flags = EXPORT_OP_NOWCC | ++ EXPORT_OP_NOSUBTREECHK | ++ EXPORT_OP_CLOSE_BEFORE_UNLINK | ++ EXPORT_OP_REMOTE_FS | ++ EXPORT_OP_NOATOMIC_ATTR | ++ EXPORT_OP_FLUSH_ON_CLOSE, + }; +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index 1d4c0387c4192..080d796547854 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -401,13 +401,23 @@ nfsd_file_check_writeback(struct nfsd_file *nf) + struct file *file = nf->nf_file; + struct address_space *mapping; + +- if (!file || !(file->f_mode & FMODE_WRITE)) ++ /* File not open for write? */ ++ if (!(file->f_mode & FMODE_WRITE)) + return false; ++ ++ /* ++ * Some filesystems (e.g. NFS) flush all dirty data on close. ++ * On others, there is no need to wait for writeback. ++ */ ++ if (!(file_inode(file)->i_sb->s_export_op->flags & EXPORT_OP_FLUSH_ON_CLOSE)) ++ return false; ++ + mapping = file->f_mapping; + return mapping_tagged(mapping, PAGECACHE_TAG_DIRTY) || + mapping_tagged(mapping, PAGECACHE_TAG_WRITEBACK); + } + ++ + static bool nfsd_file_lru_add(struct nfsd_file *nf) + { + set_bit(NFSD_FILE_REFERENCED, &nf->nf_flags); +diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h +index fe848901fcc3a..218fc5c54e901 100644 +--- a/include/linux/exportfs.h ++++ b/include/linux/exportfs.h +@@ -221,6 +221,7 @@ struct export_operations { + #define EXPORT_OP_NOATOMIC_ATTR (0x10) /* Filesystem cannot supply + atomic attribute updates + */ ++#define EXPORT_OP_FLUSH_ON_CLOSE (0x20) /* fs flushes file data on close */ + unsigned long flags; + }; + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-always-drop-directory-lock-in-nfsd_unlink.patch b/queue-5.10/nfsd-always-drop-directory-lock-in-nfsd_unlink.patch new file mode 100644 index 00000000000..7fc5947eff4 --- /dev/null +++ b/queue-5.10/nfsd-always-drop-directory-lock-in-nfsd_unlink.patch @@ -0,0 +1,94 @@ +From d6f2cfbf79987a7bbfb09f1a024895772e04fda5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 Jul 2022 16:45:30 +1000 +Subject: NFSD: always drop directory lock in nfsd_unlink() + +From: NeilBrown + +[ Upstream commit b677c0c63a135a916493c064906582e9f3ed4802 ] + +Some error paths in nfsd_unlink() allow it to exit without unlocking the +directory. This is not a problem in practice as the directory will be +locked with an fh_put(), but it is untidy and potentially confusing. + +This allows us to remove all the fh_unlock() calls that are immediately +after nfsd_unlink() calls. + +Reviewed-by: Jeff Layton +Signed-off-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3proc.c | 2 -- + fs/nfsd/nfs4proc.c | 4 +--- + fs/nfsd/vfs.c | 7 +++++-- + 3 files changed, 6 insertions(+), 7 deletions(-) + +diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c +index c71f0c359f7ae..d78dbb214c5c3 100644 +--- a/fs/nfsd/nfs3proc.c ++++ b/fs/nfsd/nfs3proc.c +@@ -490,7 +490,6 @@ nfsd3_proc_remove(struct svc_rqst *rqstp) + fh_copy(&resp->fh, &argp->fh); + resp->status = nfsd_unlink(rqstp, &resp->fh, -S_IFDIR, + argp->name, argp->len); +- fh_unlock(&resp->fh); + return rpc_success; + } + +@@ -511,7 +510,6 @@ nfsd3_proc_rmdir(struct svc_rqst *rqstp) + fh_copy(&resp->fh, &argp->fh); + resp->status = nfsd_unlink(rqstp, &resp->fh, S_IFDIR, + argp->name, argp->len); +- fh_unlock(&resp->fh); + return rpc_success; + } + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 0396fa2c1cfe7..f588e592a0703 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -1002,10 +1002,8 @@ nfsd4_remove(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + return nfserr_grace; + status = nfsd_unlink(rqstp, &cstate->current_fh, 0, + remove->rm_name, remove->rm_namelen); +- if (!status) { +- fh_unlock(&cstate->current_fh); ++ if (!status) + set_change_info(&remove->rm_cinfo, &cstate->current_fh); +- } + return status; + } + +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index 3d794533bbd4b..6b8e1826956bf 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -1767,12 +1767,12 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, + rdentry = lookup_one_len(fname, dentry, flen); + host_err = PTR_ERR(rdentry); + if (IS_ERR(rdentry)) +- goto out_drop_write; ++ goto out_unlock; + + if (d_really_is_negative(rdentry)) { + dput(rdentry); + host_err = -ENOENT; +- goto out_drop_write; ++ goto out_unlock; + } + rinode = d_inode(rdentry); + ihold(rinode); +@@ -1810,6 +1810,9 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, + } + out: + return err; ++out_unlock: ++ fh_unlock(fhp); ++ goto out_drop_write; + } + + /* +-- +2.43.0 + diff --git a/queue-5.10/nfsd-avoid-calling-fh_drop_write-twice-in-do_nfsd_cr.patch b/queue-5.10/nfsd-avoid-calling-fh_drop_write-twice-in-do_nfsd_cr.patch new file mode 100644 index 00000000000..0338afb185e --- /dev/null +++ b/queue-5.10/nfsd-avoid-calling-fh_drop_write-twice-in-do_nfsd_cr.patch @@ -0,0 +1,49 @@ +From e376345d5778201a15990ece83b7f2215f683227 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 28 Mar 2022 10:16:42 -0400 +Subject: NFSD: Avoid calling fh_drop_write() twice in do_nfsd_create() + +From: Chuck Lever + +[ Upstream commit 14ee45b70dd0d9ae76fb066cd8c0652d657353f6 ] + +Clean up: The "out" label already invokes fh_drop_write(). + +Note that fh_drop_write() is already careful not to invoke +mnt_drop_write() if either it has already been done or there is +nothing to drop. Therefore no change in behavior is expected. + +[ cel: backported to 5.10.y, prior to idmapped mounts ] +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/vfs.c | 5 +---- + 1 file changed, 1 insertion(+), 4 deletions(-) + +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index 0968eaf735c85..cdeba19db16df 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -1504,7 +1504,6 @@ do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, + case NFS3_CREATE_GUARDED: + err = nfserr_exist; + } +- fh_drop_write(fhp); + goto out; + } + +@@ -1512,10 +1511,8 @@ do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, + iap->ia_mode &= ~current_umask(); + + host_err = vfs_create(dirp, dchild, iap->ia_mode, true); +- if (host_err < 0) { +- fh_drop_write(fhp); ++ if (host_err < 0) + goto out_nfserr; +- } + if (created) + *created = true; + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-avoid-calling-opdesc-with-ops-opnum-op_illegal.patch b/queue-5.10/nfsd-avoid-calling-opdesc-with-ops-opnum-op_illegal.patch new file mode 100644 index 00000000000..0bdf98a9f4f --- /dev/null +++ b/queue-5.10/nfsd-avoid-calling-opdesc-with-ops-opnum-op_illegal.patch @@ -0,0 +1,54 @@ +From 60f1dac4113ed0d8d3e66286706019948f86cf4b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 31 Mar 2023 16:31:19 -0400 +Subject: NFSD: Avoid calling OPDESC() with ops->opnum == OP_ILLEGAL + +From: Chuck Lever + +[ Upstream commit 804d8e0a6e54427268790472781e03bc243f4ee3 ] + +OPDESC() simply indexes into nfsd4_ops[] by the op's operation +number, without range checking that value. It assumes callers are +careful to avoid calling it with an out-of-bounds opnum value. + +nfsd4_decode_compound() is not so careful, and can invoke OPDESC() +with opnum set to OP_ILLEGAL, which is 10044 -- well beyond the end +of nfsd4_ops[]. + +Reported-by: Jeff Layton +Fixes: f4f9ef4a1b0a ("nfsd4: opdesc will be useful outside nfs4proc.c") +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index d0b9fbf189ac6..e1f2f26ba93f2 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -2476,10 +2476,12 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) + for (i = 0; i < argp->opcnt; i++) { + op = &argp->ops[i]; + op->replay = NULL; ++ op->opdesc = NULL; + + if (xdr_stream_decode_u32(argp->xdr, &op->opnum) < 0) + return false; + if (nfsd4_opnum_in_range(argp, op)) { ++ op->opdesc = OPDESC(op); + op->status = nfsd4_dec_ops[op->opnum](argp, &op->u); + if (op->status != nfs_ok) + trace_nfsd_compound_decode_err(argp->rqstp, +@@ -2490,7 +2492,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) + op->opnum = OP_ILLEGAL; + op->status = nfserr_op_illegal; + } +- op->opdesc = OPDESC(op); ++ + /* + * We'll try to cache the result in the DRC if any one + * op in the compound wants to be cached: +-- +2.43.0 + diff --git a/queue-5.10/nfsd-avoid-clashing-function-prototypes.patch b/queue-5.10/nfsd-avoid-clashing-function-prototypes.patch new file mode 100644 index 00000000000..f8b8884e403 --- /dev/null +++ b/queue-5.10/nfsd-avoid-clashing-function-prototypes.patch @@ -0,0 +1,1534 @@ +From 3e1983cecf6d668ca02182ea92b719cdbdb1f061 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 2 Dec 2022 12:48:59 -0800 +Subject: NFSD: Avoid clashing function prototypes + +From: Kees Cook + +[ Upstream commit e78e274eb22d966258a3845acc71d3c5b8ee2ea8 ] + +When built with Control Flow Integrity, function prototypes between +caller and function declaration must match. These mismatches are visible +at compile time with the new -Wcast-function-type-strict in Clang[1]. + +There were 97 warnings produced by NFS. For example: + +fs/nfsd/nfs4xdr.c:2228:17: warning: cast from '__be32 (*)(struct nfsd4_compoundargs *, struct nfsd4_access *)' (aka 'unsigned int (*)(struct nfsd4_compoundargs *, struct nfsd4_access *)') to 'nfsd4_dec' (aka 'unsigned int (*)(struct nfsd4_compoundargs *, void *)') converts to incompatible function type [-Wcast-function-type-strict] + [OP_ACCESS] = (nfsd4_dec)nfsd4_decode_access, + ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The enc/dec callbacks were defined as passing "void *" as the second +argument, but were being implicitly cast to a new type. Replace the +argument with union nfsd4_op_u, and perform explicit member selection +in the function body. There are no resulting binary differences. + +Changes were made mechanically using the following Coccinelle script, +with minor by-hand fixes for members that didn't already match their +existing argument name: + +@find@ +identifier func; +type T, opsT; +identifier ops, N; +@@ + + opsT ops[] = { + [N] = (T) func, + }; + +@already_void@ +identifier find.func; +identifier name; +@@ + + func(..., +-void ++union nfsd4_op_u + *name) + { + ... + } + +@proto depends on !already_void@ +identifier find.func; +type T; +identifier name; +position p; +@@ + + func@p(..., + T name + ) { + ... + } + +@script:python get_member@ +type_name << proto.T; +member; +@@ + +coccinelle.member = cocci.make_ident(type_name.split("_", 1)[1].split(' ',1)[0]) + +@convert@ +identifier find.func; +type proto.T; +identifier proto.name; +position proto.p; +identifier get_member.member; +@@ + + func@p(..., +- T name ++ union nfsd4_op_u *u + ) { ++ T name = &u->member; + ... + } + +@cast@ +identifier find.func; +type T, opsT; +identifier ops, N; +@@ + + opsT ops[] = { + [N] = +- (T) + func, + }; + +Cc: Chuck Lever +Cc: Jeff Layton +Cc: Gustavo A. R. Silva +Cc: linux-nfs@vger.kernel.org +Signed-off-by: Kees Cook +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 632 +++++++++++++++++++++++++++------------------- + 1 file changed, 377 insertions(+), 255 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 27b38ce6f8c6e..8bbf85da1de05 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -770,16 +770,18 @@ nfsd4_decode_cb_sec(struct nfsd4_compoundargs *argp, struct nfsd4_cb_sec *cbs) + + static __be32 + nfsd4_decode_access(struct nfsd4_compoundargs *argp, +- struct nfsd4_access *access) ++ union nfsd4_op_u *u) + { ++ struct nfsd4_access *access = &u->access; + if (xdr_stream_decode_u32(argp->xdr, &access->ac_req_access) < 0) + return nfserr_bad_xdr; + return nfs_ok; + } + + static __be32 +-nfsd4_decode_close(struct nfsd4_compoundargs *argp, struct nfsd4_close *close) ++nfsd4_decode_close(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u) + { ++ struct nfsd4_close *close = &u->close; + if (xdr_stream_decode_u32(argp->xdr, &close->cl_seqid) < 0) + return nfserr_bad_xdr; + return nfsd4_decode_stateid4(argp, &close->cl_stateid); +@@ -787,8 +789,9 @@ nfsd4_decode_close(struct nfsd4_compoundargs *argp, struct nfsd4_close *close) + + + static __be32 +-nfsd4_decode_commit(struct nfsd4_compoundargs *argp, struct nfsd4_commit *commit) ++nfsd4_decode_commit(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u) + { ++ struct nfsd4_commit *commit = &u->commit; + if (xdr_stream_decode_u64(argp->xdr, &commit->co_offset) < 0) + return nfserr_bad_xdr; + if (xdr_stream_decode_u32(argp->xdr, &commit->co_count) < 0) +@@ -798,8 +801,9 @@ nfsd4_decode_commit(struct nfsd4_compoundargs *argp, struct nfsd4_commit *commit + } + + static __be32 +-nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create) ++nfsd4_decode_create(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u) + { ++ struct nfsd4_create *create = &u->create; + __be32 *p, status; + + memset(create, 0, sizeof(*create)); +@@ -844,22 +848,25 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create + } + + static inline __be32 +-nfsd4_decode_delegreturn(struct nfsd4_compoundargs *argp, struct nfsd4_delegreturn *dr) ++nfsd4_decode_delegreturn(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u) + { ++ struct nfsd4_delegreturn *dr = &u->delegreturn; + return nfsd4_decode_stateid4(argp, &dr->dr_stateid); + } + + static inline __be32 +-nfsd4_decode_getattr(struct nfsd4_compoundargs *argp, struct nfsd4_getattr *getattr) ++nfsd4_decode_getattr(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u) + { ++ struct nfsd4_getattr *getattr = &u->getattr; + memset(getattr, 0, sizeof(*getattr)); + return nfsd4_decode_bitmap4(argp, getattr->ga_bmval, + ARRAY_SIZE(getattr->ga_bmval)); + } + + static __be32 +-nfsd4_decode_link(struct nfsd4_compoundargs *argp, struct nfsd4_link *link) ++nfsd4_decode_link(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u) + { ++ struct nfsd4_link *link = &u->link; + memset(link, 0, sizeof(*link)); + return nfsd4_decode_component4(argp, &link->li_name, &link->li_namelen); + } +@@ -907,8 +914,9 @@ nfsd4_decode_locker4(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock) + } + + static __be32 +-nfsd4_decode_lock(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock) ++nfsd4_decode_lock(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u) + { ++ struct nfsd4_lock *lock = &u->lock; + memset(lock, 0, sizeof(*lock)); + if (xdr_stream_decode_u32(argp->xdr, &lock->lk_type) < 0) + return nfserr_bad_xdr; +@@ -924,8 +932,9 @@ nfsd4_decode_lock(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock) + } + + static __be32 +-nfsd4_decode_lockt(struct nfsd4_compoundargs *argp, struct nfsd4_lockt *lockt) ++nfsd4_decode_lockt(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u) + { ++ struct nfsd4_lockt *lockt = &u->lockt; + memset(lockt, 0, sizeof(*lockt)); + if (xdr_stream_decode_u32(argp->xdr, &lockt->lt_type) < 0) + return nfserr_bad_xdr; +@@ -940,8 +949,9 @@ nfsd4_decode_lockt(struct nfsd4_compoundargs *argp, struct nfsd4_lockt *lockt) + } + + static __be32 +-nfsd4_decode_locku(struct nfsd4_compoundargs *argp, struct nfsd4_locku *locku) ++nfsd4_decode_locku(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u) + { ++ struct nfsd4_locku *locku = &u->locku; + __be32 status; + + if (xdr_stream_decode_u32(argp->xdr, &locku->lu_type) < 0) +@@ -962,8 +972,9 @@ nfsd4_decode_locku(struct nfsd4_compoundargs *argp, struct nfsd4_locku *locku) + } + + static __be32 +-nfsd4_decode_lookup(struct nfsd4_compoundargs *argp, struct nfsd4_lookup *lookup) ++nfsd4_decode_lookup(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u) + { ++ struct nfsd4_lookup *lookup = &u->lookup; + return nfsd4_decode_component4(argp, &lookup->lo_name, &lookup->lo_len); + } + +@@ -1143,8 +1154,9 @@ nfsd4_decode_open_claim4(struct nfsd4_compoundargs *argp, + } + + static __be32 +-nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) ++nfsd4_decode_open(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u) + { ++ struct nfsd4_open *open = &u->open; + __be32 status; + u32 dummy; + +@@ -1171,8 +1183,10 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) + } + + static __be32 +-nfsd4_decode_open_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_open_confirm *open_conf) ++nfsd4_decode_open_confirm(struct nfsd4_compoundargs *argp, ++ union nfsd4_op_u *u) + { ++ struct nfsd4_open_confirm *open_conf = &u->open_confirm; + __be32 status; + + if (argp->minorversion >= 1) +@@ -1190,8 +1204,10 @@ nfsd4_decode_open_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_open_con + } + + static __be32 +-nfsd4_decode_open_downgrade(struct nfsd4_compoundargs *argp, struct nfsd4_open_downgrade *open_down) ++nfsd4_decode_open_downgrade(struct nfsd4_compoundargs *argp, ++ union nfsd4_op_u *u) + { ++ struct nfsd4_open_downgrade *open_down = &u->open_downgrade; + __be32 status; + + memset(open_down, 0, sizeof(*open_down)); +@@ -1209,8 +1225,9 @@ nfsd4_decode_open_downgrade(struct nfsd4_compoundargs *argp, struct nfsd4_open_d + } + + static __be32 +-nfsd4_decode_putfh(struct nfsd4_compoundargs *argp, struct nfsd4_putfh *putfh) ++nfsd4_decode_putfh(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u) + { ++ struct nfsd4_putfh *putfh = &u->putfh; + __be32 *p; + + if (xdr_stream_decode_u32(argp->xdr, &putfh->pf_fhlen) < 0) +@@ -1229,7 +1246,7 @@ nfsd4_decode_putfh(struct nfsd4_compoundargs *argp, struct nfsd4_putfh *putfh) + } + + static __be32 +-nfsd4_decode_putpubfh(struct nfsd4_compoundargs *argp, void *p) ++nfsd4_decode_putpubfh(struct nfsd4_compoundargs *argp, union nfsd4_op_u *p) + { + if (argp->minorversion == 0) + return nfs_ok; +@@ -1237,8 +1254,9 @@ nfsd4_decode_putpubfh(struct nfsd4_compoundargs *argp, void *p) + } + + static __be32 +-nfsd4_decode_read(struct nfsd4_compoundargs *argp, struct nfsd4_read *read) ++nfsd4_decode_read(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u) + { ++ struct nfsd4_read *read = &u->read; + __be32 status; + + memset(read, 0, sizeof(*read)); +@@ -1254,8 +1272,9 @@ nfsd4_decode_read(struct nfsd4_compoundargs *argp, struct nfsd4_read *read) + } + + static __be32 +-nfsd4_decode_readdir(struct nfsd4_compoundargs *argp, struct nfsd4_readdir *readdir) ++nfsd4_decode_readdir(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u) + { ++ struct nfsd4_readdir *readdir = &u->readdir; + __be32 status; + + memset(readdir, 0, sizeof(*readdir)); +@@ -1276,15 +1295,17 @@ nfsd4_decode_readdir(struct nfsd4_compoundargs *argp, struct nfsd4_readdir *read + } + + static __be32 +-nfsd4_decode_remove(struct nfsd4_compoundargs *argp, struct nfsd4_remove *remove) ++nfsd4_decode_remove(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u) + { ++ struct nfsd4_remove *remove = &u->remove; + memset(&remove->rm_cinfo, 0, sizeof(remove->rm_cinfo)); + return nfsd4_decode_component4(argp, &remove->rm_name, &remove->rm_namelen); + } + + static __be32 +-nfsd4_decode_rename(struct nfsd4_compoundargs *argp, struct nfsd4_rename *rename) ++nfsd4_decode_rename(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u) + { ++ struct nfsd4_rename *rename = &u->rename; + __be32 status; + + memset(rename, 0, sizeof(*rename)); +@@ -1295,22 +1316,25 @@ nfsd4_decode_rename(struct nfsd4_compoundargs *argp, struct nfsd4_rename *rename + } + + static __be32 +-nfsd4_decode_renew(struct nfsd4_compoundargs *argp, clientid_t *clientid) ++nfsd4_decode_renew(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u) + { ++ clientid_t *clientid = &u->renew; + return nfsd4_decode_clientid4(argp, clientid); + } + + static __be32 + nfsd4_decode_secinfo(struct nfsd4_compoundargs *argp, +- struct nfsd4_secinfo *secinfo) ++ union nfsd4_op_u *u) + { ++ struct nfsd4_secinfo *secinfo = &u->secinfo; + secinfo->si_exp = NULL; + return nfsd4_decode_component4(argp, &secinfo->si_name, &secinfo->si_namelen); + } + + static __be32 +-nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *setattr) ++nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u) + { ++ struct nfsd4_setattr *setattr = &u->setattr; + __be32 status; + + memset(setattr, 0, sizeof(*setattr)); +@@ -1324,8 +1348,9 @@ nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *seta + } + + static __be32 +-nfsd4_decode_setclientid(struct nfsd4_compoundargs *argp, struct nfsd4_setclientid *setclientid) ++nfsd4_decode_setclientid(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u) + { ++ struct nfsd4_setclientid *setclientid = &u->setclientid; + __be32 *p, status; + + memset(setclientid, 0, sizeof(*setclientid)); +@@ -1367,8 +1392,10 @@ nfsd4_decode_setclientid(struct nfsd4_compoundargs *argp, struct nfsd4_setclient + } + + static __be32 +-nfsd4_decode_setclientid_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_setclientid_confirm *scd_c) ++nfsd4_decode_setclientid_confirm(struct nfsd4_compoundargs *argp, ++ union nfsd4_op_u *u) + { ++ struct nfsd4_setclientid_confirm *scd_c = &u->setclientid_confirm; + __be32 status; + + if (argp->minorversion >= 1) +@@ -1382,8 +1409,9 @@ nfsd4_decode_setclientid_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_s + + /* Also used for NVERIFY */ + static __be32 +-nfsd4_decode_verify(struct nfsd4_compoundargs *argp, struct nfsd4_verify *verify) ++nfsd4_decode_verify(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u) + { ++ struct nfsd4_verify *verify = &u->verify; + __be32 *p, status; + + memset(verify, 0, sizeof(*verify)); +@@ -1409,8 +1437,9 @@ nfsd4_decode_verify(struct nfsd4_compoundargs *argp, struct nfsd4_verify *verify + } + + static __be32 +-nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write) ++nfsd4_decode_write(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u) + { ++ struct nfsd4_write *write = &u->write; + __be32 status; + + status = nfsd4_decode_stateid4(argp, &write->wr_stateid); +@@ -1434,8 +1463,10 @@ nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write) + } + + static __be32 +-nfsd4_decode_release_lockowner(struct nfsd4_compoundargs *argp, struct nfsd4_release_lockowner *rlockowner) ++nfsd4_decode_release_lockowner(struct nfsd4_compoundargs *argp, ++ union nfsd4_op_u *u) + { ++ struct nfsd4_release_lockowner *rlockowner = &u->release_lockowner; + __be32 status; + + if (argp->minorversion >= 1) +@@ -1452,16 +1483,20 @@ nfsd4_decode_release_lockowner(struct nfsd4_compoundargs *argp, struct nfsd4_rel + return nfs_ok; + } + +-static __be32 nfsd4_decode_backchannel_ctl(struct nfsd4_compoundargs *argp, struct nfsd4_backchannel_ctl *bc) ++static __be32 nfsd4_decode_backchannel_ctl(struct nfsd4_compoundargs *argp, ++ union nfsd4_op_u *u) + { ++ struct nfsd4_backchannel_ctl *bc = &u->backchannel_ctl; + memset(bc, 0, sizeof(*bc)); + if (xdr_stream_decode_u32(argp->xdr, &bc->bc_cb_program) < 0) + return nfserr_bad_xdr; + return nfsd4_decode_cb_sec(argp, &bc->bc_cb_sec); + } + +-static __be32 nfsd4_decode_bind_conn_to_session(struct nfsd4_compoundargs *argp, struct nfsd4_bind_conn_to_session *bcts) ++static __be32 nfsd4_decode_bind_conn_to_session(struct nfsd4_compoundargs *argp, ++ union nfsd4_op_u *u) + { ++ struct nfsd4_bind_conn_to_session *bcts = &u->bind_conn_to_session; + u32 use_conn_in_rdma_mode; + __be32 status; + +@@ -1603,8 +1638,9 @@ nfsd4_decode_nfs_impl_id4(struct nfsd4_compoundargs *argp, + + static __be32 + nfsd4_decode_exchange_id(struct nfsd4_compoundargs *argp, +- struct nfsd4_exchange_id *exid) ++ union nfsd4_op_u *u) + { ++ struct nfsd4_exchange_id *exid = &u->exchange_id; + __be32 status; + + memset(exid, 0, sizeof(*exid)); +@@ -1656,8 +1692,9 @@ nfsd4_decode_channel_attrs4(struct nfsd4_compoundargs *argp, + + static __be32 + nfsd4_decode_create_session(struct nfsd4_compoundargs *argp, +- struct nfsd4_create_session *sess) ++ union nfsd4_op_u *u) + { ++ struct nfsd4_create_session *sess = &u->create_session; + __be32 status; + + memset(sess, 0, sizeof(*sess)); +@@ -1681,23 +1718,26 @@ nfsd4_decode_create_session(struct nfsd4_compoundargs *argp, + + static __be32 + nfsd4_decode_destroy_session(struct nfsd4_compoundargs *argp, +- struct nfsd4_destroy_session *destroy_session) ++ union nfsd4_op_u *u) + { ++ struct nfsd4_destroy_session *destroy_session = &u->destroy_session; + return nfsd4_decode_sessionid4(argp, &destroy_session->sessionid); + } + + static __be32 + nfsd4_decode_free_stateid(struct nfsd4_compoundargs *argp, +- struct nfsd4_free_stateid *free_stateid) ++ union nfsd4_op_u *u) + { ++ struct nfsd4_free_stateid *free_stateid = &u->free_stateid; + return nfsd4_decode_stateid4(argp, &free_stateid->fr_stateid); + } + + #ifdef CONFIG_NFSD_PNFS + static __be32 + nfsd4_decode_getdeviceinfo(struct nfsd4_compoundargs *argp, +- struct nfsd4_getdeviceinfo *gdev) ++ union nfsd4_op_u *u) + { ++ struct nfsd4_getdeviceinfo *gdev = &u->getdeviceinfo; + __be32 status; + + memset(gdev, 0, sizeof(*gdev)); +@@ -1717,8 +1757,9 @@ nfsd4_decode_getdeviceinfo(struct nfsd4_compoundargs *argp, + + static __be32 + nfsd4_decode_layoutcommit(struct nfsd4_compoundargs *argp, +- struct nfsd4_layoutcommit *lcp) ++ union nfsd4_op_u *u) + { ++ struct nfsd4_layoutcommit *lcp = &u->layoutcommit; + __be32 *p, status; + + memset(lcp, 0, sizeof(*lcp)); +@@ -1753,8 +1794,9 @@ nfsd4_decode_layoutcommit(struct nfsd4_compoundargs *argp, + + static __be32 + nfsd4_decode_layoutget(struct nfsd4_compoundargs *argp, +- struct nfsd4_layoutget *lgp) ++ union nfsd4_op_u *u) + { ++ struct nfsd4_layoutget *lgp = &u->layoutget; + __be32 status; + + memset(lgp, 0, sizeof(*lgp)); +@@ -1781,8 +1823,9 @@ nfsd4_decode_layoutget(struct nfsd4_compoundargs *argp, + + static __be32 + nfsd4_decode_layoutreturn(struct nfsd4_compoundargs *argp, +- struct nfsd4_layoutreturn *lrp) ++ union nfsd4_op_u *u) + { ++ struct nfsd4_layoutreturn *lrp = &u->layoutreturn; + memset(lrp, 0, sizeof(*lrp)); + if (xdr_stream_decode_bool(argp->xdr, &lrp->lr_reclaim) < 0) + return nfserr_bad_xdr; +@@ -1795,8 +1838,9 @@ nfsd4_decode_layoutreturn(struct nfsd4_compoundargs *argp, + #endif /* CONFIG_NFSD_PNFS */ + + static __be32 nfsd4_decode_secinfo_no_name(struct nfsd4_compoundargs *argp, +- struct nfsd4_secinfo_no_name *sin) ++ union nfsd4_op_u *u) + { ++ struct nfsd4_secinfo_no_name *sin = &u->secinfo_no_name; + if (xdr_stream_decode_u32(argp->xdr, &sin->sin_style) < 0) + return nfserr_bad_xdr; + +@@ -1806,8 +1850,9 @@ static __be32 nfsd4_decode_secinfo_no_name(struct nfsd4_compoundargs *argp, + + static __be32 + nfsd4_decode_sequence(struct nfsd4_compoundargs *argp, +- struct nfsd4_sequence *seq) ++ union nfsd4_op_u *u) + { ++ struct nfsd4_sequence *seq = &u->sequence; + __be32 *p, status; + + status = nfsd4_decode_sessionid4(argp, &seq->sessionid); +@@ -1826,8 +1871,10 @@ nfsd4_decode_sequence(struct nfsd4_compoundargs *argp, + } + + static __be32 +-nfsd4_decode_test_stateid(struct nfsd4_compoundargs *argp, struct nfsd4_test_stateid *test_stateid) ++nfsd4_decode_test_stateid(struct nfsd4_compoundargs *argp, ++ union nfsd4_op_u *u) + { ++ struct nfsd4_test_stateid *test_stateid = &u->test_stateid; + struct nfsd4_test_stateid_id *stateid; + __be32 status; + u32 i; +@@ -1852,14 +1899,16 @@ nfsd4_decode_test_stateid(struct nfsd4_compoundargs *argp, struct nfsd4_test_sta + } + + static __be32 nfsd4_decode_destroy_clientid(struct nfsd4_compoundargs *argp, +- struct nfsd4_destroy_clientid *dc) ++ union nfsd4_op_u *u) + { ++ struct nfsd4_destroy_clientid *dc = &u->destroy_clientid; + return nfsd4_decode_clientid4(argp, &dc->clientid); + } + + static __be32 nfsd4_decode_reclaim_complete(struct nfsd4_compoundargs *argp, +- struct nfsd4_reclaim_complete *rc) ++ union nfsd4_op_u *u) + { ++ struct nfsd4_reclaim_complete *rc = &u->reclaim_complete; + if (xdr_stream_decode_bool(argp->xdr, &rc->rca_one_fs) < 0) + return nfserr_bad_xdr; + return nfs_ok; +@@ -1867,8 +1916,9 @@ static __be32 nfsd4_decode_reclaim_complete(struct nfsd4_compoundargs *argp, + + static __be32 + nfsd4_decode_fallocate(struct nfsd4_compoundargs *argp, +- struct nfsd4_fallocate *fallocate) ++ union nfsd4_op_u *u) + { ++ struct nfsd4_fallocate *fallocate = &u->allocate; + __be32 status; + + status = nfsd4_decode_stateid4(argp, &fallocate->falloc_stateid); +@@ -1924,8 +1974,9 @@ static __be32 nfsd4_decode_nl4_server(struct nfsd4_compoundargs *argp, + } + + static __be32 +-nfsd4_decode_copy(struct nfsd4_compoundargs *argp, struct nfsd4_copy *copy) ++nfsd4_decode_copy(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u) + { ++ struct nfsd4_copy *copy = &u->copy; + u32 consecutive, i, count, sync; + struct nl4_server *ns_dummy; + __be32 status; +@@ -1982,8 +2033,9 @@ nfsd4_decode_copy(struct nfsd4_compoundargs *argp, struct nfsd4_copy *copy) + + static __be32 + nfsd4_decode_copy_notify(struct nfsd4_compoundargs *argp, +- struct nfsd4_copy_notify *cn) ++ union nfsd4_op_u *u) + { ++ struct nfsd4_copy_notify *cn = &u->copy_notify; + __be32 status; + + memset(cn, 0, sizeof(*cn)); +@@ -2002,16 +2054,18 @@ nfsd4_decode_copy_notify(struct nfsd4_compoundargs *argp, + + static __be32 + nfsd4_decode_offload_status(struct nfsd4_compoundargs *argp, +- struct nfsd4_offload_status *os) ++ union nfsd4_op_u *u) + { ++ struct nfsd4_offload_status *os = &u->offload_status; + os->count = 0; + os->status = 0; + return nfsd4_decode_stateid4(argp, &os->stateid); + } + + static __be32 +-nfsd4_decode_seek(struct nfsd4_compoundargs *argp, struct nfsd4_seek *seek) ++nfsd4_decode_seek(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u) + { ++ struct nfsd4_seek *seek = &u->seek; + __be32 status; + + status = nfsd4_decode_stateid4(argp, &seek->seek_stateid); +@@ -2028,8 +2082,9 @@ nfsd4_decode_seek(struct nfsd4_compoundargs *argp, struct nfsd4_seek *seek) + } + + static __be32 +-nfsd4_decode_clone(struct nfsd4_compoundargs *argp, struct nfsd4_clone *clone) ++nfsd4_decode_clone(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u) + { ++ struct nfsd4_clone *clone = &u->clone; + __be32 status; + + status = nfsd4_decode_stateid4(argp, &clone->cl_src_stateid); +@@ -2154,8 +2209,9 @@ nfsd4_decode_xattr_name(struct nfsd4_compoundargs *argp, char **namep) + */ + static __be32 + nfsd4_decode_getxattr(struct nfsd4_compoundargs *argp, +- struct nfsd4_getxattr *getxattr) ++ union nfsd4_op_u *u) + { ++ struct nfsd4_getxattr *getxattr = &u->getxattr; + __be32 status; + u32 maxcount; + +@@ -2173,8 +2229,9 @@ nfsd4_decode_getxattr(struct nfsd4_compoundargs *argp, + + static __be32 + nfsd4_decode_setxattr(struct nfsd4_compoundargs *argp, +- struct nfsd4_setxattr *setxattr) ++ union nfsd4_op_u *u) + { ++ struct nfsd4_setxattr *setxattr = &u->setxattr; + u32 flags, maxcount, size; + __be32 status; + +@@ -2214,8 +2271,9 @@ nfsd4_decode_setxattr(struct nfsd4_compoundargs *argp, + + static __be32 + nfsd4_decode_listxattrs(struct nfsd4_compoundargs *argp, +- struct nfsd4_listxattrs *listxattrs) ++ union nfsd4_op_u *u) + { ++ struct nfsd4_listxattrs *listxattrs = &u->listxattrs; + u32 maxcount; + + memset(listxattrs, 0, sizeof(*listxattrs)); +@@ -2245,113 +2303,114 @@ nfsd4_decode_listxattrs(struct nfsd4_compoundargs *argp, + + static __be32 + nfsd4_decode_removexattr(struct nfsd4_compoundargs *argp, +- struct nfsd4_removexattr *removexattr) ++ union nfsd4_op_u *u) + { ++ struct nfsd4_removexattr *removexattr = &u->removexattr; + memset(removexattr, 0, sizeof(*removexattr)); + return nfsd4_decode_xattr_name(argp, &removexattr->rmxa_name); + } + + static __be32 +-nfsd4_decode_noop(struct nfsd4_compoundargs *argp, void *p) ++nfsd4_decode_noop(struct nfsd4_compoundargs *argp, union nfsd4_op_u *p) + { + return nfs_ok; + } + + static __be32 +-nfsd4_decode_notsupp(struct nfsd4_compoundargs *argp, void *p) ++nfsd4_decode_notsupp(struct nfsd4_compoundargs *argp, union nfsd4_op_u *p) + { + return nfserr_notsupp; + } + +-typedef __be32(*nfsd4_dec)(struct nfsd4_compoundargs *argp, void *); ++typedef __be32(*nfsd4_dec)(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u); + + static const nfsd4_dec nfsd4_dec_ops[] = { +- [OP_ACCESS] = (nfsd4_dec)nfsd4_decode_access, +- [OP_CLOSE] = (nfsd4_dec)nfsd4_decode_close, +- [OP_COMMIT] = (nfsd4_dec)nfsd4_decode_commit, +- [OP_CREATE] = (nfsd4_dec)nfsd4_decode_create, +- [OP_DELEGPURGE] = (nfsd4_dec)nfsd4_decode_notsupp, +- [OP_DELEGRETURN] = (nfsd4_dec)nfsd4_decode_delegreturn, +- [OP_GETATTR] = (nfsd4_dec)nfsd4_decode_getattr, +- [OP_GETFH] = (nfsd4_dec)nfsd4_decode_noop, +- [OP_LINK] = (nfsd4_dec)nfsd4_decode_link, +- [OP_LOCK] = (nfsd4_dec)nfsd4_decode_lock, +- [OP_LOCKT] = (nfsd4_dec)nfsd4_decode_lockt, +- [OP_LOCKU] = (nfsd4_dec)nfsd4_decode_locku, +- [OP_LOOKUP] = (nfsd4_dec)nfsd4_decode_lookup, +- [OP_LOOKUPP] = (nfsd4_dec)nfsd4_decode_noop, +- [OP_NVERIFY] = (nfsd4_dec)nfsd4_decode_verify, +- [OP_OPEN] = (nfsd4_dec)nfsd4_decode_open, +- [OP_OPENATTR] = (nfsd4_dec)nfsd4_decode_notsupp, +- [OP_OPEN_CONFIRM] = (nfsd4_dec)nfsd4_decode_open_confirm, +- [OP_OPEN_DOWNGRADE] = (nfsd4_dec)nfsd4_decode_open_downgrade, +- [OP_PUTFH] = (nfsd4_dec)nfsd4_decode_putfh, +- [OP_PUTPUBFH] = (nfsd4_dec)nfsd4_decode_putpubfh, +- [OP_PUTROOTFH] = (nfsd4_dec)nfsd4_decode_noop, +- [OP_READ] = (nfsd4_dec)nfsd4_decode_read, +- [OP_READDIR] = (nfsd4_dec)nfsd4_decode_readdir, +- [OP_READLINK] = (nfsd4_dec)nfsd4_decode_noop, +- [OP_REMOVE] = (nfsd4_dec)nfsd4_decode_remove, +- [OP_RENAME] = (nfsd4_dec)nfsd4_decode_rename, +- [OP_RENEW] = (nfsd4_dec)nfsd4_decode_renew, +- [OP_RESTOREFH] = (nfsd4_dec)nfsd4_decode_noop, +- [OP_SAVEFH] = (nfsd4_dec)nfsd4_decode_noop, +- [OP_SECINFO] = (nfsd4_dec)nfsd4_decode_secinfo, +- [OP_SETATTR] = (nfsd4_dec)nfsd4_decode_setattr, +- [OP_SETCLIENTID] = (nfsd4_dec)nfsd4_decode_setclientid, +- [OP_SETCLIENTID_CONFIRM] = (nfsd4_dec)nfsd4_decode_setclientid_confirm, +- [OP_VERIFY] = (nfsd4_dec)nfsd4_decode_verify, +- [OP_WRITE] = (nfsd4_dec)nfsd4_decode_write, +- [OP_RELEASE_LOCKOWNER] = (nfsd4_dec)nfsd4_decode_release_lockowner, ++ [OP_ACCESS] = nfsd4_decode_access, ++ [OP_CLOSE] = nfsd4_decode_close, ++ [OP_COMMIT] = nfsd4_decode_commit, ++ [OP_CREATE] = nfsd4_decode_create, ++ [OP_DELEGPURGE] = nfsd4_decode_notsupp, ++ [OP_DELEGRETURN] = nfsd4_decode_delegreturn, ++ [OP_GETATTR] = nfsd4_decode_getattr, ++ [OP_GETFH] = nfsd4_decode_noop, ++ [OP_LINK] = nfsd4_decode_link, ++ [OP_LOCK] = nfsd4_decode_lock, ++ [OP_LOCKT] = nfsd4_decode_lockt, ++ [OP_LOCKU] = nfsd4_decode_locku, ++ [OP_LOOKUP] = nfsd4_decode_lookup, ++ [OP_LOOKUPP] = nfsd4_decode_noop, ++ [OP_NVERIFY] = nfsd4_decode_verify, ++ [OP_OPEN] = nfsd4_decode_open, ++ [OP_OPENATTR] = nfsd4_decode_notsupp, ++ [OP_OPEN_CONFIRM] = nfsd4_decode_open_confirm, ++ [OP_OPEN_DOWNGRADE] = nfsd4_decode_open_downgrade, ++ [OP_PUTFH] = nfsd4_decode_putfh, ++ [OP_PUTPUBFH] = nfsd4_decode_putpubfh, ++ [OP_PUTROOTFH] = nfsd4_decode_noop, ++ [OP_READ] = nfsd4_decode_read, ++ [OP_READDIR] = nfsd4_decode_readdir, ++ [OP_READLINK] = nfsd4_decode_noop, ++ [OP_REMOVE] = nfsd4_decode_remove, ++ [OP_RENAME] = nfsd4_decode_rename, ++ [OP_RENEW] = nfsd4_decode_renew, ++ [OP_RESTOREFH] = nfsd4_decode_noop, ++ [OP_SAVEFH] = nfsd4_decode_noop, ++ [OP_SECINFO] = nfsd4_decode_secinfo, ++ [OP_SETATTR] = nfsd4_decode_setattr, ++ [OP_SETCLIENTID] = nfsd4_decode_setclientid, ++ [OP_SETCLIENTID_CONFIRM] = nfsd4_decode_setclientid_confirm, ++ [OP_VERIFY] = nfsd4_decode_verify, ++ [OP_WRITE] = nfsd4_decode_write, ++ [OP_RELEASE_LOCKOWNER] = nfsd4_decode_release_lockowner, + + /* new operations for NFSv4.1 */ +- [OP_BACKCHANNEL_CTL] = (nfsd4_dec)nfsd4_decode_backchannel_ctl, +- [OP_BIND_CONN_TO_SESSION]= (nfsd4_dec)nfsd4_decode_bind_conn_to_session, +- [OP_EXCHANGE_ID] = (nfsd4_dec)nfsd4_decode_exchange_id, +- [OP_CREATE_SESSION] = (nfsd4_dec)nfsd4_decode_create_session, +- [OP_DESTROY_SESSION] = (nfsd4_dec)nfsd4_decode_destroy_session, +- [OP_FREE_STATEID] = (nfsd4_dec)nfsd4_decode_free_stateid, +- [OP_GET_DIR_DELEGATION] = (nfsd4_dec)nfsd4_decode_notsupp, ++ [OP_BACKCHANNEL_CTL] = nfsd4_decode_backchannel_ctl, ++ [OP_BIND_CONN_TO_SESSION] = nfsd4_decode_bind_conn_to_session, ++ [OP_EXCHANGE_ID] = nfsd4_decode_exchange_id, ++ [OP_CREATE_SESSION] = nfsd4_decode_create_session, ++ [OP_DESTROY_SESSION] = nfsd4_decode_destroy_session, ++ [OP_FREE_STATEID] = nfsd4_decode_free_stateid, ++ [OP_GET_DIR_DELEGATION] = nfsd4_decode_notsupp, + #ifdef CONFIG_NFSD_PNFS +- [OP_GETDEVICEINFO] = (nfsd4_dec)nfsd4_decode_getdeviceinfo, +- [OP_GETDEVICELIST] = (nfsd4_dec)nfsd4_decode_notsupp, +- [OP_LAYOUTCOMMIT] = (nfsd4_dec)nfsd4_decode_layoutcommit, +- [OP_LAYOUTGET] = (nfsd4_dec)nfsd4_decode_layoutget, +- [OP_LAYOUTRETURN] = (nfsd4_dec)nfsd4_decode_layoutreturn, ++ [OP_GETDEVICEINFO] = nfsd4_decode_getdeviceinfo, ++ [OP_GETDEVICELIST] = nfsd4_decode_notsupp, ++ [OP_LAYOUTCOMMIT] = nfsd4_decode_layoutcommit, ++ [OP_LAYOUTGET] = nfsd4_decode_layoutget, ++ [OP_LAYOUTRETURN] = nfsd4_decode_layoutreturn, + #else +- [OP_GETDEVICEINFO] = (nfsd4_dec)nfsd4_decode_notsupp, +- [OP_GETDEVICELIST] = (nfsd4_dec)nfsd4_decode_notsupp, +- [OP_LAYOUTCOMMIT] = (nfsd4_dec)nfsd4_decode_notsupp, +- [OP_LAYOUTGET] = (nfsd4_dec)nfsd4_decode_notsupp, +- [OP_LAYOUTRETURN] = (nfsd4_dec)nfsd4_decode_notsupp, ++ [OP_GETDEVICEINFO] = nfsd4_decode_notsupp, ++ [OP_GETDEVICELIST] = nfsd4_decode_notsupp, ++ [OP_LAYOUTCOMMIT] = nfsd4_decode_notsupp, ++ [OP_LAYOUTGET] = nfsd4_decode_notsupp, ++ [OP_LAYOUTRETURN] = nfsd4_decode_notsupp, + #endif +- [OP_SECINFO_NO_NAME] = (nfsd4_dec)nfsd4_decode_secinfo_no_name, +- [OP_SEQUENCE] = (nfsd4_dec)nfsd4_decode_sequence, +- [OP_SET_SSV] = (nfsd4_dec)nfsd4_decode_notsupp, +- [OP_TEST_STATEID] = (nfsd4_dec)nfsd4_decode_test_stateid, +- [OP_WANT_DELEGATION] = (nfsd4_dec)nfsd4_decode_notsupp, +- [OP_DESTROY_CLIENTID] = (nfsd4_dec)nfsd4_decode_destroy_clientid, +- [OP_RECLAIM_COMPLETE] = (nfsd4_dec)nfsd4_decode_reclaim_complete, ++ [OP_SECINFO_NO_NAME] = nfsd4_decode_secinfo_no_name, ++ [OP_SEQUENCE] = nfsd4_decode_sequence, ++ [OP_SET_SSV] = nfsd4_decode_notsupp, ++ [OP_TEST_STATEID] = nfsd4_decode_test_stateid, ++ [OP_WANT_DELEGATION] = nfsd4_decode_notsupp, ++ [OP_DESTROY_CLIENTID] = nfsd4_decode_destroy_clientid, ++ [OP_RECLAIM_COMPLETE] = nfsd4_decode_reclaim_complete, + + /* new operations for NFSv4.2 */ +- [OP_ALLOCATE] = (nfsd4_dec)nfsd4_decode_fallocate, +- [OP_COPY] = (nfsd4_dec)nfsd4_decode_copy, +- [OP_COPY_NOTIFY] = (nfsd4_dec)nfsd4_decode_copy_notify, +- [OP_DEALLOCATE] = (nfsd4_dec)nfsd4_decode_fallocate, +- [OP_IO_ADVISE] = (nfsd4_dec)nfsd4_decode_notsupp, +- [OP_LAYOUTERROR] = (nfsd4_dec)nfsd4_decode_notsupp, +- [OP_LAYOUTSTATS] = (nfsd4_dec)nfsd4_decode_notsupp, +- [OP_OFFLOAD_CANCEL] = (nfsd4_dec)nfsd4_decode_offload_status, +- [OP_OFFLOAD_STATUS] = (nfsd4_dec)nfsd4_decode_offload_status, +- [OP_READ_PLUS] = (nfsd4_dec)nfsd4_decode_read, +- [OP_SEEK] = (nfsd4_dec)nfsd4_decode_seek, +- [OP_WRITE_SAME] = (nfsd4_dec)nfsd4_decode_notsupp, +- [OP_CLONE] = (nfsd4_dec)nfsd4_decode_clone, ++ [OP_ALLOCATE] = nfsd4_decode_fallocate, ++ [OP_COPY] = nfsd4_decode_copy, ++ [OP_COPY_NOTIFY] = nfsd4_decode_copy_notify, ++ [OP_DEALLOCATE] = nfsd4_decode_fallocate, ++ [OP_IO_ADVISE] = nfsd4_decode_notsupp, ++ [OP_LAYOUTERROR] = nfsd4_decode_notsupp, ++ [OP_LAYOUTSTATS] = nfsd4_decode_notsupp, ++ [OP_OFFLOAD_CANCEL] = nfsd4_decode_offload_status, ++ [OP_OFFLOAD_STATUS] = nfsd4_decode_offload_status, ++ [OP_READ_PLUS] = nfsd4_decode_read, ++ [OP_SEEK] = nfsd4_decode_seek, ++ [OP_WRITE_SAME] = nfsd4_decode_notsupp, ++ [OP_CLONE] = nfsd4_decode_clone, + /* RFC 8276 extended atributes operations */ +- [OP_GETXATTR] = (nfsd4_dec)nfsd4_decode_getxattr, +- [OP_SETXATTR] = (nfsd4_dec)nfsd4_decode_setxattr, +- [OP_LISTXATTRS] = (nfsd4_dec)nfsd4_decode_listxattrs, +- [OP_REMOVEXATTR] = (nfsd4_dec)nfsd4_decode_removexattr, ++ [OP_GETXATTR] = nfsd4_decode_getxattr, ++ [OP_SETXATTR] = nfsd4_decode_setxattr, ++ [OP_LISTXATTRS] = nfsd4_decode_listxattrs, ++ [OP_REMOVEXATTR] = nfsd4_decode_removexattr, + }; + + static inline bool +@@ -3641,8 +3700,10 @@ nfsd4_encode_stateid(struct xdr_stream *xdr, stateid_t *sid) + } + + static __be32 +-nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_access *access) ++nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, ++ union nfsd4_op_u *u) + { ++ struct nfsd4_access *access = &u->access; + struct xdr_stream *xdr = resp->xdr; + __be32 *p; + +@@ -3654,8 +3715,10 @@ nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_ + return 0; + } + +-static __be32 nfsd4_encode_bind_conn_to_session(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_bind_conn_to_session *bcts) ++static __be32 nfsd4_encode_bind_conn_to_session(struct nfsd4_compoundres *resp, __be32 nfserr, ++ union nfsd4_op_u *u) + { ++ struct nfsd4_bind_conn_to_session *bcts = &u->bind_conn_to_session; + struct xdr_stream *xdr = resp->xdr; + __be32 *p; + +@@ -3671,8 +3734,10 @@ static __be32 nfsd4_encode_bind_conn_to_session(struct nfsd4_compoundres *resp, + } + + static __be32 +-nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_close *close) ++nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, ++ union nfsd4_op_u *u) + { ++ struct nfsd4_close *close = &u->close; + struct xdr_stream *xdr = resp->xdr; + + return nfsd4_encode_stateid(xdr, &close->cl_stateid); +@@ -3680,8 +3745,10 @@ nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_c + + + static __be32 +-nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_commit *commit) ++nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, ++ union nfsd4_op_u *u) + { ++ struct nfsd4_commit *commit = &u->commit; + struct xdr_stream *xdr = resp->xdr; + __be32 *p; + +@@ -3694,8 +3761,10 @@ nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_ + } + + static __be32 +-nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_create *create) ++nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr, ++ union nfsd4_op_u *u) + { ++ struct nfsd4_create *create = &u->create; + struct xdr_stream *xdr = resp->xdr; + __be32 *p; + +@@ -3708,8 +3777,10 @@ nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_ + } + + static __be32 +-nfsd4_encode_getattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_getattr *getattr) ++nfsd4_encode_getattr(struct nfsd4_compoundres *resp, __be32 nfserr, ++ union nfsd4_op_u *u) + { ++ struct nfsd4_getattr *getattr = &u->getattr; + struct svc_fh *fhp = getattr->ga_fhp; + struct xdr_stream *xdr = resp->xdr; + +@@ -3718,8 +3789,10 @@ nfsd4_encode_getattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4 + } + + static __be32 +-nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, struct svc_fh **fhpp) ++nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, ++ union nfsd4_op_u *u) + { ++ struct svc_fh **fhpp = &u->getfh; + struct xdr_stream *xdr = resp->xdr; + struct svc_fh *fhp = *fhpp; + unsigned int len; +@@ -3773,8 +3846,10 @@ nfsd4_encode_lock_denied(struct xdr_stream *xdr, struct nfsd4_lock_denied *ld) + } + + static __be32 +-nfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lock *lock) ++nfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr, ++ union nfsd4_op_u *u) + { ++ struct nfsd4_lock *lock = &u->lock; + struct xdr_stream *xdr = resp->xdr; + + if (!nfserr) +@@ -3786,8 +3861,10 @@ nfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lo + } + + static __be32 +-nfsd4_encode_lockt(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lockt *lockt) ++nfsd4_encode_lockt(struct nfsd4_compoundres *resp, __be32 nfserr, ++ union nfsd4_op_u *u) + { ++ struct nfsd4_lockt *lockt = &u->lockt; + struct xdr_stream *xdr = resp->xdr; + + if (nfserr == nfserr_denied) +@@ -3796,8 +3873,10 @@ nfsd4_encode_lockt(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_l + } + + static __be32 +-nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_locku *locku) ++nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, ++ union nfsd4_op_u *u) + { ++ struct nfsd4_locku *locku = &u->locku; + struct xdr_stream *xdr = resp->xdr; + + return nfsd4_encode_stateid(xdr, &locku->lu_stateid); +@@ -3805,8 +3884,10 @@ nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_l + + + static __be32 +-nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_link *link) ++nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, ++ union nfsd4_op_u *u) + { ++ struct nfsd4_link *link = &u->link; + struct xdr_stream *xdr = resp->xdr; + __be32 *p; + +@@ -3819,8 +3900,10 @@ nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_li + + + static __be32 +-nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open *open) ++nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, ++ union nfsd4_op_u *u) + { ++ struct nfsd4_open *open = &u->open; + struct xdr_stream *xdr = resp->xdr; + __be32 *p; + +@@ -3913,16 +3996,20 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_op + } + + static __be32 +-nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_confirm *oc) ++nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, __be32 nfserr, ++ union nfsd4_op_u *u) + { ++ struct nfsd4_open_confirm *oc = &u->open_confirm; + struct xdr_stream *xdr = resp->xdr; + + return nfsd4_encode_stateid(xdr, &oc->oc_resp_stateid); + } + + static __be32 +-nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_downgrade *od) ++nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, __be32 nfserr, ++ union nfsd4_op_u *u) + { ++ struct nfsd4_open_downgrade *od = &u->open_downgrade; + struct xdr_stream *xdr = resp->xdr; + + return nfsd4_encode_stateid(xdr, &od->od_stateid); +@@ -4021,8 +4108,9 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp, + + static __be32 + nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr, +- struct nfsd4_read *read) ++ union nfsd4_op_u *u) + { ++ struct nfsd4_read *read = &u->read; + bool splice_ok = test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags); + unsigned long maxcount; + struct xdr_stream *xdr = resp->xdr; +@@ -4063,8 +4151,10 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr, + } + + static __be32 +-nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_readlink *readlink) ++nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, ++ union nfsd4_op_u *u) + { ++ struct nfsd4_readlink *readlink = &u->readlink; + __be32 *p, *maxcount_p, zero = xdr_zero; + struct xdr_stream *xdr = resp->xdr; + int length_offset = xdr->buf->len; +@@ -4108,8 +4198,10 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd + } + + static __be32 +-nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_readdir *readdir) ++nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, ++ union nfsd4_op_u *u) + { ++ struct nfsd4_readdir *readdir = &u->readdir; + int maxcount; + int bytes_left; + loff_t offset; +@@ -4199,8 +4291,10 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4 + } + + static __be32 +-nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_remove *remove) ++nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, ++ union nfsd4_op_u *u) + { ++ struct nfsd4_remove *remove = &u->remove; + struct xdr_stream *xdr = resp->xdr; + __be32 *p; + +@@ -4212,8 +4306,10 @@ nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_ + } + + static __be32 +-nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_rename *rename) ++nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, ++ union nfsd4_op_u *u) + { ++ struct nfsd4_rename *rename = &u->rename; + struct xdr_stream *xdr = resp->xdr; + __be32 *p; + +@@ -4295,8 +4391,9 @@ nfsd4_do_encode_secinfo(struct xdr_stream *xdr, struct svc_export *exp) + + static __be32 + nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, __be32 nfserr, +- struct nfsd4_secinfo *secinfo) ++ union nfsd4_op_u *u) + { ++ struct nfsd4_secinfo *secinfo = &u->secinfo; + struct xdr_stream *xdr = resp->xdr; + + return nfsd4_do_encode_secinfo(xdr, secinfo->si_exp); +@@ -4304,8 +4401,9 @@ nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, __be32 nfserr, + + static __be32 + nfsd4_encode_secinfo_no_name(struct nfsd4_compoundres *resp, __be32 nfserr, +- struct nfsd4_secinfo_no_name *secinfo) ++ union nfsd4_op_u *u) + { ++ struct nfsd4_secinfo_no_name *secinfo = &u->secinfo_no_name; + struct xdr_stream *xdr = resp->xdr; + + return nfsd4_do_encode_secinfo(xdr, secinfo->sin_exp); +@@ -4316,8 +4414,10 @@ nfsd4_encode_secinfo_no_name(struct nfsd4_compoundres *resp, __be32 nfserr, + * regardless of the error status. + */ + static __be32 +-nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setattr *setattr) ++nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, ++ union nfsd4_op_u *u) + { ++ struct nfsd4_setattr *setattr = &u->setattr; + struct xdr_stream *xdr = resp->xdr; + __be32 *p; + +@@ -4340,8 +4440,10 @@ nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4 + } + + static __be32 +-nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setclientid *scd) ++nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, ++ union nfsd4_op_u *u) + { ++ struct nfsd4_setclientid *scd = &u->setclientid; + struct xdr_stream *xdr = resp->xdr; + __be32 *p; + +@@ -4364,8 +4466,10 @@ nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct n + } + + static __be32 +-nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_write *write) ++nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, ++ union nfsd4_op_u *u) + { ++ struct nfsd4_write *write = &u->write; + struct xdr_stream *xdr = resp->xdr; + __be32 *p; + +@@ -4381,8 +4485,9 @@ nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_w + + static __be32 + nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr, +- struct nfsd4_exchange_id *exid) ++ union nfsd4_op_u *u) + { ++ struct nfsd4_exchange_id *exid = &u->exchange_id; + struct xdr_stream *xdr = resp->xdr; + __be32 *p; + char *major_id; +@@ -4459,8 +4564,9 @@ nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr, + + static __be32 + nfsd4_encode_create_session(struct nfsd4_compoundres *resp, __be32 nfserr, +- struct nfsd4_create_session *sess) ++ union nfsd4_op_u *u) + { ++ struct nfsd4_create_session *sess = &u->create_session; + struct xdr_stream *xdr = resp->xdr; + __be32 *p; + +@@ -4512,8 +4618,9 @@ nfsd4_encode_create_session(struct nfsd4_compoundres *resp, __be32 nfserr, + + static __be32 + nfsd4_encode_sequence(struct nfsd4_compoundres *resp, __be32 nfserr, +- struct nfsd4_sequence *seq) ++ union nfsd4_op_u *u) + { ++ struct nfsd4_sequence *seq = &u->sequence; + struct xdr_stream *xdr = resp->xdr; + __be32 *p; + +@@ -4535,8 +4642,9 @@ nfsd4_encode_sequence(struct nfsd4_compoundres *resp, __be32 nfserr, + + static __be32 + nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, __be32 nfserr, +- struct nfsd4_test_stateid *test_stateid) ++ union nfsd4_op_u *u) + { ++ struct nfsd4_test_stateid *test_stateid = &u->test_stateid; + struct xdr_stream *xdr = resp->xdr; + struct nfsd4_test_stateid_id *stateid, *next; + __be32 *p; +@@ -4556,8 +4664,9 @@ nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, __be32 nfserr, + #ifdef CONFIG_NFSD_PNFS + static __be32 + nfsd4_encode_getdeviceinfo(struct nfsd4_compoundres *resp, __be32 nfserr, +- struct nfsd4_getdeviceinfo *gdev) ++ union nfsd4_op_u *u) + { ++ struct nfsd4_getdeviceinfo *gdev = &u->getdeviceinfo; + struct xdr_stream *xdr = resp->xdr; + const struct nfsd4_layout_ops *ops; + u32 starting_len = xdr->buf->len, needed_len; +@@ -4609,8 +4718,9 @@ nfsd4_encode_getdeviceinfo(struct nfsd4_compoundres *resp, __be32 nfserr, + + static __be32 + nfsd4_encode_layoutget(struct nfsd4_compoundres *resp, __be32 nfserr, +- struct nfsd4_layoutget *lgp) ++ union nfsd4_op_u *u) + { ++ struct nfsd4_layoutget *lgp = &u->layoutget; + struct xdr_stream *xdr = resp->xdr; + const struct nfsd4_layout_ops *ops; + __be32 *p; +@@ -4636,8 +4746,9 @@ nfsd4_encode_layoutget(struct nfsd4_compoundres *resp, __be32 nfserr, + + static __be32 + nfsd4_encode_layoutcommit(struct nfsd4_compoundres *resp, __be32 nfserr, +- struct nfsd4_layoutcommit *lcp) ++ union nfsd4_op_u *u) + { ++ struct nfsd4_layoutcommit *lcp = &u->layoutcommit; + struct xdr_stream *xdr = resp->xdr; + __be32 *p; + +@@ -4657,8 +4768,9 @@ nfsd4_encode_layoutcommit(struct nfsd4_compoundres *resp, __be32 nfserr, + + static __be32 + nfsd4_encode_layoutreturn(struct nfsd4_compoundres *resp, __be32 nfserr, +- struct nfsd4_layoutreturn *lrp) ++ union nfsd4_op_u *u) + { ++ struct nfsd4_layoutreturn *lrp = &u->layoutreturn; + struct xdr_stream *xdr = resp->xdr; + __be32 *p; + +@@ -4743,8 +4855,9 @@ nfsd42_encode_nl4_server(struct nfsd4_compoundres *resp, struct nl4_server *ns) + + static __be32 + nfsd4_encode_copy(struct nfsd4_compoundres *resp, __be32 nfserr, +- struct nfsd4_copy *copy) ++ union nfsd4_op_u *u) + { ++ struct nfsd4_copy *copy = &u->copy; + __be32 *p; + + nfserr = nfsd42_encode_write_res(resp, ©->cp_res, +@@ -4760,8 +4873,9 @@ nfsd4_encode_copy(struct nfsd4_compoundres *resp, __be32 nfserr, + + static __be32 + nfsd4_encode_offload_status(struct nfsd4_compoundres *resp, __be32 nfserr, +- struct nfsd4_offload_status *os) ++ union nfsd4_op_u *u) + { ++ struct nfsd4_offload_status *os = &u->offload_status; + struct xdr_stream *xdr = resp->xdr; + __be32 *p; + +@@ -4811,8 +4925,9 @@ nfsd4_encode_read_plus_data(struct nfsd4_compoundres *resp, + + static __be32 + nfsd4_encode_read_plus(struct nfsd4_compoundres *resp, __be32 nfserr, +- struct nfsd4_read *read) ++ union nfsd4_op_u *u) + { ++ struct nfsd4_read *read = &u->read; + struct file *file = read->rd_nf->nf_file; + struct xdr_stream *xdr = resp->xdr; + int starting_len = xdr->buf->len; +@@ -4848,8 +4963,9 @@ nfsd4_encode_read_plus(struct nfsd4_compoundres *resp, __be32 nfserr, + + static __be32 + nfsd4_encode_copy_notify(struct nfsd4_compoundres *resp, __be32 nfserr, +- struct nfsd4_copy_notify *cn) ++ union nfsd4_op_u *u) + { ++ struct nfsd4_copy_notify *cn = &u->copy_notify; + struct xdr_stream *xdr = resp->xdr; + __be32 *p; + +@@ -4883,8 +4999,9 @@ nfsd4_encode_copy_notify(struct nfsd4_compoundres *resp, __be32 nfserr, + + static __be32 + nfsd4_encode_seek(struct nfsd4_compoundres *resp, __be32 nfserr, +- struct nfsd4_seek *seek) ++ union nfsd4_op_u *u) + { ++ struct nfsd4_seek *seek = &u->seek; + __be32 *p; + + p = xdr_reserve_space(resp->xdr, 4 + 8); +@@ -4895,7 +5012,8 @@ nfsd4_encode_seek(struct nfsd4_compoundres *resp, __be32 nfserr, + } + + static __be32 +-nfsd4_encode_noop(struct nfsd4_compoundres *resp, __be32 nfserr, void *p) ++nfsd4_encode_noop(struct nfsd4_compoundres *resp, __be32 nfserr, ++ union nfsd4_op_u *p) + { + return nfserr; + } +@@ -4946,8 +5064,9 @@ nfsd4_vbuf_to_stream(struct xdr_stream *xdr, char *buf, u32 buflen) + + static __be32 + nfsd4_encode_getxattr(struct nfsd4_compoundres *resp, __be32 nfserr, +- struct nfsd4_getxattr *getxattr) ++ union nfsd4_op_u *u) + { ++ struct nfsd4_getxattr *getxattr = &u->getxattr; + struct xdr_stream *xdr = resp->xdr; + __be32 *p, err; + +@@ -4970,8 +5089,9 @@ nfsd4_encode_getxattr(struct nfsd4_compoundres *resp, __be32 nfserr, + + static __be32 + nfsd4_encode_setxattr(struct nfsd4_compoundres *resp, __be32 nfserr, +- struct nfsd4_setxattr *setxattr) ++ union nfsd4_op_u *u) + { ++ struct nfsd4_setxattr *setxattr = &u->setxattr; + struct xdr_stream *xdr = resp->xdr; + __be32 *p; + +@@ -5011,8 +5131,9 @@ nfsd4_listxattr_validate_cookie(struct nfsd4_listxattrs *listxattrs, + + static __be32 + nfsd4_encode_listxattrs(struct nfsd4_compoundres *resp, __be32 nfserr, +- struct nfsd4_listxattrs *listxattrs) ++ union nfsd4_op_u *u) + { ++ struct nfsd4_listxattrs *listxattrs = &u->listxattrs; + struct xdr_stream *xdr = resp->xdr; + u32 cookie_offset, count_offset, eof; + u32 left, xdrleft, slen, count; +@@ -5122,8 +5243,9 @@ nfsd4_encode_listxattrs(struct nfsd4_compoundres *resp, __be32 nfserr, + + static __be32 + nfsd4_encode_removexattr(struct nfsd4_compoundres *resp, __be32 nfserr, +- struct nfsd4_removexattr *removexattr) ++ union nfsd4_op_u *u) + { ++ struct nfsd4_removexattr *removexattr = &u->removexattr; + struct xdr_stream *xdr = resp->xdr; + __be32 *p; + +@@ -5135,7 +5257,7 @@ nfsd4_encode_removexattr(struct nfsd4_compoundres *resp, __be32 nfserr, + return 0; + } + +-typedef __be32(* nfsd4_enc)(struct nfsd4_compoundres *, __be32, void *); ++typedef __be32(*nfsd4_enc)(struct nfsd4_compoundres *, __be32, union nfsd4_op_u *u); + + /* + * Note: nfsd4_enc_ops vector is shared for v4.0 and v4.1 +@@ -5143,93 +5265,93 @@ typedef __be32(* nfsd4_enc)(struct nfsd4_compoundres *, __be32, void *); + * done in the decoding phase. + */ + static const nfsd4_enc nfsd4_enc_ops[] = { +- [OP_ACCESS] = (nfsd4_enc)nfsd4_encode_access, +- [OP_CLOSE] = (nfsd4_enc)nfsd4_encode_close, +- [OP_COMMIT] = (nfsd4_enc)nfsd4_encode_commit, +- [OP_CREATE] = (nfsd4_enc)nfsd4_encode_create, +- [OP_DELEGPURGE] = (nfsd4_enc)nfsd4_encode_noop, +- [OP_DELEGRETURN] = (nfsd4_enc)nfsd4_encode_noop, +- [OP_GETATTR] = (nfsd4_enc)nfsd4_encode_getattr, +- [OP_GETFH] = (nfsd4_enc)nfsd4_encode_getfh, +- [OP_LINK] = (nfsd4_enc)nfsd4_encode_link, +- [OP_LOCK] = (nfsd4_enc)nfsd4_encode_lock, +- [OP_LOCKT] = (nfsd4_enc)nfsd4_encode_lockt, +- [OP_LOCKU] = (nfsd4_enc)nfsd4_encode_locku, +- [OP_LOOKUP] = (nfsd4_enc)nfsd4_encode_noop, +- [OP_LOOKUPP] = (nfsd4_enc)nfsd4_encode_noop, +- [OP_NVERIFY] = (nfsd4_enc)nfsd4_encode_noop, +- [OP_OPEN] = (nfsd4_enc)nfsd4_encode_open, +- [OP_OPENATTR] = (nfsd4_enc)nfsd4_encode_noop, +- [OP_OPEN_CONFIRM] = (nfsd4_enc)nfsd4_encode_open_confirm, +- [OP_OPEN_DOWNGRADE] = (nfsd4_enc)nfsd4_encode_open_downgrade, +- [OP_PUTFH] = (nfsd4_enc)nfsd4_encode_noop, +- [OP_PUTPUBFH] = (nfsd4_enc)nfsd4_encode_noop, +- [OP_PUTROOTFH] = (nfsd4_enc)nfsd4_encode_noop, +- [OP_READ] = (nfsd4_enc)nfsd4_encode_read, +- [OP_READDIR] = (nfsd4_enc)nfsd4_encode_readdir, +- [OP_READLINK] = (nfsd4_enc)nfsd4_encode_readlink, +- [OP_REMOVE] = (nfsd4_enc)nfsd4_encode_remove, +- [OP_RENAME] = (nfsd4_enc)nfsd4_encode_rename, +- [OP_RENEW] = (nfsd4_enc)nfsd4_encode_noop, +- [OP_RESTOREFH] = (nfsd4_enc)nfsd4_encode_noop, +- [OP_SAVEFH] = (nfsd4_enc)nfsd4_encode_noop, +- [OP_SECINFO] = (nfsd4_enc)nfsd4_encode_secinfo, +- [OP_SETATTR] = (nfsd4_enc)nfsd4_encode_setattr, +- [OP_SETCLIENTID] = (nfsd4_enc)nfsd4_encode_setclientid, +- [OP_SETCLIENTID_CONFIRM] = (nfsd4_enc)nfsd4_encode_noop, +- [OP_VERIFY] = (nfsd4_enc)nfsd4_encode_noop, +- [OP_WRITE] = (nfsd4_enc)nfsd4_encode_write, +- [OP_RELEASE_LOCKOWNER] = (nfsd4_enc)nfsd4_encode_noop, ++ [OP_ACCESS] = nfsd4_encode_access, ++ [OP_CLOSE] = nfsd4_encode_close, ++ [OP_COMMIT] = nfsd4_encode_commit, ++ [OP_CREATE] = nfsd4_encode_create, ++ [OP_DELEGPURGE] = nfsd4_encode_noop, ++ [OP_DELEGRETURN] = nfsd4_encode_noop, ++ [OP_GETATTR] = nfsd4_encode_getattr, ++ [OP_GETFH] = nfsd4_encode_getfh, ++ [OP_LINK] = nfsd4_encode_link, ++ [OP_LOCK] = nfsd4_encode_lock, ++ [OP_LOCKT] = nfsd4_encode_lockt, ++ [OP_LOCKU] = nfsd4_encode_locku, ++ [OP_LOOKUP] = nfsd4_encode_noop, ++ [OP_LOOKUPP] = nfsd4_encode_noop, ++ [OP_NVERIFY] = nfsd4_encode_noop, ++ [OP_OPEN] = nfsd4_encode_open, ++ [OP_OPENATTR] = nfsd4_encode_noop, ++ [OP_OPEN_CONFIRM] = nfsd4_encode_open_confirm, ++ [OP_OPEN_DOWNGRADE] = nfsd4_encode_open_downgrade, ++ [OP_PUTFH] = nfsd4_encode_noop, ++ [OP_PUTPUBFH] = nfsd4_encode_noop, ++ [OP_PUTROOTFH] = nfsd4_encode_noop, ++ [OP_READ] = nfsd4_encode_read, ++ [OP_READDIR] = nfsd4_encode_readdir, ++ [OP_READLINK] = nfsd4_encode_readlink, ++ [OP_REMOVE] = nfsd4_encode_remove, ++ [OP_RENAME] = nfsd4_encode_rename, ++ [OP_RENEW] = nfsd4_encode_noop, ++ [OP_RESTOREFH] = nfsd4_encode_noop, ++ [OP_SAVEFH] = nfsd4_encode_noop, ++ [OP_SECINFO] = nfsd4_encode_secinfo, ++ [OP_SETATTR] = nfsd4_encode_setattr, ++ [OP_SETCLIENTID] = nfsd4_encode_setclientid, ++ [OP_SETCLIENTID_CONFIRM] = nfsd4_encode_noop, ++ [OP_VERIFY] = nfsd4_encode_noop, ++ [OP_WRITE] = nfsd4_encode_write, ++ [OP_RELEASE_LOCKOWNER] = nfsd4_encode_noop, + + /* NFSv4.1 operations */ +- [OP_BACKCHANNEL_CTL] = (nfsd4_enc)nfsd4_encode_noop, +- [OP_BIND_CONN_TO_SESSION] = (nfsd4_enc)nfsd4_encode_bind_conn_to_session, +- [OP_EXCHANGE_ID] = (nfsd4_enc)nfsd4_encode_exchange_id, +- [OP_CREATE_SESSION] = (nfsd4_enc)nfsd4_encode_create_session, +- [OP_DESTROY_SESSION] = (nfsd4_enc)nfsd4_encode_noop, +- [OP_FREE_STATEID] = (nfsd4_enc)nfsd4_encode_noop, +- [OP_GET_DIR_DELEGATION] = (nfsd4_enc)nfsd4_encode_noop, ++ [OP_BACKCHANNEL_CTL] = nfsd4_encode_noop, ++ [OP_BIND_CONN_TO_SESSION] = nfsd4_encode_bind_conn_to_session, ++ [OP_EXCHANGE_ID] = nfsd4_encode_exchange_id, ++ [OP_CREATE_SESSION] = nfsd4_encode_create_session, ++ [OP_DESTROY_SESSION] = nfsd4_encode_noop, ++ [OP_FREE_STATEID] = nfsd4_encode_noop, ++ [OP_GET_DIR_DELEGATION] = nfsd4_encode_noop, + #ifdef CONFIG_NFSD_PNFS +- [OP_GETDEVICEINFO] = (nfsd4_enc)nfsd4_encode_getdeviceinfo, +- [OP_GETDEVICELIST] = (nfsd4_enc)nfsd4_encode_noop, +- [OP_LAYOUTCOMMIT] = (nfsd4_enc)nfsd4_encode_layoutcommit, +- [OP_LAYOUTGET] = (nfsd4_enc)nfsd4_encode_layoutget, +- [OP_LAYOUTRETURN] = (nfsd4_enc)nfsd4_encode_layoutreturn, ++ [OP_GETDEVICEINFO] = nfsd4_encode_getdeviceinfo, ++ [OP_GETDEVICELIST] = nfsd4_encode_noop, ++ [OP_LAYOUTCOMMIT] = nfsd4_encode_layoutcommit, ++ [OP_LAYOUTGET] = nfsd4_encode_layoutget, ++ [OP_LAYOUTRETURN] = nfsd4_encode_layoutreturn, + #else +- [OP_GETDEVICEINFO] = (nfsd4_enc)nfsd4_encode_noop, +- [OP_GETDEVICELIST] = (nfsd4_enc)nfsd4_encode_noop, +- [OP_LAYOUTCOMMIT] = (nfsd4_enc)nfsd4_encode_noop, +- [OP_LAYOUTGET] = (nfsd4_enc)nfsd4_encode_noop, +- [OP_LAYOUTRETURN] = (nfsd4_enc)nfsd4_encode_noop, ++ [OP_GETDEVICEINFO] = nfsd4_encode_noop, ++ [OP_GETDEVICELIST] = nfsd4_encode_noop, ++ [OP_LAYOUTCOMMIT] = nfsd4_encode_noop, ++ [OP_LAYOUTGET] = nfsd4_encode_noop, ++ [OP_LAYOUTRETURN] = nfsd4_encode_noop, + #endif +- [OP_SECINFO_NO_NAME] = (nfsd4_enc)nfsd4_encode_secinfo_no_name, +- [OP_SEQUENCE] = (nfsd4_enc)nfsd4_encode_sequence, +- [OP_SET_SSV] = (nfsd4_enc)nfsd4_encode_noop, +- [OP_TEST_STATEID] = (nfsd4_enc)nfsd4_encode_test_stateid, +- [OP_WANT_DELEGATION] = (nfsd4_enc)nfsd4_encode_noop, +- [OP_DESTROY_CLIENTID] = (nfsd4_enc)nfsd4_encode_noop, +- [OP_RECLAIM_COMPLETE] = (nfsd4_enc)nfsd4_encode_noop, ++ [OP_SECINFO_NO_NAME] = nfsd4_encode_secinfo_no_name, ++ [OP_SEQUENCE] = nfsd4_encode_sequence, ++ [OP_SET_SSV] = nfsd4_encode_noop, ++ [OP_TEST_STATEID] = nfsd4_encode_test_stateid, ++ [OP_WANT_DELEGATION] = nfsd4_encode_noop, ++ [OP_DESTROY_CLIENTID] = nfsd4_encode_noop, ++ [OP_RECLAIM_COMPLETE] = nfsd4_encode_noop, + + /* NFSv4.2 operations */ +- [OP_ALLOCATE] = (nfsd4_enc)nfsd4_encode_noop, +- [OP_COPY] = (nfsd4_enc)nfsd4_encode_copy, +- [OP_COPY_NOTIFY] = (nfsd4_enc)nfsd4_encode_copy_notify, +- [OP_DEALLOCATE] = (nfsd4_enc)nfsd4_encode_noop, +- [OP_IO_ADVISE] = (nfsd4_enc)nfsd4_encode_noop, +- [OP_LAYOUTERROR] = (nfsd4_enc)nfsd4_encode_noop, +- [OP_LAYOUTSTATS] = (nfsd4_enc)nfsd4_encode_noop, +- [OP_OFFLOAD_CANCEL] = (nfsd4_enc)nfsd4_encode_noop, +- [OP_OFFLOAD_STATUS] = (nfsd4_enc)nfsd4_encode_offload_status, +- [OP_READ_PLUS] = (nfsd4_enc)nfsd4_encode_read_plus, +- [OP_SEEK] = (nfsd4_enc)nfsd4_encode_seek, +- [OP_WRITE_SAME] = (nfsd4_enc)nfsd4_encode_noop, +- [OP_CLONE] = (nfsd4_enc)nfsd4_encode_noop, ++ [OP_ALLOCATE] = nfsd4_encode_noop, ++ [OP_COPY] = nfsd4_encode_copy, ++ [OP_COPY_NOTIFY] = nfsd4_encode_copy_notify, ++ [OP_DEALLOCATE] = nfsd4_encode_noop, ++ [OP_IO_ADVISE] = nfsd4_encode_noop, ++ [OP_LAYOUTERROR] = nfsd4_encode_noop, ++ [OP_LAYOUTSTATS] = nfsd4_encode_noop, ++ [OP_OFFLOAD_CANCEL] = nfsd4_encode_noop, ++ [OP_OFFLOAD_STATUS] = nfsd4_encode_offload_status, ++ [OP_READ_PLUS] = nfsd4_encode_read_plus, ++ [OP_SEEK] = nfsd4_encode_seek, ++ [OP_WRITE_SAME] = nfsd4_encode_noop, ++ [OP_CLONE] = nfsd4_encode_noop, + + /* RFC 8276 extended atributes operations */ +- [OP_GETXATTR] = (nfsd4_enc)nfsd4_encode_getxattr, +- [OP_SETXATTR] = (nfsd4_enc)nfsd4_encode_setxattr, +- [OP_LISTXATTRS] = (nfsd4_enc)nfsd4_encode_listxattrs, +- [OP_REMOVEXATTR] = (nfsd4_enc)nfsd4_encode_removexattr, ++ [OP_GETXATTR] = nfsd4_encode_getxattr, ++ [OP_SETXATTR] = nfsd4_encode_setxattr, ++ [OP_LISTXATTRS] = nfsd4_encode_listxattrs, ++ [OP_REMOVEXATTR] = nfsd4_encode_removexattr, + }; + + /* +-- +2.43.0 + diff --git a/queue-5.10/nfsd-avoid-some-useless-tests.patch b/queue-5.10/nfsd-avoid-some-useless-tests.patch new file mode 100644 index 00000000000..4d993c17f2e --- /dev/null +++ b/queue-5.10/nfsd-avoid-some-useless-tests.patch @@ -0,0 +1,56 @@ +From 64c78a02fcc489d9d5b6a1a4a8f0d6d82a6925bc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 1 Sep 2022 07:27:11 +0200 +Subject: nfsd: Avoid some useless tests + +From: Christophe JAILLET + +[ Upstream commit d44899b8bb0b919f923186c616a84f0e70e04772 ] + +memdup_user() can't return NULL, so there is no point for checking for it. + +Simplify some tests accordingly. + +Suggested-by: Dan Carpenter +Signed-off-by: Christophe JAILLET +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4recover.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c +index d08c1a8c9254b..b9394a639a41a 100644 +--- a/fs/nfsd/nfs4recover.c ++++ b/fs/nfsd/nfs4recover.c +@@ -807,7 +807,7 @@ __cld_pipe_inprogress_downcall(const struct cld_msg_v2 __user *cmsg, + if (get_user(namelen, &ci->cc_name.cn_len)) + return -EFAULT; + name.data = memdup_user(&ci->cc_name.cn_id, namelen); +- if (IS_ERR_OR_NULL(name.data)) ++ if (IS_ERR(name.data)) + return -EFAULT; + name.len = namelen; + get_user(princhashlen, &ci->cc_princhash.cp_len); +@@ -815,7 +815,7 @@ __cld_pipe_inprogress_downcall(const struct cld_msg_v2 __user *cmsg, + princhash.data = memdup_user( + &ci->cc_princhash.cp_data, + princhashlen); +- if (IS_ERR_OR_NULL(princhash.data)) { ++ if (IS_ERR(princhash.data)) { + kfree(name.data); + return -EFAULT; + } +@@ -829,7 +829,7 @@ __cld_pipe_inprogress_downcall(const struct cld_msg_v2 __user *cmsg, + if (get_user(namelen, &cnm->cn_len)) + return -EFAULT; + name.data = memdup_user(&cnm->cn_id, namelen); +- if (IS_ERR_OR_NULL(name.data)) ++ if (IS_ERR(name.data)) + return -EFAULT; + name.len = namelen; + } +-- +2.43.0 + diff --git a/queue-5.10/nfsd-batch-release-pages-during-splice-read.patch b/queue-5.10/nfsd-batch-release-pages-during-splice-read.patch new file mode 100644 index 00000000000..ee416223676 --- /dev/null +++ b/queue-5.10/nfsd-batch-release-pages-during-splice-read.patch @@ -0,0 +1,46 @@ +From d7f42e745c93c44e19d2498c3e51fad8b6e84903 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 28 Jun 2021 17:24:27 -0400 +Subject: NFSD: Batch release pages during splice read + +From: Chuck Lever + +[ Upstream commit 496d83cf0f2fa70cfe256c2499e2d3523d3868f3 ] + +Large splice reads call put_page() repeatedly. put_page() is +relatively expensive to call, so replace it with the new +svc_rqst_replace_page() helper to help amortize that cost. + +Signed-off-by: Chuck Lever +Reviewed-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/vfs.c | 9 ++------- + 1 file changed, 2 insertions(+), 7 deletions(-) + +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index 8520a2fc92dee..05b5f7e241e70 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -856,15 +856,10 @@ nfsd_splice_actor(struct pipe_inode_info *pipe, struct pipe_buffer *buf, + struct page *page = buf->page; + + if (rqstp->rq_res.page_len == 0) { +- get_page(page); +- put_page(*rqstp->rq_next_page); +- *(rqstp->rq_next_page++) = page; ++ svc_rqst_replace_page(rqstp, page); + rqstp->rq_res.page_base = buf->offset; + } else if (page != pp[-1]) { +- get_page(page); +- if (*rqstp->rq_next_page) +- put_page(*rqstp->rq_next_page); +- *(rqstp->rq_next_page++) = page; ++ svc_rqst_replace_page(rqstp, page); + } + rqstp->rq_res.page_len += sd->len; + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-call-nfsd_last_thread-before-final-nfsd_put.patch b/queue-5.10/nfsd-call-nfsd_last_thread-before-final-nfsd_put.patch new file mode 100644 index 00000000000..e4bada1fbe0 --- /dev/null +++ b/queue-5.10/nfsd-call-nfsd_last_thread-before-final-nfsd_put.patch @@ -0,0 +1,83 @@ +From 0edd6f3e2c2d415d6f5b8d9ed56a67f747fd8832 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 15 Dec 2023 11:56:31 +1100 +Subject: nfsd: call nfsd_last_thread() before final nfsd_put() + +From: NeilBrown + +[ Upstream commit 2a501f55cd641eb4d3c16a2eab0d678693fac663 ] + +If write_ports_addfd or write_ports_addxprt fail, they call nfsd_put() +without calling nfsd_last_thread(). This leaves nn->nfsd_serv pointing +to a structure that has been freed. + +So remove 'static' from nfsd_last_thread() and call it when the +nfsd_serv is about to be destroyed. + +Fixes: ec52361df99b ("SUNRPC: stop using ->sv_nrthreads as a refcount") +Signed-off-by: NeilBrown +Reviewed-by: Jeff Layton +Cc: +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsctl.c | 9 +++++++-- + fs/nfsd/nfsd.h | 1 + + fs/nfsd/nfssvc.c | 2 +- + 3 files changed, 9 insertions(+), 3 deletions(-) + +diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c +index 76a60e7a75097..eec442edb6556 100644 +--- a/fs/nfsd/nfsctl.c ++++ b/fs/nfsd/nfsctl.c +@@ -720,8 +720,10 @@ static ssize_t __write_ports_addfd(char *buf, struct net *net, const struct cred + + err = svc_addsock(nn->nfsd_serv, net, fd, buf, SIMPLE_TRANSACTION_LIMIT, cred); + +- if (err >= 0 && +- !nn->nfsd_serv->sv_nrthreads && !xchg(&nn->keep_active, 1)) ++ if (err < 0 && !nn->nfsd_serv->sv_nrthreads && !nn->keep_active) ++ nfsd_last_thread(net); ++ else if (err >= 0 && ++ !nn->nfsd_serv->sv_nrthreads && !xchg(&nn->keep_active, 1)) + svc_get(nn->nfsd_serv); + + nfsd_put(net); +@@ -771,6 +773,9 @@ static ssize_t __write_ports_addxprt(char *buf, struct net *net, const struct cr + svc_xprt_put(xprt); + } + out_err: ++ if (!nn->nfsd_serv->sv_nrthreads && !nn->keep_active) ++ nfsd_last_thread(net); ++ + nfsd_put(net); + return err; + } +diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h +index 867dcfd64d426..3796015dc7656 100644 +--- a/fs/nfsd/nfsd.h ++++ b/fs/nfsd/nfsd.h +@@ -138,6 +138,7 @@ int nfsd_vers(struct nfsd_net *nn, int vers, enum vers_op change); + int nfsd_minorversion(struct nfsd_net *nn, u32 minorversion, enum vers_op change); + void nfsd_reset_versions(struct nfsd_net *nn); + int nfsd_create_serv(struct net *net); ++void nfsd_last_thread(struct net *net); + + extern int nfsd_max_blksize; + +diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c +index 2a1dd580dfb94..3d4fd40c987bd 100644 +--- a/fs/nfsd/nfssvc.c ++++ b/fs/nfsd/nfssvc.c +@@ -529,7 +529,7 @@ static struct notifier_block nfsd_inet6addr_notifier = { + /* Only used under nfsd_mutex, so this atomic may be overkill: */ + static atomic_t nfsd_notifier_refcount = ATOMIC_INIT(0); + +-static void nfsd_last_thread(struct net *net) ++void nfsd_last_thread(struct net *net) + { + struct nfsd_net *nn = net_generic(net, nfsd_net_id); + struct svc_serv *serv = nn->nfsd_serv; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-call-op_release-even-when-op_func-returns-an-er.patch b/queue-5.10/nfsd-call-op_release-even-when-op_func-returns-an-er.patch new file mode 100644 index 00000000000..235f264bd2b --- /dev/null +++ b/queue-5.10/nfsd-call-op_release-even-when-op_func-returns-an-er.patch @@ -0,0 +1,69 @@ +From 6de8a45ecd040aca7d7ae40b06ca91a540d4ab87 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 27 Mar 2023 06:21:37 -0400 +Subject: nfsd: call op_release, even when op_func returns an error + +From: Jeff Layton + +[ Upstream commit 15a8b55dbb1ba154d82627547c5761cac884d810 ] + +For ops with "trivial" replies, nfsd4_encode_operation will shortcut +most of the encoding work and skip to just marshalling up the status. +One of the things it skips is calling op_release. This could cause a +memory leak in the layoutget codepath if there is an error at an +inopportune time. + +Have the compound processing engine always call op_release, even when +op_func sets an error in op->status. With this change, we also need +nfsd4_block_get_device_info_scsi to set the gd_device pointer to NULL +on error to avoid a double free. + +Reported-by: Zhi Li +Link: https://bugzilla.redhat.com/show_bug.cgi?id=2181403 +Fixes: 34b1744c91cc ("nfsd4: define ->op_release for compound ops") +Signed-off-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 11 +++++------ + 1 file changed, 5 insertions(+), 6 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index e1f2f26ba93f2..d62382dfc135e 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -5397,10 +5397,8 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) + __be32 *p; + + p = xdr_reserve_space(xdr, 8); +- if (!p) { +- WARN_ON_ONCE(1); +- return; +- } ++ if (!p) ++ goto release; + *p++ = cpu_to_be32(op->opnum); + post_err_offset = xdr->buf->len; + +@@ -5415,8 +5413,6 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) + op->status = encoder(resp, op->status, &op->u); + if (op->status) + trace_nfsd_compound_encode_err(rqstp, op->opnum, op->status); +- if (opdesc && opdesc->op_release) +- opdesc->op_release(&op->u); + xdr_commit_encode(xdr); + + /* nfsd4_check_resp_size guarantees enough room for error status */ +@@ -5457,6 +5453,9 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) + } + status: + *p = op->status; ++release: ++ if (opdesc && opdesc->op_release) ++ opdesc->op_release(&op->u); + } + + /* +-- +2.43.0 + diff --git a/queue-5.10/nfsd-cap-rsize_bop-result-based-on-send-buffer-size.patch b/queue-5.10/nfsd-cap-rsize_bop-result-based-on-send-buffer-size.patch new file mode 100644 index 00000000000..2158057966e --- /dev/null +++ b/queue-5.10/nfsd-cap-rsize_bop-result-based-on-send-buffer-size.patch @@ -0,0 +1,145 @@ +From a112f202c58c07e5600d13601657813f1e508841 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 1 Sep 2022 15:29:55 -0400 +Subject: NFSD: Cap rsize_bop result based on send buffer size + +From: Chuck Lever + +[ Upstream commit 76ce4dcec0dc08a032db916841ddc4e3998be317 ] + +Since before the git era, NFSD has conserved the number of pages +held by each nfsd thread by combining the RPC receive and send +buffers into a single array of pages. This works because there are +no cases where an operation needs a large RPC Call message and a +large RPC Reply at the same time. + +Once an RPC Call has been received, svc_process() updates +svc_rqst::rq_res to describe the part of rq_pages that can be +used for constructing the Reply. This means that the send buffer +(rq_res) shrinks when the received RPC record containing the RPC +Call is large. + +Add an NFSv4 helper that computes the size of the send buffer. It +replaces svc_max_payload() in spots where svc_max_payload() returns +a value that might be larger than the remaining send buffer space. +Callers who need to know the transport's actual maximum payload size +will continue to use svc_max_payload(). + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 48 +++++++++++++++++++++++----------------------- + 1 file changed, 24 insertions(+), 24 deletions(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index e1aa48d496b98..50fd4ba04a3e0 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -2763,6 +2763,22 @@ nfsd4_proc_compound(struct svc_rqst *rqstp) + + #define op_encode_channel_attrs_maxsz (6 + 1 + 1) + ++/* ++ * The _rsize() helpers are invoked by the NFSv4 COMPOUND decoder, which ++ * is called before sunrpc sets rq_res.buflen. Thus we have to compute ++ * the maximum payload size here, based on transport limits and the size ++ * of the remaining space in the rq_pages array. ++ */ ++static u32 nfsd4_max_payload(const struct svc_rqst *rqstp) ++{ ++ u32 buflen; ++ ++ buflen = (rqstp->rq_page_end - rqstp->rq_next_page) * PAGE_SIZE; ++ buflen -= rqstp->rq_auth_slack; ++ buflen -= rqstp->rq_res.head[0].iov_len; ++ return min_t(u32, buflen, svc_max_payload(rqstp)); ++} ++ + static u32 nfsd4_only_status_rsize(const struct svc_rqst *rqstp, + const struct nfsd4_op *op) + { +@@ -2808,9 +2824,9 @@ static u32 nfsd4_getattr_rsize(const struct svc_rqst *rqstp, + u32 ret = 0; + + if (bmap0 & FATTR4_WORD0_ACL) +- return svc_max_payload(rqstp); ++ return nfsd4_max_payload(rqstp); + if (bmap0 & FATTR4_WORD0_FS_LOCATIONS) +- return svc_max_payload(rqstp); ++ return nfsd4_max_payload(rqstp); + + if (bmap1 & FATTR4_WORD1_OWNER) { + ret += IDMAP_NAMESZ + 4; +@@ -2870,10 +2886,7 @@ static u32 nfsd4_open_rsize(const struct svc_rqst *rqstp, + static u32 nfsd4_read_rsize(const struct svc_rqst *rqstp, + const struct nfsd4_op *op) + { +- u32 maxcount = 0, rlen = 0; +- +- maxcount = svc_max_payload(rqstp); +- rlen = min(op->u.read.rd_length, maxcount); ++ u32 rlen = min(op->u.read.rd_length, nfsd4_max_payload(rqstp)); + + return (op_encode_hdr_size + 2 + XDR_QUADLEN(rlen)) * sizeof(__be32); + } +@@ -2881,8 +2894,7 @@ static u32 nfsd4_read_rsize(const struct svc_rqst *rqstp, + static u32 nfsd4_read_plus_rsize(const struct svc_rqst *rqstp, + const struct nfsd4_op *op) + { +- u32 maxcount = svc_max_payload(rqstp); +- u32 rlen = min(op->u.read.rd_length, maxcount); ++ u32 rlen = min(op->u.read.rd_length, nfsd4_max_payload(rqstp)); + /* + * If we detect that the file changed during hole encoding, then we + * recover by encoding the remaining reply as data. This means we need +@@ -2896,10 +2908,7 @@ static u32 nfsd4_read_plus_rsize(const struct svc_rqst *rqstp, + static u32 nfsd4_readdir_rsize(const struct svc_rqst *rqstp, + const struct nfsd4_op *op) + { +- u32 maxcount = 0, rlen = 0; +- +- maxcount = svc_max_payload(rqstp); +- rlen = min(op->u.readdir.rd_maxcount, maxcount); ++ u32 rlen = min(op->u.readdir.rd_maxcount, nfsd4_max_payload(rqstp)); + + return (op_encode_hdr_size + op_encode_verifier_maxsz + + XDR_QUADLEN(rlen)) * sizeof(__be32); +@@ -3038,10 +3047,7 @@ static u32 nfsd4_copy_notify_rsize(const struct svc_rqst *rqstp, + static u32 nfsd4_getdeviceinfo_rsize(const struct svc_rqst *rqstp, + const struct nfsd4_op *op) + { +- u32 maxcount = 0, rlen = 0; +- +- maxcount = svc_max_payload(rqstp); +- rlen = min(op->u.getdeviceinfo.gd_maxcount, maxcount); ++ u32 rlen = min(op->u.getdeviceinfo.gd_maxcount, nfsd4_max_payload(rqstp)); + + return (op_encode_hdr_size + + 1 /* gd_layout_type*/ + +@@ -3091,10 +3097,7 @@ static u32 nfsd4_seek_rsize(const struct svc_rqst *rqstp, + static u32 nfsd4_getxattr_rsize(const struct svc_rqst *rqstp, + const struct nfsd4_op *op) + { +- u32 maxcount, rlen; +- +- maxcount = svc_max_payload(rqstp); +- rlen = min_t(u32, XATTR_SIZE_MAX, maxcount); ++ u32 rlen = min_t(u32, XATTR_SIZE_MAX, nfsd4_max_payload(rqstp)); + + return (op_encode_hdr_size + 1 + XDR_QUADLEN(rlen)) * sizeof(__be32); + } +@@ -3108,10 +3111,7 @@ static u32 nfsd4_setxattr_rsize(const struct svc_rqst *rqstp, + static u32 nfsd4_listxattrs_rsize(const struct svc_rqst *rqstp, + const struct nfsd4_op *op) + { +- u32 maxcount, rlen; +- +- maxcount = svc_max_payload(rqstp); +- rlen = min(op->u.listxattrs.lsxa_maxcount, maxcount); ++ u32 rlen = min(op->u.listxattrs.lsxa_maxcount, nfsd4_max_payload(rqstp)); + + return (op_encode_hdr_size + 4 + XDR_QUADLEN(rlen)) * sizeof(__be32); + } +-- +2.43.0 + diff --git a/queue-5.10/nfsd-capture-every-cb-state-transition.patch b/queue-5.10/nfsd-capture-every-cb-state-transition.patch new file mode 100644 index 00000000000..696f2ac7748 --- /dev/null +++ b/queue-5.10/nfsd-capture-every-cb-state-transition.patch @@ -0,0 +1,106 @@ +From fc92f50d7a025c5f25ae3e948f2fffa1dd93a6d2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 14 May 2021 15:56:31 -0400 +Subject: NFSD: Capture every CB state transition + +From: Chuck Lever + +[ Upstream commit 8476c69a7fa0f1f9705ec0caa4e97c08b5045779 ] + +We were missing one. + +As a clean-up, add a helper that sets the new CB state and fires +a tracepoint. The tracepoint fires only when the state changes, to +help reduce trace log noise. + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4callback.c | 28 +++++++++++++++------------- + 1 file changed, 15 insertions(+), 13 deletions(-) + +diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c +index f5b7ad0847f20..2e6a4a9e59ca1 100644 +--- a/fs/nfsd/nfs4callback.c ++++ b/fs/nfsd/nfs4callback.c +@@ -945,20 +945,26 @@ static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *c + return 0; + } + ++static void nfsd4_mark_cb_state(struct nfs4_client *clp, int newstate) ++{ ++ if (clp->cl_cb_state != newstate) { ++ clp->cl_cb_state = newstate; ++ trace_nfsd_cb_state(clp); ++ } ++} ++ + static void nfsd4_mark_cb_down(struct nfs4_client *clp, int reason) + { + if (test_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_flags)) + return; +- clp->cl_cb_state = NFSD4_CB_DOWN; +- trace_nfsd_cb_state(clp); ++ nfsd4_mark_cb_state(clp, NFSD4_CB_DOWN); + } + + static void nfsd4_mark_cb_fault(struct nfs4_client *clp, int reason) + { + if (test_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_flags)) + return; +- clp->cl_cb_state = NFSD4_CB_FAULT; +- trace_nfsd_cb_state(clp); ++ nfsd4_mark_cb_state(clp, NFSD4_CB_FAULT); + } + + static void nfsd4_cb_probe_done(struct rpc_task *task, void *calldata) +@@ -968,10 +974,8 @@ static void nfsd4_cb_probe_done(struct rpc_task *task, void *calldata) + trace_nfsd_cb_done(clp, task->tk_status); + if (task->tk_status) + nfsd4_mark_cb_down(clp, task->tk_status); +- else { +- clp->cl_cb_state = NFSD4_CB_UP; +- trace_nfsd_cb_state(clp); +- } ++ else ++ nfsd4_mark_cb_state(clp, NFSD4_CB_UP); + } + + static void nfsd4_cb_probe_release(void *calldata) +@@ -995,8 +999,7 @@ static const struct rpc_call_ops nfsd4_cb_probe_ops = { + */ + void nfsd4_probe_callback(struct nfs4_client *clp) + { +- clp->cl_cb_state = NFSD4_CB_UNKNOWN; +- trace_nfsd_cb_state(clp); ++ nfsd4_mark_cb_state(clp, NFSD4_CB_UNKNOWN); + set_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_flags); + nfsd4_run_cb(&clp->cl_cb_null); + } +@@ -1009,11 +1012,10 @@ void nfsd4_probe_callback_sync(struct nfs4_client *clp) + + void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *conn) + { +- clp->cl_cb_state = NFSD4_CB_UNKNOWN; ++ nfsd4_mark_cb_state(clp, NFSD4_CB_UNKNOWN); + spin_lock(&clp->cl_lock); + memcpy(&clp->cl_cb_conn, conn, sizeof(struct nfs4_cb_conn)); + spin_unlock(&clp->cl_lock); +- trace_nfsd_cb_state(clp); + } + + /* +@@ -1345,7 +1347,7 @@ nfsd4_run_cb_work(struct work_struct *work) + * Don't send probe messages for 4.1 or later. + */ + if (!cb->cb_ops && clp->cl_minorversion) { +- clp->cl_cb_state = NFSD4_CB_UP; ++ nfsd4_mark_cb_state(clp, NFSD4_CB_UP); + nfsd41_destroy_cb(cb); + return; + } +-- +2.43.0 + diff --git a/queue-5.10/nfsd-change-nfsd_create-nfsd_symlink-to-unlock-direc.patch b/queue-5.10/nfsd-change-nfsd_create-nfsd_symlink-to-unlock-direc.patch new file mode 100644 index 00000000000..c60eb535429 --- /dev/null +++ b/queue-5.10/nfsd-change-nfsd_create-nfsd_symlink-to-unlock-direc.patch @@ -0,0 +1,144 @@ +From e8303e85a2ac5f27363bcddf080e3ef842aa6f9d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 Jul 2022 16:45:30 +1000 +Subject: NFSD: change nfsd_create()/nfsd_symlink() to unlock directory before + returning. + +From: NeilBrown + +[ Upstream commit 927bfc5600cd6333c9ef9f090f19e66b7d4c8ee1 ] + +nfsd_create() usually returns with the directory still locked. +nfsd_symlink() usually returns with it unlocked. This is clumsy. + +Until recently nfsd_create() needed to keep the directory locked until +ACLs and security label had been set. These are now set inside +nfsd_create() (in nfsd_setattr()) so this need is gone. + +So change nfsd_create() and nfsd_symlink() to always unlock, and remove +any fh_unlock() calls that follow calls to these functions. + +Signed-off-by: NeilBrown +[ cel: backported to 5.10.y, prior to idmapped mounts ] +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3proc.c | 2 -- + fs/nfsd/nfs4proc.c | 2 -- + fs/nfsd/vfs.c | 38 +++++++++++++++++++++----------------- + 3 files changed, 21 insertions(+), 21 deletions(-) + +diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c +index 394f6fb201974..c71f0c359f7ae 100644 +--- a/fs/nfsd/nfs3proc.c ++++ b/fs/nfsd/nfs3proc.c +@@ -388,7 +388,6 @@ nfsd3_proc_mkdir(struct svc_rqst *rqstp) + fh_init(&resp->fh, NFS3_FHSIZE); + resp->status = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len, + &attrs, S_IFDIR, 0, &resp->fh); +- fh_unlock(&resp->dirfh); + return rpc_success; + } + +@@ -469,7 +468,6 @@ nfsd3_proc_mknod(struct svc_rqst *rqstp) + type = nfs3_ftypes[argp->ftype]; + resp->status = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len, + &attrs, type, rdev, &resp->fh); +- fh_unlock(&resp->dirfh); + out: + return rpc_success; + } +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 507a2aa967133..0396fa2c1cfe7 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -823,8 +823,6 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + create->cr_bmval[2] &= ~FATTR4_WORD2_SECURITY_LABEL; + if (attrs.na_aclerr) + create->cr_bmval[0] &= ~FATTR4_WORD0_ACL; +- +- fh_unlock(&cstate->current_fh); + set_change_info(&create->cr_cinfo, &cstate->current_fh); + fh_dup2(&cstate->current_fh, &resfh); + out: +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index bed542ba8ad8e..3d794533bbd4b 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -1395,8 +1395,10 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, + fh_lock_nested(fhp, I_MUTEX_PARENT); + dchild = lookup_one_len(fname, dentry, flen); + host_err = PTR_ERR(dchild); +- if (IS_ERR(dchild)) +- return nfserrno(host_err); ++ if (IS_ERR(dchild)) { ++ err = nfserrno(host_err); ++ goto out_unlock; ++ } + err = fh_compose(resfhp, fhp->fh_export, dchild, fhp); + /* + * We unconditionally drop our ref to dchild as fh_compose will have +@@ -1404,9 +1406,12 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, + */ + dput(dchild); + if (err) +- return err; +- return nfsd_create_locked(rqstp, fhp, fname, flen, attrs, type, +- rdev, resfhp); ++ goto out_unlock; ++ err = nfsd_create_locked(rqstp, fhp, fname, flen, attrs, type, ++ rdev, resfhp); ++out_unlock: ++ fh_unlock(fhp); ++ return err; + } + + /* +@@ -1483,16 +1488,19 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, + goto out; + + host_err = fh_want_write(fhp); +- if (host_err) +- goto out_nfserr; ++ if (host_err) { ++ err = nfserrno(host_err); ++ goto out; ++ } + + fh_lock(fhp); + dentry = fhp->fh_dentry; + dnew = lookup_one_len(fname, dentry, flen); +- host_err = PTR_ERR(dnew); +- if (IS_ERR(dnew)) +- goto out_nfserr; +- ++ if (IS_ERR(dnew)) { ++ err = nfserrno(PTR_ERR(dnew)); ++ fh_unlock(fhp); ++ goto out_drop_write; ++ } + host_err = vfs_symlink(d_inode(dentry), dnew, path); + err = nfserrno(host_err); + cerr = fh_compose(resfhp, fhp->fh_export, dnew, fhp); +@@ -1501,16 +1509,12 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, + fh_unlock(fhp); + if (!err) + err = nfserrno(commit_metadata(fhp)); +- fh_drop_write(fhp); +- + dput(dnew); + if (err==0) err = cerr; ++out_drop_write: ++ fh_drop_write(fhp); + out: + return err; +- +-out_nfserr: +- err = nfserrno(host_err); +- goto out; + } + + /* +-- +2.43.0 + diff --git a/queue-5.10/nfsd-change-the-way-the-expected-length-of-a-fattr4-.patch b/queue-5.10/nfsd-change-the-way-the-expected-length-of-a-fattr4-.patch new file mode 100644 index 00000000000..fa6e07b4422 --- /dev/null +++ b/queue-5.10/nfsd-change-the-way-the-expected-length-of-a-fattr4-.patch @@ -0,0 +1,172 @@ +From b42bbe0415a430db0263f3e9f2595c8a33bdbc8f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Nov 2020 13:09:13 -0500 +Subject: NFSD: Change the way the expected length of a fattr4 is checked + +From: Chuck Lever + +[ Upstream commit 081d53fe0b43c47c36d1832b759bf14edde9cdbb ] + +Because the fattr4 is now managed in an xdr_stream, all that is +needed is to store the initial position of the stream before +decoding the attribute list. Then the actual length of the list +is computed using the final stream position, after decoding is +complete. + +No behavior change is expected. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 34 +++++++++++----------------------- + 1 file changed, 11 insertions(+), 23 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 8251b905d5479..de5ac334cb8ab 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -250,7 +250,8 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, + struct iattr *iattr, struct nfs4_acl **acl, + struct xdr_netobj *label, int *umask) + { +- int expected_len, len = 0; ++ unsigned int starting_pos; ++ u32 attrlist4_count; + u32 dummy32; + char *buf; + +@@ -267,12 +268,12 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, + return nfserr_attrnotsupp; + } + +- READ_BUF(4); +- expected_len = be32_to_cpup(p++); ++ if (xdr_stream_decode_u32(argp->xdr, &attrlist4_count) < 0) ++ return nfserr_bad_xdr; ++ starting_pos = xdr_stream_pos(argp->xdr); + + if (bmval[0] & FATTR4_WORD0_SIZE) { + READ_BUF(8); +- len += 8; + p = xdr_decode_hyper(p, &iattr->ia_size); + iattr->ia_valid |= ATTR_SIZE; + } +@@ -280,7 +281,7 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, + u32 nace; + struct nfs4_ace *ace; + +- READ_BUF(4); len += 4; ++ READ_BUF(4); + nace = be32_to_cpup(p++); + + if (nace > xdr_stream_remaining(argp->xdr) / sizeof(struct nfs4_ace)) +@@ -297,13 +298,12 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, + + (*acl)->naces = nace; + for (ace = (*acl)->aces; ace < (*acl)->aces + nace; ace++) { +- READ_BUF(16); len += 16; ++ READ_BUF(16); + ace->type = be32_to_cpup(p++); + ace->flag = be32_to_cpup(p++); + ace->access_mask = be32_to_cpup(p++); + dummy32 = be32_to_cpup(p++); + READ_BUF(dummy32); +- len += XDR_QUADLEN(dummy32) << 2; + READMEM(buf, dummy32); + ace->whotype = nfs4_acl_get_whotype(buf, dummy32); + status = nfs_ok; +@@ -322,17 +322,14 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, + *acl = NULL; + if (bmval[1] & FATTR4_WORD1_MODE) { + READ_BUF(4); +- len += 4; + iattr->ia_mode = be32_to_cpup(p++); + iattr->ia_mode &= (S_IFMT | S_IALLUGO); + iattr->ia_valid |= ATTR_MODE; + } + if (bmval[1] & FATTR4_WORD1_OWNER) { + READ_BUF(4); +- len += 4; + dummy32 = be32_to_cpup(p++); + READ_BUF(dummy32); +- len += (XDR_QUADLEN(dummy32) << 2); + READMEM(buf, dummy32); + if ((status = nfsd_map_name_to_uid(argp->rqstp, buf, dummy32, &iattr->ia_uid))) + return status; +@@ -340,10 +337,8 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, + } + if (bmval[1] & FATTR4_WORD1_OWNER_GROUP) { + READ_BUF(4); +- len += 4; + dummy32 = be32_to_cpup(p++); + READ_BUF(dummy32); +- len += (XDR_QUADLEN(dummy32) << 2); + READMEM(buf, dummy32); + if ((status = nfsd_map_name_to_gid(argp->rqstp, buf, dummy32, &iattr->ia_gid))) + return status; +@@ -351,11 +346,9 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, + } + if (bmval[1] & FATTR4_WORD1_TIME_ACCESS_SET) { + READ_BUF(4); +- len += 4; + dummy32 = be32_to_cpup(p++); + switch (dummy32) { + case NFS4_SET_TO_CLIENT_TIME: +- len += 12; + status = nfsd4_decode_time(argp, &iattr->ia_atime); + if (status) + return status; +@@ -370,11 +363,9 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, + } + if (bmval[1] & FATTR4_WORD1_TIME_MODIFY_SET) { + READ_BUF(4); +- len += 4; + dummy32 = be32_to_cpup(p++); + switch (dummy32) { + case NFS4_SET_TO_CLIENT_TIME: +- len += 12; + status = nfsd4_decode_time(argp, &iattr->ia_mtime); + if (status) + return status; +@@ -392,18 +383,14 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, + if (IS_ENABLED(CONFIG_NFSD_V4_SECURITY_LABEL) && + bmval[2] & FATTR4_WORD2_SECURITY_LABEL) { + READ_BUF(4); +- len += 4; + dummy32 = be32_to_cpup(p++); /* lfs: we don't use it */ + READ_BUF(4); +- len += 4; + dummy32 = be32_to_cpup(p++); /* pi: we don't use it either */ + READ_BUF(4); +- len += 4; + dummy32 = be32_to_cpup(p++); + READ_BUF(dummy32); + if (dummy32 > NFS4_MAXLABELLEN) + return nfserr_badlabel; +- len += (XDR_QUADLEN(dummy32) << 2); + READMEM(buf, dummy32); + label->len = dummy32; + label->data = svcxdr_dupstr(argp, buf, dummy32); +@@ -414,15 +401,16 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, + if (!umask) + goto xdr_error; + READ_BUF(8); +- len += 8; + dummy32 = be32_to_cpup(p++); + iattr->ia_mode = dummy32 & (S_IFMT | S_IALLUGO); + dummy32 = be32_to_cpup(p++); + *umask = dummy32 & S_IRWXUGO; + iattr->ia_valid |= ATTR_MODE; + } +- if (len != expected_len) +- goto xdr_error; ++ ++ /* request sanity: did attrlist4 contain the expected number of words? */ ++ if (attrlist4_count != xdr_stream_pos(argp->xdr) - starting_pos) ++ return nfserr_bad_xdr; + + DECODE_TAIL; + } +-- +2.43.0 + diff --git a/queue-5.10/nfsd-clean-up-_lm_-operation-names.patch b/queue-5.10/nfsd-clean-up-_lm_-operation-names.patch new file mode 100644 index 00000000000..de22c3fc8d6 --- /dev/null +++ b/queue-5.10/nfsd-clean-up-_lm_-operation-names.patch @@ -0,0 +1,60 @@ +From 71dbeb3e5b82cf44f5cfa04159b04ed0a52909e3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 16 Feb 2022 11:26:06 -0500 +Subject: NFSD: Clean up _lm_ operation names + +From: Chuck Lever + +[ Upstream commit 35aff0678f99b0623bb72d50112de9e163a19559 ] + +The common practice is to name function instances the same as the +method names, but with a uniquifying prefix. Commit aef9583b234a +("NFSD: Get reference of lockowner when coping file_lock") missed +this -- the new function names should both have been of the form +"nfsd4_lm_*". + +Before more lock manager operations are added in NFSD, rename these +two functions for consistency. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 60d5d1cb2cc65..0170aaf318ea2 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -6566,7 +6566,7 @@ nfs4_transform_lock_offset(struct file_lock *lock) + } + + static fl_owner_t +-nfsd4_fl_get_owner(fl_owner_t owner) ++nfsd4_lm_get_owner(fl_owner_t owner) + { + struct nfs4_lockowner *lo = (struct nfs4_lockowner *)owner; + +@@ -6575,7 +6575,7 @@ nfsd4_fl_get_owner(fl_owner_t owner) + } + + static void +-nfsd4_fl_put_owner(fl_owner_t owner) ++nfsd4_lm_put_owner(fl_owner_t owner) + { + struct nfs4_lockowner *lo = (struct nfs4_lockowner *)owner; + +@@ -6610,8 +6610,8 @@ nfsd4_lm_notify(struct file_lock *fl) + + static const struct lock_manager_operations nfsd_posix_mng_ops = { + .lm_notify = nfsd4_lm_notify, +- .lm_get_owner = nfsd4_fl_get_owner, +- .lm_put_owner = nfsd4_fl_put_owner, ++ .lm_get_owner = nfsd4_lm_get_owner, ++ .lm_put_owner = nfsd4_lm_put_owner, + }; + + static inline void +-- +2.43.0 + diff --git a/queue-5.10/nfsd-clean-up-after-updating-nfsv2-acl-decoders.patch b/queue-5.10/nfsd-clean-up-after-updating-nfsv2-acl-decoders.patch new file mode 100644 index 00000000000..dc16e19f852 --- /dev/null +++ b/queue-5.10/nfsd-clean-up-after-updating-nfsv2-acl-decoders.patch @@ -0,0 +1,67 @@ +From d41a3fed9b1b3814da2dda190a7cbc673fd90a28 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Oct 2020 17:49:16 -0400 +Subject: NFSD: Clean up after updating NFSv2 ACL decoders + +From: Chuck Lever + +[ Upstream commit baadce65d6ee3032b921d9c043ba808bc69d6b13 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsxdr.c | 18 ------------------ + fs/nfsd/xdr.h | 1 - + 2 files changed, 19 deletions(-) + +diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c +index 5ab9fc14816c2..5d79ef6a0c7fc 100644 +--- a/fs/nfsd/nfsxdr.c ++++ b/fs/nfsd/nfsxdr.c +@@ -26,18 +26,6 @@ static u32 nfs_ftypes[] = { + * Basic NFSv2 data types (RFC 1094 Section 2.3) + */ + +-static __be32 * +-decode_fh(__be32 *p, struct svc_fh *fhp) +-{ +- fh_init(fhp, NFS_FHSIZE); +- memcpy(&fhp->fh_handle.fh_base, p, NFS_FHSIZE); +- fhp->fh_handle.fh_size = NFS_FHSIZE; +- +- /* FIXME: Look up export pointer here and verify +- * Sun Secure RPC if requested */ +- return p + (NFS_FHSIZE >> 2); +-} +- + /** + * svcxdr_decode_fhandle - Decode an NFSv2 file handle + * @xdr: XDR stream positioned at an encoded NFSv2 FH +@@ -62,12 +50,6 @@ svcxdr_decode_fhandle(struct xdr_stream *xdr, struct svc_fh *fhp) + return true; + } + +-/* Helper function for NFSv2 ACL code */ +-__be32 *nfs2svc_decode_fh(__be32 *p, struct svc_fh *fhp) +-{ +- return decode_fh(p, fhp); +-} +- + static __be32 * + encode_fh(__be32 *p, struct svc_fh *fhp) + { +diff --git a/fs/nfsd/xdr.h b/fs/nfsd/xdr.h +index 77afad72c2aa1..b92f1acec9e77 100644 +--- a/fs/nfsd/xdr.h ++++ b/fs/nfsd/xdr.h +@@ -164,7 +164,6 @@ void nfssvc_release_readres(struct svc_rqst *rqstp); + + /* Helper functions for NFSv2 ACL code */ + __be32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, struct kstat *stat); +-__be32 *nfs2svc_decode_fh(__be32 *p, struct svc_fh *fhp); + bool svcxdr_decode_fhandle(struct xdr_stream *xdr, struct svc_fh *fhp); + + #endif /* LINUX_NFSD_H */ +-- +2.43.0 + diff --git a/queue-5.10/nfsd-clean-up-after-updating-nfsv2-acl-encoders.patch b/queue-5.10/nfsd-clean-up-after-updating-nfsv2-acl-encoders.patch new file mode 100644 index 00000000000..505c34ef0a5 --- /dev/null +++ b/queue-5.10/nfsd-clean-up-after-updating-nfsv2-acl-encoders.patch @@ -0,0 +1,113 @@ +From 4e4d5042dc52e3364a001af97982278da6fbc957 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 15 Nov 2020 14:31:42 -0500 +Subject: NFSD: Clean up after updating NFSv2 ACL encoders + +From: Chuck Lever + +[ Upstream commit 83d0b84572775a29f800de67a1b9b642a5376bc3 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsxdr.c | 64 ------------------------------------------------ + fs/nfsd/xdr.h | 1 - + 2 files changed, 65 deletions(-) + +diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c +index 1fed3a8deb183..b800cfefcab7a 100644 +--- a/fs/nfsd/nfsxdr.c ++++ b/fs/nfsd/nfsxdr.c +@@ -201,64 +201,6 @@ svcxdr_decode_sattr(struct svc_rqst *rqstp, struct xdr_stream *xdr, + return true; + } + +-static __be32 * +-encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, +- struct kstat *stat) +-{ +- struct user_namespace *userns = nfsd_user_namespace(rqstp); +- struct dentry *dentry = fhp->fh_dentry; +- int type; +- struct timespec64 time; +- u32 f; +- +- type = (stat->mode & S_IFMT); +- +- *p++ = htonl(nfs_ftypes[type >> 12]); +- *p++ = htonl((u32) stat->mode); +- *p++ = htonl((u32) stat->nlink); +- *p++ = htonl((u32) from_kuid_munged(userns, stat->uid)); +- *p++ = htonl((u32) from_kgid_munged(userns, stat->gid)); +- +- if (S_ISLNK(type) && stat->size > NFS_MAXPATHLEN) { +- *p++ = htonl(NFS_MAXPATHLEN); +- } else { +- *p++ = htonl((u32) stat->size); +- } +- *p++ = htonl((u32) stat->blksize); +- if (S_ISCHR(type) || S_ISBLK(type)) +- *p++ = htonl(new_encode_dev(stat->rdev)); +- else +- *p++ = htonl(0xffffffff); +- *p++ = htonl((u32) stat->blocks); +- switch (fsid_source(fhp)) { +- default: +- case FSIDSOURCE_DEV: +- *p++ = htonl(new_encode_dev(stat->dev)); +- break; +- case FSIDSOURCE_FSID: +- *p++ = htonl((u32) fhp->fh_export->ex_fsid); +- break; +- case FSIDSOURCE_UUID: +- f = ((u32*)fhp->fh_export->ex_uuid)[0]; +- f ^= ((u32*)fhp->fh_export->ex_uuid)[1]; +- f ^= ((u32*)fhp->fh_export->ex_uuid)[2]; +- f ^= ((u32*)fhp->fh_export->ex_uuid)[3]; +- *p++ = htonl(f); +- break; +- } +- *p++ = htonl((u32) stat->ino); +- *p++ = htonl((u32) stat->atime.tv_sec); +- *p++ = htonl(stat->atime.tv_nsec ? stat->atime.tv_nsec / 1000 : 0); +- time = stat->mtime; +- lease_get_mtime(d_inode(dentry), &time); +- *p++ = htonl((u32) time.tv_sec); +- *p++ = htonl(time.tv_nsec ? time.tv_nsec / 1000 : 0); +- *p++ = htonl((u32) stat->ctime.tv_sec); +- *p++ = htonl(stat->ctime.tv_nsec ? stat->ctime.tv_nsec / 1000 : 0); +- +- return p; +-} +- + /** + * svcxdr_encode_fattr - Encode NFSv2 file attributes + * @rqstp: Context of a completed RPC transaction +@@ -328,12 +270,6 @@ svcxdr_encode_fattr(struct svc_rqst *rqstp, struct xdr_stream *xdr, + return true; + } + +-/* Helper function for NFSv2 ACL code */ +-__be32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, struct kstat *stat) +-{ +- return encode_fattr(rqstp, p, fhp, stat); +-} +- + /* + * XDR decode functions + */ +diff --git a/fs/nfsd/xdr.h b/fs/nfsd/xdr.h +index 8bcdc37398ab5..c67ad02b9a028 100644 +--- a/fs/nfsd/xdr.h ++++ b/fs/nfsd/xdr.h +@@ -168,7 +168,6 @@ void nfssvc_release_diropres(struct svc_rqst *rqstp); + void nfssvc_release_readres(struct svc_rqst *rqstp); + + /* Helper functions for NFSv2 ACL code */ +-__be32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, struct kstat *stat); + bool svcxdr_decode_fhandle(struct xdr_stream *xdr, struct svc_fh *fhp); + bool svcxdr_encode_stat(struct xdr_stream *xdr, __be32 status); + bool svcxdr_encode_fattr(struct svc_rqst *rqstp, struct xdr_stream *xdr, +-- +2.43.0 + diff --git a/queue-5.10/nfsd-clean-up-after-updating-nfsv3-acl-decoders.patch b/queue-5.10/nfsd-clean-up-after-updating-nfsv3-acl-decoders.patch new file mode 100644 index 00000000000..c9d51e77278 --- /dev/null +++ b/queue-5.10/nfsd-clean-up-after-updating-nfsv3-acl-decoders.patch @@ -0,0 +1,63 @@ +From 5f9ee5d8874cd10ca4abae0eeb2ddf23002d17a5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Oct 2020 09:56:52 -0400 +Subject: NFSD: Clean up after updating NFSv3 ACL decoders + +From: Chuck Lever + +[ Upstream commit 9cee763ee654ce8622d673b8e32687d738e24ace ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3xdr.c | 20 -------------------- + fs/nfsd/xdr3.h | 2 -- + 2 files changed, 22 deletions(-) + +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index aa55d0ba2a548..00a96054280a6 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -82,26 +82,6 @@ svcxdr_decode_nfs_fh3(struct xdr_stream *xdr, struct svc_fh *fhp) + return true; + } + +-static __be32 * +-decode_fh(__be32 *p, struct svc_fh *fhp) +-{ +- unsigned int size; +- fh_init(fhp, NFS3_FHSIZE); +- size = ntohl(*p++); +- if (size > NFS3_FHSIZE) +- return NULL; +- +- memcpy(&fhp->fh_handle.fh_base, p, size); +- fhp->fh_handle.fh_size = size; +- return p + XDR_QUADLEN(size); +-} +- +-/* Helper function for NFSv3 ACL code */ +-__be32 *nfs3svc_decode_fh(__be32 *p, struct svc_fh *fhp) +-{ +- return decode_fh(p, fhp); +-} +- + static __be32 * + encode_fh(__be32 *p, struct svc_fh *fhp) + { +diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h +index 7456aee74f3df..3e1578953f544 100644 +--- a/fs/nfsd/xdr3.h ++++ b/fs/nfsd/xdr3.h +@@ -307,8 +307,6 @@ int nfs3svc_encode_entry_plus(void *, const char *name, + /* Helper functions for NFSv3 ACL code */ + __be32 *nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, + struct svc_fh *fhp); +-__be32 *nfs3svc_decode_fh(__be32 *p, struct svc_fh *fhp); + bool svcxdr_decode_nfs_fh3(struct xdr_stream *xdr, struct svc_fh *fhp); + +- + #endif /* _LINUX_NFSD_XDR3_H */ +-- +2.43.0 + diff --git a/queue-5.10/nfsd-clean-up-after-updating-nfsv3-acl-encoders.patch b/queue-5.10/nfsd-clean-up-after-updating-nfsv3-acl-encoders.patch new file mode 100644 index 00000000000..ff2f13ebff9 --- /dev/null +++ b/queue-5.10/nfsd-clean-up-after-updating-nfsv3-acl-encoders.patch @@ -0,0 +1,143 @@ +From eeb2414a5de09c9083ab876e753af42aa286ff30 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 15 Nov 2020 15:09:16 -0500 +Subject: NFSD: Clean up after updating NFSv3 ACL encoders + +From: Chuck Lever + +[ Upstream commit 1416f435303d81070c6bcf5a4a9b4ed0f7a9f013 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3xdr.c | 86 ----------------------------------------------- + fs/nfsd/xdr3.h | 2 -- + 2 files changed, 88 deletions(-) + +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index 941740a97f8f5..fcfa0d611b931 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -48,13 +48,6 @@ static const u32 nfs3_ftypes[] = { + * Basic NFSv3 data types (RFC 1813 Sections 2.5 and 2.6) + */ + +-static __be32 * +-encode_time3(__be32 *p, struct timespec64 *time) +-{ +- *p++ = htonl((u32) time->tv_sec); *p++ = htonl(time->tv_nsec); +- return p; +-} +- + static __be32 * + encode_nfstime3(__be32 *p, const struct timespec64 *time) + { +@@ -396,54 +389,6 @@ svcxdr_encode_fattr3(struct svc_rqst *rqstp, struct xdr_stream *xdr, + return true; + } + +-static __be32 *encode_fsid(__be32 *p, struct svc_fh *fhp) +-{ +- u64 f; +- switch(fsid_source(fhp)) { +- default: +- case FSIDSOURCE_DEV: +- p = xdr_encode_hyper(p, (u64)huge_encode_dev +- (fhp->fh_dentry->d_sb->s_dev)); +- break; +- case FSIDSOURCE_FSID: +- p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid); +- break; +- case FSIDSOURCE_UUID: +- f = ((u64*)fhp->fh_export->ex_uuid)[0]; +- f ^= ((u64*)fhp->fh_export->ex_uuid)[1]; +- p = xdr_encode_hyper(p, f); +- break; +- } +- return p; +-} +- +-static __be32 * +-encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, +- struct kstat *stat) +-{ +- struct user_namespace *userns = nfsd_user_namespace(rqstp); +- *p++ = htonl(nfs3_ftypes[(stat->mode & S_IFMT) >> 12]); +- *p++ = htonl((u32) (stat->mode & S_IALLUGO)); +- *p++ = htonl((u32) stat->nlink); +- *p++ = htonl((u32) from_kuid_munged(userns, stat->uid)); +- *p++ = htonl((u32) from_kgid_munged(userns, stat->gid)); +- if (S_ISLNK(stat->mode) && stat->size > NFS3_MAXPATHLEN) { +- p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN); +- } else { +- p = xdr_encode_hyper(p, (u64) stat->size); +- } +- p = xdr_encode_hyper(p, ((u64)stat->blocks) << 9); +- *p++ = htonl((u32) MAJOR(stat->rdev)); +- *p++ = htonl((u32) MINOR(stat->rdev)); +- p = encode_fsid(p, fhp); +- p = xdr_encode_hyper(p, stat->ino); +- p = encode_time3(p, &stat->atime); +- p = encode_time3(p, &stat->mtime); +- p = encode_time3(p, &stat->ctime); +- +- return p; +-} +- + static bool + svcxdr_encode_wcc_attr(struct xdr_stream *xdr, const struct svc_fh *fhp) + { +@@ -512,37 +457,6 @@ svcxdr_encode_post_op_attr(struct svc_rqst *rqstp, struct xdr_stream *xdr, + return xdr_stream_encode_item_absent(xdr) > 0; + } + +-/* +- * Encode post-operation attributes. +- * The inode may be NULL if the call failed because of a stale file +- * handle. In this case, no attributes are returned. +- */ +-static __be32 * +-encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp) +-{ +- struct dentry *dentry = fhp->fh_dentry; +- if (!fhp->fh_no_wcc && dentry && d_really_is_positive(dentry)) { +- __be32 err; +- struct kstat stat; +- +- err = fh_getattr(fhp, &stat); +- if (!err) { +- *p++ = xdr_one; /* attributes follow */ +- lease_get_mtime(d_inode(dentry), &stat.mtime); +- return encode_fattr3(rqstp, p, fhp, &stat); +- } +- } +- *p++ = xdr_zero; +- return p; +-} +- +-/* Helper for NFSv3 ACLs */ +-__be32 * +-nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp) +-{ +- return encode_post_op_attr(rqstp, p, fhp); +-} +- + /* + * Encode weak cache consistency data + */ +diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h +index 746c5f79964f1..933008382bbeb 100644 +--- a/fs/nfsd/xdr3.h ++++ b/fs/nfsd/xdr3.h +@@ -305,8 +305,6 @@ int nfs3svc_encode_entry3(void *data, const char *name, int namlen, + int nfs3svc_encode_entryplus3(void *data, const char *name, int namlen, + loff_t offset, u64 ino, unsigned int d_type); + /* Helper functions for NFSv3 ACL code */ +-__be32 *nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, +- struct svc_fh *fhp); + bool svcxdr_decode_nfs_fh3(struct xdr_stream *xdr, struct svc_fh *fhp); + bool svcxdr_encode_nfsstat3(struct xdr_stream *xdr, __be32 status); + bool svcxdr_encode_post_op_attr(struct svc_rqst *rqstp, struct xdr_stream *xdr, +-- +2.43.0 + diff --git a/queue-5.10/nfsd-clean-up-find_or_add_file.patch b/queue-5.10/nfsd-clean-up-find_or_add_file.patch new file mode 100644 index 00000000000..8c051d761a6 --- /dev/null +++ b/queue-5.10/nfsd-clean-up-find_or_add_file.patch @@ -0,0 +1,128 @@ +From b3a3d8e55bdc863e1866965135f44a847244660e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Oct 2022 10:47:41 -0400 +Subject: NFSD: Clean up find_or_add_file() + +From: Chuck Lever + +[ Upstream commit 9270fc514ba7d415636b23bcb937573a1ce54f6a ] + +Remove the call to find_file_locked() in insert_nfs4_file(). Tracing +shows that over 99% of these calls return NULL. Thus it is not worth +the expense of the extra bucket list traversal. insert_file() already +deals correctly with the case where the item is already in the hash +bucket. + +Since nfsd4_file_hash_insert() is now just a wrapper around +insert_file(), move the meat of insert_file() into +nfsd4_file_hash_insert() and get rid of it. + +Signed-off-by: Chuck Lever +Reviewed-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 64 ++++++++++++++++++++------------------------- + 1 file changed, 28 insertions(+), 36 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index c464403c23a25..d2664aa4bde0d 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -4698,24 +4698,42 @@ find_file_locked(const struct svc_fh *fh, unsigned int hashval) + return NULL; + } + +-static struct nfs4_file *insert_file(struct nfs4_file *new, struct svc_fh *fh, +- unsigned int hashval) ++static struct nfs4_file * find_file(struct svc_fh *fh) + { + struct nfs4_file *fp; ++ unsigned int hashval = file_hashval(fh); ++ ++ rcu_read_lock(); ++ fp = find_file_locked(fh, hashval); ++ rcu_read_unlock(); ++ return fp; ++} ++ ++/* ++ * On hash insertion, identify entries with the same inode but ++ * distinct filehandles. They will all be in the same hash bucket ++ * because nfs4_file's are hashed by the address in the fi_inode ++ * field. ++ */ ++static noinline_for_stack struct nfs4_file * ++nfsd4_file_hash_insert(struct nfs4_file *new, const struct svc_fh *fhp) ++{ ++ unsigned int hashval = file_hashval(fhp); + struct nfs4_file *ret = NULL; + bool alias_found = false; ++ struct nfs4_file *fi; + + spin_lock(&state_lock); +- hlist_for_each_entry_rcu(fp, &file_hashtbl[hashval], fi_hash, ++ hlist_for_each_entry_rcu(fi, &file_hashtbl[hashval], fi_hash, + lockdep_is_held(&state_lock)) { +- if (fh_match(&fp->fi_fhandle, &fh->fh_handle)) { +- if (refcount_inc_not_zero(&fp->fi_ref)) +- ret = fp; +- } else if (d_inode(fh->fh_dentry) == fp->fi_inode) +- fp->fi_aliased = alias_found = true; ++ if (fh_match(&fi->fi_fhandle, &fhp->fh_handle)) { ++ if (refcount_inc_not_zero(&fi->fi_ref)) ++ ret = fi; ++ } else if (d_inode(fhp->fh_dentry) == fi->fi_inode) ++ fi->fi_aliased = alias_found = true; + } + if (likely(ret == NULL)) { +- nfsd4_file_init(fh, new); ++ nfsd4_file_init(fhp, new); + hlist_add_head_rcu(&new->fi_hash, &file_hashtbl[hashval]); + new->fi_aliased = alias_found; + ret = new; +@@ -4724,32 +4742,6 @@ static struct nfs4_file *insert_file(struct nfs4_file *new, struct svc_fh *fh, + return ret; + } + +-static struct nfs4_file * find_file(struct svc_fh *fh) +-{ +- struct nfs4_file *fp; +- unsigned int hashval = file_hashval(fh); +- +- rcu_read_lock(); +- fp = find_file_locked(fh, hashval); +- rcu_read_unlock(); +- return fp; +-} +- +-static struct nfs4_file * +-find_or_add_file(struct nfs4_file *new, struct svc_fh *fh) +-{ +- struct nfs4_file *fp; +- unsigned int hashval = file_hashval(fh); +- +- rcu_read_lock(); +- fp = find_file_locked(fh, hashval); +- rcu_read_unlock(); +- if (fp) +- return fp; +- +- return insert_file(new, fh, hashval); +-} +- + static noinline_for_stack void nfsd4_file_hash_remove(struct nfs4_file *fi) + { + hlist_del_rcu(&fi->fi_hash); +@@ -5641,7 +5633,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf + * and check for delegations in the process of being recalled. + * If not found, create the nfs4_file struct + */ +- fp = find_or_add_file(open->op_file, current_fh); ++ fp = nfsd4_file_hash_insert(open->op_file, current_fh); + if (fp != open->op_file) { + status = nfs4_check_deleg(cl, open, &dp); + if (status) +-- +2.43.0 + diff --git a/queue-5.10/nfsd-clean-up-mounted_on_fileid-handling.patch b/queue-5.10/nfsd-clean-up-mounted_on_fileid-handling.patch new file mode 100644 index 00000000000..b6dab9df62f --- /dev/null +++ b/queue-5.10/nfsd-clean-up-mounted_on_fileid-handling.patch @@ -0,0 +1,79 @@ +From df4ece7941ae278d00ce40566be9cc1b3db12a32 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Sep 2022 12:31:07 -0400 +Subject: nfsd: clean up mounted_on_fileid handling + +From: Jeff Layton + +[ Upstream commit 6106d9119b6599fa23dc556b429d887b4c2d9f62 ] + +We only need the inode number for this, not a full rack of attributes. +Rename this function make it take a pointer to a u64 instead of +struct kstat, and change it to just request STATX_INO. + +Signed-off-by: Jeff Layton +[ cel: renamed get_mounted_on_ino() ] +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 16 +++++++++------- + 1 file changed, 9 insertions(+), 7 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index b9398b7b3539a..b5ca83045d6e9 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -2769,9 +2769,10 @@ static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *bmval2, u32 + } + + +-static int get_parent_attributes(struct svc_export *exp, struct kstat *stat) ++static int nfsd4_get_mounted_on_ino(struct svc_export *exp, u64 *pino) + { + struct path path = exp->ex_path; ++ struct kstat stat; + int err; + + path_get(&path); +@@ -2779,8 +2780,10 @@ static int get_parent_attributes(struct svc_export *exp, struct kstat *stat) + if (path.dentry != path.mnt->mnt_root) + break; + } +- err = vfs_getattr(&path, stat, STATX_BASIC_STATS, AT_STATX_SYNC_AS_STAT); ++ err = vfs_getattr(&path, &stat, STATX_INO, AT_STATX_SYNC_AS_STAT); + path_put(&path); ++ if (!err) ++ *pino = stat.ino; + return err; + } + +@@ -3277,22 +3280,21 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, + *p++ = cpu_to_be32(stat.btime.tv_nsec); + } + if (bmval1 & FATTR4_WORD1_MOUNTED_ON_FILEID) { +- struct kstat parent_stat; + u64 ino = stat.ino; + + p = xdr_reserve_space(xdr, 8); + if (!p) + goto out_resource; + /* +- * Get parent's attributes if not ignoring crossmount +- * and this is the root of a cross-mounted filesystem. ++ * Get ino of mountpoint in parent filesystem, if not ignoring ++ * crossmount and this is the root of a cross-mounted ++ * filesystem. + */ + if (ignore_crossmnt == 0 && + dentry == exp->ex_path.mnt->mnt_root) { +- err = get_parent_attributes(exp, &parent_stat); ++ err = nfsd4_get_mounted_on_ino(exp, &ino); + if (err) + goto out_nfserr; +- ino = parent_stat.ino; + } + p = xdr_encode_hyper(p, ino); + } +-- +2.43.0 + diff --git a/queue-5.10/nfsd-clean-up-nfs4_preprocess_stateid_op-call-sites.patch b/queue-5.10/nfsd-clean-up-nfs4_preprocess_stateid_op-call-sites.patch new file mode 100644 index 00000000000..c44a0b80f00 --- /dev/null +++ b/queue-5.10/nfsd-clean-up-nfs4_preprocess_stateid_op-call-sites.patch @@ -0,0 +1,111 @@ +From 0283976b9ef0e2815b3d035c25a53ffc61104026 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Oct 2022 10:46:57 -0400 +Subject: NFSD: Clean up nfs4_preprocess_stateid_op() call sites + +From: Chuck Lever + +[ Upstream commit eeff73f7c1c583f79a401284f46c619294859310 ] + +Remove the lame-duck dprintk()s around nfs4_preprocess_stateid_op() +call sites. + +Signed-off-by: Chuck Lever +Tested-by: Jeff Layton +Reviewed-by: Jeff Layton +Reviewed-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 31 +++++++------------------------ + 1 file changed, 7 insertions(+), 24 deletions(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 3fe1966ed7358..32fccca7de185 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -943,12 +943,7 @@ nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh, + &read->rd_stateid, RD_STATE, + &read->rd_nf, NULL); +- if (status) { +- dprintk("NFSD: nfsd4_read: couldn't process stateid!\n"); +- goto out; +- } +- status = nfs_ok; +-out: ++ + read->rd_rqstp = rqstp; + read->rd_fhp = &cstate->current_fh; + return status; +@@ -1117,10 +1112,8 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + status = nfs4_preprocess_stateid_op(rqstp, cstate, + &cstate->current_fh, &setattr->sa_stateid, + WR_STATE, NULL, NULL); +- if (status) { +- dprintk("NFSD: nfsd4_setattr: couldn't process stateid!\n"); ++ if (status) + return status; +- } + } + err = fh_want_write(&cstate->current_fh); + if (err) +@@ -1168,10 +1161,8 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + write->wr_offset, cnt); + status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh, + stateid, WR_STATE, &nf, NULL); +- if (status) { +- dprintk("NFSD: nfsd4_write: couldn't process stateid!\n"); ++ if (status) + return status; +- } + + write->wr_how_written = write->wr_stable_how; + +@@ -1202,17 +1193,13 @@ nfsd4_verify_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + + status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->save_fh, + src_stateid, RD_STATE, src, NULL); +- if (status) { +- dprintk("NFSD: %s: couldn't process src stateid!\n", __func__); ++ if (status) + goto out; +- } + + status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh, + dst_stateid, WR_STATE, dst, NULL); +- if (status) { +- dprintk("NFSD: %s: couldn't process dst stateid!\n", __func__); ++ if (status) + goto out_put_src; +- } + + /* fix up for NFS-specific error code */ + if (!S_ISREG(file_inode((*src)->nf_file)->i_mode) || +@@ -1949,10 +1936,8 @@ nfsd4_fallocate(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh, + &fallocate->falloc_stateid, + WR_STATE, &nf, NULL); +- if (status != nfs_ok) { +- dprintk("NFSD: nfsd4_fallocate: couldn't process stateid!\n"); ++ if (status != nfs_ok) + return status; +- } + + status = nfsd4_vfs_fallocate(rqstp, &cstate->current_fh, nf->nf_file, + fallocate->falloc_offset, +@@ -2008,10 +1993,8 @@ nfsd4_seek(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh, + &seek->seek_stateid, + RD_STATE, &nf, NULL); +- if (status) { +- dprintk("NFSD: nfsd4_seek: couldn't process stateid!\n"); ++ if (status) + return status; +- } + + switch (seek->seek_whence) { + case NFS4_CONTENT_DATA: +-- +2.43.0 + diff --git a/queue-5.10/nfsd-clean-up-nfs4svc_encode_compoundres.patch b/queue-5.10/nfsd-clean-up-nfs4svc_encode_compoundres.patch new file mode 100644 index 00000000000..64271a208e5 --- /dev/null +++ b/queue-5.10/nfsd-clean-up-nfs4svc_encode_compoundres.patch @@ -0,0 +1,42 @@ +From 90110d3d90f7d959d33c7ddc340ce940d86bc263 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Sep 2022 17:23:19 -0400 +Subject: NFSD: Clean up nfs4svc_encode_compoundres() + +From: Chuck Lever + +[ Upstream commit 9993a66317fc9951322483a9edbfae95a640b210 ] + +In today's Linux NFS server implementation, the NFS dispatcher +initializes each XDR result stream, and the NFSv4 .pc_func and +.pc_encode methods all use xdr_stream-based encoding. This keeps +rq_res.len automatically updated. There is no longer a need for +the WARN_ON_ONCE() check in nfs4svc_encode_compoundres(). + +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 04699198eace7..fc587381cd087 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -5467,12 +5467,8 @@ bool + nfs4svc_encode_compoundres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd4_compoundres *resp = rqstp->rq_resp; +- struct xdr_buf *buf = xdr->buf; + __be32 *p; + +- WARN_ON_ONCE(buf->len != buf->head[0].iov_len + buf->page_len + +- buf->tail[0].iov_len); +- + /* + * Send buffer space for the following items is reserved + * at the top of nfsd4_proc_compound(). +-- +2.43.0 + diff --git a/queue-5.10/nfsd-clean-up-nfsd3_proc_create.patch b/queue-5.10/nfsd-clean-up-nfsd3_proc_create.patch new file mode 100644 index 00000000000..f26e74cc9c6 --- /dev/null +++ b/queue-5.10/nfsd-clean-up-nfsd3_proc_create.patch @@ -0,0 +1,59 @@ +From 00110fedbab7424cc8f296fb4c0004c06522a3c1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 25 Mar 2022 14:47:54 -0400 +Subject: NFSD: Clean up nfsd3_proc_create() + +From: Chuck Lever + +[ Upstream commit e61568599c9ad638fdaba150fee07d7065e31851 ] + +As near as I can tell, mode bit masking and setting S_IFREG is +already done by do_nfsd_create() and vfs_create(). The NFSv4 path +(do_open_lookup), for example, does not bother with this special +processing. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3proc.c | 16 ++-------------- + 1 file changed, 2 insertions(+), 14 deletions(-) + +diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c +index 936eebd4c56dc..981a2a71c5af7 100644 +--- a/fs/nfsd/nfs3proc.c ++++ b/fs/nfsd/nfs3proc.c +@@ -229,8 +229,7 @@ nfsd3_proc_create(struct svc_rqst *rqstp) + { + struct nfsd3_createargs *argp = rqstp->rq_argp; + struct nfsd3_diropres *resp = rqstp->rq_resp; +- svc_fh *dirfhp, *newfhp = NULL; +- struct iattr *attr; ++ svc_fh *dirfhp, *newfhp; + + dprintk("nfsd: CREATE(3) %s %.*s\n", + SVCFH_fmt(&argp->fh), +@@ -239,20 +238,9 @@ nfsd3_proc_create(struct svc_rqst *rqstp) + + dirfhp = fh_copy(&resp->dirfh, &argp->fh); + newfhp = fh_init(&resp->fh, NFS3_FHSIZE); +- attr = &argp->attrs; +- +- /* Unfudge the mode bits */ +- attr->ia_mode &= ~S_IFMT; +- if (!(attr->ia_valid & ATTR_MODE)) { +- attr->ia_valid |= ATTR_MODE; +- attr->ia_mode = S_IFREG; +- } else { +- attr->ia_mode = (attr->ia_mode & ~S_IFMT) | S_IFREG; +- } + +- /* Now create the file and set attributes */ + resp->status = do_nfsd_create(rqstp, dirfhp, argp->name, argp->len, +- attr, newfhp, argp->createmode, ++ &argp->attrs, newfhp, argp->createmode, + (u32 *)argp->verf, NULL, NULL); + return rpc_success; + } +-- +2.43.0 + diff --git a/queue-5.10/nfsd-clean-up-nfsd4_encode_readlink.patch b/queue-5.10/nfsd-clean-up-nfsd4_encode_readlink.patch new file mode 100644 index 00000000000..eca2edf4851 --- /dev/null +++ b/queue-5.10/nfsd-clean-up-nfsd4_encode_readlink.patch @@ -0,0 +1,67 @@ +From 7c7676be41ea6140042a97c20be181058933edf5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 Jul 2022 16:09:23 -0400 +Subject: NFSD: Clean up nfsd4_encode_readlink() + +From: Chuck Lever + +[ Upstream commit 99b002a1fa00d90e66357315757e7277447ce973 ] + +Similar changes to nfsd4_encode_readv(), all bundled into a single +patch. + +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 24 +++++++++--------------- + 1 file changed, 9 insertions(+), 15 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 4d74eb1fee8f1..a98513cb35b10 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -4019,16 +4019,13 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr, + static __be32 + nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_readlink *readlink) + { +- int maxcount; +- __be32 wire_count; +- int zero = 0; ++ __be32 *p, *maxcount_p, zero = xdr_zero; + struct xdr_stream *xdr = resp->xdr; + int length_offset = xdr->buf->len; +- int status; +- __be32 *p; ++ int maxcount, status; + +- p = xdr_reserve_space(xdr, 4); +- if (!p) ++ maxcount_p = xdr_reserve_space(xdr, XDR_UNIT); ++ if (!maxcount_p) + return nfserr_resource; + maxcount = PAGE_SIZE; + +@@ -4053,14 +4050,11 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd + nfserr = nfserrno(status); + goto out_err; + } +- +- wire_count = htonl(maxcount); +- write_bytes_to_xdr_buf(xdr->buf, length_offset, &wire_count, 4); +- xdr_truncate_encode(xdr, length_offset + 4 + ALIGN(maxcount, 4)); +- if (maxcount & 3) +- write_bytes_to_xdr_buf(xdr->buf, length_offset + 4 + maxcount, +- &zero, 4 - (maxcount&3)); +- return 0; ++ *maxcount_p = cpu_to_be32(maxcount); ++ xdr_truncate_encode(xdr, length_offset + 4 + xdr_align_size(maxcount)); ++ write_bytes_to_xdr_buf(xdr->buf, length_offset + 4 + maxcount, &zero, ++ xdr_pad_size(maxcount)); ++ return nfs_ok; + + out_err: + xdr_truncate_encode(xdr, length_offset); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-clean-up-nfsd4_init_file.patch b/queue-5.10/nfsd-clean-up-nfsd4_init_file.patch new file mode 100644 index 00000000000..ee3f7b1e701 --- /dev/null +++ b/queue-5.10/nfsd-clean-up-nfsd4_init_file.patch @@ -0,0 +1,66 @@ +From 8e19c40dc48dc5e98708b3c2bc2ae6b24d7d0d62 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Oct 2022 10:47:28 -0400 +Subject: NFSD: Clean up nfsd4_init_file() + +From: Chuck Lever + +[ Upstream commit 81a21fa3e7fdecb3c5b97014f0fc5a17d5806cae ] + +Name this function more consistently. I'm going to use nfsd4_file_ +and nfsd4_file_hash_ for these helpers. + +Change the @fh parameter to be const pointer for better type safety. + +Finally, move the hash insertion operation to the caller. This is +typical for most other "init_object" type helpers, and it is where +most of the other nfs4_file hash table operations are located. + +Signed-off-by: Chuck Lever +Reviewed-by: NeilBrown +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 90505095d7e0c..d6e0052b3f682 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -4277,11 +4277,9 @@ static struct nfs4_file *nfsd4_alloc_file(void) + } + + /* OPEN Share state helper functions */ +-static void nfsd4_init_file(struct svc_fh *fh, unsigned int hashval, +- struct nfs4_file *fp) +-{ +- lockdep_assert_held(&state_lock); + ++static void nfsd4_file_init(const struct svc_fh *fh, struct nfs4_file *fp) ++{ + refcount_set(&fp->fi_ref, 1); + spin_lock_init(&fp->fi_lock); + INIT_LIST_HEAD(&fp->fi_stateids); +@@ -4299,7 +4297,6 @@ static void nfsd4_init_file(struct svc_fh *fh, unsigned int hashval, + INIT_LIST_HEAD(&fp->fi_lo_states); + atomic_set(&fp->fi_lo_recalls, 0); + #endif +- hlist_add_head_rcu(&fp->fi_hash, &file_hashtbl[hashval]); + } + + void +@@ -4717,7 +4714,8 @@ static struct nfs4_file *insert_file(struct nfs4_file *new, struct svc_fh *fh, + fp->fi_aliased = alias_found = true; + } + if (likely(ret == NULL)) { +- nfsd4_init_file(fh, hashval, new); ++ nfsd4_file_init(fh, new); ++ hlist_add_head_rcu(&new->fi_hash, &file_hashtbl[hashval]); + new->fi_aliased = alias_found; + ret = new; + } +-- +2.43.0 + diff --git a/queue-5.10/nfsd-clean-up-nfsd_file_put.patch b/queue-5.10/nfsd-clean-up-nfsd_file_put.patch new file mode 100644 index 00000000000..bac95a51c95 --- /dev/null +++ b/queue-5.10/nfsd-clean-up-nfsd_file_put.patch @@ -0,0 +1,51 @@ +From a41fb75770584c4619d7d6687d50f8ac4b51452f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 31 Mar 2022 09:54:02 -0400 +Subject: nfsd: Clean up nfsd_file_put() + +From: Trond Myklebust + +[ Upstream commit 999397926ab3f78c7d1235cc4ca6e3c89d2769bf ] + +Make it a little less racy, by removing the refcount_read() test. Then +remove the redundant 'is_hashed' variable. + +Signed-off-by: Trond Myklebust +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 13 +++---------- + 1 file changed, 3 insertions(+), 10 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index 496f7b3f75237..8f7ed5dbb0031 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -301,21 +301,14 @@ nfsd_file_put_noref(struct nfsd_file *nf) + void + nfsd_file_put(struct nfsd_file *nf) + { +- bool is_hashed; +- + set_bit(NFSD_FILE_REFERENCED, &nf->nf_flags); +- if (refcount_read(&nf->nf_ref) > 2 || !nf->nf_file) { +- nfsd_file_put_noref(nf); +- return; +- } +- +- is_hashed = test_bit(NFSD_FILE_HASHED, &nf->nf_flags) != 0; +- if (!is_hashed) { ++ if (test_bit(NFSD_FILE_HASHED, &nf->nf_flags) == 0) { + nfsd_file_flush(nf); + nfsd_file_put_noref(nf); + } else { + nfsd_file_put_noref(nf); +- nfsd_file_schedule_laundrette(); ++ if (nf->nf_file) ++ nfsd_file_schedule_laundrette(); + } + if (atomic_long_read(&nfsd_filecache_count) >= NFSD_FILE_LRU_LIMIT) + nfsd_file_gc(); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-clean-up-nfsd_open_verified.patch b/queue-5.10/nfsd-clean-up-nfsd_open_verified.patch new file mode 100644 index 00000000000..fcedd8c9f86 --- /dev/null +++ b/queue-5.10/nfsd-clean-up-nfsd_open_verified.patch @@ -0,0 +1,82 @@ +From 93230b5b5a5de954b2bfe56ffc2174e095af9a59 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 27 Mar 2022 16:46:47 -0400 +Subject: NFSD: Clean up nfsd_open_verified() + +From: Chuck Lever + +[ Upstream commit f4d84c52643ae1d63a8e73e2585464470e7944d1 ] + +Its only caller always passes S_IFREG as the @type parameter. As an +additional clean-up, add a kerneldoc comment. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 4 ++-- + fs/nfsd/vfs.c | 15 ++++++++++++--- + fs/nfsd/vfs.h | 2 +- + 3 files changed, 15 insertions(+), 6 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index 7e99e75b75d73..3c297ccfcc59d 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -996,8 +996,8 @@ nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + + nf->nf_mark = nfsd_file_mark_find_or_create(nf); + if (nf->nf_mark) +- status = nfsd_open_verified(rqstp, fhp, S_IFREG, +- may_flags, &nf->nf_file); ++ status = nfsd_open_verified(rqstp, fhp, may_flags, ++ &nf->nf_file); + else + status = nfserr_jukebox; + /* +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index 26ae28b6f9b02..5c8dc1a05e57e 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -852,14 +852,23 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, + return err; + } + ++/** ++ * nfsd_open_verified - Open a regular file for the filecache ++ * @rqstp: RPC request ++ * @fhp: NFS filehandle of the file to open ++ * @may_flags: internal permission flags ++ * @filp: OUT: open "struct file *" ++ * ++ * Returns an nfsstat value in network byte order. ++ */ + __be32 +-nfsd_open_verified(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, +- int may_flags, struct file **filp) ++nfsd_open_verified(struct svc_rqst *rqstp, struct svc_fh *fhp, int may_flags, ++ struct file **filp) + { + __be32 err; + + validate_process_creds(); +- err = __nfsd_open(rqstp, fhp, type, may_flags, filp); ++ err = __nfsd_open(rqstp, fhp, S_IFREG, may_flags, filp); + validate_process_creds(); + return err; + } +diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h +index f99794b033a55..26347d76f44a0 100644 +--- a/fs/nfsd/vfs.h ++++ b/fs/nfsd/vfs.h +@@ -86,7 +86,7 @@ __be32 nfsd_setxattr(struct svc_rqst *rqstp, struct svc_fh *fhp, + int nfsd_open_break_lease(struct inode *, int); + __be32 nfsd_open(struct svc_rqst *, struct svc_fh *, umode_t, + int, struct file **); +-__be32 nfsd_open_verified(struct svc_rqst *, struct svc_fh *, umode_t, ++__be32 nfsd_open_verified(struct svc_rqst *, struct svc_fh *, + int, struct file **); + __be32 nfsd_splice_read(struct svc_rqst *rqstp, struct svc_fh *fhp, + struct file *file, loff_t offset, +-- +2.43.0 + diff --git a/queue-5.10/nfsd-clean-up-nfsd_splice_actor.patch b/queue-5.10/nfsd-clean-up-nfsd_splice_actor.patch new file mode 100644 index 00000000000..4d61864d6d5 --- /dev/null +++ b/queue-5.10/nfsd-clean-up-nfsd_splice_actor.patch @@ -0,0 +1,52 @@ +From e8e145ed61b952fddf366c019b4153e08a247da5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 7 Apr 2022 16:48:24 -0400 +Subject: NFSD: Clean up nfsd_splice_actor() + +From: Chuck Lever + +[ Upstream commit 91e23b1c39820bfed642119ff6b6ef9f43cf09ce ] + +nfsd_splice_actor() checks that the page being spliced does not +match the previous element in the svc_rqst::rq_pages array. We +believe this is to prevent a double put_page() in cases where the +READ payload is partially contained in the xdr_buf's head buffer. + +However, the NFSD READ proc functions no longer place any part of +the READ payload in the head buffer, in order to properly support +NFS/RDMA READ with Write chunks. Therefore, simplify the logic in +nfsd_splice_actor() to remove this unnecessary check. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/vfs.c | 10 ++-------- + 1 file changed, 2 insertions(+), 8 deletions(-) + +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index 86584e727ce09..0968eaf735c85 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -874,17 +874,11 @@ nfsd_splice_actor(struct pipe_inode_info *pipe, struct pipe_buffer *buf, + struct splice_desc *sd) + { + struct svc_rqst *rqstp = sd->u.data; +- struct page **pp = rqstp->rq_next_page; +- struct page *page = buf->page; + +- if (rqstp->rq_res.page_len == 0) { +- svc_rqst_replace_page(rqstp, page); ++ svc_rqst_replace_page(rqstp, buf->page); ++ if (rqstp->rq_res.page_len == 0) + rqstp->rq_res.page_base = buf->offset; +- } else if (page != pp[-1]) { +- svc_rqst_replace_page(rqstp, page); +- } + rqstp->rq_res.page_len += sd->len; +- + return sd->len; + } + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-clean-up-nfsd_vfs_write.patch b/queue-5.10/nfsd-clean-up-nfsd_vfs_write.patch new file mode 100644 index 00000000000..c54d3ee0e3b --- /dev/null +++ b/queue-5.10/nfsd-clean-up-nfsd_vfs_write.patch @@ -0,0 +1,54 @@ +From 466bfba6e83a13238d8389e31fc5c58df2d3ee7e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Dec 2021 14:19:41 -0500 +Subject: NFSD: Clean up nfsd_vfs_write() + +From: Chuck Lever + +[ Upstream commit 33388b3aefefd4d83764dab8038cb54068161a44 ] + +The RWF_SYNC and !RWF_SYNC arms are now exactly alike except that +the RWF_SYNC arm resets the boot verifier twice in a row. Fix that +redundancy and de-duplicate the code. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/vfs.c | 21 +++++---------------- + 1 file changed, 5 insertions(+), 16 deletions(-) + +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index b343677b01efa..cef8435d76a69 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -1023,22 +1023,11 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf, + + iov_iter_kvec(&iter, WRITE, vec, vlen, *cnt); + since = READ_ONCE(file->f_wb_err); +- if (flags & RWF_SYNC) { +- if (verf) +- nfsd_copy_boot_verifier(verf, +- net_generic(SVC_NET(rqstp), +- nfsd_net_id)); +- host_err = vfs_iter_write(file, &iter, &pos, flags); +- if (host_err < 0) +- nfsd_reset_boot_verifier(net_generic(SVC_NET(rqstp), +- nfsd_net_id)); +- } else { +- if (verf) +- nfsd_copy_boot_verifier(verf, +- net_generic(SVC_NET(rqstp), +- nfsd_net_id)); +- host_err = vfs_iter_write(file, &iter, &pos, flags); +- } ++ if (verf) ++ nfsd_copy_boot_verifier(verf, ++ net_generic(SVC_NET(rqstp), ++ nfsd_net_id)); ++ host_err = vfs_iter_write(file, &iter, &pos, flags); + if (host_err < 0) { + nfsd_reset_boot_verifier(net_generic(SVC_NET(rqstp), + nfsd_net_id)); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-clean-up-nfsddbg_facility-macro.patch b/queue-5.10/nfsd-clean-up-nfsddbg_facility-macro.patch new file mode 100644 index 00000000000..74c07574e7a --- /dev/null +++ b/queue-5.10/nfsd-clean-up-nfsddbg_facility-macro.patch @@ -0,0 +1,49 @@ +From 59fea1f7db24ddb35bef715887ace259b72e6136 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 5 Mar 2021 14:22:32 -0500 +Subject: NFSD: Clean up NFSDDBG_FACILITY macro + +From: Chuck Lever + +[ Upstream commit 219a170502b3d597c52eeec088aee8fbf7b90da5 ] + +These are no longer needed because there are no dprintk() call sites +in these files. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3xdr.c | 3 --- + fs/nfsd/nfsxdr.c | 2 -- + 2 files changed, 5 deletions(-) + +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index fcfa0d611b931..0a5ebc52e6a9c 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -14,9 +14,6 @@ + #include "netns.h" + #include "vfs.h" + +-#define NFSDDBG_FACILITY NFSDDBG_XDR +- +- + /* + * Force construction of an empty post-op attr + */ +diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c +index b800cfefcab7a..a06c05fe3b421 100644 +--- a/fs/nfsd/nfsxdr.c ++++ b/fs/nfsd/nfsxdr.c +@@ -9,8 +9,6 @@ + #include "xdr.h" + #include "auth.h" + +-#define NFSDDBG_FACILITY NFSDDBG_XDR +- + /* + * Mapping of S_IF* types to NFS file types + */ +-- +2.43.0 + diff --git a/queue-5.10/nfsd-clean-up-potential-nfsd_file-refcount-leaks-in-.patch b/queue-5.10/nfsd-clean-up-potential-nfsd_file-refcount-leaks-in-.patch new file mode 100644 index 00000000000..a7132ff8d72 --- /dev/null +++ b/queue-5.10/nfsd-clean-up-potential-nfsd_file-refcount-leaks-in-.patch @@ -0,0 +1,108 @@ +From 902fe2a0cdfa6c1667d2e35911f1ca86c33d5f5d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Jan 2023 14:38:31 -0500 +Subject: nfsd: clean up potential nfsd_file refcount leaks in COPY codepath + +From: Jeff Layton + +[ Upstream commit 6ba434cb1a8d403ea9aad1b667c3ea3ad8b3191f ] + +There are two different flavors of the nfsd4_copy struct. One is +embedded in the compound and is used directly in synchronous copies. The +other is dynamically allocated, refcounted and tracked in the client +struture. For the embedded one, the cleanup just involves releasing any +nfsd_files held on its behalf. For the async one, the cleanup is a bit +more involved, and we need to dequeue it from lists, unhash it, etc. + +There is at least one potential refcount leak in this code now. If the +kthread_create call fails, then both the src and dst nfsd_files in the +original nfsd4_copy object are leaked. + +The cleanup in this codepath is also sort of weird. In the async copy +case, we'll have up to four nfsd_file references (src and dst for both +flavors of copy structure). They are both put at the end of +nfsd4_do_async_copy, even though the ones held on behalf of the embedded +one outlive that structure. + +Change it so that we always clean up the nfsd_file refs held by the +embedded copy structure before nfsd4_copy returns. Rework +cleanup_async_copy to handle both inter and intra copies. Eliminate +nfsd4_cleanup_intra_ssc since it now becomes a no-op. + +Signed-off-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 23 ++++++++++------------- + 1 file changed, 10 insertions(+), 13 deletions(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 5e175133b7bc7..0fe00d6d385a1 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -1512,7 +1512,6 @@ nfsd4_cleanup_inter_ssc(struct nfsd4_ssc_umount_item *nsui, struct file *filp, + long timeout = msecs_to_jiffies(nfsd4_ssc_umount_timeout); + + nfs42_ssc_close(filp); +- nfsd_file_put(dst); + fput(filp); + + spin_lock(&nn->nfsd_ssc_lock); +@@ -1562,13 +1561,6 @@ nfsd4_setup_intra_ssc(struct svc_rqst *rqstp, + ©->nf_dst); + } + +-static void +-nfsd4_cleanup_intra_ssc(struct nfsd_file *src, struct nfsd_file *dst) +-{ +- nfsd_file_put(src); +- nfsd_file_put(dst); +-} +- + static void nfsd4_cb_offload_release(struct nfsd4_callback *cb) + { + struct nfsd4_cb_offload *cbo = +@@ -1683,12 +1675,18 @@ static void dup_copy_fields(struct nfsd4_copy *src, struct nfsd4_copy *dst) + dst->ss_nsui = src->ss_nsui; + } + ++static void release_copy_files(struct nfsd4_copy *copy) ++{ ++ if (copy->nf_src) ++ nfsd_file_put(copy->nf_src); ++ if (copy->nf_dst) ++ nfsd_file_put(copy->nf_dst); ++} ++ + static void cleanup_async_copy(struct nfsd4_copy *copy) + { + nfs4_free_copy_state(copy); +- nfsd_file_put(copy->nf_dst); +- if (!nfsd4_ssc_is_inter(copy)) +- nfsd_file_put(copy->nf_src); ++ release_copy_files(copy); + spin_lock(©->cp_clp->async_lock); + list_del(©->copies); + spin_unlock(©->cp_clp->async_lock); +@@ -1748,7 +1746,6 @@ static int nfsd4_do_async_copy(void *data) + } else { + nfserr = nfsd4_do_copy(copy, copy->nf_src->nf_file, + copy->nf_dst->nf_file, false); +- nfsd4_cleanup_intra_ssc(copy->nf_src, copy->nf_dst); + } + + do_callback: +@@ -1811,9 +1808,9 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + } else { + status = nfsd4_do_copy(copy, copy->nf_src->nf_file, + copy->nf_dst->nf_file, true); +- nfsd4_cleanup_intra_ssc(copy->nf_src, copy->nf_dst); + } + out: ++ release_copy_files(copy); + return status; + out_err: + if (async_copy) +-- +2.43.0 + diff --git a/queue-5.10/nfsd-clean-up-splice-actor.patch b/queue-5.10/nfsd-clean-up-splice-actor.patch new file mode 100644 index 00000000000..b3cd46be5e3 --- /dev/null +++ b/queue-5.10/nfsd-clean-up-splice-actor.patch @@ -0,0 +1,67 @@ +From 965bfaf2f60ab42453f5486294f11a843b130821 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 28 Jun 2021 16:34:20 -0400 +Subject: NFSD: Clean up splice actor + +From: Chuck Lever + +[ Upstream commit c7e0b781b73c2e26e442ed71397cc2bc5945a732 ] + +A few useful observations: + + - The value in @size is never modified. + + - splice_desc.len is an unsigned int, and so is xdr_buf.page_len. + An implicit cast to size_t is unnecessary. + + - The computation of .page_len is the same in all three arms + of the "if" statement, so hoist it out to make it clear that + the operation is an unconditional invariant. + +The resulting function is 18 bytes shorter on my system (-Os). + +Signed-off-by: Chuck Lever +Reviewed-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/vfs.c | 11 +++-------- + 1 file changed, 3 insertions(+), 8 deletions(-) + +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index 74b2c6c5ad0b9..8520a2fc92dee 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -854,26 +854,21 @@ nfsd_splice_actor(struct pipe_inode_info *pipe, struct pipe_buffer *buf, + struct svc_rqst *rqstp = sd->u.data; + struct page **pp = rqstp->rq_next_page; + struct page *page = buf->page; +- size_t size; +- +- size = sd->len; + + if (rqstp->rq_res.page_len == 0) { + get_page(page); + put_page(*rqstp->rq_next_page); + *(rqstp->rq_next_page++) = page; + rqstp->rq_res.page_base = buf->offset; +- rqstp->rq_res.page_len = size; + } else if (page != pp[-1]) { + get_page(page); + if (*rqstp->rq_next_page) + put_page(*rqstp->rq_next_page); + *(rqstp->rq_next_page++) = page; +- rqstp->rq_res.page_len += size; +- } else +- rqstp->rq_res.page_len += size; ++ } ++ rqstp->rq_res.page_len += sd->len; + +- return size; ++ return sd->len; + } + + static int nfsd_direct_splice_actor(struct pipe_inode_info *pipe, +-- +2.43.0 + diff --git a/queue-5.10/nfsd-clean-up-splice_ok-in-nfsd4_encode_read.patch b/queue-5.10/nfsd-clean-up-splice_ok-in-nfsd4_encode_read.patch new file mode 100644 index 00000000000..1de25e23be1 --- /dev/null +++ b/queue-5.10/nfsd-clean-up-splice_ok-in-nfsd4_encode_read.patch @@ -0,0 +1,58 @@ +From 357d145f37854b859f31ba8c4c52a6057aa8edd7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 Jul 2022 16:08:51 -0400 +Subject: NFSD: Clean up SPLICE_OK in nfsd4_encode_read() + +From: Chuck Lever + +[ Upstream commit c738b218a2e5a753a336b4b7fee6720b902c7ace ] + +Do the test_bit() once -- this reduces the number of locked-bus +operations and makes the function a little easier to read. + +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 1e388cdf9b005..059e920c21919 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -3991,6 +3991,7 @@ static __be32 + nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr, + struct nfsd4_read *read) + { ++ bool splice_ok = test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags); + unsigned long maxcount; + struct xdr_stream *xdr = resp->xdr; + struct file *file; +@@ -4003,11 +4004,10 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr, + + p = xdr_reserve_space(xdr, 8); /* eof flag and byte count */ + if (!p) { +- WARN_ON_ONCE(test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags)); ++ WARN_ON_ONCE(splice_ok); + return nfserr_resource; + } +- if (resp->xdr->buf->page_len && +- test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags)) { ++ if (resp->xdr->buf->page_len && splice_ok) { + WARN_ON_ONCE(1); + return nfserr_serverfault; + } +@@ -4016,8 +4016,7 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr, + maxcount = min_t(unsigned long, read->rd_length, + (xdr->buf->buflen - xdr->buf->len)); + +- if (file->f_op->splice_read && +- test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags)) ++ if (file->f_op->splice_read && splice_ok) + nfserr = nfsd4_encode_splice_read(resp, read, file, maxcount); + else + nfserr = nfsd4_encode_readv(resp, read, file, maxcount); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-clean-up-the-nfsd_net-nfssvc_boot-field.patch b/queue-5.10/nfsd-clean-up-the-nfsd_net-nfssvc_boot-field.patch new file mode 100644 index 00000000000..7b2809c0432 --- /dev/null +++ b/queue-5.10/nfsd-clean-up-the-nfsd_net-nfssvc_boot-field.patch @@ -0,0 +1,173 @@ +From e6d38d070831b0d56bebdcae2f12618300b193d7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 29 Dec 2021 14:43:16 -0500 +Subject: NFSD: Clean up the nfsd_net::nfssvc_boot field + +From: Chuck Lever + +[ Upstream commit 91d2e9b56cf5c80f9efc530d494968369a8a0e0d ] + +There are two boot-time fields in struct nfsd_net: one called +boot_time and one called nfssvc_boot. The latter is used only to +form write verifiers, but its documenting comment declares: + + /* Time of server startup */ + +Since commit 27c438f53e79 ("nfsd: Support the server resetting the +boot verifier"), this field can be reset at any time; it's no +longer tied to server restart. So that comment is stale. + +Also, according to pahole, struct timespec64 is 16 bytes long on +x86_64. The nfssvc_boot field is used only to form a write verifier, +which is 8 bytes long. + +Let's clarify this situation by manufacturing an 8-byte verifier +in nfs_reset_boot_verifier() and storing only that in struct +nfsd_net. + +We're grabbing 128 bits of time, so compress all of those into a +64-bit verifier instead of throwing out the high-order bits. +In the future, the siphash_key can be re-used for other hashed +objects per-nfsd_net. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/netns.h | 8 +++++--- + fs/nfsd/nfsctl.c | 3 ++- + fs/nfsd/nfssvc.c | 51 ++++++++++++++++++++++++++++++++++++------------ + 3 files changed, 45 insertions(+), 17 deletions(-) + +diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h +index 9e8b77d2a3a47..a6ed300259849 100644 +--- a/fs/nfsd/netns.h ++++ b/fs/nfsd/netns.h +@@ -11,6 +11,7 @@ + #include + #include + #include ++#include + + /* Hash tables for nfs4_clientid state */ + #define CLIENT_HASH_BITS 4 +@@ -108,9 +109,8 @@ struct nfsd_net { + bool nfsd_net_up; + bool lockd_up; + +- /* Time of server startup */ +- struct timespec64 nfssvc_boot; +- seqlock_t boot_lock; ++ seqlock_t writeverf_lock; ++ unsigned char writeverf[8]; + + /* + * Max number of connections this nfsd container will allow. Defaults +@@ -187,6 +187,8 @@ struct nfsd_net { + char nfsd_name[UNX_MAXNODENAME+1]; + + struct nfsd_fcache_disposal *fcache_disposal; ++ ++ siphash_key_t siphash_key; + }; + + /* Simple check to find out if a given net was properly initialized */ +diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c +index 504b169d27881..68b020f2002b7 100644 +--- a/fs/nfsd/nfsctl.c ++++ b/fs/nfsd/nfsctl.c +@@ -1484,7 +1484,8 @@ static __net_init int nfsd_init_net(struct net *net) + nn->clientid_counter = nn->clientid_base + 1; + nn->s2s_cp_cl_id = nn->clientid_counter++; + +- seqlock_init(&nn->boot_lock); ++ get_random_bytes(&nn->siphash_key, sizeof(nn->siphash_key)); ++ seqlock_init(&nn->writeverf_lock); + + return 0; + +diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c +index 4d1d8aa6d7f9d..5a60664695352 100644 +--- a/fs/nfsd/nfssvc.c ++++ b/fs/nfsd/nfssvc.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -344,33 +345,57 @@ static bool nfsd_needs_lockd(struct nfsd_net *nn) + return nfsd_vers(nn, 2, NFSD_TEST) || nfsd_vers(nn, 3, NFSD_TEST); + } + ++/** ++ * nfsd_copy_boot_verifier - Atomically copy a write verifier ++ * @verf: buffer in which to receive the verifier cookie ++ * @nn: NFS net namespace ++ * ++ * This function provides a wait-free mechanism for copying the ++ * namespace's boot verifier without tearing it. ++ */ + void nfsd_copy_boot_verifier(__be32 verf[2], struct nfsd_net *nn) + { + int seq = 0; + + do { +- read_seqbegin_or_lock(&nn->boot_lock, &seq); +- /* +- * This is opaque to client, so no need to byte-swap. Use +- * __force to keep sparse happy. y2038 time_t overflow is +- * irrelevant in this usage +- */ +- verf[0] = (__force __be32)nn->nfssvc_boot.tv_sec; +- verf[1] = (__force __be32)nn->nfssvc_boot.tv_nsec; +- } while (need_seqretry(&nn->boot_lock, seq)); +- done_seqretry(&nn->boot_lock, seq); ++ read_seqbegin_or_lock(&nn->writeverf_lock, &seq); ++ memcpy(verf, nn->writeverf, sizeof(*verf)); ++ } while (need_seqretry(&nn->writeverf_lock, seq)); ++ done_seqretry(&nn->writeverf_lock, seq); + } + + static void nfsd_reset_boot_verifier_locked(struct nfsd_net *nn) + { +- ktime_get_raw_ts64(&nn->nfssvc_boot); ++ struct timespec64 now; ++ u64 verf; ++ ++ /* ++ * Because the time value is hashed, y2038 time_t overflow ++ * is irrelevant in this usage. ++ */ ++ ktime_get_raw_ts64(&now); ++ verf = siphash_2u64(now.tv_sec, now.tv_nsec, &nn->siphash_key); ++ memcpy(nn->writeverf, &verf, sizeof(nn->writeverf)); + } + ++/** ++ * nfsd_reset_boot_verifier - Generate a new boot verifier ++ * @nn: NFS net namespace ++ * ++ * This function updates the ->writeverf field of @nn. This field ++ * contains an opaque cookie that, according to Section 18.32.3 of ++ * RFC 8881, "the client can use to determine whether a server has ++ * changed instance state (e.g., server restart) between a call to ++ * WRITE and a subsequent call to either WRITE or COMMIT. This ++ * cookie MUST be unchanged during a single instance of the NFSv4.1 ++ * server and MUST be unique between instances of the NFSv4.1 ++ * server." ++ */ + void nfsd_reset_boot_verifier(struct nfsd_net *nn) + { +- write_seqlock(&nn->boot_lock); ++ write_seqlock(&nn->writeverf_lock); + nfsd_reset_boot_verifier_locked(nn); +- write_sequnlock(&nn->boot_lock); ++ write_sequnlock(&nn->writeverf_lock); + } + + static int nfsd_startup_net(struct net *net, const struct cred *cred) +-- +2.43.0 + diff --git a/queue-5.10/nfsd-clean-up-the-show_nf_flags-macro.patch b/queue-5.10/nfsd-clean-up-the-show_nf_flags-macro.patch new file mode 100644 index 00000000000..1ac07f5a4de --- /dev/null +++ b/queue-5.10/nfsd-clean-up-the-show_nf_flags-macro.patch @@ -0,0 +1,38 @@ +From 6940491956aabf3c8bd780e642b91d3c138696b7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 27 Mar 2022 16:43:03 -0400 +Subject: NFSD: Clean up the show_nf_flags() macro + +From: Chuck Lever + +[ Upstream commit bb283ca18d1e67c82d22a329c96c9d6036a74790 ] + +The flags are defined using C macros, so TRACE_DEFINE_ENUM is +unnecessary. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/trace.h | 6 ------ + 1 file changed, 6 deletions(-) + +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index c4c073e85fdd9..8ccce4ac66b4e 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -703,12 +703,6 @@ DEFINE_CLID_EVENT(confirmed_r); + /* + * from fs/nfsd/filecache.h + */ +-TRACE_DEFINE_ENUM(NFSD_FILE_HASHED); +-TRACE_DEFINE_ENUM(NFSD_FILE_PENDING); +-TRACE_DEFINE_ENUM(NFSD_FILE_BREAK_READ); +-TRACE_DEFINE_ENUM(NFSD_FILE_BREAK_WRITE); +-TRACE_DEFINE_ENUM(NFSD_FILE_REFERENCED); +- + #define show_nf_flags(val) \ + __print_flags(val, "|", \ + { 1 << NFSD_FILE_HASHED, "HASHED" }, \ +-- +2.43.0 + diff --git a/queue-5.10/nfsd-clean-up-the-show_nf_may-macro.patch b/queue-5.10/nfsd-clean-up-the-show_nf_may-macro.patch new file mode 100644 index 00000000000..9e56e8446d2 --- /dev/null +++ b/queue-5.10/nfsd-clean-up-the-show_nf_may-macro.patch @@ -0,0 +1,112 @@ +From 0988cdb54998a0dd5898b8f25b4a604fe5c20d3f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 19 Aug 2020 12:56:40 -0400 +Subject: NFSD: Clean up the show_nf_may macro + +From: Chuck Lever + +[ Upstream commit b76278ae68848cea13b325d247aa5cf31c87edac ] + +Display all currently possible NFSD_MAY permission flags. + +Move and rename show_nf_may with a more generic name because the +NFSD_MAY permission flags are used in other places besides the file +cache. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/trace.h | 40 ++++++++++++++++++++++++++-------------- + 1 file changed, 26 insertions(+), 14 deletions(-) + +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index a952f4a9b2a68..7bb1c398daa51 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -12,6 +12,22 @@ + #include "export.h" + #include "nfsfh.h" + ++#define show_nfsd_may_flags(x) \ ++ __print_flags(x, "|", \ ++ { NFSD_MAY_EXEC, "EXEC" }, \ ++ { NFSD_MAY_WRITE, "WRITE" }, \ ++ { NFSD_MAY_READ, "READ" }, \ ++ { NFSD_MAY_SATTR, "SATTR" }, \ ++ { NFSD_MAY_TRUNC, "TRUNC" }, \ ++ { NFSD_MAY_LOCK, "LOCK" }, \ ++ { NFSD_MAY_OWNER_OVERRIDE, "OWNER_OVERRIDE" }, \ ++ { NFSD_MAY_LOCAL_ACCESS, "LOCAL_ACCESS" }, \ ++ { NFSD_MAY_BYPASS_GSS_ON_ROOT, "BYPASS_GSS_ON_ROOT" }, \ ++ { NFSD_MAY_NOT_BREAK_LEASE, "NOT_BREAK_LEASE" }, \ ++ { NFSD_MAY_BYPASS_GSS, "BYPASS_GSS" }, \ ++ { NFSD_MAY_READ_IF_EXEC, "READ_IF_EXEC" }, \ ++ { NFSD_MAY_64BIT_COOKIE, "64BIT_COOKIE" }) ++ + TRACE_EVENT(nfsd_compound, + TP_PROTO(const struct svc_rqst *rqst, + u32 args_opcnt), +@@ -392,6 +408,9 @@ TRACE_EVENT(nfsd_clid_inuse_err, + __entry->cl_boot, __entry->cl_id) + ) + ++/* ++ * from fs/nfsd/filecache.h ++ */ + TRACE_DEFINE_ENUM(NFSD_FILE_HASHED); + TRACE_DEFINE_ENUM(NFSD_FILE_PENDING); + TRACE_DEFINE_ENUM(NFSD_FILE_BREAK_READ); +@@ -406,13 +425,6 @@ TRACE_DEFINE_ENUM(NFSD_FILE_REFERENCED); + { 1 << NFSD_FILE_BREAK_WRITE, "BREAK_WRITE" }, \ + { 1 << NFSD_FILE_REFERENCED, "REFERENCED"}) + +-/* FIXME: This should probably be fleshed out in the future. */ +-#define show_nf_may(val) \ +- __print_flags(val, "|", \ +- { NFSD_MAY_READ, "READ" }, \ +- { NFSD_MAY_WRITE, "WRITE" }, \ +- { NFSD_MAY_NOT_BREAK_LEASE, "NOT_BREAK_LEASE" }) +- + DECLARE_EVENT_CLASS(nfsd_file_class, + TP_PROTO(struct nfsd_file *nf), + TP_ARGS(nf), +@@ -437,7 +449,7 @@ DECLARE_EVENT_CLASS(nfsd_file_class, + __entry->nf_inode, + __entry->nf_ref, + show_nf_flags(__entry->nf_flags), +- show_nf_may(__entry->nf_may), ++ show_nfsd_may_flags(__entry->nf_may), + __entry->nf_file) + ) + +@@ -463,10 +475,10 @@ TRACE_EVENT(nfsd_file_acquire, + __field(u32, xid) + __field(unsigned int, hash) + __field(void *, inode) +- __field(unsigned int, may_flags) ++ __field(unsigned long, may_flags) + __field(int, nf_ref) + __field(unsigned long, nf_flags) +- __field(unsigned char, nf_may) ++ __field(unsigned long, nf_may) + __field(struct file *, nf_file) + __field(u32, status) + ), +@@ -485,10 +497,10 @@ TRACE_EVENT(nfsd_file_acquire, + + TP_printk("xid=0x%x hash=0x%x inode=0x%p may_flags=%s ref=%d nf_flags=%s nf_may=%s nf_file=0x%p status=%u", + __entry->xid, __entry->hash, __entry->inode, +- show_nf_may(__entry->may_flags), __entry->nf_ref, +- show_nf_flags(__entry->nf_flags), +- show_nf_may(__entry->nf_may), __entry->nf_file, +- __entry->status) ++ show_nfsd_may_flags(__entry->may_flags), ++ __entry->nf_ref, show_nf_flags(__entry->nf_flags), ++ show_nfsd_may_flags(__entry->nf_may), ++ __entry->nf_file, __entry->status) + ); + + DECLARE_EVENT_CLASS(nfsd_file_search_class, +-- +2.43.0 + diff --git a/queue-5.10/nfsd-clean-up-unused-code-after-rhashtable-conversio.patch b/queue-5.10/nfsd-clean-up-unused-code-after-rhashtable-conversio.patch new file mode 100644 index 00000000000..30cc4533b77 --- /dev/null +++ b/queue-5.10/nfsd-clean-up-unused-code-after-rhashtable-conversio.patch @@ -0,0 +1,132 @@ +From 62c4f98cb54899c3a8e70f4088e1b01e47e3ad7b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 Jul 2022 14:26:36 -0400 +Subject: NFSD: Clean up unused code after rhashtable conversion + +From: Chuck Lever + +[ Upstream commit 0ec8e9d1539a7b8109a554028bbce441052f847e ] + +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 33 +-------------------------------- + fs/nfsd/filecache.h | 1 - + 2 files changed, 1 insertion(+), 33 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index 45dd4f3fa0905..c6dc55c0f758b 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -21,11 +21,6 @@ + #include "filecache.h" + #include "trace.h" + +-#define NFSDDBG_FACILITY NFSDDBG_FH +- +-/* FIXME: dynamically size this for the machine somehow? */ +-#define NFSD_FILE_HASH_BITS 12 +-#define NFSD_FILE_HASH_SIZE (1 << NFSD_FILE_HASH_BITS) + #define NFSD_LAUNDRETTE_DELAY (2 * HZ) + + #define NFSD_FILE_CACHE_UP (0) +@@ -33,13 +28,6 @@ + /* We only care about NFSD_MAY_READ/WRITE for this cache */ + #define NFSD_FILE_MAY_MASK (NFSD_MAY_READ|NFSD_MAY_WRITE) + +-struct nfsd_fcache_bucket { +- struct hlist_head nfb_head; +- spinlock_t nfb_lock; +- unsigned int nfb_count; +- unsigned int nfb_maxcount; +-}; +- + static DEFINE_PER_CPU(unsigned long, nfsd_file_cache_hits); + static DEFINE_PER_CPU(unsigned long, nfsd_file_acquisitions); + static DEFINE_PER_CPU(unsigned long, nfsd_file_releases); +@@ -57,7 +45,6 @@ static struct workqueue_struct *nfsd_filecache_wq __read_mostly; + + static struct kmem_cache *nfsd_file_slab; + static struct kmem_cache *nfsd_file_mark_slab; +-static struct nfsd_fcache_bucket *nfsd_file_hashtbl; + static struct list_lru nfsd_file_lru; + static unsigned long nfsd_file_flags; + static struct fsnotify_group *nfsd_file_fsnotify_group; +@@ -302,7 +289,6 @@ nfsd_file_alloc(struct nfsd_file_lookup_key *key, unsigned int may) + + nf = kmem_cache_alloc(nfsd_file_slab, GFP_KERNEL); + if (nf) { +- INIT_HLIST_NODE(&nf->nf_node); + INIT_LIST_HEAD(&nf->nf_lru); + nf->nf_birthtime = ktime_get(); + nf->nf_file = NULL; +@@ -810,8 +796,7 @@ static const struct fsnotify_ops nfsd_file_fsnotify_ops = { + int + nfsd_file_cache_init(void) + { +- int ret; +- unsigned int i; ++ int ret; + + lockdep_assert_held(&nfsd_mutex); + if (test_and_set_bit(NFSD_FILE_CACHE_UP, &nfsd_file_flags) == 1) +@@ -826,13 +811,6 @@ nfsd_file_cache_init(void) + if (!nfsd_filecache_wq) + goto out; + +- nfsd_file_hashtbl = kvcalloc(NFSD_FILE_HASH_SIZE, +- sizeof(*nfsd_file_hashtbl), GFP_KERNEL); +- if (!nfsd_file_hashtbl) { +- pr_err("nfsd: unable to allocate nfsd_file_hashtbl\n"); +- goto out_err; +- } +- + nfsd_file_slab = kmem_cache_create("nfsd_file", + sizeof(struct nfsd_file), 0, 0, NULL); + if (!nfsd_file_slab) { +@@ -876,11 +854,6 @@ nfsd_file_cache_init(void) + goto out_notifier; + } + +- for (i = 0; i < NFSD_FILE_HASH_SIZE; i++) { +- INIT_HLIST_HEAD(&nfsd_file_hashtbl[i].nfb_head); +- spin_lock_init(&nfsd_file_hashtbl[i].nfb_lock); +- } +- + INIT_DELAYED_WORK(&nfsd_filecache_laundrette, nfsd_file_gc_worker); + out: + return ret; +@@ -895,8 +868,6 @@ nfsd_file_cache_init(void) + nfsd_file_slab = NULL; + kmem_cache_destroy(nfsd_file_mark_slab); + nfsd_file_mark_slab = NULL; +- kvfree(nfsd_file_hashtbl); +- nfsd_file_hashtbl = NULL; + destroy_workqueue(nfsd_filecache_wq); + nfsd_filecache_wq = NULL; + rhashtable_destroy(&nfsd_file_rhash_tbl); +@@ -1026,8 +997,6 @@ nfsd_file_cache_shutdown(void) + fsnotify_wait_marks_destroyed(); + kmem_cache_destroy(nfsd_file_mark_slab); + nfsd_file_mark_slab = NULL; +- kvfree(nfsd_file_hashtbl); +- nfsd_file_hashtbl = NULL; + destroy_workqueue(nfsd_filecache_wq); + nfsd_filecache_wq = NULL; + rhashtable_destroy(&nfsd_file_rhash_tbl); +diff --git a/fs/nfsd/filecache.h b/fs/nfsd/filecache.h +index 5cbfc61a7d7d9..ee9ed99d8b8fa 100644 +--- a/fs/nfsd/filecache.h ++++ b/fs/nfsd/filecache.h +@@ -30,7 +30,6 @@ struct nfsd_file_mark { + */ + struct nfsd_file { + struct rhash_head nf_rhash; +- struct hlist_node nf_node; + struct list_head nf_lru; + struct rcu_head nf_rcu; + struct file *nf_file; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-clean-up-write-arg-decoders.patch b/queue-5.10/nfsd-clean-up-write-arg-decoders.patch new file mode 100644 index 00000000000..19579a9b1ee --- /dev/null +++ b/queue-5.10/nfsd-clean-up-write-arg-decoders.patch @@ -0,0 +1,54 @@ +From 10235c321996a61245f4cbb9e24ad195b64b9ddb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Sep 2022 17:23:07 -0400 +Subject: NFSD: Clean up WRITE arg decoders + +From: Chuck Lever + +[ Upstream commit d4da5baa533215b14625458e645056baf646bb2e ] + +xdr_stream_subsegment() already returns a boolean value. + +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3xdr.c | 4 +--- + fs/nfsd/nfsxdr.c | 4 +--- + 2 files changed, 2 insertions(+), 6 deletions(-) + +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index 71e32cf288854..3308dd671ef0b 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -571,10 +571,8 @@ nfs3svc_decode_writeargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + args->count = max_blocksize; + args->len = max_blocksize; + } +- if (!xdr_stream_subsegment(xdr, &args->payload, args->count)) +- return false; + +- return true; ++ return xdr_stream_subsegment(xdr, &args->payload, args->count); + } + + bool +diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c +index aba8520b4b8b6..caf6355b18fa9 100644 +--- a/fs/nfsd/nfsxdr.c ++++ b/fs/nfsd/nfsxdr.c +@@ -338,10 +338,8 @@ nfssvc_decode_writeargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + return false; + if (args->len > NFSSVC_MAXBLKSIZE_V2) + return false; +- if (!xdr_stream_subsegment(xdr, &args->payload, args->len)) +- return false; + +- return true; ++ return xdr_stream_subsegment(xdr, &args->payload, args->len); + } + + bool +-- +2.43.0 + diff --git a/queue-5.10/nfsd-close-cached-files-prior-to-a-remove-or-rename-.patch b/queue-5.10/nfsd-close-cached-files-prior-to-a-remove-or-rename-.patch new file mode 100644 index 00000000000..8517430a227 --- /dev/null +++ b/queue-5.10/nfsd-close-cached-files-prior-to-a-remove-or-rename-.patch @@ -0,0 +1,155 @@ +From ac4a334158da9104b77f1c2c25520e9a638f9031 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Nov 2020 17:03:16 -0500 +Subject: nfsd: close cached files prior to a REMOVE or RENAME that would + replace target + +From: Jeff Layton + +[ Upstream commit 7f84b488f9add1d5cca3e6197c95914c7bd3c1cf ] + +It's not uncommon for some workloads to do a bunch of I/O to a file and +delete it just afterward. If knfsd has a cached open file however, then +the file may still be open when the dentry is unlinked. If the +underlying filesystem is nfs, then that could trigger it to do a +sillyrename. + +On a REMOVE or RENAME scan the nfsd_file cache for open files that +correspond to the inode, and proactively unhash and put their +references. This should prevent any delete-on-last-close activity from +occurring, solely due to knfsd's open file cache. + +This must be done synchronously though so we use the variants that call +flush_delayed_fput. There are deadlock possibilities if you call +flush_delayed_fput while holding locks, however. In the case of +nfsd_rename, we don't even do the lookups of the dentries to be renamed +until we've locked for rename. + +Once we've figured out what the target dentry is for a rename, check to +see whether there are cached open files associated with it. If there +are, then unwind all of the locking, close them all, and then reattempt +the rename. + +None of this is really necessary for "typical" filesystems though. It's +mostly of use for NFS, so declare a new export op flag and use that to +determine whether to close the files beforehand. + +Signed-off-by: Jeff Layton +Signed-off-by: Lance Shelton +Signed-off-by: Trond Myklebust +[ cel: adjusted to apply to 5.10.y ] +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + Documentation/filesystems/nfs/exporting.rst | 13 +++++++++++++ + fs/nfs/export.c | 2 +- + fs/nfsd/vfs.c | 16 +++++++++------- + include/linux/exportfs.h | 5 +++-- + 4 files changed, 26 insertions(+), 10 deletions(-) + +diff --git a/Documentation/filesystems/nfs/exporting.rst b/Documentation/filesystems/nfs/exporting.rst +index 960be64446cb9..0e98edd353b5f 100644 +--- a/Documentation/filesystems/nfs/exporting.rst ++++ b/Documentation/filesystems/nfs/exporting.rst +@@ -202,3 +202,16 @@ following flags are defined: + This flag exempts the filesystem from subtree checking and causes + exportfs to get back an error if it tries to enable subtree checking + on it. ++ ++ EXPORT_OP_CLOSE_BEFORE_UNLINK - always close cached files before unlinking ++ On some exportable filesystems (such as NFS) unlinking a file that ++ is still open can cause a fair bit of extra work. For instance, ++ the NFS client will do a "sillyrename" to ensure that the file ++ sticks around while it's still open. When reexporting, that open ++ file is held by nfsd so we usually end up doing a sillyrename, and ++ then immediately deleting the sillyrenamed file just afterward when ++ the link count actually goes to zero. Sometimes this delete can race ++ with other operations (for instance an rmdir of the parent directory). ++ This flag causes nfsd to close any open files for this inode _before_ ++ calling into the vfs to do an unlink or a rename that would replace ++ an existing file. +diff --git a/fs/nfs/export.c b/fs/nfs/export.c +index b9ba306bf9120..5428713af5fee 100644 +--- a/fs/nfs/export.c ++++ b/fs/nfs/export.c +@@ -171,5 +171,5 @@ const struct export_operations nfs_export_ops = { + .encode_fh = nfs_encode_fh, + .fh_to_dentry = nfs_fh_to_dentry, + .get_parent = nfs_get_parent, +- .flags = EXPORT_OP_NOWCC|EXPORT_OP_NOSUBTREECHK, ++ .flags = EXPORT_OP_NOWCC|EXPORT_OP_NOSUBTREECHK|EXPORT_OP_CLOSE_BEFORE_UNLINK, + }; +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index 31edb883afd0d..fb4e6c57ce0bb 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -1739,7 +1739,7 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, + struct inode *fdir, *tdir; + __be32 err; + int host_err; +- bool has_cached = false; ++ bool close_cached = false; + + err = fh_verify(rqstp, ffhp, S_IFDIR, NFSD_MAY_REMOVE); + if (err) +@@ -1798,8 +1798,9 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, + if (ndentry == trap) + goto out_dput_new; + +- if (nfsd_has_cached_files(ndentry)) { +- has_cached = true; ++ if ((ndentry->d_sb->s_export_op->flags & EXPORT_OP_CLOSE_BEFORE_UNLINK) && ++ nfsd_has_cached_files(ndentry)) { ++ close_cached = true; + goto out_dput_old; + } else { + host_err = vfs_rename(fdir, odentry, tdir, ndentry, NULL, 0); +@@ -1820,7 +1821,7 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, + * as that would do the wrong thing if the two directories + * were the same, so again we do it by hand. + */ +- if (!has_cached) { ++ if (!close_cached) { + fill_post_wcc(ffhp); + fill_post_wcc(tfhp); + } +@@ -1834,8 +1835,8 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, + * shouldn't be done with locks held however, so we delay it until this + * point and then reattempt the whole shebang. + */ +- if (has_cached) { +- has_cached = false; ++ if (close_cached) { ++ close_cached = false; + nfsd_close_cached_files(ndentry); + dput(ndentry); + goto retry; +@@ -1887,7 +1888,8 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, + type = d_inode(rdentry)->i_mode & S_IFMT; + + if (type != S_IFDIR) { +- nfsd_close_cached_files(rdentry); ++ if (rdentry->d_sb->s_export_op->flags & EXPORT_OP_CLOSE_BEFORE_UNLINK) ++ nfsd_close_cached_files(rdentry); + host_err = vfs_unlink(dirp, rdentry, NULL); + } else { + host_err = vfs_rmdir(dirp, rdentry); +diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h +index 2fcbab0f6b612..d829403ffd3bb 100644 +--- a/include/linux/exportfs.h ++++ b/include/linux/exportfs.h +@@ -213,8 +213,9 @@ struct export_operations { + bool write, u32 *device_generation); + int (*commit_blocks)(struct inode *inode, struct iomap *iomaps, + int nr_iomaps, struct iattr *iattr); +-#define EXPORT_OP_NOWCC (0x1) /* Don't collect wcc data for NFSv3 replies */ +-#define EXPORT_OP_NOSUBTREECHK (0x2) /* Subtree checking is not supported! */ ++#define EXPORT_OP_NOWCC (0x1) /* don't collect v3 wcc data */ ++#define EXPORT_OP_NOSUBTREECHK (0x2) /* no subtree checking */ ++#define EXPORT_OP_CLOSE_BEFORE_UNLINK (0x4) /* close files before unlink */ + unsigned long flags; + }; + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-combine-xdr-error-tracepoints.patch b/queue-5.10/nfsd-combine-xdr-error-tracepoints.patch new file mode 100644 index 00000000000..0d772becaa5 --- /dev/null +++ b/queue-5.10/nfsd-combine-xdr-error-tracepoints.patch @@ -0,0 +1,70 @@ +From 389c30106f788fe6869acfffbe8b5f523a00217d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 Oct 2021 12:11:45 -0400 +Subject: NFSD: Combine XDR error tracepoints + +From: Chuck Lever + +[ Upstream commit 70e94d757b3e1f46486d573729d84c8955c81dce ] + +Clean up: The garbage_args and cant_encode tracepoints report the +same information as each other, so combine them into a single +tracepoint class to reduce code duplication and slightly reduce the +size of trace.o. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/trace.h | 28 +++++++--------------------- + 1 file changed, 7 insertions(+), 21 deletions(-) + +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index de245f433392d..cba38e0b204b9 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -46,7 +46,7 @@ + rqstp->rq_xprt->xpt_remotelen); \ + } while (0); + +-TRACE_EVENT(nfsd_garbage_args_err, ++DECLARE_EVENT_CLASS(nfsd_xdr_err_class, + TP_PROTO( + const struct svc_rqst *rqstp + ), +@@ -68,27 +68,13 @@ TRACE_EVENT(nfsd_garbage_args_err, + ) + ); + +-TRACE_EVENT(nfsd_cant_encode_err, +- TP_PROTO( +- const struct svc_rqst *rqstp +- ), +- TP_ARGS(rqstp), +- TP_STRUCT__entry( +- NFSD_TRACE_PROC_ARG_FIELDS ++#define DEFINE_NFSD_XDR_ERR_EVENT(name) \ ++DEFINE_EVENT(nfsd_xdr_err_class, nfsd_##name##_err, \ ++ TP_PROTO(const struct svc_rqst *rqstp), \ ++ TP_ARGS(rqstp)) + +- __field(u32, vers) +- __field(u32, proc) +- ), +- TP_fast_assign( +- NFSD_TRACE_PROC_ARG_ASSIGNMENTS +- +- __entry->vers = rqstp->rq_vers; +- __entry->proc = rqstp->rq_proc; +- ), +- TP_printk("xid=0x%08x vers=%u proc=%u", +- __entry->xid, __entry->vers, __entry->proc +- ) +-); ++DEFINE_NFSD_XDR_ERR_EVENT(garbage_args); ++DEFINE_NFSD_XDR_ERR_EVENT(cant_encode); + + #define show_nfsd_may_flags(x) \ + __print_flags(x, "|", \ +-- +2.43.0 + diff --git a/queue-5.10/nfsd-commit-operations-must-not-return-nfs-err_inval.patch b/queue-5.10/nfsd-commit-operations-must-not-return-nfs-err_inval.patch new file mode 100644 index 00000000000..d2ee2f33272 --- /dev/null +++ b/queue-5.10/nfsd-commit-operations-must-not-return-nfs-err_inval.patch @@ -0,0 +1,181 @@ +From f08b0773778f16b9a2cbe8bf0fa5d45eb85d6ce8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 24 Jan 2022 15:50:31 -0500 +Subject: NFSD: COMMIT operations must not return NFS?ERR_INVAL + +From: Chuck Lever + +[ Upstream commit 3f965021c8bc38965ecb1924f570c4842b33d408 ] + +Since, well, forever, the Linux NFS server's nfsd_commit() function +has returned nfserr_inval when the passed-in byte range arguments +were non-sensical. + +However, according to RFC 1813 section 3.3.21, NFSv3 COMMIT requests +are permitted to return only the following non-zero status codes: + + NFS3ERR_IO + NFS3ERR_STALE + NFS3ERR_BADHANDLE + NFS3ERR_SERVERFAULT + +NFS3ERR_INVAL is not included in that list. Likewise, NFS4ERR_INVAL +is not listed in the COMMIT row of Table 6 in RFC 8881. + +RFC 7530 does permit COMMIT to return NFS4ERR_INVAL, but does not +specify when it can or should be used. + +Instead of dropping or failing a COMMIT request in a byte range that +is not supported, turn it into a valid request by treating one or +both arguments as zero. Offset zero means start-of-file, count zero +means until-end-of-file, so we only ever extend the commit range. +NFS servers are always allowed to commit more and sooner than +requested. + +The range check is no longer bounded by NFS_OFFSET_MAX, but rather +by the value that is returned in the maxfilesize field of the NFSv3 +FSINFO procedure or the NFSv4 maxfilesize file attribute. + +Note that this change results in a new pynfs failure: + +CMT4 st_commit.testCommitOverflow : RUNNING +CMT4 st_commit.testCommitOverflow : FAILURE + COMMIT with offset + count overflow should return + NFS4ERR_INVAL, instead got NFS4_OK + +IMO the test is not correct as written: RFC 8881 does not allow the +COMMIT operation to return NFS4ERR_INVAL. + +Reported-by: Dan Aloni +Cc: stable@vger.kernel.org +Signed-off-by: Chuck Lever +Reviewed-by: Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3proc.c | 6 ------ + fs/nfsd/vfs.c | 53 +++++++++++++++++++++++++++++++--------------- + fs/nfsd/vfs.h | 4 ++-- + 3 files changed, 38 insertions(+), 25 deletions(-) + +diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c +index b540489ea240d..936eebd4c56dc 100644 +--- a/fs/nfsd/nfs3proc.c ++++ b/fs/nfsd/nfs3proc.c +@@ -660,15 +660,9 @@ nfsd3_proc_commit(struct svc_rqst *rqstp) + argp->count, + (unsigned long long) argp->offset); + +- if (argp->offset > NFS_OFFSET_MAX) { +- resp->status = nfserr_inval; +- goto out; +- } +- + fh_copy(&resp->fh, &argp->fh); + resp->status = nfsd_commit(rqstp, &resp->fh, argp->offset, + argp->count, resp->verf); +-out: + return rpc_success; + } + +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index 09e4a0af6fb43..89c50ccedf4d3 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -1140,42 +1140,61 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, + } + + #ifdef CONFIG_NFSD_V3 +-/* +- * Commit all pending writes to stable storage. ++/** ++ * nfsd_commit - Commit pending writes to stable storage ++ * @rqstp: RPC request being processed ++ * @fhp: NFS filehandle ++ * @offset: raw offset from beginning of file ++ * @count: raw count of bytes to sync ++ * @verf: filled in with the server's current write verifier + * +- * Note: we only guarantee that data that lies within the range specified +- * by the 'offset' and 'count' parameters will be synced. ++ * Note: we guarantee that data that lies within the range specified ++ * by the 'offset' and 'count' parameters will be synced. The server ++ * is permitted to sync data that lies outside this range at the ++ * same time. + * + * Unfortunately we cannot lock the file to make sure we return full WCC + * data to the client, as locking happens lower down in the filesystem. ++ * ++ * Return values: ++ * An nfsstat value in network byte order. + */ + __be32 +-nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, +- loff_t offset, unsigned long count, __be32 *verf) ++nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, u64 offset, ++ u32 count, __be32 *verf) + { ++ u64 maxbytes; ++ loff_t start, end; + struct nfsd_net *nn; + struct nfsd_file *nf; +- loff_t end = LLONG_MAX; +- __be32 err = nfserr_inval; +- +- if (offset < 0) +- goto out; +- if (count != 0) { +- end = offset + (loff_t)count - 1; +- if (end < offset) +- goto out; +- } ++ __be32 err; + + err = nfsd_file_acquire(rqstp, fhp, + NFSD_MAY_WRITE|NFSD_MAY_NOT_BREAK_LEASE, &nf); + if (err) + goto out; ++ ++ /* ++ * Convert the client-provided (offset, count) range to a ++ * (start, end) range. If the client-provided range falls ++ * outside the maximum file size of the underlying FS, ++ * clamp the sync range appropriately. ++ */ ++ start = 0; ++ end = LLONG_MAX; ++ maxbytes = (u64)fhp->fh_dentry->d_sb->s_maxbytes; ++ if (offset < maxbytes) { ++ start = offset; ++ if (count && (offset + count - 1 < maxbytes)) ++ end = offset + count - 1; ++ } ++ + nn = net_generic(nf->nf_net, nfsd_net_id); + if (EX_ISSYNC(fhp->fh_export)) { + errseq_t since = READ_ONCE(nf->nf_file->f_wb_err); + int err2; + +- err2 = vfs_fsync_range(nf->nf_file, offset, end, 0); ++ err2 = vfs_fsync_range(nf->nf_file, start, end, 0); + switch (err2) { + case 0: + nfsd_copy_write_verifier(verf, nn); +diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h +index 9f56dcb22ff72..2c43d10e3cab4 100644 +--- a/fs/nfsd/vfs.h ++++ b/fs/nfsd/vfs.h +@@ -74,8 +74,8 @@ __be32 do_nfsd_create(struct svc_rqst *, struct svc_fh *, + char *name, int len, struct iattr *attrs, + struct svc_fh *res, int createmode, + u32 *verifier, bool *truncp, bool *created); +-__be32 nfsd_commit(struct svc_rqst *, struct svc_fh *, +- loff_t, unsigned long, __be32 *verf); ++__be32 nfsd_commit(struct svc_rqst *rqst, struct svc_fh *fhp, ++ u64 offset, u32 count, __be32 *verf); + #endif /* CONFIG_NFSD_V3 */ + #ifdef CONFIG_NFSD_V4 + __be32 nfsd_getxattr(struct svc_rqst *rqstp, struct svc_fh *fhp, +-- +2.43.0 + diff --git a/queue-5.10/nfsd-constify-fh-argument-of-knfsd_fh_hash.patch b/queue-5.10/nfsd-constify-fh-argument-of-knfsd_fh_hash.patch new file mode 100644 index 00000000000..39d433b2d82 --- /dev/null +++ b/queue-5.10/nfsd-constify-fh-argument-of-knfsd_fh_hash.patch @@ -0,0 +1,45 @@ +From 840dbe657365ec3f6bec95e1d0799501a5dd36c2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 14 May 2021 15:56:25 -0400 +Subject: NFSD: Constify @fh argument of knfsd_fh_hash() + +From: Chuck Lever + +[ Upstream commit 1736aec82a15cb5d4b3bbe0b2fbae0ede66b1a1a ] + +Enable knfsd_fh_hash() to be invoked in functions where the +filehandle pointer is a const. + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsfh.h | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h +index aff2cda5c6c33..6106697adc04b 100644 +--- a/fs/nfsd/nfsfh.h ++++ b/fs/nfsd/nfsfh.h +@@ -225,15 +225,12 @@ static inline bool fh_fsid_match(struct knfsd_fh *fh1, struct knfsd_fh *fh2) + * returns a crc32 hash for the filehandle that is compatible with + * the one displayed by "wireshark". + */ +- +-static inline u32 +-knfsd_fh_hash(struct knfsd_fh *fh) ++static inline u32 knfsd_fh_hash(const struct knfsd_fh *fh) + { + return ~crc32_le(0xFFFFFFFF, (unsigned char *)&fh->fh_base, fh->fh_size); + } + #else +-static inline u32 +-knfsd_fh_hash(struct knfsd_fh *fh) ++static inline u32 knfsd_fh_hash(const struct knfsd_fh *fh) + { + return 0; + } +-- +2.43.0 + diff --git a/queue-5.10/nfsd-convert-filecache-to-rhltable.patch b/queue-5.10/nfsd-convert-filecache-to-rhltable.patch new file mode 100644 index 00000000000..c050f0694d4 --- /dev/null +++ b/queue-5.10/nfsd-convert-filecache-to-rhltable.patch @@ -0,0 +1,578 @@ +From 41114b0ccba84c04186668ee24ede7a2449da89a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 24 Nov 2022 15:09:04 -0500 +Subject: NFSD: Convert filecache to rhltable + +From: Chuck Lever + +[ Upstream commit c4c649ab413ba6a785b25f0edbb12f617c87db2a ] + +While we were converting the nfs4_file hashtable to use the kernel's +resizable hashtable data structure, Neil Brown observed that the +list variant (rhltable) would be better for managing nfsd_file items +as well. The nfsd_file hash table will contain multiple entries for +the same inode -- these should be kept together on a list. And, it +could be possible for exotic or malicious client behavior to cause +the hash table to resize itself on every insertion. + +A nice simplification is that rhltable_lookup() can return a list +that contains only nfsd_file items that match a given inode, which +enables us to eliminate specialized hash table helper functions and +use the default functions provided by the rhashtable implementation). + +Since we are now storing nfsd_file items for the same inode on a +single list, that effectively reduces the number of hash entries +that have to be tracked in the hash table. The mininum bucket count +is therefore lowered. + +Light testing with fstests generic/531 show no regressions. + +Suggested-by: Neil Brown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 311 ++++++++++++++++++-------------------------- + fs/nfsd/filecache.h | 9 +- + 2 files changed, 133 insertions(+), 187 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index 080d796547854..52e67ec267965 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -73,70 +73,9 @@ static struct list_lru nfsd_file_lru; + static unsigned long nfsd_file_flags; + static struct fsnotify_group *nfsd_file_fsnotify_group; + static struct delayed_work nfsd_filecache_laundrette; +-static struct rhashtable nfsd_file_rhash_tbl ++static struct rhltable nfsd_file_rhltable + ____cacheline_aligned_in_smp; + +-enum nfsd_file_lookup_type { +- NFSD_FILE_KEY_INODE, +- NFSD_FILE_KEY_FULL, +-}; +- +-struct nfsd_file_lookup_key { +- struct inode *inode; +- struct net *net; +- const struct cred *cred; +- unsigned char need; +- bool gc; +- enum nfsd_file_lookup_type type; +-}; +- +-/* +- * The returned hash value is based solely on the address of an in-code +- * inode, a pointer to a slab-allocated object. The entropy in such a +- * pointer is concentrated in its middle bits. +- */ +-static u32 nfsd_file_inode_hash(const struct inode *inode, u32 seed) +-{ +- unsigned long ptr = (unsigned long)inode; +- u32 k; +- +- k = ptr >> L1_CACHE_SHIFT; +- k &= 0x00ffffff; +- return jhash2(&k, 1, seed); +-} +- +-/** +- * nfsd_file_key_hashfn - Compute the hash value of a lookup key +- * @data: key on which to compute the hash value +- * @len: rhash table's key_len parameter (unused) +- * @seed: rhash table's random seed of the day +- * +- * Return value: +- * Computed 32-bit hash value +- */ +-static u32 nfsd_file_key_hashfn(const void *data, u32 len, u32 seed) +-{ +- const struct nfsd_file_lookup_key *key = data; +- +- return nfsd_file_inode_hash(key->inode, seed); +-} +- +-/** +- * nfsd_file_obj_hashfn - Compute the hash value of an nfsd_file +- * @data: object on which to compute the hash value +- * @len: rhash table's key_len parameter (unused) +- * @seed: rhash table's random seed of the day +- * +- * Return value: +- * Computed 32-bit hash value +- */ +-static u32 nfsd_file_obj_hashfn(const void *data, u32 len, u32 seed) +-{ +- const struct nfsd_file *nf = data; +- +- return nfsd_file_inode_hash(nf->nf_inode, seed); +-} +- + static bool + nfsd_match_cred(const struct cred *c1, const struct cred *c2) + { +@@ -157,55 +96,16 @@ nfsd_match_cred(const struct cred *c1, const struct cred *c2) + return true; + } + +-/** +- * nfsd_file_obj_cmpfn - Match a cache item against search criteria +- * @arg: search criteria +- * @ptr: cache item to check +- * +- * Return values: +- * %0 - Item matches search criteria +- * %1 - Item does not match search criteria +- */ +-static int nfsd_file_obj_cmpfn(struct rhashtable_compare_arg *arg, +- const void *ptr) +-{ +- const struct nfsd_file_lookup_key *key = arg->key; +- const struct nfsd_file *nf = ptr; +- +- switch (key->type) { +- case NFSD_FILE_KEY_INODE: +- if (test_bit(NFSD_FILE_GC, &nf->nf_flags) != key->gc) +- return 1; +- if (nf->nf_inode != key->inode) +- return 1; +- break; +- case NFSD_FILE_KEY_FULL: +- if (nf->nf_inode != key->inode) +- return 1; +- if (nf->nf_may != key->need) +- return 1; +- if (nf->nf_net != key->net) +- return 1; +- if (!nfsd_match_cred(nf->nf_cred, key->cred)) +- return 1; +- if (test_bit(NFSD_FILE_GC, &nf->nf_flags) != key->gc) +- return 1; +- if (test_bit(NFSD_FILE_HASHED, &nf->nf_flags) == 0) +- return 1; +- break; +- } +- return 0; +-} +- + static const struct rhashtable_params nfsd_file_rhash_params = { + .key_len = sizeof_field(struct nfsd_file, nf_inode), + .key_offset = offsetof(struct nfsd_file, nf_inode), +- .head_offset = offsetof(struct nfsd_file, nf_rhash), +- .hashfn = nfsd_file_key_hashfn, +- .obj_hashfn = nfsd_file_obj_hashfn, +- .obj_cmpfn = nfsd_file_obj_cmpfn, +- /* Reduce resizing churn on light workloads */ +- .min_size = 512, /* buckets */ ++ .head_offset = offsetof(struct nfsd_file, nf_rlist), ++ ++ /* ++ * Start with a single page hash table to reduce resizing churn ++ * on light workloads. ++ */ ++ .min_size = 256, + .automatic_shrinking = true, + }; + +@@ -308,27 +208,27 @@ nfsd_file_mark_find_or_create(struct nfsd_file *nf, struct inode *inode) + } + + static struct nfsd_file * +-nfsd_file_alloc(struct nfsd_file_lookup_key *key, unsigned int may) ++nfsd_file_alloc(struct net *net, struct inode *inode, unsigned char need, ++ bool want_gc) + { + struct nfsd_file *nf; + + nf = kmem_cache_alloc(nfsd_file_slab, GFP_KERNEL); +- if (nf) { +- INIT_LIST_HEAD(&nf->nf_lru); +- nf->nf_birthtime = ktime_get(); +- nf->nf_file = NULL; +- nf->nf_cred = get_current_cred(); +- nf->nf_net = key->net; +- nf->nf_flags = 0; +- __set_bit(NFSD_FILE_HASHED, &nf->nf_flags); +- __set_bit(NFSD_FILE_PENDING, &nf->nf_flags); +- if (key->gc) +- __set_bit(NFSD_FILE_GC, &nf->nf_flags); +- nf->nf_inode = key->inode; +- refcount_set(&nf->nf_ref, 1); +- nf->nf_may = key->need; +- nf->nf_mark = NULL; +- } ++ if (unlikely(!nf)) ++ return NULL; ++ ++ INIT_LIST_HEAD(&nf->nf_lru); ++ nf->nf_birthtime = ktime_get(); ++ nf->nf_file = NULL; ++ nf->nf_cred = get_current_cred(); ++ nf->nf_net = net; ++ nf->nf_flags = want_gc ? ++ BIT(NFSD_FILE_HASHED) | BIT(NFSD_FILE_PENDING) | BIT(NFSD_FILE_GC) : ++ BIT(NFSD_FILE_HASHED) | BIT(NFSD_FILE_PENDING); ++ nf->nf_inode = inode; ++ refcount_set(&nf->nf_ref, 1); ++ nf->nf_may = need; ++ nf->nf_mark = NULL; + return nf; + } + +@@ -353,8 +253,8 @@ static void + nfsd_file_hash_remove(struct nfsd_file *nf) + { + trace_nfsd_file_unhash(nf); +- rhashtable_remove_fast(&nfsd_file_rhash_tbl, &nf->nf_rhash, +- nfsd_file_rhash_params); ++ rhltable_remove(&nfsd_file_rhltable, &nf->nf_rlist, ++ nfsd_file_rhash_params); + } + + static bool +@@ -687,8 +587,8 @@ nfsd_file_cond_queue(struct nfsd_file *nf, struct list_head *dispose) + * @inode: inode on which to close out nfsd_files + * @dispose: list on which to gather nfsd_files to close out + * +- * An nfsd_file represents a struct file being held open on behalf of nfsd. An +- * open file however can block other activity (such as leases), or cause ++ * An nfsd_file represents a struct file being held open on behalf of nfsd. ++ * An open file however can block other activity (such as leases), or cause + * undesirable behavior (e.g. spurious silly-renames when reexporting NFS). + * + * This function is intended to find open nfsd_files when this sort of +@@ -701,21 +601,17 @@ nfsd_file_cond_queue(struct nfsd_file *nf, struct list_head *dispose) + static void + nfsd_file_queue_for_close(struct inode *inode, struct list_head *dispose) + { +- struct nfsd_file_lookup_key key = { +- .type = NFSD_FILE_KEY_INODE, +- .inode = inode, +- .gc = true, +- }; ++ struct rhlist_head *tmp, *list; + struct nfsd_file *nf; + + rcu_read_lock(); +- do { +- nf = rhashtable_lookup(&nfsd_file_rhash_tbl, &key, +- nfsd_file_rhash_params); +- if (!nf) +- break; ++ list = rhltable_lookup(&nfsd_file_rhltable, &inode, ++ nfsd_file_rhash_params); ++ rhl_for_each_entry_rcu(nf, tmp, list, nf_rlist) { ++ if (!test_bit(NFSD_FILE_GC, &nf->nf_flags)) ++ continue; + nfsd_file_cond_queue(nf, dispose); +- } while (1); ++ } + rcu_read_unlock(); + } + +@@ -839,7 +735,7 @@ nfsd_file_cache_init(void) + if (test_and_set_bit(NFSD_FILE_CACHE_UP, &nfsd_file_flags) == 1) + return 0; + +- ret = rhashtable_init(&nfsd_file_rhash_tbl, &nfsd_file_rhash_params); ++ ret = rhltable_init(&nfsd_file_rhltable, &nfsd_file_rhash_params); + if (ret) + return ret; + +@@ -907,7 +803,7 @@ nfsd_file_cache_init(void) + nfsd_file_mark_slab = NULL; + destroy_workqueue(nfsd_filecache_wq); + nfsd_filecache_wq = NULL; +- rhashtable_destroy(&nfsd_file_rhash_tbl); ++ rhltable_destroy(&nfsd_file_rhltable); + goto out; + } + +@@ -926,7 +822,7 @@ __nfsd_file_cache_purge(struct net *net) + struct nfsd_file *nf; + LIST_HEAD(dispose); + +- rhashtable_walk_enter(&nfsd_file_rhash_tbl, &iter); ++ rhltable_walk_enter(&nfsd_file_rhltable, &iter); + do { + rhashtable_walk_start(&iter); + +@@ -1032,7 +928,7 @@ nfsd_file_cache_shutdown(void) + nfsd_file_mark_slab = NULL; + destroy_workqueue(nfsd_filecache_wq); + nfsd_filecache_wq = NULL; +- rhashtable_destroy(&nfsd_file_rhash_tbl); ++ rhltable_destroy(&nfsd_file_rhltable); + + for_each_possible_cpu(i) { + per_cpu(nfsd_file_cache_hits, i) = 0; +@@ -1043,6 +939,35 @@ nfsd_file_cache_shutdown(void) + } + } + ++static struct nfsd_file * ++nfsd_file_lookup_locked(const struct net *net, const struct cred *cred, ++ struct inode *inode, unsigned char need, ++ bool want_gc) ++{ ++ struct rhlist_head *tmp, *list; ++ struct nfsd_file *nf; ++ ++ list = rhltable_lookup(&nfsd_file_rhltable, &inode, ++ nfsd_file_rhash_params); ++ rhl_for_each_entry_rcu(nf, tmp, list, nf_rlist) { ++ if (nf->nf_may != need) ++ continue; ++ if (nf->nf_net != net) ++ continue; ++ if (!nfsd_match_cred(nf->nf_cred, cred)) ++ continue; ++ if (test_bit(NFSD_FILE_GC, &nf->nf_flags) != want_gc) ++ continue; ++ if (test_bit(NFSD_FILE_HASHED, &nf->nf_flags) == 0) ++ continue; ++ ++ if (!nfsd_file_get(nf)) ++ continue; ++ return nf; ++ } ++ return NULL; ++} ++ + /** + * nfsd_file_is_cached - are there any cached open files for this inode? + * @inode: inode to check +@@ -1057,16 +982,20 @@ nfsd_file_cache_shutdown(void) + bool + nfsd_file_is_cached(struct inode *inode) + { +- struct nfsd_file_lookup_key key = { +- .type = NFSD_FILE_KEY_INODE, +- .inode = inode, +- .gc = true, +- }; ++ struct rhlist_head *tmp, *list; ++ struct nfsd_file *nf; + bool ret = false; + +- if (rhashtable_lookup_fast(&nfsd_file_rhash_tbl, &key, +- nfsd_file_rhash_params) != NULL) +- ret = true; ++ rcu_read_lock(); ++ list = rhltable_lookup(&nfsd_file_rhltable, &inode, ++ nfsd_file_rhash_params); ++ rhl_for_each_entry_rcu(nf, tmp, list, nf_rlist) ++ if (test_bit(NFSD_FILE_GC, &nf->nf_flags)) { ++ ret = true; ++ break; ++ } ++ rcu_read_unlock(); ++ + trace_nfsd_file_is_cached(inode, (int)ret); + return ret; + } +@@ -1076,14 +1005,12 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + unsigned int may_flags, struct file *file, + struct nfsd_file **pnf, bool want_gc) + { +- struct nfsd_file_lookup_key key = { +- .type = NFSD_FILE_KEY_FULL, +- .need = may_flags & NFSD_FILE_MAY_MASK, +- .net = SVC_NET(rqstp), +- .gc = want_gc, +- }; ++ unsigned char need = may_flags & NFSD_FILE_MAY_MASK; ++ struct net *net = SVC_NET(rqstp); ++ struct nfsd_file *new, *nf; ++ const struct cred *cred; + bool open_retry = true; +- struct nfsd_file *nf; ++ struct inode *inode; + __be32 status; + int ret; + +@@ -1091,14 +1018,12 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + may_flags|NFSD_MAY_OWNER_OVERRIDE); + if (status != nfs_ok) + return status; +- key.inode = d_inode(fhp->fh_dentry); +- key.cred = get_current_cred(); ++ inode = d_inode(fhp->fh_dentry); ++ cred = get_current_cred(); + + retry: + rcu_read_lock(); +- nf = rhashtable_lookup(&nfsd_file_rhash_tbl, &key, +- nfsd_file_rhash_params); +- nf = nfsd_file_get(nf); ++ nf = nfsd_file_lookup_locked(net, cred, inode, need, want_gc); + rcu_read_unlock(); + + if (nf) { +@@ -1112,21 +1037,32 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + goto wait_for_construction; + } + +- nf = nfsd_file_alloc(&key, may_flags); +- if (!nf) { ++ new = nfsd_file_alloc(net, inode, need, want_gc); ++ if (!new) { + status = nfserr_jukebox; + goto out; + } + +- ret = rhashtable_lookup_insert_key(&nfsd_file_rhash_tbl, +- &key, &nf->nf_rhash, +- nfsd_file_rhash_params); ++ rcu_read_lock(); ++ spin_lock(&inode->i_lock); ++ nf = nfsd_file_lookup_locked(net, cred, inode, need, want_gc); ++ if (unlikely(nf)) { ++ spin_unlock(&inode->i_lock); ++ rcu_read_unlock(); ++ nfsd_file_slab_free(&new->nf_rcu); ++ goto wait_for_construction; ++ } ++ nf = new; ++ ret = rhltable_insert(&nfsd_file_rhltable, &nf->nf_rlist, ++ nfsd_file_rhash_params); ++ spin_unlock(&inode->i_lock); ++ rcu_read_unlock(); + if (likely(ret == 0)) + goto open_file; + + if (ret == -EEXIST) + goto retry; +- trace_nfsd_file_insert_err(rqstp, key.inode, may_flags, ret); ++ trace_nfsd_file_insert_err(rqstp, inode, may_flags, ret); + status = nfserr_jukebox; + goto construction_err; + +@@ -1135,7 +1071,7 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + + /* Did construction of this file fail? */ + if (!test_bit(NFSD_FILE_HASHED, &nf->nf_flags)) { +- trace_nfsd_file_cons_err(rqstp, key.inode, may_flags, nf); ++ trace_nfsd_file_cons_err(rqstp, inode, may_flags, nf); + if (!open_retry) { + status = nfserr_jukebox; + goto construction_err; +@@ -1157,13 +1093,13 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + nfsd_file_check_write_error(nf); + *pnf = nf; + } +- put_cred(key.cred); +- trace_nfsd_file_acquire(rqstp, key.inode, may_flags, nf, status); ++ put_cred(cred); ++ trace_nfsd_file_acquire(rqstp, inode, may_flags, nf, status); + return status; + + open_file: + trace_nfsd_file_alloc(nf); +- nf->nf_mark = nfsd_file_mark_find_or_create(nf, key.inode); ++ nf->nf_mark = nfsd_file_mark_find_or_create(nf, inode); + if (nf->nf_mark) { + if (file) { + get_file(file); +@@ -1181,7 +1117,7 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + * If construction failed, or we raced with a call to unlink() + * then unhash. + */ +- if (status == nfs_ok && key.inode->i_nlink == 0) ++ if (status != nfs_ok || inode->i_nlink == 0) + status = nfserr_jukebox; + if (status != nfs_ok) + nfsd_file_unhash(nf); +@@ -1208,8 +1144,11 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + * seconds after the final nfsd_file_put() in case the caller + * wants to re-use it. + * +- * Returns nfs_ok and sets @pnf on success; otherwise an nfsstat in +- * network byte order is returned. ++ * Return values: ++ * %nfs_ok - @pnf points to an nfsd_file with its reference ++ * count boosted. ++ * ++ * On error, an nfsstat value in network byte order is returned. + */ + __be32 + nfsd_file_acquire_gc(struct svc_rqst *rqstp, struct svc_fh *fhp, +@@ -1229,8 +1168,11 @@ nfsd_file_acquire_gc(struct svc_rqst *rqstp, struct svc_fh *fhp, + * but not garbage-collected. The object is unhashed after the + * final nfsd_file_put(). + * +- * Returns nfs_ok and sets @pnf on success; otherwise an nfsstat in +- * network byte order is returned. ++ * Return values: ++ * %nfs_ok - @pnf points to an nfsd_file with its reference ++ * count boosted. ++ * ++ * On error, an nfsstat value in network byte order is returned. + */ + __be32 + nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, +@@ -1251,8 +1193,11 @@ nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + * and @file is non-NULL, use it to instantiate a new nfsd_file instead of + * opening a new one. + * +- * Returns nfs_ok and sets @pnf on success; otherwise an nfsstat in +- * network byte order is returned. ++ * Return values: ++ * %nfs_ok - @pnf points to an nfsd_file with its reference ++ * count boosted. ++ * ++ * On error, an nfsstat value in network byte order is returned. + */ + __be32 + nfsd_file_acquire_opened(struct svc_rqst *rqstp, struct svc_fh *fhp, +@@ -1283,7 +1228,7 @@ int nfsd_file_cache_stats_show(struct seq_file *m, void *v) + lru = list_lru_count(&nfsd_file_lru); + + rcu_read_lock(); +- ht = &nfsd_file_rhash_tbl; ++ ht = &nfsd_file_rhltable.ht; + count = atomic_read(&ht->nelems); + tbl = rht_dereference_rcu(ht->tbl, ht); + buckets = tbl->size; +@@ -1299,7 +1244,7 @@ int nfsd_file_cache_stats_show(struct seq_file *m, void *v) + evictions += per_cpu(nfsd_file_evictions, i); + } + +- seq_printf(m, "total entries: %u\n", count); ++ seq_printf(m, "total inodes: %u\n", count); + seq_printf(m, "hash buckets: %u\n", buckets); + seq_printf(m, "lru entries: %lu\n", lru); + seq_printf(m, "cache hits: %lu\n", hits); +diff --git a/fs/nfsd/filecache.h b/fs/nfsd/filecache.h +index 41516a4263ea5..e54165a3224f0 100644 +--- a/fs/nfsd/filecache.h ++++ b/fs/nfsd/filecache.h +@@ -29,9 +29,8 @@ struct nfsd_file_mark { + * never be dereferenced, only used for comparison. + */ + struct nfsd_file { +- struct rhash_head nf_rhash; +- struct list_head nf_lru; +- struct rcu_head nf_rcu; ++ struct rhlist_head nf_rlist; ++ void *nf_inode; + struct file *nf_file; + const struct cred *nf_cred; + struct net *nf_net; +@@ -40,10 +39,12 @@ struct nfsd_file { + #define NFSD_FILE_REFERENCED (2) + #define NFSD_FILE_GC (3) + unsigned long nf_flags; +- struct inode *nf_inode; /* don't deref */ + refcount_t nf_ref; + unsigned char nf_may; ++ + struct nfsd_file_mark *nf_mark; ++ struct list_head nf_lru; ++ struct rcu_head nf_rcu; + ktime_t nf_birthtime; + }; + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-convert-the-filecache-to-use-rhashtable.patch b/queue-5.10/nfsd-convert-the-filecache-to-use-rhashtable.patch new file mode 100644 index 00000000000..9715581337b --- /dev/null +++ b/queue-5.10/nfsd-convert-the-filecache-to-use-rhashtable.patch @@ -0,0 +1,545 @@ +From f892035fa0fc6f697c91b13e1e2d6cf97b4e6b0e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 Jul 2022 14:26:30 -0400 +Subject: NFSD: Convert the filecache to use rhashtable + +From: Chuck Lever + +[ Upstream commit ce502f81ba884c1fe45dc0ebddbcaaa4ec0fc5fb ] + +Enable the filecache hash table to start small, then grow with the +workload. Smaller server deployments benefit because there should +be lower memory utilization. Larger server deployments should see +improved scaling with the number of open files. + +Suggested-by: Jeff Layton +Suggested-by: Dave Chinner +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 265 +++++++++++++++++++------------------------- + fs/nfsd/trace.h | 63 ++++++++++- + 2 files changed, 179 insertions(+), 149 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index 95e7e15b567e2..45dd4f3fa0905 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -61,7 +61,6 @@ static struct nfsd_fcache_bucket *nfsd_file_hashtbl; + static struct list_lru nfsd_file_lru; + static unsigned long nfsd_file_flags; + static struct fsnotify_group *nfsd_file_fsnotify_group; +-static atomic_long_t nfsd_filecache_count; + static struct delayed_work nfsd_filecache_laundrette; + static struct rhashtable nfsd_file_rhash_tbl + ____cacheline_aligned_in_smp; +@@ -197,7 +196,7 @@ static const struct rhashtable_params nfsd_file_rhash_params = { + static void + nfsd_file_schedule_laundrette(void) + { +- if ((atomic_long_read(&nfsd_filecache_count) == 0) || ++ if ((atomic_read(&nfsd_file_rhash_tbl.nelems) == 0) || + test_bit(NFSD_FILE_CACHE_UP, &nfsd_file_flags) == 0) + return; + +@@ -297,7 +296,7 @@ nfsd_file_mark_find_or_create(struct nfsd_file *nf) + } + + static struct nfsd_file * +-nfsd_file_alloc(struct inode *inode, unsigned int may, struct net *net) ++nfsd_file_alloc(struct nfsd_file_lookup_key *key, unsigned int may) + { + struct nfsd_file *nf; + +@@ -308,11 +307,14 @@ nfsd_file_alloc(struct inode *inode, unsigned int may, struct net *net) + nf->nf_birthtime = ktime_get(); + nf->nf_file = NULL; + nf->nf_cred = get_current_cred(); +- nf->nf_net = net; ++ nf->nf_net = key->net; + nf->nf_flags = 0; +- nf->nf_inode = inode; +- refcount_set(&nf->nf_ref, 1); +- nf->nf_may = may & NFSD_FILE_MAY_MASK; ++ __set_bit(NFSD_FILE_HASHED, &nf->nf_flags); ++ __set_bit(NFSD_FILE_PENDING, &nf->nf_flags); ++ nf->nf_inode = key->inode; ++ /* nf_ref is pre-incremented for hash table */ ++ refcount_set(&nf->nf_ref, 2); ++ nf->nf_may = key->need; + nf->nf_mark = NULL; + trace_nfsd_file_alloc(nf); + } +@@ -398,40 +400,21 @@ static void nfsd_file_lru_remove(struct nfsd_file *nf) + } + + static void +-nfsd_file_do_unhash(struct nfsd_file *nf) ++nfsd_file_hash_remove(struct nfsd_file *nf) + { +- struct inode *inode = nf->nf_inode; +- unsigned int hashval = (unsigned int)hash_long(inode->i_ino, +- NFSD_FILE_HASH_BITS); +- +- lockdep_assert_held(&nfsd_file_hashtbl[hashval].nfb_lock); +- + trace_nfsd_file_unhash(nf); + + if (nfsd_file_check_write_error(nf)) + nfsd_reset_write_verifier(net_generic(nf->nf_net, nfsd_net_id)); +- --nfsd_file_hashtbl[hashval].nfb_count; +- hlist_del_rcu(&nf->nf_node); +- atomic_long_dec(&nfsd_filecache_count); +-} +- +-static void +-nfsd_file_hash_remove(struct nfsd_file *nf) +-{ +- struct inode *inode = nf->nf_inode; +- unsigned int hashval = (unsigned int)hash_long(inode->i_ino, +- NFSD_FILE_HASH_BITS); +- +- spin_lock(&nfsd_file_hashtbl[hashval].nfb_lock); +- nfsd_file_do_unhash(nf); +- spin_unlock(&nfsd_file_hashtbl[hashval].nfb_lock); ++ rhashtable_remove_fast(&nfsd_file_rhash_tbl, &nf->nf_rhash, ++ nfsd_file_rhash_params); + } + + static bool + nfsd_file_unhash(struct nfsd_file *nf) + { + if (test_and_clear_bit(NFSD_FILE_HASHED, &nf->nf_flags)) { +- nfsd_file_do_unhash(nf); ++ nfsd_file_hash_remove(nf); + return true; + } + return false; +@@ -441,9 +424,9 @@ nfsd_file_unhash(struct nfsd_file *nf) + * Return true if the file was unhashed. + */ + static bool +-nfsd_file_unhash_and_release_locked(struct nfsd_file *nf, struct list_head *dispose) ++nfsd_file_unhash_and_dispose(struct nfsd_file *nf, struct list_head *dispose) + { +- trace_nfsd_file_unhash_and_release_locked(nf); ++ trace_nfsd_file_unhash_and_dispose(nf); + if (!nfsd_file_unhash(nf)) + return false; + /* keep final reference for nfsd_file_lru_dispose */ +@@ -702,20 +685,23 @@ static struct shrinker nfsd_file_shrinker = { + static unsigned int + __nfsd_file_close_inode(struct inode *inode, struct list_head *dispose) + { +- unsigned int hashval = (unsigned int)hash_long(inode->i_ino, +- NFSD_FILE_HASH_BITS); +- unsigned int count = 0; +- struct nfsd_file *nf; +- struct hlist_node *tmp; +- +- spin_lock(&nfsd_file_hashtbl[hashval].nfb_lock); +- hlist_for_each_entry_safe(nf, tmp, &nfsd_file_hashtbl[hashval].nfb_head, nf_node) { +- if (inode == nf->nf_inode) { +- nfsd_file_unhash_and_release_locked(nf, dispose); +- count++; +- } +- } +- spin_unlock(&nfsd_file_hashtbl[hashval].nfb_lock); ++ struct nfsd_file_lookup_key key = { ++ .type = NFSD_FILE_KEY_INODE, ++ .inode = inode, ++ }; ++ unsigned int count = 0; ++ struct nfsd_file *nf; ++ ++ rcu_read_lock(); ++ do { ++ nf = rhashtable_lookup(&nfsd_file_rhash_tbl, &key, ++ nfsd_file_rhash_params); ++ if (!nf) ++ break; ++ nfsd_file_unhash_and_dispose(nf, dispose); ++ count++; ++ } while (1); ++ rcu_read_unlock(); + return count; + } + +@@ -923,30 +909,35 @@ nfsd_file_cache_init(void) + static void + __nfsd_file_cache_purge(struct net *net) + { +- unsigned int i; +- struct nfsd_file *nf; +- struct hlist_node *next; ++ struct rhashtable_iter iter; ++ struct nfsd_file *nf; + LIST_HEAD(dispose); + bool del; + +- for (i = 0; i < NFSD_FILE_HASH_SIZE; i++) { +- struct nfsd_fcache_bucket *nfb = &nfsd_file_hashtbl[i]; ++ rhashtable_walk_enter(&nfsd_file_rhash_tbl, &iter); ++ do { ++ rhashtable_walk_start(&iter); + +- spin_lock(&nfb->nfb_lock); +- hlist_for_each_entry_safe(nf, next, &nfb->nfb_head, nf_node) { ++ nf = rhashtable_walk_next(&iter); ++ while (!IS_ERR_OR_NULL(nf)) { + if (net && nf->nf_net != net) + continue; +- del = nfsd_file_unhash_and_release_locked(nf, &dispose); ++ del = nfsd_file_unhash_and_dispose(nf, &dispose); + + /* + * Deadlock detected! Something marked this entry as + * unhased, but hasn't removed it from the hash list. + */ + WARN_ON_ONCE(!del); ++ ++ nf = rhashtable_walk_next(&iter); + } +- spin_unlock(&nfb->nfb_lock); +- nfsd_file_dispose_list(&dispose); +- } ++ ++ rhashtable_walk_stop(&iter); ++ } while (nf == ERR_PTR(-EAGAIN)); ++ rhashtable_walk_exit(&iter); ++ ++ nfsd_file_dispose_list(&dispose); + } + + static struct nfsd_fcache_disposal * +@@ -1051,56 +1042,29 @@ nfsd_file_cache_shutdown(void) + } + } + +-static struct nfsd_file * +-nfsd_file_find_locked(struct inode *inode, unsigned int may_flags, +- unsigned int hashval, struct net *net) +-{ +- struct nfsd_file *nf; +- unsigned char need = may_flags & NFSD_FILE_MAY_MASK; +- +- hlist_for_each_entry_rcu(nf, &nfsd_file_hashtbl[hashval].nfb_head, +- nf_node, lockdep_is_held(&nfsd_file_hashtbl[hashval].nfb_lock)) { +- if (nf->nf_may != need) +- continue; +- if (nf->nf_inode != inode) +- continue; +- if (nf->nf_net != net) +- continue; +- if (!nfsd_match_cred(nf->nf_cred, current_cred())) +- continue; +- if (!test_bit(NFSD_FILE_HASHED, &nf->nf_flags)) +- continue; +- if (nfsd_file_get(nf) != NULL) +- return nf; +- } +- return NULL; +-} +- + /** +- * nfsd_file_is_cached - are there any cached open files for this fh? +- * @inode: inode of the file to check ++ * nfsd_file_is_cached - are there any cached open files for this inode? ++ * @inode: inode to check ++ * ++ * The lookup matches inodes in all net namespaces and is atomic wrt ++ * nfsd_file_acquire(). + * +- * Scan the hashtable for open files that match this fh. Returns true if there +- * are any, and false if not. ++ * Return values: ++ * %true: filecache contains at least one file matching this inode ++ * %false: filecache contains no files matching this inode + */ + bool + nfsd_file_is_cached(struct inode *inode) + { +- bool ret = false; +- struct nfsd_file *nf; +- unsigned int hashval; +- +- hashval = (unsigned int)hash_long(inode->i_ino, NFSD_FILE_HASH_BITS); +- +- rcu_read_lock(); +- hlist_for_each_entry_rcu(nf, &nfsd_file_hashtbl[hashval].nfb_head, +- nf_node) { +- if (inode == nf->nf_inode) { +- ret = true; +- break; +- } +- } +- rcu_read_unlock(); ++ struct nfsd_file_lookup_key key = { ++ .type = NFSD_FILE_KEY_INODE, ++ .inode = inode, ++ }; ++ bool ret = false; ++ ++ if (rhashtable_lookup_fast(&nfsd_file_rhash_tbl, &key, ++ nfsd_file_rhash_params) != NULL) ++ ret = true; + trace_nfsd_file_is_cached(inode, (int)ret); + return ret; + } +@@ -1109,39 +1073,51 @@ static __be32 + nfsd_do_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + unsigned int may_flags, struct nfsd_file **pnf, bool open) + { +- __be32 status; +- struct net *net = SVC_NET(rqstp); ++ struct nfsd_file_lookup_key key = { ++ .type = NFSD_FILE_KEY_FULL, ++ .need = may_flags & NFSD_FILE_MAY_MASK, ++ .net = SVC_NET(rqstp), ++ }; + struct nfsd_file *nf, *new; +- struct inode *inode; +- unsigned int hashval; + bool retry = true; ++ __be32 status; + +- /* FIXME: skip this if fh_dentry is already set? */ + status = fh_verify(rqstp, fhp, S_IFREG, + may_flags|NFSD_MAY_OWNER_OVERRIDE); + if (status != nfs_ok) + return status; ++ key.inode = d_inode(fhp->fh_dentry); ++ key.cred = get_current_cred(); + +- inode = d_inode(fhp->fh_dentry); +- hashval = (unsigned int)hash_long(inode->i_ino, NFSD_FILE_HASH_BITS); + retry: +- rcu_read_lock(); +- nf = nfsd_file_find_locked(inode, may_flags, hashval, net); +- rcu_read_unlock(); ++ /* Avoid allocation if the item is already in cache */ ++ nf = rhashtable_lookup_fast(&nfsd_file_rhash_tbl, &key, ++ nfsd_file_rhash_params); ++ if (nf) ++ nf = nfsd_file_get(nf); + if (nf) + goto wait_for_construction; + +- new = nfsd_file_alloc(inode, may_flags, net); ++ new = nfsd_file_alloc(&key, may_flags); + if (!new) { + status = nfserr_jukebox; + goto out_status; + } + +- spin_lock(&nfsd_file_hashtbl[hashval].nfb_lock); +- nf = nfsd_file_find_locked(inode, may_flags, hashval, net); +- if (nf == NULL) ++ nf = rhashtable_lookup_get_insert_key(&nfsd_file_rhash_tbl, ++ &key, &new->nf_rhash, ++ nfsd_file_rhash_params); ++ if (!nf) { ++ nf = new; ++ goto open_file; ++ } ++ if (IS_ERR(nf)) ++ goto insert_err; ++ nf = nfsd_file_get(nf); ++ if (nf == NULL) { ++ nf = new; + goto open_file; +- spin_unlock(&nfsd_file_hashtbl[hashval].nfb_lock); ++ } + nfsd_file_slab_free(&new->nf_rcu); + + wait_for_construction: +@@ -1149,6 +1125,7 @@ nfsd_do_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + + /* Did construction of this file fail? */ + if (!test_bit(NFSD_FILE_HASHED, &nf->nf_flags)) { ++ trace_nfsd_file_cons_err(rqstp, key.inode, may_flags, nf); + if (!retry) { + status = nfserr_jukebox; + goto out; +@@ -1173,22 +1150,11 @@ nfsd_do_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + } + + out_status: +- trace_nfsd_file_acquire(rqstp, inode, may_flags, nf, status); ++ put_cred(key.cred); ++ trace_nfsd_file_acquire(rqstp, key.inode, may_flags, nf, status); + return status; + + open_file: +- nf = new; +- /* Take reference for the hashtable */ +- refcount_inc(&nf->nf_ref); +- __set_bit(NFSD_FILE_HASHED, &nf->nf_flags); +- __set_bit(NFSD_FILE_PENDING, &nf->nf_flags); +- hlist_add_head_rcu(&nf->nf_node, &nfsd_file_hashtbl[hashval].nfb_head); +- ++nfsd_file_hashtbl[hashval].nfb_count; +- nfsd_file_hashtbl[hashval].nfb_maxcount = max(nfsd_file_hashtbl[hashval].nfb_maxcount, +- nfsd_file_hashtbl[hashval].nfb_count); +- spin_unlock(&nfsd_file_hashtbl[hashval].nfb_lock); +- atomic_long_inc(&nfsd_filecache_count); +- + nf->nf_mark = nfsd_file_mark_find_or_create(nf); + if (nf->nf_mark) { + if (open) { +@@ -1203,19 +1169,20 @@ nfsd_do_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + * If construction failed, or we raced with a call to unlink() + * then unhash. + */ +- if (status != nfs_ok || inode->i_nlink == 0) { +- bool do_free; +- nfsd_file_lru_remove(nf); +- spin_lock(&nfsd_file_hashtbl[hashval].nfb_lock); +- do_free = nfsd_file_unhash(nf); +- spin_unlock(&nfsd_file_hashtbl[hashval].nfb_lock); +- if (do_free) ++ if (status != nfs_ok || key.inode->i_nlink == 0) ++ if (nfsd_file_unhash(nf)) + nfsd_file_put_noref(nf); +- } + clear_bit_unlock(NFSD_FILE_PENDING, &nf->nf_flags); + smp_mb__after_atomic(); + wake_up_bit(&nf->nf_flags, NFSD_FILE_PENDING); + goto out; ++ ++insert_err: ++ nfsd_file_slab_free(&new->nf_rcu); ++ trace_nfsd_file_insert_err(rqstp, key.inode, may_flags, PTR_ERR(nf)); ++ nf = NULL; ++ status = nfserr_jukebox; ++ goto out_status; + } + + /** +@@ -1261,21 +1228,23 @@ static int nfsd_file_cache_stats_show(struct seq_file *m, void *v) + { + unsigned long releases = 0, pages_flushed = 0, evictions = 0; + unsigned long hits = 0, acquisitions = 0; +- unsigned int i, count = 0, longest = 0; ++ unsigned int i, count = 0, buckets = 0; + unsigned long lru = 0, total_age = 0; + +- /* +- * No need for spinlocks here since we're not terribly interested in +- * accuracy. We do take the nfsd_mutex simply to ensure that we +- * don't end up racing with server shutdown +- */ ++ /* Serialize with server shutdown */ + mutex_lock(&nfsd_mutex); + if (test_bit(NFSD_FILE_CACHE_UP, &nfsd_file_flags) == 1) { +- for (i = 0; i < NFSD_FILE_HASH_SIZE; i++) { +- count += nfsd_file_hashtbl[i].nfb_count; +- longest = max(longest, nfsd_file_hashtbl[i].nfb_count); +- } ++ struct bucket_table *tbl; ++ struct rhashtable *ht; ++ + lru = list_lru_count(&nfsd_file_lru); ++ ++ rcu_read_lock(); ++ ht = &nfsd_file_rhash_tbl; ++ count = atomic_read(&ht->nelems); ++ tbl = rht_dereference_rcu(ht->tbl, ht); ++ buckets = tbl->size; ++ rcu_read_unlock(); + } + mutex_unlock(&nfsd_mutex); + +@@ -1289,7 +1258,7 @@ static int nfsd_file_cache_stats_show(struct seq_file *m, void *v) + } + + seq_printf(m, "total entries: %u\n", count); +- seq_printf(m, "longest chain: %u\n", longest); ++ seq_printf(m, "hash buckets: %u\n", buckets); + seq_printf(m, "lru entries: %lu\n", lru); + seq_printf(m, "cache hits: %lu\n", hits); + seq_printf(m, "acquisitions: %lu\n", acquisitions); +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index f170f07ec0fd2..33bd8618c20a6 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -743,7 +743,7 @@ DEFINE_NFSD_FILE_EVENT(nfsd_file_alloc); + DEFINE_NFSD_FILE_EVENT(nfsd_file_put_final); + DEFINE_NFSD_FILE_EVENT(nfsd_file_unhash); + DEFINE_NFSD_FILE_EVENT(nfsd_file_put); +-DEFINE_NFSD_FILE_EVENT(nfsd_file_unhash_and_release_locked); ++DEFINE_NFSD_FILE_EVENT(nfsd_file_unhash_and_dispose); + + TRACE_EVENT(nfsd_file_acquire, + TP_PROTO( +@@ -786,6 +786,67 @@ TRACE_EVENT(nfsd_file_acquire, + __entry->nf_file, __entry->status) + ); + ++TRACE_EVENT(nfsd_file_insert_err, ++ TP_PROTO( ++ const struct svc_rqst *rqstp, ++ const struct inode *inode, ++ unsigned int may_flags, ++ long error ++ ), ++ TP_ARGS(rqstp, inode, may_flags, error), ++ TP_STRUCT__entry( ++ __field(u32, xid) ++ __field(const void *, inode) ++ __field(unsigned long, may_flags) ++ __field(long, error) ++ ), ++ TP_fast_assign( ++ __entry->xid = be32_to_cpu(rqstp->rq_xid); ++ __entry->inode = inode; ++ __entry->may_flags = may_flags; ++ __entry->error = error; ++ ), ++ TP_printk("xid=0x%x inode=%p may_flags=%s error=%ld", ++ __entry->xid, __entry->inode, ++ show_nfsd_may_flags(__entry->may_flags), ++ __entry->error ++ ) ++); ++ ++TRACE_EVENT(nfsd_file_cons_err, ++ TP_PROTO( ++ const struct svc_rqst *rqstp, ++ const struct inode *inode, ++ unsigned int may_flags, ++ const struct nfsd_file *nf ++ ), ++ TP_ARGS(rqstp, inode, may_flags, nf), ++ TP_STRUCT__entry( ++ __field(u32, xid) ++ __field(const void *, inode) ++ __field(unsigned long, may_flags) ++ __field(unsigned int, nf_ref) ++ __field(unsigned long, nf_flags) ++ __field(unsigned long, nf_may) ++ __field(const void *, nf_file) ++ ), ++ TP_fast_assign( ++ __entry->xid = be32_to_cpu(rqstp->rq_xid); ++ __entry->inode = inode; ++ __entry->may_flags = may_flags; ++ __entry->nf_ref = refcount_read(&nf->nf_ref); ++ __entry->nf_flags = nf->nf_flags; ++ __entry->nf_may = nf->nf_may; ++ __entry->nf_file = nf->nf_file; ++ ), ++ TP_printk("xid=0x%x inode=%p may_flags=%s ref=%u nf_flags=%s nf_may=%s nf_file=%p", ++ __entry->xid, __entry->inode, ++ show_nfsd_may_flags(__entry->may_flags), __entry->nf_ref, ++ show_nf_flags(__entry->nf_flags), ++ show_nfsd_may_flags(__entry->nf_may), __entry->nf_file ++ ) ++); ++ + TRACE_EVENT(nfsd_file_open, + TP_PROTO(struct nfsd_file *nf, __be32 status), + TP_ARGS(nf, status), +-- +2.43.0 + diff --git a/queue-5.10/nfsd-copy-the-whole-verifier-in-nfsd_copy_write_veri.patch b/queue-5.10/nfsd-copy-the-whole-verifier-in-nfsd_copy_write_veri.patch new file mode 100644 index 00000000000..3aa36dce014 --- /dev/null +++ b/queue-5.10/nfsd-copy-the-whole-verifier-in-nfsd_copy_write_veri.patch @@ -0,0 +1,36 @@ +From 839aaea0e5e5e7f8e179005fd0cbde8f9fa11b78 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 14 Feb 2023 10:07:59 -0500 +Subject: NFSD: copy the whole verifier in nfsd_copy_write_verifier + +From: Chuck Lever + +[ Upstream commit 90d2175572470ba7f55da8447c72ddd4942923c4 ] + +Currently, we're only memcpy'ing the first __be32. Ensure we copy into +both words. + +Fixes: 91d2e9b56cf5 ("NFSD: Clean up the nfsd_net::nfssvc_boot field") +Reported-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfssvc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c +index 325d3d3f12110..a0ecec54d3d7d 100644 +--- a/fs/nfsd/nfssvc.c ++++ b/fs/nfsd/nfssvc.c +@@ -363,7 +363,7 @@ void nfsd_copy_write_verifier(__be32 verf[2], struct nfsd_net *nn) + + do { + read_seqbegin_or_lock(&nn->writeverf_lock, &seq); +- memcpy(verf, nn->writeverf, sizeof(*verf)); ++ memcpy(verf, nn->writeverf, sizeof(nn->writeverf)); + } while (need_seqretry(&nn->writeverf_lock, seq)); + done_seqretry(&nn->writeverf_lock, seq); + } +-- +2.43.0 + diff --git a/queue-5.10/nfsd-copy-with-length-0-should-copy-to-end-of-file.patch b/queue-5.10/nfsd-copy-with-length-0-should-copy-to-end-of-file.patch new file mode 100644 index 00000000000..4776b578395 --- /dev/null +++ b/queue-5.10/nfsd-copy-with-length-0-should-copy-to-end-of-file.patch @@ -0,0 +1,39 @@ +From a91173819ee1e4f198ca81e18558f39c74176b9f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Mar 2021 20:03:23 -0400 +Subject: nfsd: COPY with length 0 should copy to end of file + +From: J. Bruce Fields + +[ Upstream commit 792a5112aa90e59c048b601c6382fe3498d75db7 ] + +>From https://tools.ietf.org/html/rfc7862#page-65 + + A count of 0 (zero) requests that all bytes from ca_src_offset + through EOF be copied to the destination. + +Reported-by: +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 2fba0808d975c..949d9cedef5d1 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -1380,6 +1380,9 @@ static ssize_t _nfsd_copy_file_range(struct nfsd4_copy *copy) + u64 src_pos = copy->cp_src_pos; + u64 dst_pos = copy->cp_dst_pos; + ++ /* See RFC 7862 p.67: */ ++ if (bytes_total == 0) ++ bytes_total = ULLONG_MAX; + do { + if (kthread_should_stop()) + break; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-count-bytes-instead-of-pages-in-the-nfsv2-readd.patch b/queue-5.10/nfsd-count-bytes-instead-of-pages-in-the-nfsv2-readd.patch new file mode 100644 index 00000000000..0541c1a6d3e --- /dev/null +++ b/queue-5.10/nfsd-count-bytes-instead-of-pages-in-the-nfsv2-readd.patch @@ -0,0 +1,72 @@ +From 206a632e7cd061b83292c406c3c2d4e2ac38f5ea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Nov 2020 16:57:44 -0500 +Subject: NFSD: Count bytes instead of pages in the NFSv2 READDIR encoder + +From: Chuck Lever + +[ Upstream commit 8141d6a2bb6c655ff0c0b81ced80d9025f03e926 ] + +Clean up: Counting the bytes used by each returned directory entry +seems less brittle to me than trying to measure consumed pages after +the fact. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsproc.c | 4 ---- + fs/nfsd/nfsxdr.c | 3 ++- + 2 files changed, 2 insertions(+), 5 deletions(-) + +diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c +index 2d3d7cdffd52f..23b2a900cb79d 100644 +--- a/fs/nfsd/nfsproc.c ++++ b/fs/nfsd/nfsproc.c +@@ -578,14 +578,12 @@ nfsd_proc_readdir(struct svc_rqst *rqstp) + struct nfsd_readdirargs *argp = rqstp->rq_argp; + struct nfsd_readdirres *resp = rqstp->rq_resp; + loff_t offset; +- __be32 *buffer; + + dprintk("nfsd: READDIR %s %d bytes at %d\n", + SVCFH_fmt(&argp->fh), + argp->count, argp->cookie); + + nfsd_init_dirlist_pages(rqstp, resp, argp->count); +- buffer = resp->buffer; + + resp->offset = NULL; + resp->common.err = nfs_ok; +@@ -593,8 +591,6 @@ nfsd_proc_readdir(struct svc_rqst *rqstp) + offset = argp->cookie; + resp->status = nfsd_readdir(rqstp, &argp->fh, &offset, + &resp->common, nfssvc_encode_entry); +- +- resp->count = resp->buffer - buffer; + nfssvc_encode_nfscookie(resp, offset); + + fh_put(&argp->fh); +diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c +index a87b21cfe0d03..8ae23ed6dc5db 100644 +--- a/fs/nfsd/nfsxdr.c ++++ b/fs/nfsd/nfsxdr.c +@@ -584,7 +584,7 @@ nfssvc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p) + p = resp->buffer; + *p++ = 0; /* no more entries */ + *p++ = htonl((resp->common.err == nfserr_eof)); +- rqstp->rq_res.page_len = (((unsigned long)p-1) & ~PAGE_MASK)+1; ++ rqstp->rq_res.page_len = resp->count << 2; + + return 1; + } +@@ -667,6 +667,7 @@ nfssvc_encode_entry(void *ccdv, const char *name, + cd->offset = p; /* remember pointer */ + *p++ = htonl(~0U); /* offset of next entry */ + ++ cd->count += p - cd->buffer; + cd->buflen = buflen; + cd->buffer = p; + cd->common.err = nfs_ok; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-count-bytes-instead-of-pages-in-the-nfsv3-readd.patch b/queue-5.10/nfsd-count-bytes-instead-of-pages-in-the-nfsv3-readd.patch new file mode 100644 index 00000000000..62c41e69a08 --- /dev/null +++ b/queue-5.10/nfsd-count-bytes-instead-of-pages-in-the-nfsv3-readd.patch @@ -0,0 +1,114 @@ +From de10563cde72e8c01bf459b39f5ce9c2255d8cfa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 9 Nov 2020 13:13:21 -0500 +Subject: NFSD: Count bytes instead of pages in the NFSv3 READDIR encoder + +From: Chuck Lever + +[ Upstream commit a1409e2de4f11034c8eb30775cc3e37039a4ef13 ] + +Clean up: Counting the bytes used by each returned directory entry +seems less brittle to me than trying to measure consumed pages after +the fact. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3proc.c | 31 ++----------------------------- + fs/nfsd/nfs3xdr.c | 1 + + 2 files changed, 3 insertions(+), 29 deletions(-) + +diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c +index acb0a2d37dcbb..7dcc7abb1f346 100644 +--- a/fs/nfsd/nfs3proc.c ++++ b/fs/nfsd/nfs3proc.c +@@ -467,10 +467,7 @@ nfsd3_proc_readdir(struct svc_rqst *rqstp) + { + struct nfsd3_readdirargs *argp = rqstp->rq_argp; + struct nfsd3_readdirres *resp = rqstp->rq_resp; +- int count = 0; + loff_t offset; +- struct page **p; +- caddr_t page_addr = NULL; + + dprintk("nfsd: READDIR(3) %s %d bytes at %d\n", + SVCFH_fmt(&argp->fh), +@@ -481,6 +478,7 @@ nfsd3_proc_readdir(struct svc_rqst *rqstp) + /* Read directory and encode entries on the fly */ + fh_copy(&resp->fh, &argp->fh); + ++ resp->count = 0; + resp->common.err = nfs_ok; + resp->rqstp = rqstp; + offset = argp->cookie; +@@ -488,18 +486,6 @@ nfsd3_proc_readdir(struct svc_rqst *rqstp) + resp->status = nfsd_readdir(rqstp, &resp->fh, &offset, + &resp->common, nfs3svc_encode_entry); + memcpy(resp->verf, argp->verf, 8); +- count = 0; +- for (p = rqstp->rq_respages + 1; p < rqstp->rq_next_page; p++) { +- page_addr = page_address(*p); +- +- if (((caddr_t)resp->buffer >= page_addr) && +- ((caddr_t)resp->buffer < page_addr + PAGE_SIZE)) { +- count += (caddr_t)resp->buffer - page_addr; +- break; +- } +- count += PAGE_SIZE; +- } +- resp->count = count >> 2; + nfs3svc_encode_cookie3(resp, offset); + + return rpc_success; +@@ -514,10 +500,7 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp) + { + struct nfsd3_readdirargs *argp = rqstp->rq_argp; + struct nfsd3_readdirres *resp = rqstp->rq_resp; +- int count = 0; + loff_t offset; +- struct page **p; +- caddr_t page_addr = NULL; + + dprintk("nfsd: READDIR+(3) %s %d bytes at %d\n", + SVCFH_fmt(&argp->fh), +@@ -528,6 +511,7 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp) + /* Read directory and encode entries on the fly */ + fh_copy(&resp->fh, &argp->fh); + ++ resp->count = 0; + resp->common.err = nfs_ok; + resp->rqstp = rqstp; + offset = argp->cookie; +@@ -544,17 +528,6 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp) + resp->status = nfsd_readdir(rqstp, &resp->fh, &offset, + &resp->common, nfs3svc_encode_entry_plus); + memcpy(resp->verf, argp->verf, 8); +- for (p = rqstp->rq_respages + 1; p < rqstp->rq_next_page; p++) { +- page_addr = page_address(*p); +- +- if (((caddr_t)resp->buffer >= page_addr) && +- ((caddr_t)resp->buffer < page_addr + PAGE_SIZE)) { +- count += (caddr_t)resp->buffer - page_addr; +- break; +- } +- count += PAGE_SIZE; +- } +- resp->count = count >> 2; + nfs3svc_encode_cookie3(resp, offset); + + out: +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index e334a1454edbb..523b2dca04944 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -1364,6 +1364,7 @@ encode_entry(struct readdir_cd *ccd, const char *name, int namlen, + return -EINVAL; + } + ++ cd->count += num_entry_words; + cd->buflen -= num_entry_words; + cd->buffer = p; + cd->common.err = nfs_ok; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-cstate-session-se_client-cstate-clp.patch b/queue-5.10/nfsd-cstate-session-se_client-cstate-clp.patch new file mode 100644 index 00000000000..61336945559 --- /dev/null +++ b/queue-5.10/nfsd-cstate-session-se_client-cstate-clp.patch @@ -0,0 +1,110 @@ +From bee476687a05f770473395d7707f1a0ab06dd64c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 Jan 2021 17:57:45 -0500 +Subject: nfsd: cstate->session->se_client -> cstate->clp + +From: J. Bruce Fields + +[ Upstream commit ec59659b4972ec25851aa03b4b5baba6764a62e4 ] + +I'm not sure why we're writing this out the hard way in so many places. + +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 5 ++--- + fs/nfsd/nfs4state.c | 16 ++++++++-------- + 2 files changed, 10 insertions(+), 11 deletions(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 5d304b51914a2..0acf7af9aab8f 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -378,8 +378,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + * Before RECLAIM_COMPLETE done, server should deny new lock + */ + if (nfsd4_has_session(cstate) && +- !test_bit(NFSD4_CLIENT_RECLAIM_COMPLETE, +- &cstate->session->se_client->cl_flags) && ++ !test_bit(NFSD4_CLIENT_RECLAIM_COMPLETE, &cstate->clp->cl_flags) && + open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS) + return nfserr_grace; + +@@ -1881,7 +1880,7 @@ nfsd4_getdeviceinfo(struct svc_rqst *rqstp, + nfserr = nfs_ok; + if (gdp->gd_maxcount != 0) { + nfserr = ops->proc_getdeviceinfo(exp->ex_path.mnt->mnt_sb, +- rqstp, cstate->session->se_client, gdp); ++ rqstp, cstate->clp, gdp); + } + + gdp->gd_notify_types &= ops->notify_types; +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 4da8467a3570d..c2eba93ab5138 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -3923,6 +3923,7 @@ nfsd4_reclaim_complete(struct svc_rqst *rqstp, + struct nfsd4_compound_state *cstate, union nfsd4_op_u *u) + { + struct nfsd4_reclaim_complete *rc = &u->reclaim_complete; ++ struct nfs4_client *clp = cstate->clp; + __be32 status = 0; + + if (rc->rca_one_fs) { +@@ -3936,12 +3937,11 @@ nfsd4_reclaim_complete(struct svc_rqst *rqstp, + } + + status = nfserr_complete_already; +- if (test_and_set_bit(NFSD4_CLIENT_RECLAIM_COMPLETE, +- &cstate->session->se_client->cl_flags)) ++ if (test_and_set_bit(NFSD4_CLIENT_RECLAIM_COMPLETE, &clp->cl_flags)) + goto out; + + status = nfserr_stale_clientid; +- if (is_client_expired(cstate->session->se_client)) ++ if (is_client_expired(clp)) + /* + * The following error isn't really legal. + * But we only get here if the client just explicitly +@@ -3952,8 +3952,8 @@ nfsd4_reclaim_complete(struct svc_rqst *rqstp, + goto out; + + status = nfs_ok; +- nfsd4_client_record_create(cstate->session->se_client); +- inc_reclaim_complete(cstate->session->se_client); ++ nfsd4_client_record_create(clp); ++ inc_reclaim_complete(clp); + out: + return status; + } +@@ -5938,7 +5938,7 @@ nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + { + struct nfsd4_test_stateid *test_stateid = &u->test_stateid; + struct nfsd4_test_stateid_id *stateid; +- struct nfs4_client *cl = cstate->session->se_client; ++ struct nfs4_client *cl = cstate->clp; + + list_for_each_entry(stateid, &test_stateid->ts_stateid_list, ts_id_list) + stateid->ts_id_status = +@@ -5984,7 +5984,7 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + stateid_t *stateid = &free_stateid->fr_stateid; + struct nfs4_stid *s; + struct nfs4_delegation *dp; +- struct nfs4_client *cl = cstate->session->se_client; ++ struct nfs4_client *cl = cstate->clp; + __be32 ret = nfserr_bad_stateid; + + spin_lock(&cl->cl_lock); +@@ -6716,7 +6716,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + if (nfsd4_has_session(cstate)) + /* See rfc 5661 18.10.3: given clientid is ignored: */ + memcpy(&lock->lk_new_clientid, +- &cstate->session->se_client->cl_clientid, ++ &cstate->clp->cl_clientid, + sizeof(clientid_t)); + + /* validate and update open stateid and open seqid */ +-- +2.43.0 + diff --git a/queue-5.10/nfsd-de-duplicate-hash-bucket-indexing.patch b/queue-5.10/nfsd-de-duplicate-hash-bucket-indexing.patch new file mode 100644 index 00000000000..aee98d66a2a --- /dev/null +++ b/queue-5.10/nfsd-de-duplicate-hash-bucket-indexing.patch @@ -0,0 +1,83 @@ +From 5893a6a88d752928a2409ab0d9e987bb75401f87 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Sep 2021 19:19:57 -0400 +Subject: NFSD: De-duplicate hash bucket indexing + +From: Chuck Lever + +[ Upstream commit 378a6109dd142a678f629b740f558365150f60f9 ] + +Clean up: The details of finding the right hash bucket are exactly +the same in both nfsd_cache_lookup() and nfsd_cache_update(). + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfscache.c | 22 ++++++++++------------ + 1 file changed, 10 insertions(+), 12 deletions(-) + +diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c +index a4a69ab6ab280..f79790d367288 100644 +--- a/fs/nfsd/nfscache.c ++++ b/fs/nfsd/nfscache.c +@@ -84,12 +84,6 @@ nfsd_hashsize(unsigned int limit) + return roundup_pow_of_two(limit / TARGET_BUCKET_SIZE); + } + +-static u32 +-nfsd_cache_hash(__be32 xid, struct nfsd_net *nn) +-{ +- return hash_32((__force u32)xid, nn->maskbits); +-} +- + static struct svc_cacherep * + nfsd_reply_cache_alloc(struct svc_rqst *rqstp, __wsum csum, + struct nfsd_net *nn) +@@ -241,6 +235,14 @@ lru_put_end(struct nfsd_drc_bucket *b, struct svc_cacherep *rp) + list_move_tail(&rp->c_lru, &b->lru_head); + } + ++static noinline struct nfsd_drc_bucket * ++nfsd_cache_bucket_find(__be32 xid, struct nfsd_net *nn) ++{ ++ unsigned int hash = hash_32((__force u32)xid, nn->maskbits); ++ ++ return &nn->drc_hashtbl[hash]; ++} ++ + static long prune_bucket(struct nfsd_drc_bucket *b, struct nfsd_net *nn, + unsigned int max) + { +@@ -421,10 +423,8 @@ int nfsd_cache_lookup(struct svc_rqst *rqstp) + { + struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); + struct svc_cacherep *rp, *found; +- __be32 xid = rqstp->rq_xid; + __wsum csum; +- u32 hash = nfsd_cache_hash(xid, nn); +- struct nfsd_drc_bucket *b = &nn->drc_hashtbl[hash]; ++ struct nfsd_drc_bucket *b = nfsd_cache_bucket_find(rqstp->rq_xid, nn); + int type = rqstp->rq_cachetype; + int rtn = RC_DOIT; + +@@ -528,7 +528,6 @@ void nfsd_cache_update(struct svc_rqst *rqstp, int cachetype, __be32 *statp) + struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); + struct svc_cacherep *rp = rqstp->rq_cacherep; + struct kvec *resv = &rqstp->rq_res.head[0], *cachv; +- u32 hash; + struct nfsd_drc_bucket *b; + int len; + size_t bufsize = 0; +@@ -536,8 +535,7 @@ void nfsd_cache_update(struct svc_rqst *rqstp, int cachetype, __be32 *statp) + if (!rp) + return; + +- hash = nfsd_cache_hash(rp->c_key.k_xid, nn); +- b = &nn->drc_hashtbl[hash]; ++ b = nfsd_cache_bucket_find(rp->c_key.k_xid, nn); + + len = resv->iov_len - ((char*)statp - (char*)resv->iov_base); + len >>= 2; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-de-duplicate-net_generic-nf-nf_net-nfsd_net_id.patch b/queue-5.10/nfsd-de-duplicate-net_generic-nf-nf_net-nfsd_net_id.patch new file mode 100644 index 00000000000..9ce1a5639fd --- /dev/null +++ b/queue-5.10/nfsd-de-duplicate-net_generic-nf-nf_net-nfsd_net_id.patch @@ -0,0 +1,67 @@ +From 96395a44a13cb291ef7ccb9d78ef9837e95f0bb9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Dec 2021 14:26:03 -0500 +Subject: NFSD: De-duplicate net_generic(nf->nf_net, nfsd_net_id) + +From: Chuck Lever + +[ Upstream commit 2c445a0e72cb1fbfbdb7f9473c53556ee27c1d90 ] + +Since this pointer is used repeatedly, move it to a stack variable. + +[ cel: adjusted to apply to v5.10.y ] +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/vfs.c | 11 +++++------ + 1 file changed, 5 insertions(+), 6 deletions(-) + +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index aba9d479d0840..2e3b0bd560fcc 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -1129,6 +1129,7 @@ __be32 + nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, + loff_t offset, unsigned long count, __be32 *verf) + { ++ struct nfsd_net *nn; + struct nfsd_file *nf; + loff_t end = LLONG_MAX; + __be32 err = nfserr_inval; +@@ -1145,6 +1146,7 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, + NFSD_MAY_WRITE|NFSD_MAY_NOT_BREAK_LEASE, &nf); + if (err) + goto out; ++ nn = net_generic(nf->nf_net, nfsd_net_id); + if (EX_ISSYNC(fhp->fh_export)) { + errseq_t since = READ_ONCE(nf->nf_file->f_wb_err); + int err2; +@@ -1152,8 +1154,7 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, + err2 = vfs_fsync_range(nf->nf_file, offset, end, 0); + switch (err2) { + case 0: +- nfsd_copy_boot_verifier(verf, net_generic(nf->nf_net, +- nfsd_net_id)); ++ nfsd_copy_boot_verifier(verf, nn); + err2 = filemap_check_wb_err(nf->nf_file->f_mapping, + since); + err = nfserrno(err2); +@@ -1162,13 +1163,11 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, + err = nfserr_notsupp; + break; + default: +- nfsd_reset_boot_verifier(net_generic(nf->nf_net, +- nfsd_net_id)); ++ nfsd_reset_boot_verifier(nn); + err = nfserrno(err2); + } + } else +- nfsd_copy_boot_verifier(verf, net_generic(nf->nf_net, +- nfsd_net_id)); ++ nfsd_copy_boot_verifier(verf, nn); + + nfsd_file_put(nf); + out: +-- +2.43.0 + diff --git a/queue-5.10/nfsd-de-duplicate-net_generic-svc_net-rqstp-nfsd_net.patch b/queue-5.10/nfsd-de-duplicate-net_generic-svc_net-rqstp-nfsd_net.patch new file mode 100644 index 00000000000..04d4b13d088 --- /dev/null +++ b/queue-5.10/nfsd-de-duplicate-net_generic-svc_net-rqstp-nfsd_net.patch @@ -0,0 +1,58 @@ +From 524dd7ceac56cbf5f5fa1cc910c6da6a015c51ba Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Dec 2021 12:41:32 -0500 +Subject: NFSD: De-duplicate net_generic(SVC_NET(rqstp), nfsd_net_id) + +From: Chuck Lever + +[ Upstream commit fb7622c2dbd1aa41133a8c73e1137b833c074519 ] + +Since this pointer is used repeatedly, move it to a stack variable. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/vfs.c | 11 ++++------- + 1 file changed, 4 insertions(+), 7 deletions(-) + +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index cef8435d76a69..aba9d479d0840 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -980,6 +980,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf, + unsigned long *cnt, int stable, + __be32 *verf) + { ++ struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); + struct file *file = nf->nf_file; + struct super_block *sb = file_inode(file)->i_sb; + struct svc_export *exp; +@@ -1024,13 +1025,10 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf, + iov_iter_kvec(&iter, WRITE, vec, vlen, *cnt); + since = READ_ONCE(file->f_wb_err); + if (verf) +- nfsd_copy_boot_verifier(verf, +- net_generic(SVC_NET(rqstp), +- nfsd_net_id)); ++ nfsd_copy_boot_verifier(verf, nn); + host_err = vfs_iter_write(file, &iter, &pos, flags); + if (host_err < 0) { +- nfsd_reset_boot_verifier(net_generic(SVC_NET(rqstp), +- nfsd_net_id)); ++ nfsd_reset_boot_verifier(nn); + goto out_nfserr; + } + *cnt = host_err; +@@ -1043,8 +1041,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf, + if (stable && use_wgather) { + host_err = wait_for_concurrent_writes(file); + if (host_err < 0) +- nfsd_reset_boot_verifier(net_generic(SVC_NET(rqstp), +- nfsd_net_id)); ++ nfsd_reset_boot_verifier(nn); + } + + out_nfserr: +-- +2.43.0 + diff --git a/queue-5.10/nfsd-de-duplicate-nfsd4_decode_bitmap4.patch b/queue-5.10/nfsd-de-duplicate-nfsd4_decode_bitmap4.patch new file mode 100644 index 00000000000..187ea67c2d5 --- /dev/null +++ b/queue-5.10/nfsd-de-duplicate-nfsd4_decode_bitmap4.patch @@ -0,0 +1,51 @@ +From b796d284aaab3a0d84459cab42f90a8e60b824af Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Dec 2021 10:20:45 -0500 +Subject: NFSD: De-duplicate nfsd4_decode_bitmap4() + +From: Chuck Lever + +[ Upstream commit cd2e999c7c394ae916d8be741418b3c6c1dddea8 ] + +Clean up. Trond points out that xdr_stream_decode_uint32_array() +does the same thing as nfsd4_decode_bitmap4(). + +Suggested-by: Trond Myklebust +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 17 +++-------------- + 1 file changed, 3 insertions(+), 14 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 638a626af18dc..adf97d72bda80 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -277,21 +277,10 @@ nfsd4_decode_verifier4(struct nfsd4_compoundargs *argp, nfs4_verifier *verf) + static __be32 + nfsd4_decode_bitmap4(struct nfsd4_compoundargs *argp, u32 *bmval, u32 bmlen) + { +- u32 i, count; +- __be32 *p; +- +- if (xdr_stream_decode_u32(argp->xdr, &count) < 0) +- return nfserr_bad_xdr; +- /* request sanity */ +- if (count > 1000) +- return nfserr_bad_xdr; +- p = xdr_inline_decode(argp->xdr, count << 2); +- if (!p) +- return nfserr_bad_xdr; +- for (i = 0; i < bmlen; i++) +- bmval[i] = (i < count) ? be32_to_cpup(p++) : 0; ++ ssize_t status; + +- return nfs_ok; ++ status = xdr_stream_decode_uint32_array(argp->xdr, bmval, bmlen); ++ return status == -EBADMSG ? nfserr_bad_xdr : nfs_ok; + } + + static __be32 +-- +2.43.0 + diff --git a/queue-5.10/nfsd-decode-nfsv4-birth-time-attribute.patch b/queue-5.10/nfsd-decode-nfsv4-birth-time-attribute.patch new file mode 100644 index 00000000000..b434cb7077c --- /dev/null +++ b/queue-5.10/nfsd-decode-nfsv4-birth-time-attribute.patch @@ -0,0 +1,83 @@ +From 024bea089bc5beb867b3f176c04bfd86348d8058 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 10 Jul 2022 14:46:04 -0400 +Subject: NFSD: Decode NFSv4 birth time attribute + +From: Chuck Lever + +[ Upstream commit 5b2f3e0777da2a5dd62824bbe2fdab1d12caaf8f ] + +NFSD has advertised support for the NFSv4 time_create attribute +since commit e377a3e698fb ("nfsd: Add support for the birth time +attribute"). + +Igor Mammedov reports that Mac OS clients attempt to set the NFSv4 +birth time attribute via OPEN(CREATE) and SETATTR if the server +indicates that it supports it, but since the above commit was +merged, those attempts now fail. + +Table 5 in RFC 8881 lists the time_create attribute as one that can +be both set and retrieved, but the above commit did not add server +support for clients to provide a time_create attribute. IMO that's +a bug in our implementation of the NFSv4 protocol, which this commit +addresses. + +Whether NFSD silently ignores the new birth time or actually sets it +is another matter. I haven't found another filesystem service in the +Linux kernel that enables users or clients to modify a file's birth +time attribute. + +This commit reflects my (perhaps incorrect) understanding of whether +Linux users can set a file's birth time. NFSD will now recognize a +time_create attribute but it ignores its value. It clears the +time_create bit in the returned attribute bitmask to indicate that +the value was not used. + +Reported-by: Igor Mammedov +Fixes: e377a3e698fb ("nfsd: Add support for the birth time attribute") +Tested-by: Igor Mammedov +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 9 +++++++++ + fs/nfsd/nfsd.h | 3 ++- + 2 files changed, 11 insertions(+), 1 deletion(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 804c137fabec5..b98a24c2a753c 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -470,6 +470,15 @@ nfsd4_decode_fattr4(struct nfsd4_compoundargs *argp, u32 *bmval, u32 bmlen, + return nfserr_bad_xdr; + } + } ++ if (bmval[1] & FATTR4_WORD1_TIME_CREATE) { ++ struct timespec64 ts; ++ ++ /* No Linux filesystem supports setting this attribute. */ ++ bmval[1] &= ~FATTR4_WORD1_TIME_CREATE; ++ status = nfsd4_decode_nfstime4(argp, &ts); ++ if (status) ++ return status; ++ } + if (bmval[1] & FATTR4_WORD1_TIME_MODIFY_SET) { + u32 set_it; + +diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h +index 847b482155ae9..9a8b09afc1733 100644 +--- a/fs/nfsd/nfsd.h ++++ b/fs/nfsd/nfsd.h +@@ -465,7 +465,8 @@ static inline bool nfsd_attrs_supported(u32 minorversion, const u32 *bmval) + (FATTR4_WORD0_SIZE | FATTR4_WORD0_ACL) + #define NFSD_WRITEABLE_ATTRS_WORD1 \ + (FATTR4_WORD1_MODE | FATTR4_WORD1_OWNER | FATTR4_WORD1_OWNER_GROUP \ +- | FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_MODIFY_SET) ++ | FATTR4_WORD1_TIME_ACCESS_SET | FATTR4_WORD1_TIME_CREATE \ ++ | FATTR4_WORD1_TIME_MODIFY_SET) + #ifdef CONFIG_NFSD_V4_SECURITY_LABEL + #define MAYBE_FATTR4_WORD2_SECURITY_LABEL \ + FATTR4_WORD2_SECURITY_LABEL +-- +2.43.0 + diff --git a/queue-5.10/nfsd-delay-unmount-source-s-export-after-inter-serve.patch b/queue-5.10/nfsd-delay-unmount-source-s-export-after-inter-serve.patch new file mode 100644 index 00000000000..8ee3358abb0 --- /dev/null +++ b/queue-5.10/nfsd-delay-unmount-source-s-export-after-inter-serve.patch @@ -0,0 +1,402 @@ +From fa95c4f5b77056cb07a36ae9969c799a2d16c282 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 21 May 2021 15:09:37 -0400 +Subject: NFSD: delay unmount source's export after inter-server copy + completed. + +From: Dai Ngo + +[ Upstream commit f4e44b393389c77958f7c58bf4415032b4cda15b ] + +Currently the source's export is mounted and unmounted on every +inter-server copy operation. This patch is an enhancement to delay +the unmount of the source export for a certain period of time to +eliminate the mount and unmount overhead on subsequent copy operations. + +After a copy operation completes, a work entry is added to the +delayed unmount list with an expiration time. This list is serviced +by the laundromat thread to unmount the export of the expired entries. +Each time the export is being used again, its expiration time is +extended and the entry is re-inserted to the tail of the list. + +The unmount task and the mount operation of the copy request are +synced to make sure the export is not unmounted while it's being +used. + +Signed-off-by: Dai Ngo +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/netns.h | 6 ++ + fs/nfsd/nfs4proc.c | 135 ++++++++++++++++++++++++++++++++++++++-- + fs/nfsd/nfs4state.c | 71 +++++++++++++++++++++ + fs/nfsd/nfsd.h | 4 ++ + fs/nfsd/nfssvc.c | 3 + + include/linux/nfs_ssc.h | 14 +++++ + 6 files changed, 229 insertions(+), 4 deletions(-) + +diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h +index a75abeb1e6988..935c1028c2175 100644 +--- a/fs/nfsd/netns.h ++++ b/fs/nfsd/netns.h +@@ -176,6 +176,12 @@ struct nfsd_net { + unsigned int longest_chain_cachesize; + + struct shrinker nfsd_reply_cache_shrinker; ++ ++ /* tracking server-to-server copy mounts */ ++ spinlock_t nfsd_ssc_lock; ++ struct list_head nfsd_ssc_mount_list; ++ wait_queue_head_t nfsd_ssc_waitq; ++ + /* utsname taken from the process that starts the server */ + char nfsd_name[UNX_MAXNODENAME+1]; + }; +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index aa0da0737a3ff..573c550e7aceb 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -55,6 +55,13 @@ module_param(inter_copy_offload_enable, bool, 0644); + MODULE_PARM_DESC(inter_copy_offload_enable, + "Enable inter server to server copy offload. Default: false"); + ++#ifdef CONFIG_NFSD_V4_2_INTER_SSC ++static int nfsd4_ssc_umount_timeout = 900000; /* default to 15 mins */ ++module_param(nfsd4_ssc_umount_timeout, int, 0644); ++MODULE_PARM_DESC(nfsd4_ssc_umount_timeout, ++ "idle msecs before unmount export from source server"); ++#endif ++ + #ifdef CONFIG_NFSD_V4_SECURITY_LABEL + #include + +@@ -1168,6 +1175,81 @@ extern void nfs_sb_deactive(struct super_block *sb); + + #define NFSD42_INTERSSC_MOUNTOPS "vers=4.2,addr=%s,sec=sys" + ++/* ++ * setup a work entry in the ssc delayed unmount list. ++ */ ++static int nfsd4_ssc_setup_dul(struct nfsd_net *nn, char *ipaddr, ++ struct nfsd4_ssc_umount_item **retwork, struct vfsmount **ss_mnt) ++{ ++ struct nfsd4_ssc_umount_item *ni = 0; ++ struct nfsd4_ssc_umount_item *work = NULL; ++ struct nfsd4_ssc_umount_item *tmp; ++ DEFINE_WAIT(wait); ++ ++ *ss_mnt = NULL; ++ *retwork = NULL; ++ work = kzalloc(sizeof(*work), GFP_KERNEL); ++try_again: ++ spin_lock(&nn->nfsd_ssc_lock); ++ list_for_each_entry_safe(ni, tmp, &nn->nfsd_ssc_mount_list, nsui_list) { ++ if (strncmp(ni->nsui_ipaddr, ipaddr, sizeof(ni->nsui_ipaddr))) ++ continue; ++ /* found a match */ ++ if (ni->nsui_busy) { ++ /* wait - and try again */ ++ prepare_to_wait(&nn->nfsd_ssc_waitq, &wait, ++ TASK_INTERRUPTIBLE); ++ spin_unlock(&nn->nfsd_ssc_lock); ++ ++ /* allow 20secs for mount/unmount for now - revisit */ ++ if (signal_pending(current) || ++ (schedule_timeout(20*HZ) == 0)) { ++ kfree(work); ++ return nfserr_eagain; ++ } ++ finish_wait(&nn->nfsd_ssc_waitq, &wait); ++ goto try_again; ++ } ++ *ss_mnt = ni->nsui_vfsmount; ++ refcount_inc(&ni->nsui_refcnt); ++ spin_unlock(&nn->nfsd_ssc_lock); ++ kfree(work); ++ ++ /* return vfsmount in ss_mnt */ ++ return 0; ++ } ++ if (work) { ++ strncpy(work->nsui_ipaddr, ipaddr, sizeof(work->nsui_ipaddr)); ++ refcount_set(&work->nsui_refcnt, 2); ++ work->nsui_busy = true; ++ list_add_tail(&work->nsui_list, &nn->nfsd_ssc_mount_list); ++ *retwork = work; ++ } ++ spin_unlock(&nn->nfsd_ssc_lock); ++ return 0; ++} ++ ++static void nfsd4_ssc_update_dul_work(struct nfsd_net *nn, ++ struct nfsd4_ssc_umount_item *work, struct vfsmount *ss_mnt) ++{ ++ /* set nsui_vfsmount, clear busy flag and wakeup waiters */ ++ spin_lock(&nn->nfsd_ssc_lock); ++ work->nsui_vfsmount = ss_mnt; ++ work->nsui_busy = false; ++ wake_up_all(&nn->nfsd_ssc_waitq); ++ spin_unlock(&nn->nfsd_ssc_lock); ++} ++ ++static void nfsd4_ssc_cancel_dul_work(struct nfsd_net *nn, ++ struct nfsd4_ssc_umount_item *work) ++{ ++ spin_lock(&nn->nfsd_ssc_lock); ++ list_del(&work->nsui_list); ++ wake_up_all(&nn->nfsd_ssc_waitq); ++ spin_unlock(&nn->nfsd_ssc_lock); ++ kfree(work); ++} ++ + /* + * Support one copy source server for now. + */ +@@ -1184,6 +1266,8 @@ nfsd4_interssc_connect(struct nl4_server *nss, struct svc_rqst *rqstp, + char *ipaddr, *dev_name, *raw_data; + int len, raw_len; + __be32 status = nfserr_inval; ++ struct nfsd4_ssc_umount_item *work = NULL; ++ struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); + + naddr = &nss->u.nl4_addr; + tmp_addrlen = rpc_uaddr2sockaddr(SVC_NET(rqstp), naddr->addr, +@@ -1232,12 +1316,23 @@ nfsd4_interssc_connect(struct nl4_server *nss, struct svc_rqst *rqstp, + goto out_free_rawdata; + snprintf(dev_name, len + 5, "%s%s%s:/", startsep, ipaddr, endsep); + ++ status = nfsd4_ssc_setup_dul(nn, ipaddr, &work, &ss_mnt); ++ if (status) ++ goto out_free_devname; ++ if (ss_mnt) ++ goto out_done; ++ + /* Use an 'internal' mount: SB_KERNMOUNT -> MNT_INTERNAL */ + ss_mnt = vfs_kern_mount(type, SB_KERNMOUNT, dev_name, raw_data); + module_put(type->owner); +- if (IS_ERR(ss_mnt)) ++ if (IS_ERR(ss_mnt)) { ++ if (work) ++ nfsd4_ssc_cancel_dul_work(nn, work); + goto out_free_devname; +- ++ } ++ if (work) ++ nfsd4_ssc_update_dul_work(nn, work, ss_mnt); ++out_done: + status = 0; + *mount = ss_mnt; + +@@ -1297,10 +1392,42 @@ static void + nfsd4_cleanup_inter_ssc(struct vfsmount *ss_mnt, struct nfsd_file *src, + struct nfsd_file *dst) + { ++ bool found = false; ++ long timeout; ++ struct nfsd4_ssc_umount_item *tmp; ++ struct nfsd4_ssc_umount_item *ni = 0; ++ struct nfsd_net *nn = net_generic(dst->nf_net, nfsd_net_id); ++ + nfs42_ssc_close(src->nf_file); +- fput(src->nf_file); + nfsd_file_put(dst); +- mntput(ss_mnt); ++ fput(src->nf_file); ++ ++ if (!nn) { ++ mntput(ss_mnt); ++ return; ++ } ++ spin_lock(&nn->nfsd_ssc_lock); ++ timeout = msecs_to_jiffies(nfsd4_ssc_umount_timeout); ++ list_for_each_entry_safe(ni, tmp, &nn->nfsd_ssc_mount_list, nsui_list) { ++ if (ni->nsui_vfsmount->mnt_sb == ss_mnt->mnt_sb) { ++ list_del(&ni->nsui_list); ++ /* ++ * vfsmount can be shared by multiple exports, ++ * decrement refcnt. If the count drops to 1 it ++ * will be unmounted when nsui_expire expires. ++ */ ++ refcount_dec(&ni->nsui_refcnt); ++ ni->nsui_expire = jiffies + timeout; ++ list_add_tail(&ni->nsui_list, &nn->nfsd_ssc_mount_list); ++ found = true; ++ break; ++ } ++ } ++ spin_unlock(&nn->nfsd_ssc_lock); ++ if (!found) { ++ mntput(ss_mnt); ++ return; ++ } + } + + #else /* CONFIG_NFSD_V4_2_INTER_SSC */ +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 09967037eb1a3..3dd6e25d5d90f 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -44,6 +44,7 @@ + #include + #include + #include ++#include + #include "xdr4.h" + #include "xdr4cb.h" + #include "vfs.h" +@@ -5522,6 +5523,69 @@ static bool state_expired(struct laundry_time *lt, time64_t last_refresh) + return false; + } + ++#ifdef CONFIG_NFSD_V4_2_INTER_SSC ++void nfsd4_ssc_init_umount_work(struct nfsd_net *nn) ++{ ++ spin_lock_init(&nn->nfsd_ssc_lock); ++ INIT_LIST_HEAD(&nn->nfsd_ssc_mount_list); ++ init_waitqueue_head(&nn->nfsd_ssc_waitq); ++} ++EXPORT_SYMBOL_GPL(nfsd4_ssc_init_umount_work); ++ ++/* ++ * This is called when nfsd is being shutdown, after all inter_ssc ++ * cleanup were done, to destroy the ssc delayed unmount list. ++ */ ++static void nfsd4_ssc_shutdown_umount(struct nfsd_net *nn) ++{ ++ struct nfsd4_ssc_umount_item *ni = 0; ++ struct nfsd4_ssc_umount_item *tmp; ++ ++ spin_lock(&nn->nfsd_ssc_lock); ++ list_for_each_entry_safe(ni, tmp, &nn->nfsd_ssc_mount_list, nsui_list) { ++ list_del(&ni->nsui_list); ++ spin_unlock(&nn->nfsd_ssc_lock); ++ mntput(ni->nsui_vfsmount); ++ kfree(ni); ++ spin_lock(&nn->nfsd_ssc_lock); ++ } ++ spin_unlock(&nn->nfsd_ssc_lock); ++} ++ ++static void nfsd4_ssc_expire_umount(struct nfsd_net *nn) ++{ ++ bool do_wakeup = false; ++ struct nfsd4_ssc_umount_item *ni = 0; ++ struct nfsd4_ssc_umount_item *tmp; ++ ++ spin_lock(&nn->nfsd_ssc_lock); ++ list_for_each_entry_safe(ni, tmp, &nn->nfsd_ssc_mount_list, nsui_list) { ++ if (time_after(jiffies, ni->nsui_expire)) { ++ if (refcount_read(&ni->nsui_refcnt) > 1) ++ continue; ++ ++ /* mark being unmount */ ++ ni->nsui_busy = true; ++ spin_unlock(&nn->nfsd_ssc_lock); ++ mntput(ni->nsui_vfsmount); ++ spin_lock(&nn->nfsd_ssc_lock); ++ ++ /* waiters need to start from begin of list */ ++ list_del(&ni->nsui_list); ++ kfree(ni); ++ ++ /* wakeup ssc_connect waiters */ ++ do_wakeup = true; ++ continue; ++ } ++ break; ++ } ++ if (do_wakeup) ++ wake_up_all(&nn->nfsd_ssc_waitq); ++ spin_unlock(&nn->nfsd_ssc_lock); ++} ++#endif ++ + static time64_t + nfs4_laundromat(struct nfsd_net *nn) + { +@@ -5631,6 +5695,10 @@ nfs4_laundromat(struct nfsd_net *nn) + list_del_init(&nbl->nbl_lru); + free_blocked_lock(nbl); + } ++#ifdef CONFIG_NFSD_V4_2_INTER_SSC ++ /* service the server-to-server copy delayed unmount list */ ++ nfsd4_ssc_expire_umount(nn); ++#endif + out: + return max_t(time64_t, lt.new_timeo, NFSD_LAUNDROMAT_MINTIMEOUT); + } +@@ -7546,6 +7614,9 @@ nfs4_state_shutdown_net(struct net *net) + + nfsd4_client_tracking_exit(net); + nfs4_state_destroy_net(net); ++#ifdef CONFIG_NFSD_V4_2_INTER_SSC ++ nfsd4_ssc_shutdown_umount(nn); ++#endif + } + + void +diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h +index 14dbfa75059d5..9664303afdaf3 100644 +--- a/fs/nfsd/nfsd.h ++++ b/fs/nfsd/nfsd.h +@@ -484,6 +484,10 @@ static inline bool nfsd_attrs_supported(u32 minorversion, const u32 *bmval) + extern int nfsd4_is_junction(struct dentry *dentry); + extern int register_cld_notifier(void); + extern void unregister_cld_notifier(void); ++#ifdef CONFIG_NFSD_V4_2_INTER_SSC ++extern void nfsd4_ssc_init_umount_work(struct nfsd_net *nn); ++#endif ++ + #else /* CONFIG_NFSD_V4 */ + static inline int nfsd4_is_junction(struct dentry *dentry) + { +diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c +index 731d89898903a..373695cc62a7a 100644 +--- a/fs/nfsd/nfssvc.c ++++ b/fs/nfsd/nfssvc.c +@@ -403,6 +403,9 @@ static int nfsd_startup_net(struct net *net, const struct cred *cred) + if (ret) + goto out_filecache; + ++#ifdef CONFIG_NFSD_V4_2_INTER_SSC ++ nfsd4_ssc_init_umount_work(nn); ++#endif + nn->nfsd_net_up = true; + return 0; + +diff --git a/include/linux/nfs_ssc.h b/include/linux/nfs_ssc.h +index f5ba0fbff72fe..222ae8883e854 100644 +--- a/include/linux/nfs_ssc.h ++++ b/include/linux/nfs_ssc.h +@@ -8,6 +8,7 @@ + */ + + #include ++#include + + extern struct nfs_ssc_client_ops_tbl nfs_ssc_client_tbl; + +@@ -52,6 +53,19 @@ static inline void nfs42_ssc_close(struct file *filep) + if (nfs_ssc_client_tbl.ssc_nfs4_ops) + (*nfs_ssc_client_tbl.ssc_nfs4_ops->sco_close)(filep); + } ++ ++struct nfsd4_ssc_umount_item { ++ struct list_head nsui_list; ++ bool nsui_busy; ++ /* ++ * nsui_refcnt inited to 2, 1 on list and 1 for consumer. Entry ++ * is removed when refcnt drops to 1 and nsui_expire expires. ++ */ ++ refcount_t nsui_refcnt; ++ unsigned long nsui_expire; ++ struct vfsmount *nsui_vfsmount; ++ char nsui_ipaddr[RPC_MAX_ADDRBUFLEN]; ++}; + #endif + + /* +-- +2.43.0 + diff --git a/queue-5.10/nfsd-demote-a-warn-to-a-pr_warn.patch b/queue-5.10/nfsd-demote-a-warn-to-a-pr_warn.patch new file mode 100644 index 00000000000..d0cf5b141f1 --- /dev/null +++ b/queue-5.10/nfsd-demote-a-warn-to-a-pr_warn.patch @@ -0,0 +1,38 @@ +From 5911269f24b99bcbb2b43637668777c1a3f5ee9e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 Jul 2022 14:23:45 -0400 +Subject: NFSD: Demote a WARN to a pr_warn() + +From: Chuck Lever + +[ Upstream commit ca3f9acb6d3faf78da2b63324f7c737dbddf7f69 ] + +The call trace doesn't add much value, but it sure is noisy. + +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index cb4a037266709..08c2eaca4f24e 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -630,9 +630,9 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + } + + status = nfsd4_process_open2(rqstp, resfh, open); +- WARN(status && open->op_created, +- "nfsd4_process_open2 failed to open newly-created file! status=%u\n", +- be32_to_cpu(status)); ++ if (status && open->op_created) ++ pr_warn("nfsd4_process_open2 failed to open newly-created file: status=%u\n", ++ be32_to_cpu(status)); + if (reclaim && !status) + nn->somebody_reclaimed = true; + out: +-- +2.43.0 + diff --git a/queue-5.10/nfsd-deprecate-nfs_offset_max.patch b/queue-5.10/nfsd-deprecate-nfs_offset_max.patch new file mode 100644 index 00000000000..0f9b37bf676 --- /dev/null +++ b/queue-5.10/nfsd-deprecate-nfs_offset_max.patch @@ -0,0 +1,69 @@ +From 9ddc5ed403d9a4909b2e6c8c65fd15c336982981 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 25 Jan 2022 15:57:45 -0500 +Subject: NFSD: Deprecate NFS_OFFSET_MAX + +From: Chuck Lever + +[ Upstream commit c306d737691ef84305d4ed0d302c63db2932f0bb ] + +NFS_OFFSET_MAX was introduced way back in Linux v2.3.y before there +was a kernel-wide OFFSET_MAX value. As a clean up, replace the last +few uses of it with its generic equivalent, and get rid of it. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3xdr.c | 2 +- + fs/nfsd/nfs4xdr.c | 2 +- + include/linux/nfs.h | 8 -------- + 3 files changed, 2 insertions(+), 10 deletions(-) + +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index 2e47a07029f1d..0293b8d65f10f 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -1060,7 +1060,7 @@ svcxdr_encode_entry3_common(struct nfsd3_readdirres *resp, const char *name, + return false; + /* cookie */ + resp->cookie_offset = dirlist->len; +- if (xdr_stream_encode_u64(xdr, NFS_OFFSET_MAX) < 0) ++ if (xdr_stream_encode_u64(xdr, OFFSET_MAX) < 0) + return false; + + return true; +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index be0995bb9459a..a7b9c3faf7a79 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -3495,7 +3495,7 @@ nfsd4_encode_dirent(void *ccdv, const char *name, int namlen, + p = xdr_reserve_space(xdr, 3*4 + namlen); + if (!p) + goto fail; +- p = xdr_encode_hyper(p, NFS_OFFSET_MAX); /* offset of next entry */ ++ p = xdr_encode_hyper(p, OFFSET_MAX); /* offset of next entry */ + p = xdr_encode_array(p, name, namlen); /* name length & name */ + + nfserr = nfsd4_encode_dirent_fattr(xdr, cd, name, namlen); +diff --git a/include/linux/nfs.h b/include/linux/nfs.h +index 0dc7ad38a0da4..b06375e88e589 100644 +--- a/include/linux/nfs.h ++++ b/include/linux/nfs.h +@@ -36,14 +36,6 @@ static inline void nfs_copy_fh(struct nfs_fh *target, const struct nfs_fh *sourc + memcpy(target->data, source->data, source->size); + } + +- +-/* +- * This is really a general kernel constant, but since nothing like +- * this is defined in the kernel headers, I have to do it here. +- */ +-#define NFS_OFFSET_MAX ((__s64)((~(__u64)0) >> 1)) +- +- + enum nfs3_stable_how { + NFS_UNSTABLE = 0, + NFS_DATA_SYNC = 1, +-- +2.43.0 + diff --git a/queue-5.10/nfsd-destroy-percpu-stats-counters-after-reply-cache.patch b/queue-5.10/nfsd-destroy-percpu-stats-counters-after-reply-cache.patch new file mode 100644 index 00000000000..d8b80945d80 --- /dev/null +++ b/queue-5.10/nfsd-destroy-percpu-stats-counters-after-reply-cache.patch @@ -0,0 +1,50 @@ +From 3154b26d1dbbdd5ceb793e04c1d4d7ce42f0d994 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 May 2022 18:52:26 +0000 +Subject: nfsd: destroy percpu stats counters after reply cache shutdown +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Julian Schroeder + +[ Upstream commit fd5e363eac77ef81542db77ddad0559fa0f9204e ] + +Upon nfsd shutdown any pending DRC cache is freed. DRC cache use is +tracked via a percpu counter. In the current code the percpu counter +is destroyed before. If any pending cache is still present, +percpu_counter_add is called with a percpu counter==NULL. This causes +a kernel crash. +The solution is to destroy the percpu counter after the cache is freed. + +Fixes: e567b98ce9a4b (“nfsd: protect concurrent access to nfsd stats counters”) +Signed-off-by: Julian Schroeder +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfscache.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c +index 0b3f12aa37ff5..7da88bdc0d6c3 100644 +--- a/fs/nfsd/nfscache.c ++++ b/fs/nfsd/nfscache.c +@@ -206,7 +206,6 @@ void nfsd_reply_cache_shutdown(struct nfsd_net *nn) + struct svc_cacherep *rp; + unsigned int i; + +- nfsd_reply_cache_stats_destroy(nn); + unregister_shrinker(&nn->nfsd_reply_cache_shrinker); + + for (i = 0; i < nn->drc_hashsize; i++) { +@@ -217,6 +216,7 @@ void nfsd_reply_cache_shutdown(struct nfsd_net *nn) + rp, nn); + } + } ++ nfsd_reply_cache_stats_destroy(nn); + + kvfree(nn->drc_hashtbl); + nn->drc_hashtbl = NULL; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-discard-fh_locked-flag-and-fh_lock-fh_unlock.patch b/queue-5.10/nfsd-discard-fh_locked-flag-and-fh_lock-fh_unlock.patch new file mode 100644 index 00000000000..617d5671755 --- /dev/null +++ b/queue-5.10/nfsd-discard-fh_locked-flag-and-fh_lock-fh_unlock.patch @@ -0,0 +1,189 @@ +From d5718890a84cf21070b1287fc4f3cae553f21585 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 Jul 2022 16:45:30 +1000 +Subject: NFSD: discard fh_locked flag and fh_lock/fh_unlock + +From: NeilBrown + +[ Upstream commit dd8dd403d7b223cc77ee89d8d09caf045e90e648 ] + +As all inode locking is now fully balanced, fh_put() does not need to +call fh_unlock(). +fh_lock() and fh_unlock() are no longer used, so discard them. +These are the only real users of ->fh_locked, so discard that too. + +Reviewed-by: Jeff Layton +Signed-off-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsfh.c | 3 +-- + fs/nfsd/nfsfh.h | 56 ++++--------------------------------------------- + fs/nfsd/vfs.c | 17 +-------------- + 3 files changed, 6 insertions(+), 70 deletions(-) + +diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c +index cc680deecafa7..db8d62632a5be 100644 +--- a/fs/nfsd/nfsfh.c ++++ b/fs/nfsd/nfsfh.c +@@ -547,7 +547,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, + if (ref_fh == fhp) + fh_put(ref_fh); + +- if (fhp->fh_locked || fhp->fh_dentry) { ++ if (fhp->fh_dentry) { + printk(KERN_ERR "fh_compose: fh %pd2 not initialized!\n", + dentry); + } +@@ -698,7 +698,6 @@ fh_put(struct svc_fh *fhp) + struct dentry * dentry = fhp->fh_dentry; + struct svc_export * exp = fhp->fh_export; + if (dentry) { +- fh_unlock(fhp); + fhp->fh_dentry = NULL; + dput(dentry); + fh_clear_pre_post_attrs(fhp); +diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h +index 28a4f9a94e2c8..c3ae6414fc5cf 100644 +--- a/fs/nfsd/nfsfh.h ++++ b/fs/nfsd/nfsfh.h +@@ -81,7 +81,6 @@ typedef struct svc_fh { + struct dentry * fh_dentry; /* validated dentry */ + struct svc_export * fh_export; /* export pointer */ + +- bool fh_locked; /* inode locked by us */ + bool fh_want_write; /* remount protection taken */ + bool fh_no_wcc; /* no wcc data needed */ + bool fh_no_atomic_attr; +@@ -93,7 +92,7 @@ typedef struct svc_fh { + bool fh_post_saved; /* post-op attrs saved */ + bool fh_pre_saved; /* pre-op attrs saved */ + +- /* Pre-op attributes saved during fh_lock */ ++ /* Pre-op attributes saved when inode is locked */ + __u64 fh_pre_size; /* size before operation */ + struct timespec64 fh_pre_mtime; /* mtime before oper */ + struct timespec64 fh_pre_ctime; /* ctime before oper */ +@@ -103,7 +102,7 @@ typedef struct svc_fh { + */ + u64 fh_pre_change; + +- /* Post-op attributes saved in fh_unlock */ ++ /* Post-op attributes saved in fh_fill_post_attrs() */ + struct kstat fh_post_attr; /* full attrs after operation */ + u64 fh_post_change; /* nfsv4 change; see above */ + } svc_fh; +@@ -223,8 +222,8 @@ void fh_put(struct svc_fh *); + static __inline__ struct svc_fh * + fh_copy(struct svc_fh *dst, struct svc_fh *src) + { +- WARN_ON(src->fh_dentry || src->fh_locked); +- ++ WARN_ON(src->fh_dentry); ++ + *dst = *src; + return dst; + } +@@ -323,51 +322,4 @@ static inline u64 nfsd4_change_attribute(struct kstat *stat, + extern void fh_fill_pre_attrs(struct svc_fh *fhp); + extern void fh_fill_post_attrs(struct svc_fh *fhp); + extern void fh_fill_both_attrs(struct svc_fh *fhp); +- +-/* +- * Lock a file handle/inode +- * NOTE: both fh_lock and fh_unlock are done "by hand" in +- * vfs.c:nfsd_rename as it needs to grab 2 i_mutex's at once +- * so, any changes here should be reflected there. +- */ +- +-static inline void +-fh_lock_nested(struct svc_fh *fhp, unsigned int subclass) +-{ +- struct dentry *dentry = fhp->fh_dentry; +- struct inode *inode; +- +- BUG_ON(!dentry); +- +- if (fhp->fh_locked) { +- printk(KERN_WARNING "fh_lock: %pd2 already locked!\n", +- dentry); +- return; +- } +- +- inode = d_inode(dentry); +- inode_lock_nested(inode, subclass); +- fh_fill_pre_attrs(fhp); +- fhp->fh_locked = true; +-} +- +-static inline void +-fh_lock(struct svc_fh *fhp) +-{ +- fh_lock_nested(fhp, I_MUTEX_NORMAL); +-} +- +-/* +- * Unlock a file handle/inode +- */ +-static inline void +-fh_unlock(struct svc_fh *fhp) +-{ +- if (fhp->fh_locked) { +- fh_fill_post_attrs(fhp); +- inode_unlock(d_inode(fhp->fh_dentry)); +- fhp->fh_locked = false; +- } +-} +- + #endif /* _LINUX_NFSD_NFSFH_H */ +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index 504a3ddfaf75b..5a7fee4ee2079 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -1282,13 +1282,6 @@ nfsd_create_locked(struct svc_rqst *rqstp, struct svc_fh *fhp, + dirp = d_inode(dentry); + + dchild = dget(resfhp->fh_dentry); +- if (!fhp->fh_locked) { +- WARN_ONCE(1, "nfsd_create: parent %pd2 not locked!\n", +- dentry); +- err = nfserr_io; +- goto out; +- } +- + err = nfsd_permission(rqstp, fhp->fh_export, dentry, NFSD_MAY_CREATE); + if (err) + goto out; +@@ -1656,10 +1649,7 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, + goto out; + } + +- /* cannot use fh_lock as we need deadlock protective ordering +- * so do it by hand */ + trap = lock_rename(tdentry, fdentry); +- ffhp->fh_locked = tfhp->fh_locked = true; + fh_fill_pre_attrs(ffhp); + fh_fill_pre_attrs(tfhp); + +@@ -1707,17 +1697,12 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, + dput(odentry); + out_nfserr: + err = nfserrno(host_err); +- /* +- * We cannot rely on fh_unlock on the two filehandles, +- * as that would do the wrong thing if the two directories +- * were the same, so again we do it by hand. +- */ ++ + if (!close_cached) { + fh_fill_post_attrs(ffhp); + fh_fill_post_attrs(tfhp); + } + unlock_rename(tdentry, fdentry); +- ffhp->fh_locked = tfhp->fh_locked = false; + fh_drop_write(ffhp); + + /* +-- +2.43.0 + diff --git a/queue-5.10/nfsd-don-t-allow-nfsd-threads-to-be-signalled.patch b/queue-5.10/nfsd-don-t-allow-nfsd-threads-to-be-signalled.patch new file mode 100644 index 00000000000..4e8a417495e --- /dev/null +++ b/queue-5.10/nfsd-don-t-allow-nfsd-threads-to-be-signalled.patch @@ -0,0 +1,210 @@ +From cd49516311e2b7b5960700cda413da028450f7c6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 3 Jun 2024 10:35:02 -0400 +Subject: nfsd: don't allow nfsd threads to be signalled. + +From: Chuck Lever + +[ Upstream commit 3903902401451b1cd9d797a8c79769eb26ac7fe5 ] + +The original implementation of nfsd used signals to stop threads during +shutdown. +In Linux 2.3.46pre5 nfsd gained the ability to shutdown threads +internally it if was asked to run "0" threads. After this user-space +transitioned to using "rpc.nfsd 0" to stop nfsd and sending signals to +threads was no longer an important part of the API. + +In commit 3ebdbe5203a8 ("SUNRPC: discard svo_setup and rename +svc_set_num_threads_sync()") (v5.17-rc1~75^2~41) we finally removed the +use of signals for stopping threads, using kthread_stop() instead. + +This patch makes the "obvious" next step and removes the ability to +signal nfsd threads - or any svc threads. nfsd stops allowing signals +and we don't check for their delivery any more. + +This will allow for some simplification in later patches. + +A change worth noting is in nfsd4_ssc_setup_dul(). There was previously +a signal_pending() check which would only succeed when the thread was +being shut down. It should really have tested kthread_should_stop() as +well. Now it just does the latter, not the former. + +Signed-off-by: NeilBrown +Reviewed-by: Jeff Layton +[ cel: adjusted to apply to v5.10.y ] +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfs/callback.c | 11 ++--------- + fs/nfsd/nfs4proc.c | 8 ++++---- + fs/nfsd/nfssvc.c | 12 ------------ + net/sunrpc/svc_xprt.c | 20 ++++++++------------ + 4 files changed, 14 insertions(+), 37 deletions(-) + +diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c +index 456af7d230cf1..8fe143cad4a2b 100644 +--- a/fs/nfs/callback.c ++++ b/fs/nfs/callback.c +@@ -80,9 +80,6 @@ nfs4_callback_svc(void *vrqstp) + set_freezable(); + + while (!kthread_freezable_should_stop(NULL)) { +- +- if (signal_pending(current)) +- flush_signals(current); + /* + * Listen for a request on the socket + */ +@@ -112,11 +109,7 @@ nfs41_callback_svc(void *vrqstp) + set_freezable(); + + while (!kthread_freezable_should_stop(NULL)) { +- +- if (signal_pending(current)) +- flush_signals(current); +- +- prepare_to_wait(&serv->sv_cb_waitq, &wq, TASK_INTERRUPTIBLE); ++ prepare_to_wait(&serv->sv_cb_waitq, &wq, TASK_IDLE); + spin_lock_bh(&serv->sv_cb_lock); + if (!list_empty(&serv->sv_cb_list)) { + req = list_first_entry(&serv->sv_cb_list, +@@ -131,7 +124,7 @@ nfs41_callback_svc(void *vrqstp) + } else { + spin_unlock_bh(&serv->sv_cb_lock); + if (!kthread_should_stop()) +- schedule(); ++ freezable_schedule(); + finish_wait(&serv->sv_cb_waitq, &wq); + } + } +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 9c51c10bcf080..8560a11daa47d 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -38,6 +38,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -1313,13 +1314,12 @@ static __be32 nfsd4_ssc_setup_dul(struct nfsd_net *nn, char *ipaddr, + /* found a match */ + if (ni->nsui_busy) { + /* wait - and try again */ +- prepare_to_wait(&nn->nfsd_ssc_waitq, &wait, +- TASK_INTERRUPTIBLE); ++ prepare_to_wait(&nn->nfsd_ssc_waitq, &wait, TASK_IDLE); + spin_unlock(&nn->nfsd_ssc_lock); + + /* allow 20secs for mount/unmount for now - revisit */ +- if (signal_pending(current) || +- (schedule_timeout(20*HZ) == 0)) { ++ if (kthread_should_stop() || ++ (freezable_schedule_timeout(20*HZ) == 0)) { + finish_wait(&nn->nfsd_ssc_waitq, &wait); + kfree(work); + return nfserr_eagain; +diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c +index a0ecec54d3d7d..8063fab2c0279 100644 +--- a/fs/nfsd/nfssvc.c ++++ b/fs/nfsd/nfssvc.c +@@ -952,15 +952,6 @@ nfsd(void *vrqstp) + + current->fs->umask = 0; + +- /* +- * thread is spawned with all signals set to SIG_IGN, re-enable +- * the ones that will bring down the thread +- */ +- allow_signal(SIGKILL); +- allow_signal(SIGHUP); +- allow_signal(SIGINT); +- allow_signal(SIGQUIT); +- + atomic_inc(&nfsdstats.th_cnt); + + set_freezable(); +@@ -985,9 +976,6 @@ nfsd(void *vrqstp) + validate_process_creds(); + } + +- /* Clear signals before calling svc_exit_thread() */ +- flush_signals(current); +- + atomic_dec(&nfsdstats.th_cnt); + + out: +diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c +index 000b737784bd9..d1eacf3358b81 100644 +--- a/net/sunrpc/svc_xprt.c ++++ b/net/sunrpc/svc_xprt.c +@@ -674,13 +674,13 @@ static int svc_alloc_arg(struct svc_rqst *rqstp) + while (rqstp->rq_pages[i] == NULL) { + struct page *p = alloc_page(GFP_KERNEL); + if (!p) { +- set_current_state(TASK_INTERRUPTIBLE); +- if (signalled() || kthread_should_stop()) { ++ set_current_state(TASK_IDLE); ++ if (kthread_should_stop()) { + set_current_state(TASK_RUNNING); + return -EINTR; + } +- schedule_timeout(msecs_to_jiffies(500)); + } ++ freezable_schedule_timeout(msecs_to_jiffies(500)); + rqstp->rq_pages[i] = p; + } + rqstp->rq_page_end = &rqstp->rq_pages[i]; +@@ -713,7 +713,7 @@ rqst_should_sleep(struct svc_rqst *rqstp) + return false; + + /* are we shutting down? */ +- if (signalled() || kthread_should_stop()) ++ if (kthread_should_stop()) + return false; + + /* are we freezing? */ +@@ -735,18 +735,14 @@ static struct svc_xprt *svc_get_next_xprt(struct svc_rqst *rqstp, long timeout) + if (rqstp->rq_xprt) + goto out_found; + +- /* +- * We have to be able to interrupt this wait +- * to bring down the daemons ... +- */ +- set_current_state(TASK_INTERRUPTIBLE); ++ set_current_state(TASK_IDLE); + smp_mb__before_atomic(); + clear_bit(SP_CONGESTED, &pool->sp_flags); + clear_bit(RQ_BUSY, &rqstp->rq_flags); + smp_mb__after_atomic(); + + if (likely(rqst_should_sleep(rqstp))) +- time_left = schedule_timeout(timeout); ++ time_left = freezable_schedule_timeout(timeout); + else + __set_current_state(TASK_RUNNING); + +@@ -761,7 +757,7 @@ static struct svc_xprt *svc_get_next_xprt(struct svc_rqst *rqstp, long timeout) + if (!time_left) + atomic_long_inc(&pool->sp_stats.threads_timedout); + +- if (signalled() || kthread_should_stop()) ++ if (kthread_should_stop()) + return ERR_PTR(-EINTR); + return ERR_PTR(-EAGAIN); + out_found: +@@ -860,7 +856,7 @@ int svc_recv(struct svc_rqst *rqstp, long timeout) + try_to_freeze(); + cond_resched(); + err = -EINTR; +- if (signalled() || kthread_should_stop()) ++ if (kthread_should_stop()) + goto out; + + xprt = svc_get_next_xprt(rqstp, timeout); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-don-t-call-locks_release_private-twice-concurre.patch b/queue-5.10/nfsd-don-t-call-locks_release_private-twice-concurre.patch new file mode 100644 index 00000000000..94b00aec1b3 --- /dev/null +++ b/queue-5.10/nfsd-don-t-call-locks_release_private-twice-concurre.patch @@ -0,0 +1,57 @@ +From e4a5f7c0487f17119fe6fb63a3d83c32d6a9b194 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 31 Jan 2024 11:17:40 +1100 +Subject: nfsd: don't call locks_release_private() twice concurrently + +From: NeilBrown + +[ Upstream commit 05eda6e75773592760285e10ac86c56d683be17f ] + +It is possible for free_blocked_lock() to be called twice concurrently, +once from nfsd4_lock() and once from nfsd4_release_lockowner() calling +remove_blocked_locks(). This is why a kref was added. + +It is perfectly safe for locks_delete_block() and kref_put() to be +called in parallel as they use locking or atomicity respectively as +protection. However locks_release_private() has no locking. It is +safe for it to be called twice sequentially, but not concurrently. + +This patch moves that call from free_blocked_lock() where it could race +with itself, to free_nbl() where it cannot. This will slightly delay +the freeing of private info or release of the owner - but not by much. +It is arguably more natural for this freeing to happen in free_nbl() +where the structure itself is freed. + +This bug was found by code inspection - it has not been seen in practice. + +Fixes: 47446d74f170 ("nfsd4: add refcount for nfsd4_blocked_lock") +Signed-off-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 165acd8138abe..228560f3fd0e0 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -318,6 +318,7 @@ free_nbl(struct kref *kref) + struct nfsd4_blocked_lock *nbl; + + nbl = container_of(kref, struct nfsd4_blocked_lock, nbl_kref); ++ locks_release_private(&nbl->nbl_lock); + kfree(nbl); + } + +@@ -325,7 +326,6 @@ static void + free_blocked_lock(struct nfsd4_blocked_lock *nbl) + { + locks_delete_block(&nbl->nbl_lock); +- locks_release_private(&nbl->nbl_lock); + kref_put(&nbl->nbl_kref, free_nbl); + } + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-don-t-destroy-global-nfs4_file-table-in-per-net.patch b/queue-5.10/nfsd-don-t-destroy-global-nfs4_file-table-in-per-net.patch new file mode 100644 index 00000000000..b58e8e955b7 --- /dev/null +++ b/queue-5.10/nfsd-don-t-destroy-global-nfs4_file-table-in-per-net.patch @@ -0,0 +1,47 @@ +From 81c31f4a2c1652e6f01add0378ed6cf90298b25c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 11 Feb 2023 07:50:08 -0500 +Subject: nfsd: don't destroy global nfs4_file table in per-net shutdown + +From: Jeff Layton + +[ Upstream commit 4102db175b5d884d133270fdbd0e59111ce688fc ] + +The nfs4_file table is global, so shutting it down when a containerized +nfsd is shut down is wrong and can lead to double-frees. Tear down the +nfs4_file_rhltable in nfs4_state_shutdown instead of +nfs4_state_shutdown_net. + +Fixes: d47b295e8d76 ("NFSD: Use rhashtable for managing nfs4_file objects") +Link: https://bugzilla.redhat.com/show_bug.cgi?id=2169017 +Reported-by: JianHong Yin +Signed-off-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 3dd64caf06158..6c11f2701af88 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -8192,7 +8192,6 @@ nfs4_state_shutdown_net(struct net *net) + + nfsd4_client_tracking_exit(net); + nfs4_state_destroy_net(net); +- rhltable_destroy(&nfs4_file_rhltable); + #ifdef CONFIG_NFSD_V4_2_INTER_SSC + nfsd4_ssc_shutdown_umount(nn); + #endif +@@ -8202,6 +8201,7 @@ void + nfs4_state_shutdown(void) + { + nfsd4_destroy_callback_queue(); ++ rhltable_destroy(&nfs4_file_rhltable); + } + + static void +-- +2.43.0 + diff --git a/queue-5.10/nfsd-don-t-free-files-unconditionally-in-__nfsd_file.patch b/queue-5.10/nfsd-don-t-free-files-unconditionally-in-__nfsd_file.patch new file mode 100644 index 00000000000..ef1a2913f59 --- /dev/null +++ b/queue-5.10/nfsd-don-t-free-files-unconditionally-in-__nfsd_file.patch @@ -0,0 +1,121 @@ +From 9e2698a93071add7d221031d8af02c1776f024ca Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Jan 2023 14:52:14 -0500 +Subject: nfsd: don't free files unconditionally in __nfsd_file_cache_purge + +From: Jeff Layton + +[ Upstream commit 4bdbba54e9b1c769da8ded9abd209d765715e1d6 ] + +nfsd_file_cache_purge is called when the server is shutting down, in +which case, tearing things down is generally fine, but it also gets +called when the exports cache is flushed. + +Instead of walking the cache and freeing everything unconditionally, +handle it the same as when we have a notification of conflicting access. + +Fixes: ac3a2585f018 ("nfsd: rework refcounting in filecache") +Reported-by: Ruben Vestergaard +Reported-by: Torkil Svensgaard +Reported-by: Shachar Kagan +Signed-off-by: Jeff Layton +Tested-by: Shachar Kagan +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 61 ++++++++++++++++++++++++++------------------- + 1 file changed, 36 insertions(+), 25 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index 6a62d95d5ce64..68c7c82f8b3bb 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -660,6 +660,39 @@ static struct shrinker nfsd_file_shrinker = { + .seeks = 1, + }; + ++/** ++ * nfsd_file_cond_queue - conditionally unhash and queue a nfsd_file ++ * @nf: nfsd_file to attempt to queue ++ * @dispose: private list to queue successfully-put objects ++ * ++ * Unhash an nfsd_file, try to get a reference to it, and then put that ++ * reference. If it's the last reference, queue it to the dispose list. ++ */ ++static void ++nfsd_file_cond_queue(struct nfsd_file *nf, struct list_head *dispose) ++ __must_hold(RCU) ++{ ++ int decrement = 1; ++ ++ /* If we raced with someone else unhashing, ignore it */ ++ if (!nfsd_file_unhash(nf)) ++ return; ++ ++ /* If we can't get a reference, ignore it */ ++ if (!nfsd_file_get(nf)) ++ return; ++ ++ /* Extra decrement if we remove from the LRU */ ++ if (nfsd_file_lru_remove(nf)) ++ ++decrement; ++ ++ /* If refcount goes to 0, then put on the dispose list */ ++ if (refcount_sub_and_test(decrement, &nf->nf_ref)) { ++ list_add(&nf->nf_lru, dispose); ++ trace_nfsd_file_closing(nf); ++ } ++} ++ + /** + * nfsd_file_queue_for_close: try to close out any open nfsd_files for an inode + * @inode: inode on which to close out nfsd_files +@@ -687,30 +720,11 @@ nfsd_file_queue_for_close(struct inode *inode, struct list_head *dispose) + + rcu_read_lock(); + do { +- int decrement = 1; +- + nf = rhashtable_lookup(&nfsd_file_rhash_tbl, &key, + nfsd_file_rhash_params); + if (!nf) + break; +- +- /* If we raced with someone else unhashing, ignore it */ +- if (!nfsd_file_unhash(nf)) +- continue; +- +- /* If we can't get a reference, ignore it */ +- if (!nfsd_file_get(nf)) +- continue; +- +- /* Extra decrement if we remove from the LRU */ +- if (nfsd_file_lru_remove(nf)) +- ++decrement; +- +- /* If refcount goes to 0, then put on the dispose list */ +- if (refcount_sub_and_test(decrement, &nf->nf_ref)) { +- list_add(&nf->nf_lru, dispose); +- trace_nfsd_file_closing(nf); +- } ++ nfsd_file_cond_queue(nf, dispose); + } while (1); + rcu_read_unlock(); + } +@@ -927,11 +941,8 @@ __nfsd_file_cache_purge(struct net *net) + + nf = rhashtable_walk_next(&iter); + while (!IS_ERR_OR_NULL(nf)) { +- if (!net || nf->nf_net == net) { +- nfsd_file_unhash(nf); +- nfsd_file_lru_remove(nf); +- list_add(&nf->nf_lru, &dispose); +- } ++ if (!net || nf->nf_net == net) ++ nfsd_file_cond_queue(nf, &dispose); + nf = rhashtable_walk_next(&iter); + } + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-don-t-fsync-nfsd_files-on-last-close.patch b/queue-5.10/nfsd-don-t-fsync-nfsd_files-on-last-close.patch new file mode 100644 index 00000000000..e16c4190335 --- /dev/null +++ b/queue-5.10/nfsd-don-t-fsync-nfsd_files-on-last-close.patch @@ -0,0 +1,176 @@ +From 2c2ae9063856e06c4bc858f2b070036d9b8a8ca6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Feb 2023 12:02:46 -0500 +Subject: nfsd: don't fsync nfsd_files on last close + +From: Jeff Layton + +[ Upstream commit 4c475eee02375ade6e864f1db16976ba0d96a0a2 ] + +Most of the time, NFSv4 clients issue a COMMIT before the final CLOSE of +an open stateid, so with NFSv4, the fsync in the nfsd_file_free path is +usually a no-op and doesn't block. + +We have a customer running knfsd over very slow storage (XFS over Ceph +RBD). They were using the "async" export option because performance was +more important than data integrity for this application. That export +option turns NFSv4 COMMIT calls into no-ops. Due to the fsync in this +codepath however, their final CLOSE calls would still stall (since a +CLOSE effectively became a COMMIT). + +I think this fsync is not strictly necessary. We only use that result to +reset the write verifier. Instead of fsync'ing all of the data when we +free an nfsd_file, we can just check for writeback errors when one is +acquired and when it is freed. + +If the client never comes back, then it'll never see the error anyway +and there is no point in resetting it. If an error occurs after the +nfsd_file is removed from the cache but before the inode is evicted, +then it will reset the write verifier on the next nfsd_file_acquire, +(since there will be an unseen error). + +The only exception here is if something else opens and fsyncs the file +during that window. Given that local applications work with this +limitation today, I don't see that as an issue. + +Link: https://bugzilla.redhat.com/show_bug.cgi?id=2166658 +Fixes: ac3a2585f018 ("nfsd: rework refcounting in filecache") +Reported-and-tested-by: Pierguido Lambri +Signed-off-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 44 ++++++++++++-------------------------------- + fs/nfsd/trace.h | 31 ------------------------------- + 2 files changed, 12 insertions(+), 63 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index 206742bbbd682..4a3796c6bd957 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -330,37 +330,27 @@ nfsd_file_alloc(struct nfsd_file_lookup_key *key, unsigned int may) + return nf; + } + ++/** ++ * nfsd_file_check_write_error - check for writeback errors on a file ++ * @nf: nfsd_file to check for writeback errors ++ * ++ * Check whether a nfsd_file has an unseen error. Reset the write ++ * verifier if so. ++ */ + static void +-nfsd_file_fsync(struct nfsd_file *nf) +-{ +- struct file *file = nf->nf_file; +- int ret; +- +- if (!file || !(file->f_mode & FMODE_WRITE)) +- return; +- ret = vfs_fsync(file, 1); +- trace_nfsd_file_fsync(nf, ret); +- if (ret) +- nfsd_reset_write_verifier(net_generic(nf->nf_net, nfsd_net_id)); +-} +- +-static int + nfsd_file_check_write_error(struct nfsd_file *nf) + { + struct file *file = nf->nf_file; + +- if (!file || !(file->f_mode & FMODE_WRITE)) +- return 0; +- return filemap_check_wb_err(file->f_mapping, READ_ONCE(file->f_wb_err)); ++ if ((file->f_mode & FMODE_WRITE) && ++ filemap_check_wb_err(file->f_mapping, READ_ONCE(file->f_wb_err))) ++ nfsd_reset_write_verifier(net_generic(nf->nf_net, nfsd_net_id)); + } + + static void + nfsd_file_hash_remove(struct nfsd_file *nf) + { + trace_nfsd_file_unhash(nf); +- +- if (nfsd_file_check_write_error(nf)) +- nfsd_reset_write_verifier(net_generic(nf->nf_net, nfsd_net_id)); + rhashtable_remove_fast(&nfsd_file_rhash_tbl, &nf->nf_rhash, + nfsd_file_rhash_params); + } +@@ -386,23 +376,12 @@ nfsd_file_free(struct nfsd_file *nf) + this_cpu_add(nfsd_file_total_age, age); + + nfsd_file_unhash(nf); +- +- /* +- * We call fsync here in order to catch writeback errors. It's not +- * strictly required by the protocol, but an nfsd_file could get +- * evicted from the cache before a COMMIT comes in. If another +- * task were to open that file in the interim and scrape the error, +- * then the client may never see it. By calling fsync here, we ensure +- * that writeback happens before the entry is freed, and that any +- * errors reported result in the write verifier changing. +- */ +- nfsd_file_fsync(nf); +- + if (nf->nf_mark) + nfsd_file_mark_put(nf->nf_mark); + if (nf->nf_file) { + get_file(nf->nf_file); + filp_close(nf->nf_file, NULL); ++ nfsd_file_check_write_error(nf); + fput(nf->nf_file); + } + +@@ -1157,6 +1136,7 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + out: + if (status == nfs_ok) { + this_cpu_inc(nfsd_file_acquisitions); ++ nfsd_file_check_write_error(nf); + *pnf = nf; + } else { + if (refcount_dec_and_test(&nf->nf_ref)) +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index 0f674982785ce..445d00f00eab7 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -1112,37 +1112,6 @@ TRACE_EVENT(nfsd_file_close, + ) + ); + +-TRACE_EVENT(nfsd_file_fsync, +- TP_PROTO( +- const struct nfsd_file *nf, +- int ret +- ), +- TP_ARGS(nf, ret), +- TP_STRUCT__entry( +- __field(void *, nf_inode) +- __field(int, nf_ref) +- __field(int, ret) +- __field(unsigned long, nf_flags) +- __field(unsigned char, nf_may) +- __field(struct file *, nf_file) +- ), +- TP_fast_assign( +- __entry->nf_inode = nf->nf_inode; +- __entry->nf_ref = refcount_read(&nf->nf_ref); +- __entry->ret = ret; +- __entry->nf_flags = nf->nf_flags; +- __entry->nf_may = nf->nf_may; +- __entry->nf_file = nf->nf_file; +- ), +- TP_printk("inode=%p ref=%d flags=%s may=%s nf_file=%p ret=%d", +- __entry->nf_inode, +- __entry->nf_ref, +- show_nf_flags(__entry->nf_flags), +- show_nfsd_may_flags(__entry->nf_may), +- __entry->nf_file, __entry->ret +- ) +-); +- + #include "cache.h" + + TRACE_DEFINE_ENUM(RC_DROPIT); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-don-t-hand-out-delegation-on-setuid-files-being.patch b/queue-5.10/nfsd-don-t-hand-out-delegation-on-setuid-files-being.patch new file mode 100644 index 00000000000..c91f8d04f0f --- /dev/null +++ b/queue-5.10/nfsd-don-t-hand-out-delegation-on-setuid-files-being.patch @@ -0,0 +1,96 @@ +From ebefc2a477e9dee1cf04a68091f5c437a44374a2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Jan 2023 07:09:33 -0500 +Subject: nfsd: don't hand out delegation on setuid files being opened for + write + +From: Jeff Layton + +[ Upstream commit 826b67e6376c2a788e3a62c4860dcd79500a27d5 ] + +We had a bug report that xfstest generic/355 was failing on NFSv4.0. +This test sets various combinations of setuid/setgid modes and tests +whether DIO writes will cause them to be stripped. + +What I found was that the server did properly strip those bits, but +the client didn't notice because it held a delegation that was not +recalled. The recall didn't occur because the client itself was the +one generating the activity and we avoid recalls in that case. + +Clearing setuid bits is an "implicit" activity. The client didn't +specifically request that we do that, so we need the server to issue a +CB_RECALL, or avoid the situation entirely by not issuing a delegation. + +The easiest fix here is to simply not give out a delegation if the file +is being opened for write, and the mode has the setuid and/or setgid bit +set. Note that there is a potential race between the mode and lease +being set, so we test for this condition both before and after setting +the lease. + +This patch fixes generic/355, generic/683 and generic/684 for me. (Note +that 355 fails only on v4.0, and 683 and 684 require NFSv4.2 to run and +fail). + +Reported-by: Boyang Xue +Signed-off-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 27 +++++++++++++++++++++++++++ + 1 file changed, 27 insertions(+) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 2733eb33d5df2..f57137ef306bd 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -5435,6 +5435,23 @@ nfsd4_verify_deleg_dentry(struct nfsd4_open *open, struct nfs4_file *fp, + return 0; + } + ++/* ++ * We avoid breaking delegations held by a client due to its own activity, but ++ * clearing setuid/setgid bits on a write is an implicit activity and the client ++ * may not notice and continue using the old mode. Avoid giving out a delegation ++ * on setuid/setgid files when the client is requesting an open for write. ++ */ ++static int ++nfsd4_verify_setuid_write(struct nfsd4_open *open, struct nfsd_file *nf) ++{ ++ struct inode *inode = file_inode(nf->nf_file); ++ ++ if ((open->op_share_access & NFS4_SHARE_ACCESS_WRITE) && ++ (inode->i_mode & (S_ISUID|S_ISGID))) ++ return -EAGAIN; ++ return 0; ++} ++ + static struct nfs4_delegation * + nfs4_set_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp, + struct svc_fh *parent) +@@ -5468,6 +5485,8 @@ nfs4_set_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp, + spin_lock(&fp->fi_lock); + if (nfs4_delegation_exists(clp, fp)) + status = -EAGAIN; ++ else if (nfsd4_verify_setuid_write(open, nf)) ++ status = -EAGAIN; + else if (!fp->fi_deleg_file) { + fp->fi_deleg_file = nf; + /* increment early to prevent fi_deleg_file from being +@@ -5508,6 +5527,14 @@ nfs4_set_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp, + if (status) + goto out_unlock; + ++ /* ++ * Now that the deleg is set, check again to ensure that nothing ++ * raced in and changed the mode while we weren't lookng. ++ */ ++ status = nfsd4_verify_setuid_write(open, fp->fi_deleg_file); ++ if (status) ++ goto out_unlock; ++ + spin_lock(&state_lock); + spin_lock(&fp->fi_lock); + if (fp->fi_had_conflict) +-- +2.43.0 + diff --git a/queue-5.10/nfsd-don-t-ignore-high-bits-of-copy-count.patch b/queue-5.10/nfsd-don-t-ignore-high-bits-of-copy-count.patch new file mode 100644 index 00000000000..f8a5d2e6dad --- /dev/null +++ b/queue-5.10/nfsd-don-t-ignore-high-bits-of-copy-count.patch @@ -0,0 +1,37 @@ +From a1941f7f8b03e6b8cdef3ccdefd8ae542f47487b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Mar 2021 20:03:22 -0400 +Subject: nfsd: don't ignore high bits of copy count + +From: J. Bruce Fields + +[ Upstream commit e7a833e9cc6c3b58fe94f049d2b40943cba07086 ] + +Note size_t is 32-bit on a 32-bit architecture, but cp_count is defined +by the protocol to be 64 bit, so we could be turning a large copy into a +0-length copy here. + +Reported-by: +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 949d9cedef5d1..f85958f81a266 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -1376,7 +1376,7 @@ static ssize_t _nfsd_copy_file_range(struct nfsd4_copy *copy) + struct file *dst = copy->nf_dst->nf_file; + struct file *src = copy->nf_src->nf_file; + ssize_t bytes_copied = 0; +- size_t bytes_total = copy->cp_count; ++ u64 bytes_total = copy->cp_count; + u64 src_pos = copy->cp_src_pos; + u64 dst_pos = copy->cp_dst_pos; + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-don-t-kill-nfsd_files-because-of-lease-break-er.patch b/queue-5.10/nfsd-don-t-kill-nfsd_files-because-of-lease-break-er.patch new file mode 100644 index 00000000000..1b816b19159 --- /dev/null +++ b/queue-5.10/nfsd-don-t-kill-nfsd_files-because-of-lease-break-er.patch @@ -0,0 +1,101 @@ +From de52e979804be7cbbec977710a1dccea86241801 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Jan 2023 07:15:11 -0500 +Subject: nfsd: don't kill nfsd_files because of lease break error + +From: Jeff Layton + +[ Upstream commit c6593366c0bf222be9c7561354dfb921c611745e ] + +An error from break_lease is non-fatal, so we needn't destroy the +nfsd_file in that case. Just put the reference like we normally would +and return the error. + +Signed-off-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 29 +++++++++++++++-------------- + 1 file changed, 15 insertions(+), 14 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index d61c8223082a4..43bb2fd47cf58 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -1101,7 +1101,7 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + nf = nfsd_file_alloc(&key, may_flags); + if (!nf) { + status = nfserr_jukebox; +- goto out_status; ++ goto out; + } + + ret = rhashtable_lookup_insert_key(&nfsd_file_rhash_tbl, +@@ -1110,13 +1110,11 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + if (likely(ret == 0)) + goto open_file; + +- nfsd_file_slab_free(&nf->nf_rcu); +- nf = NULL; + if (ret == -EEXIST) + goto retry; + trace_nfsd_file_insert_err(rqstp, key.inode, may_flags, ret); + status = nfserr_jukebox; +- goto out_status; ++ goto construction_err; + + wait_for_construction: + wait_on_bit(&nf->nf_flags, NFSD_FILE_PENDING, TASK_UNINTERRUPTIBLE); +@@ -1126,29 +1124,25 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + trace_nfsd_file_cons_err(rqstp, key.inode, may_flags, nf); + if (!open_retry) { + status = nfserr_jukebox; +- goto out; ++ goto construction_err; + } + open_retry = false; +- if (refcount_dec_and_test(&nf->nf_ref)) +- nfsd_file_free(nf); + goto retry; + } +- + this_cpu_inc(nfsd_file_cache_hits); + + status = nfserrno(nfsd_open_break_lease(file_inode(nf->nf_file), may_flags)); ++ if (status != nfs_ok) { ++ nfsd_file_put(nf); ++ nf = NULL; ++ } ++ + out: + if (status == nfs_ok) { + this_cpu_inc(nfsd_file_acquisitions); + nfsd_file_check_write_error(nf); + *pnf = nf; +- } else { +- if (refcount_dec_and_test(&nf->nf_ref)) +- nfsd_file_free(nf); +- nf = NULL; + } +- +-out_status: + put_cred(key.cred); + trace_nfsd_file_acquire(rqstp, key.inode, may_flags, nf, status); + return status; +@@ -1178,6 +1172,13 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + if (status != nfs_ok) + nfsd_file_unhash(nf); + clear_and_wake_up_bit(NFSD_FILE_PENDING, &nf->nf_flags); ++ if (status == nfs_ok) ++ goto out; ++ ++construction_err: ++ if (refcount_dec_and_test(&nf->nf_ref)) ++ nfsd_file_free(nf); ++ nf = NULL; + goto out; + } + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-don-t-open-code-clear_and_wake_up_bit.patch b/queue-5.10/nfsd-don-t-open-code-clear_and_wake_up_bit.patch new file mode 100644 index 00000000000..9d6a40da2dd --- /dev/null +++ b/queue-5.10/nfsd-don-t-open-code-clear_and_wake_up_bit.patch @@ -0,0 +1,34 @@ +From ad4c35b8bcd955d4d4141977e8916cce3004faa8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Jan 2023 07:15:09 -0500 +Subject: nfsd: don't open-code clear_and_wake_up_bit + +From: Jeff Layton + +[ Upstream commit b8bea9f6cdd7236c7c2238d022145e9b2f8aac22 ] + +Signed-off-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index 4a3796c6bd957..677a8d935ccc2 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -1173,9 +1173,7 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + status = nfserr_jukebox; + if (status != nfs_ok) + nfsd_file_unhash(nf); +- clear_bit_unlock(NFSD_FILE_PENDING, &nf->nf_flags); +- smp_mb__after_atomic(); +- wake_up_bit(&nf->nf_flags, NFSD_FILE_PENDING); ++ clear_and_wake_up_bit(NFSD_FILE_PENDING, &nf->nf_flags); + goto out; + } + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-don-t-replace-page-in-rq_pages-if-it-s-a-contin.patch b/queue-5.10/nfsd-don-t-replace-page-in-rq_pages-if-it-s-a-contin.patch new file mode 100644 index 00000000000..c86fd4ce4e2 --- /dev/null +++ b/queue-5.10/nfsd-don-t-replace-page-in-rq_pages-if-it-s-a-contin.patch @@ -0,0 +1,65 @@ +From 28c71491e17daa6758b7240bb5105c4e0c9bfc28 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Mar 2023 13:13:08 -0400 +Subject: nfsd: don't replace page in rq_pages if it's a continuation of last + page + +From: Jeff Layton + +[ Upstream commit 27c934dd8832dd40fd34776f916dc201e18b319b ] + +The splice read calls nfsd_splice_actor to put the pages containing file +data into the svc_rqst->rq_pages array. It's possible however to get a +splice result that only has a partial page at the end, if (e.g.) the +filesystem hands back a short read that doesn't cover the whole page. + +nfsd_splice_actor will plop the partial page into its rq_pages array and +return. Then later, when nfsd_splice_actor is called again, the +remainder of the page may end up being filled out. At this point, +nfsd_splice_actor will put the page into the array _again_ corrupting +the reply. If this is done enough times, rq_next_page will overrun the +array and corrupt the trailing fields -- the rq_respages and +rq_next_page pointers themselves. + +If we've already added the page to the array in the last pass, don't add +it to the array a second time when dealing with a splice continuation. +This was originally handled properly in nfsd_splice_actor, but commit +91e23b1c3982 ("NFSD: Clean up nfsd_splice_actor()") removed the check +for it. + +Fixes: 91e23b1c3982 ("NFSD: Clean up nfsd_splice_actor()") +Cc: Al Viro +Reported-by: Dario Lesca +Tested-by: David Critch +Link: https://bugzilla.redhat.com/show_bug.cgi?id=2150630 +Signed-off-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/vfs.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index ddf424d76d410..abc682854507b 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -954,8 +954,15 @@ nfsd_splice_actor(struct pipe_inode_info *pipe, struct pipe_buffer *buf, + struct page *last_page; + + last_page = page + (offset + sd->len - 1) / PAGE_SIZE; +- for (page += offset / PAGE_SIZE; page <= last_page; page++) ++ for (page += offset / PAGE_SIZE; page <= last_page; page++) { ++ /* ++ * Skip page replacement when extending the contents ++ * of the current page. ++ */ ++ if (page == *(rqstp->rq_next_page - 1)) ++ continue; + svc_rqst_replace_page(rqstp, page); ++ } + if (rqstp->rq_res.page_len == 0) // first call + rqstp->rq_res.page_base = offset % PAGE_SIZE; + rqstp->rq_res.page_len += sd->len; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-don-t-take-fi_lock-in-nfsd_break_deleg_cb.patch b/queue-5.10/nfsd-don-t-take-fi_lock-in-nfsd_break_deleg_cb.patch new file mode 100644 index 00000000000..b03168067d5 --- /dev/null +++ b/queue-5.10/nfsd-don-t-take-fi_lock-in-nfsd_break_deleg_cb.patch @@ -0,0 +1,97 @@ +From b3444bfbe0a1be0f9f31e508372a5b8b6702793c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 5 Feb 2024 13:22:39 +1100 +Subject: nfsd: don't take fi_lock in nfsd_break_deleg_cb() + +From: NeilBrown + +[ Upstream commit 5ea9a7c5fe4149f165f0e3b624fe08df02b6c301 ] + +A recent change to check_for_locks() changed it to take ->flc_lock while +holding ->fi_lock. This creates a lock inversion (reported by lockdep) +because there is a case where ->fi_lock is taken while holding +->flc_lock. + +->flc_lock is held across ->fl_lmops callbacks, and +nfsd_break_deleg_cb() is one of those and does take ->fi_lock. However +it doesn't need to. + +Prior to v4.17-rc1~110^2~22 ("nfsd: create a separate lease for each +delegation") nfsd_break_deleg_cb() would walk the ->fi_delegations list +and so needed the lock. Since then it doesn't walk the list and doesn't +need the lock. + +Two actions are performed under the lock. One is to call +nfsd_break_one_deleg which calls nfsd4_run_cb(). These doesn't act on +the nfs4_file at all, so don't need the lock. + +The other is to set ->fi_had_conflict which is in the nfs4_file. +This field is only ever set here (except when initialised to false) +so there is no possible problem will multiple threads racing when +setting it. + +The field is tested twice in nfs4_set_delegation(). The first test does +not hold a lock and is documented as an opportunistic optimisation, so +it doesn't impose any need to hold ->fi_lock while setting +->fi_had_conflict. + +The second test in nfs4_set_delegation() *is* make under ->fi_lock, so +removing the locking when ->fi_had_conflict is set could make a change. +The change could only be interesting if ->fi_had_conflict tested as +false even though nfsd_break_one_deleg() ran before ->fi_lock was +unlocked. i.e. while hash_delegation_locked() was running. +As hash_delegation_lock() doesn't interact in any way with nfs4_run_cb() +there can be no importance to this interaction. + +So this patch removes the locking from nfsd_break_one_deleg() and moves +the final test on ->fi_had_conflict out of the locked region to make it +clear that locking isn't important to the test. It is still tested +*after* vfs_setlease() has succeeded. This might be significant and as +vfs_setlease() takes ->flc_lock, and nfsd_break_one_deleg() is called +under ->flc_lock this "after" is a true ordering provided by a spinlock. + +Fixes: edcf9725150e ("nfsd: fix RELEASE_LOCKOWNER") +Signed-off-by: NeilBrown +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 11 +++++------ + 1 file changed, 5 insertions(+), 6 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index c073cc23c5285..165acd8138abe 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -4946,10 +4946,8 @@ nfsd_break_deleg_cb(struct file_lock *fl) + */ + fl->fl_break_time = 0; + +- spin_lock(&fp->fi_lock); + fp->fi_had_conflict = true; + nfsd_break_one_deleg(dp); +- spin_unlock(&fp->fi_lock); + return false; + } + +@@ -5537,12 +5535,13 @@ nfs4_set_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp, + if (status) + goto out_unlock; + ++ status = -EAGAIN; ++ if (fp->fi_had_conflict) ++ goto out_unlock; ++ + spin_lock(&state_lock); + spin_lock(&fp->fi_lock); +- if (fp->fi_had_conflict) +- status = -EAGAIN; +- else +- status = hash_delegation_locked(dp, fp); ++ status = hash_delegation_locked(dp, fp); + spin_unlock(&fp->fi_lock); + spin_unlock(&state_lock); + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-don-t-take-put-an-extra-reference-when-putting-.patch b/queue-5.10/nfsd-don-t-take-put-an-extra-reference-when-putting-.patch new file mode 100644 index 00000000000..96f8be9b0e9 --- /dev/null +++ b/queue-5.10/nfsd-don-t-take-put-an-extra-reference-when-putting-.patch @@ -0,0 +1,38 @@ +From dcc82b518e8190a1eff27c9902bcc18494541fc2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Jan 2023 12:31:37 -0500 +Subject: nfsd: don't take/put an extra reference when putting a file + +From: Jeff Layton + +[ Upstream commit b2ff1bd71db2a1b193a6dde0845adcd69cbcf75e ] + +The last thing that filp_close does is an fput, so don't bother taking +and putting the extra reference. + +Signed-off-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index faa0c7d0253eb..786e06cf107ff 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -381,10 +381,8 @@ nfsd_file_free(struct nfsd_file *nf) + if (nf->nf_mark) + nfsd_file_mark_put(nf->nf_mark); + if (nf->nf_file) { +- get_file(nf->nf_file); +- filp_close(nf->nf_file, NULL); + nfsd_file_check_write_error(nf); +- fput(nf->nf_file); ++ filp_close(nf->nf_file, NULL); + } + + /* +-- +2.43.0 + diff --git a/queue-5.10/nfsd-drop-fh-argument-from-alloc_init_deleg.patch b/queue-5.10/nfsd-drop-fh-argument-from-alloc_init_deleg.patch new file mode 100644 index 00000000000..356f84f4007 --- /dev/null +++ b/queue-5.10/nfsd-drop-fh-argument-from-alloc_init_deleg.patch @@ -0,0 +1,94 @@ +From 77586cd216130f4978bad6619b3dce837a37985e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 Jul 2022 16:45:30 +1000 +Subject: NFSD: drop fh argument from alloc_init_deleg + +From: Jeff Layton + +[ Upstream commit bbf936edd543e7220f60f9cbd6933b916550396d ] + +Currently, we pass the fh of the opened file down through several +functions so that alloc_init_deleg can pass it to delegation_blocked. +The filehandle of the open file is available in the nfs4_file however, +so there's no need to pass it in a separate argument. + +Drop the argument from alloc_init_deleg, nfs4_open_delegation and +nfs4_set_delegation. + +Signed-off-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 14 ++++++-------- + 1 file changed, 6 insertions(+), 8 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 1babc08fcb88f..194d8aeb1fd46 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -1143,7 +1143,6 @@ static void block_delegations(struct knfsd_fh *fh) + + static struct nfs4_delegation * + alloc_init_deleg(struct nfs4_client *clp, struct nfs4_file *fp, +- struct svc_fh *current_fh, + struct nfs4_clnt_odstate *odstate) + { + struct nfs4_delegation *dp; +@@ -1153,7 +1152,7 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_file *fp, + n = atomic_long_inc_return(&num_delegations); + if (n < 0 || n > max_delegations) + goto out_dec; +- if (delegation_blocked(¤t_fh->fh_handle)) ++ if (delegation_blocked(&fp->fi_fhandle)) + goto out_dec; + dp = delegstateid(nfs4_alloc_stid(clp, deleg_slab, nfs4_free_deleg)); + if (dp == NULL) +@@ -5307,7 +5306,7 @@ static int nfsd4_check_conflicting_opens(struct nfs4_client *clp, + } + + static struct nfs4_delegation * +-nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh, ++nfs4_set_delegation(struct nfs4_client *clp, + struct nfs4_file *fp, struct nfs4_clnt_odstate *odstate) + { + int status = 0; +@@ -5352,7 +5351,7 @@ nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh, + return ERR_PTR(status); + + status = -ENOMEM; +- dp = alloc_init_deleg(clp, fp, fh, odstate); ++ dp = alloc_init_deleg(clp, fp, odstate); + if (!dp) + goto out_delegees; + +@@ -5420,8 +5419,7 @@ static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status) + * proper support for them. + */ + static void +-nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, +- struct nfs4_ol_stateid *stp) ++nfs4_open_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp) + { + struct nfs4_delegation *dp; + struct nfs4_openowner *oo = openowner(stp->st_stateowner); +@@ -5453,7 +5451,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, + default: + goto out_no_deleg; + } +- dp = nfs4_set_delegation(clp, fh, stp->st_stid.sc_file, stp->st_clnt_odstate); ++ dp = nfs4_set_delegation(clp, stp->st_stid.sc_file, stp->st_clnt_odstate); + if (IS_ERR(dp)) + goto out_no_deleg; + +@@ -5585,7 +5583,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf + * Attempt to hand out a delegation. No error return, because the + * OPEN succeeds even if we fail. + */ +- nfs4_open_delegation(current_fh, open, stp); ++ nfs4_open_delegation(open, stp); + nodeleg: + status = nfs_ok; + trace_nfsd_open(&stp->st_stid.sc_stateid); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-drop-fname-and-flen-args-from-nfsd_create_locke.patch b/queue-5.10/nfsd-drop-fname-and-flen-args-from-nfsd_create_locke.patch new file mode 100644 index 00000000000..6ed5a2646b7 --- /dev/null +++ b/queue-5.10/nfsd-drop-fname-and-flen-args-from-nfsd_create_locke.patch @@ -0,0 +1,79 @@ +From f1a943a39f2eabe5f5b81a68dff4f0a1a04a5b22 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 6 Sep 2022 10:42:19 +1000 +Subject: NFSD: drop fname and flen args from nfsd_create_locked() + +From: NeilBrown + +[ Upstream commit 9558f9304ca1903090fa5d995a3269a8e82804b4 ] + +nfsd_create_locked() does not use the "fname" and "flen" arguments, so +drop them from declaration and all callers. + +Signed-off-by: NeilBrown +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsproc.c | 5 ++--- + fs/nfsd/vfs.c | 5 ++--- + fs/nfsd/vfs.h | 4 ++-- + 3 files changed, 6 insertions(+), 8 deletions(-) + +diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c +index 749c3354304c2..7ed03ac6bdab3 100644 +--- a/fs/nfsd/nfsproc.c ++++ b/fs/nfsd/nfsproc.c +@@ -391,9 +391,8 @@ nfsd_proc_create(struct svc_rqst *rqstp) + resp->status = nfs_ok; + if (!inode) { + /* File doesn't exist. Create it and set attrs */ +- resp->status = nfsd_create_locked(rqstp, dirfhp, argp->name, +- argp->len, &attrs, type, rdev, +- newfhp); ++ resp->status = nfsd_create_locked(rqstp, dirfhp, &attrs, type, ++ rdev, newfhp); + } else if (type == S_IFREG) { + dprintk("nfsd: existing %s, valid=%x, size=%ld\n", + argp->name, attr->ia_valid, (long) attr->ia_size); +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index bc377ee177171..5ec1119a87859 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -1273,7 +1273,7 @@ nfsd_check_ignore_resizing(struct iattr *iap) + /* The parent directory should already be locked: */ + __be32 + nfsd_create_locked(struct svc_rqst *rqstp, struct svc_fh *fhp, +- char *fname, int flen, struct nfsd_attrs *attrs, ++ struct nfsd_attrs *attrs, + int type, dev_t rdev, struct svc_fh *resfhp) + { + struct dentry *dentry, *dchild; +@@ -1399,8 +1399,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, + if (err) + goto out_unlock; + fh_fill_pre_attrs(fhp); +- err = nfsd_create_locked(rqstp, fhp, fname, flen, attrs, type, +- rdev, resfhp); ++ err = nfsd_create_locked(rqstp, fhp, attrs, type, rdev, resfhp); + fh_fill_post_attrs(fhp); + out_unlock: + inode_unlock(dentry->d_inode); +diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h +index c95cd414b4bb0..120521bc7b247 100644 +--- a/fs/nfsd/vfs.h ++++ b/fs/nfsd/vfs.h +@@ -79,8 +79,8 @@ __be32 nfsd4_clone_file_range(struct svc_rqst *rqstp, + u64 count, bool sync); + #endif /* CONFIG_NFSD_V4 */ + __be32 nfsd_create_locked(struct svc_rqst *, struct svc_fh *, +- char *name, int len, struct nfsd_attrs *attrs, +- int type, dev_t rdev, struct svc_fh *res); ++ struct nfsd_attrs *attrs, int type, dev_t rdev, ++ struct svc_fh *res); + __be32 nfsd_create(struct svc_rqst *, struct svc_fh *, + char *name, int len, struct nfsd_attrs *attrs, + int type, dev_t rdev, struct svc_fh *res); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-drop-support-for-ancient-filehandles.patch b/queue-5.10/nfsd-drop-support-for-ancient-filehandles.patch new file mode 100644 index 00000000000..137a602e9da --- /dev/null +++ b/queue-5.10/nfsd-drop-support-for-ancient-filehandles.patch @@ -0,0 +1,324 @@ +From 4f4b556d21c48c6aebd18ba12df536783e52c00f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Sep 2021 11:15:29 +1000 +Subject: NFSD: drop support for ancient filehandles + +From: NeilBrown + +[ Upstream commit c645a883df34ee10b884ec921e850def54b7f461 ] + +Filehandles not in the "new" or "version 1" format have not been handed +out for new mounts since Linux 2.4 which was released 20 years ago. +I think it is safe to say that no such file handles are still in use, +and that we can drop support for them. + +Signed-off-by: NeilBrown +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsfh.c | 160 +++++++++++++++--------------------------------- + fs/nfsd/nfsfh.h | 34 +--------- + 2 files changed, 54 insertions(+), 140 deletions(-) + +diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c +index 04930056222b7..7e5a508173a04 100644 +--- a/fs/nfsd/nfsfh.c ++++ b/fs/nfsd/nfsfh.c +@@ -153,11 +153,12 @@ static inline __be32 check_pseudo_root(struct svc_rqst *rqstp, + static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp) + { + struct knfsd_fh *fh = &fhp->fh_handle; +- struct fid *fid = NULL, sfid; ++ struct fid *fid = NULL; + struct svc_export *exp; + struct dentry *dentry; + int fileid_type; + int data_left = fh->fh_size/4; ++ int len; + __be32 error; + + error = nfserr_stale; +@@ -166,48 +167,35 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp) + if (rqstp->rq_vers == 4 && fh->fh_size == 0) + return nfserr_nofilehandle; + +- if (fh->fh_version == 1) { +- int len; +- +- if (--data_left < 0) +- return error; +- if (fh->fh_auth_type != 0) +- return error; +- len = key_len(fh->fh_fsid_type) / 4; +- if (len == 0) +- return error; +- if (fh->fh_fsid_type == FSID_MAJOR_MINOR) { +- /* deprecated, convert to type 3 */ +- len = key_len(FSID_ENCODE_DEV)/4; +- fh->fh_fsid_type = FSID_ENCODE_DEV; +- /* +- * struct knfsd_fh uses host-endian fields, which are +- * sometimes used to hold net-endian values. This +- * confuses sparse, so we must use __force here to +- * keep it from complaining. +- */ +- fh->fh_fsid[0] = new_encode_dev(MKDEV(ntohl((__force __be32)fh->fh_fsid[0]), +- ntohl((__force __be32)fh->fh_fsid[1]))); +- fh->fh_fsid[1] = fh->fh_fsid[2]; +- } +- data_left -= len; +- if (data_left < 0) +- return error; +- exp = rqst_exp_find(rqstp, fh->fh_fsid_type, fh->fh_fsid); +- fid = (struct fid *)(fh->fh_fsid + len); +- } else { +- __u32 tfh[2]; +- dev_t xdev; +- ino_t xino; +- +- if (fh->fh_size != NFS_FHSIZE) +- return error; +- /* assume old filehandle format */ +- xdev = old_decode_dev(fh->ofh_xdev); +- xino = u32_to_ino_t(fh->ofh_xino); +- mk_fsid(FSID_DEV, tfh, xdev, xino, 0, NULL); +- exp = rqst_exp_find(rqstp, FSID_DEV, tfh); ++ if (fh->fh_version != 1) ++ return error; ++ ++ if (--data_left < 0) ++ return error; ++ if (fh->fh_auth_type != 0) ++ return error; ++ len = key_len(fh->fh_fsid_type) / 4; ++ if (len == 0) ++ return error; ++ if (fh->fh_fsid_type == FSID_MAJOR_MINOR) { ++ /* deprecated, convert to type 3 */ ++ len = key_len(FSID_ENCODE_DEV)/4; ++ fh->fh_fsid_type = FSID_ENCODE_DEV; ++ /* ++ * struct knfsd_fh uses host-endian fields, which are ++ * sometimes used to hold net-endian values. This ++ * confuses sparse, so we must use __force here to ++ * keep it from complaining. ++ */ ++ fh->fh_fsid[0] = new_encode_dev(MKDEV(ntohl((__force __be32)fh->fh_fsid[0]), ++ ntohl((__force __be32)fh->fh_fsid[1]))); ++ fh->fh_fsid[1] = fh->fh_fsid[2]; + } ++ data_left -= len; ++ if (data_left < 0) ++ return error; ++ exp = rqst_exp_find(rqstp, fh->fh_fsid_type, fh->fh_fsid); ++ fid = (struct fid *)(fh->fh_fsid + len); + + error = nfserr_stale; + if (IS_ERR(exp)) { +@@ -252,18 +240,7 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp) + if (rqstp->rq_vers > 2) + error = nfserr_badhandle; + +- if (fh->fh_version != 1) { +- sfid.i32.ino = fh->ofh_ino; +- sfid.i32.gen = fh->ofh_generation; +- sfid.i32.parent_ino = fh->ofh_dirino; +- fid = &sfid; +- data_left = 3; +- if (fh->ofh_dirino == 0) +- fileid_type = FILEID_INO32_GEN; +- else +- fileid_type = FILEID_INO32_GEN_PARENT; +- } else +- fileid_type = fh->fh_fileid_type; ++ fileid_type = fh->fh_fileid_type; + + if (fileid_type == FILEID_ROOT) + dentry = dget(exp->ex_path.dentry); +@@ -451,20 +428,6 @@ static void _fh_update(struct svc_fh *fhp, struct svc_export *exp, + } + } + +-/* +- * for composing old style file handles +- */ +-static inline void _fh_update_old(struct dentry *dentry, +- struct svc_export *exp, +- struct knfsd_fh *fh) +-{ +- fh->ofh_ino = ino_t_to_u32(d_inode(dentry)->i_ino); +- fh->ofh_generation = d_inode(dentry)->i_generation; +- if (d_is_dir(dentry) || +- (exp->ex_flags & NFSEXP_NOSUBTREECHECK)) +- fh->ofh_dirino = 0; +-} +- + static bool is_root_export(struct svc_export *exp) + { + return exp->ex_path.dentry == exp->ex_path.dentry->d_sb->s_root; +@@ -561,9 +524,6 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, + /* ref_fh is a reference file handle. + * if it is non-null and for the same filesystem, then we should compose + * a filehandle which is of the same version, where possible. +- * Currently, that means that if ref_fh->fh_handle.fh_version == 0xca +- * Then create a 32byte filehandle using nfs_fhbase_old +- * + */ + + struct inode * inode = d_inode(dentry); +@@ -599,35 +559,21 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, + fhp->fh_dentry = dget(dentry); /* our internal copy */ + fhp->fh_export = exp_get(exp); + +- if (fhp->fh_handle.fh_version == 0xca) { +- /* old style filehandle please */ +- memset(&fhp->fh_handle.fh_base, 0, NFS_FHSIZE); +- fhp->fh_handle.fh_size = NFS_FHSIZE; +- fhp->fh_handle.ofh_dcookie = 0xfeebbaca; +- fhp->fh_handle.ofh_dev = old_encode_dev(ex_dev); +- fhp->fh_handle.ofh_xdev = fhp->fh_handle.ofh_dev; +- fhp->fh_handle.ofh_xino = +- ino_t_to_u32(d_inode(exp->ex_path.dentry)->i_ino); +- fhp->fh_handle.ofh_dirino = ino_t_to_u32(parent_ino(dentry)); +- if (inode) +- _fh_update_old(dentry, exp, &fhp->fh_handle); +- } else { +- fhp->fh_handle.fh_size = +- key_len(fhp->fh_handle.fh_fsid_type) + 4; +- fhp->fh_handle.fh_auth_type = 0; +- +- mk_fsid(fhp->fh_handle.fh_fsid_type, +- fhp->fh_handle.fh_fsid, +- ex_dev, +- d_inode(exp->ex_path.dentry)->i_ino, +- exp->ex_fsid, exp->ex_uuid); +- +- if (inode) +- _fh_update(fhp, exp, dentry); +- if (fhp->fh_handle.fh_fileid_type == FILEID_INVALID) { +- fh_put(fhp); +- return nfserr_opnotsupp; +- } ++ fhp->fh_handle.fh_size = ++ key_len(fhp->fh_handle.fh_fsid_type) + 4; ++ fhp->fh_handle.fh_auth_type = 0; ++ ++ mk_fsid(fhp->fh_handle.fh_fsid_type, ++ fhp->fh_handle.fh_fsid, ++ ex_dev, ++ d_inode(exp->ex_path.dentry)->i_ino, ++ exp->ex_fsid, exp->ex_uuid); ++ ++ if (inode) ++ _fh_update(fhp, exp, dentry); ++ if (fhp->fh_handle.fh_fileid_type == FILEID_INVALID) { ++ fh_put(fhp); ++ return nfserr_opnotsupp; + } + + return 0; +@@ -648,16 +594,12 @@ fh_update(struct svc_fh *fhp) + dentry = fhp->fh_dentry; + if (d_really_is_negative(dentry)) + goto out_negative; +- if (fhp->fh_handle.fh_version != 1) { +- _fh_update_old(dentry, fhp->fh_export, &fhp->fh_handle); +- } else { +- if (fhp->fh_handle.fh_fileid_type != FILEID_ROOT) +- return 0; ++ if (fhp->fh_handle.fh_fileid_type != FILEID_ROOT) ++ return 0; + +- _fh_update(fhp, fhp->fh_export, dentry); +- if (fhp->fh_handle.fh_fileid_type == FILEID_INVALID) +- return nfserr_opnotsupp; +- } ++ _fh_update(fhp, fhp->fh_export, dentry); ++ if (fhp->fh_handle.fh_fileid_type == FILEID_INVALID) ++ return nfserr_opnotsupp; + return 0; + out_bad: + printk(KERN_ERR "fh_update: fh not verified!\n"); +diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h +index ad47f16676a8c..8b5587f274a7d 100644 +--- a/fs/nfsd/nfsfh.h ++++ b/fs/nfsd/nfsfh.h +@@ -14,26 +14,7 @@ + #include + #include + +- +-/* +- * This is the old "dentry style" Linux NFSv2 file handle. +- * +- * The xino and xdev fields are currently used to transport the +- * ino/dev of the exported inode. +- */ +-struct nfs_fhbase_old { +- u32 fb_dcookie; /* dentry cookie - always 0xfeebbaca */ +- u32 fb_ino; /* our inode number */ +- u32 fb_dirino; /* dir inode number, 0 for directories */ +- u32 fb_dev; /* our device */ +- u32 fb_xdev; +- u32 fb_xino; +- u32 fb_generation; +-}; +- + /* +- * This is the new flexible, extensible style NFSv2/v3/v4 file handle. +- * + * The file handle starts with a sequence of four-byte words. + * The first word contains a version number (1) and three descriptor bytes + * that tell how the remaining 3 variable length fields should be handled. +@@ -57,7 +38,7 @@ struct nfs_fhbase_old { + * 6 - 16 byte uuid + * 7 - 8 byte inode number and 16 byte uuid + * +- * The fileid_type identified how the file within the filesystem is encoded. ++ * The fileid_type identifies how the file within the filesystem is encoded. + * The values for this field are filesystem specific, exccept that + * filesystems must not use the values '0' or '0xff'. 'See enum fid_type' + * in include/linux/exportfs.h for currently registered values. +@@ -65,7 +46,7 @@ struct nfs_fhbase_old { + struct nfs_fhbase_new { + union { + struct { +- u8 fb_version_aux; /* == 1, even => nfs_fhbase_old */ ++ u8 fb_version_aux; /* == 1 */ + u8 fb_auth_type_aux; + u8 fb_fsid_type_aux; + u8 fb_fileid_type_aux; +@@ -74,7 +55,7 @@ struct nfs_fhbase_new { + /* u32 fb_fileid[0]; floating */ + }; + struct { +- u8 fb_version; /* == 1, even => nfs_fhbase_old */ ++ u8 fb_version; /* == 1 */ + u8 fb_auth_type; + u8 fb_fsid_type; + u8 fb_fileid_type; +@@ -89,20 +70,11 @@ struct knfsd_fh { + * a new file handle + */ + union { +- struct nfs_fhbase_old fh_old; + u32 fh_pad[NFS4_FHSIZE/4]; + struct nfs_fhbase_new fh_new; + } fh_base; + }; + +-#define ofh_dcookie fh_base.fh_old.fb_dcookie +-#define ofh_ino fh_base.fh_old.fb_ino +-#define ofh_dirino fh_base.fh_old.fb_dirino +-#define ofh_dev fh_base.fh_old.fb_dev +-#define ofh_xdev fh_base.fh_old.fb_xdev +-#define ofh_xino fh_base.fh_old.fb_xino +-#define ofh_generation fh_base.fh_old.fb_generation +- + #define fh_version fh_base.fh_new.fb_version + #define fh_fsid_type fh_base.fh_new.fb_fsid_type + #define fh_auth_type fh_base.fh_new.fb_auth_type +-- +2.43.0 + diff --git a/queue-5.10/nfsd-drop-the-nfsd_put-helper.patch b/queue-5.10/nfsd-drop-the-nfsd_put-helper.patch new file mode 100644 index 00000000000..11fb81b4434 --- /dev/null +++ b/queue-5.10/nfsd-drop-the-nfsd_put-helper.patch @@ -0,0 +1,132 @@ +From 14930d2a542feab5a85a23e29682f779b90ac2da Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 3 Jan 2024 08:36:52 -0500 +Subject: nfsd: drop the nfsd_put helper + +From: Jeff Layton + +[ Upstream commit 64e6304169f1e1f078e7f0798033f80a7fb0ea46 ] + +It's not safe to call nfsd_put once nfsd_last_thread has been called, as +that function will zero out the nn->nfsd_serv pointer. + +Drop the nfsd_put helper altogether and open-code the svc_put in its +callers instead. That allows us to not be reliant on the value of that +pointer when handling an error. + +Fixes: 2a501f55cd64 ("nfsd: call nfsd_last_thread() before final nfsd_put()") +Reported-by: Zhi Li +Cc: NeilBrown +Signed-off-by: Jeffrey Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsctl.c | 31 +++++++++++++++++-------------- + fs/nfsd/nfsd.h | 7 ------- + 2 files changed, 17 insertions(+), 21 deletions(-) + +diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c +index eec442edb6556..f77f00c931723 100644 +--- a/fs/nfsd/nfsctl.c ++++ b/fs/nfsd/nfsctl.c +@@ -709,6 +709,7 @@ static ssize_t __write_ports_addfd(char *buf, struct net *net, const struct cred + char *mesg = buf; + int fd, err; + struct nfsd_net *nn = net_generic(net, nfsd_net_id); ++ struct svc_serv *serv; + + err = get_int(&mesg, &fd); + if (err != 0 || fd < 0) +@@ -718,15 +719,15 @@ static ssize_t __write_ports_addfd(char *buf, struct net *net, const struct cred + if (err != 0) + return err; + +- err = svc_addsock(nn->nfsd_serv, net, fd, buf, SIMPLE_TRANSACTION_LIMIT, cred); ++ serv = nn->nfsd_serv; ++ err = svc_addsock(serv, net, fd, buf, SIMPLE_TRANSACTION_LIMIT, cred); + +- if (err < 0 && !nn->nfsd_serv->sv_nrthreads && !nn->keep_active) ++ if (err < 0 && !serv->sv_nrthreads && !nn->keep_active) + nfsd_last_thread(net); +- else if (err >= 0 && +- !nn->nfsd_serv->sv_nrthreads && !xchg(&nn->keep_active, 1)) +- svc_get(nn->nfsd_serv); ++ else if (err >= 0 && !serv->sv_nrthreads && !xchg(&nn->keep_active, 1)) ++ svc_get(serv); + +- nfsd_put(net); ++ svc_put(serv); + return err; + } + +@@ -740,6 +741,7 @@ static ssize_t __write_ports_addxprt(char *buf, struct net *net, const struct cr + struct svc_xprt *xprt; + int port, err; + struct nfsd_net *nn = net_generic(net, nfsd_net_id); ++ struct svc_serv *serv; + + if (sscanf(buf, "%15s %5u", transport, &port) != 2) + return -EINVAL; +@@ -751,32 +753,33 @@ static ssize_t __write_ports_addxprt(char *buf, struct net *net, const struct cr + if (err != 0) + return err; + +- err = svc_xprt_create(nn->nfsd_serv, transport, net, ++ serv = nn->nfsd_serv; ++ err = svc_xprt_create(serv, transport, net, + PF_INET, port, SVC_SOCK_ANONYMOUS, cred); + if (err < 0) + goto out_err; + +- err = svc_xprt_create(nn->nfsd_serv, transport, net, ++ err = svc_xprt_create(serv, transport, net, + PF_INET6, port, SVC_SOCK_ANONYMOUS, cred); + if (err < 0 && err != -EAFNOSUPPORT) + goto out_close; + +- if (!nn->nfsd_serv->sv_nrthreads && !xchg(&nn->keep_active, 1)) +- svc_get(nn->nfsd_serv); ++ if (!serv->sv_nrthreads && !xchg(&nn->keep_active, 1)) ++ svc_get(serv); + +- nfsd_put(net); ++ svc_put(serv); + return 0; + out_close: +- xprt = svc_find_xprt(nn->nfsd_serv, transport, net, PF_INET, port); ++ xprt = svc_find_xprt(serv, transport, net, PF_INET, port); + if (xprt != NULL) { + svc_xprt_close(xprt); + svc_xprt_put(xprt); + } + out_err: +- if (!nn->nfsd_serv->sv_nrthreads && !nn->keep_active) ++ if (!serv->sv_nrthreads && !nn->keep_active) + nfsd_last_thread(net); + +- nfsd_put(net); ++ svc_put(serv); + return err; + } + +diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h +index 3796015dc7656..013bfa24ced21 100644 +--- a/fs/nfsd/nfsd.h ++++ b/fs/nfsd/nfsd.h +@@ -96,13 +96,6 @@ int nfsd_pool_stats_open(struct inode *, struct file *); + int nfsd_pool_stats_release(struct inode *, struct file *); + void nfsd_shutdown_threads(struct net *net); + +-static inline void nfsd_put(struct net *net) +-{ +- struct nfsd_net *nn = net_generic(net, nfsd_net_id); +- +- svc_put(nn->nfsd_serv); +-} +- + bool i_am_nfsd(void); + + struct nfsdfs_client { +-- +2.43.0 + diff --git a/queue-5.10/nfsd-drop-trace_define_enum-for-nfsd4_cb_-state-macr.patch b/queue-5.10/nfsd-drop-trace_define_enum-for-nfsd4_cb_-state-macr.patch new file mode 100644 index 00000000000..48b2678d19d --- /dev/null +++ b/queue-5.10/nfsd-drop-trace_define_enum-for-nfsd4_cb_-state-macr.patch @@ -0,0 +1,38 @@ +From 4a2e10fd50fb51c9cfc945cb7b39623d161c0827 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 14 May 2021 15:56:37 -0400 +Subject: NFSD: Drop TRACE_DEFINE_ENUM for NFSD4_CB_ macros + +From: Chuck Lever + +[ Upstream commit 167145cc64ce4b4b177e636829909a6b14004f9e ] + +TRACE_DEFINE_ENUM() is necessary for enum {} but not for C macros. + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/trace.h | 5 ----- + 1 file changed, 5 deletions(-) + +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index de461c82dbf40..3683076e0fcd3 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -877,11 +877,6 @@ TRACE_EVENT(nfsd_cb_nodelegs, + TP_printk("client %08x:%08x", __entry->cl_boot, __entry->cl_id) + ) + +-TRACE_DEFINE_ENUM(NFSD4_CB_UP); +-TRACE_DEFINE_ENUM(NFSD4_CB_UNKNOWN); +-TRACE_DEFINE_ENUM(NFSD4_CB_DOWN); +-TRACE_DEFINE_ENUM(NFSD4_CB_FAULT); +- + #define show_cb_state(val) \ + __print_symbolic(val, \ + { NFSD4_CB_UP, "UP" }, \ +-- +2.43.0 + diff --git a/queue-5.10/nfsd-eliminate-the-nfsd_file_break_-flags.patch b/queue-5.10/nfsd-eliminate-the-nfsd_file_break_-flags.patch new file mode 100644 index 00000000000..933d34a43d6 --- /dev/null +++ b/queue-5.10/nfsd-eliminate-the-nfsd_file_break_-flags.patch @@ -0,0 +1,119 @@ +From 88fc57c09273ee7b92e6fd2f29171b6cb495e1a6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 Jul 2022 17:01:07 -0400 +Subject: nfsd: eliminate the NFSD_FILE_BREAK_* flags + +From: Jeff Layton + +[ Upstream commit 23ba98de6dcec665e15c0ca19244379bb0d30932 ] + +We had a report from the spring Bake-a-thon of data corruption in some +nfstest_interop tests. Looking at the traces showed the NFS server +allowing a v3 WRITE to proceed while a read delegation was still +outstanding. + +Currently, we only set NFSD_FILE_BREAK_* flags if +NFSD_MAY_NOT_BREAK_LEASE was set when we call nfsd_file_alloc. +NFSD_MAY_NOT_BREAK_LEASE was intended to be set when finding files for +COMMIT ops, where we need a writeable filehandle but don't need to +break read leases. + +It doesn't make any sense to consult that flag when allocating a file +since the file may be used on subsequent calls where we do want to break +the lease (and the usage of it here seems to be reverse from what it +should be anyway). + +Also, after calling nfsd_open_break_lease, we don't want to clear the +BREAK_* bits. A lease could end up being set on it later (more than +once) and we need to be able to break those leases as well. + +This means that the NFSD_FILE_BREAK_* flags now just mirror +NFSD_MAY_{READ,WRITE} flags, so there's no need for them at all. Just +drop those flags and unconditionally call nfsd_open_break_lease every +time. + +Reported-by: Olga Kornieskaia +Link: https://bugzilla.redhat.com/show_bug.cgi?id=2107360 +Fixes: 65294c1f2c5e (nfsd: add a new struct file caching facility to nfsd) +Cc: # 5.4.x : bb283ca18d1e NFSD: Clean up the show_nf_flags() macro +Cc: # 5.4.x +Signed-off-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 22 +--------------------- + fs/nfsd/filecache.h | 4 +--- + fs/nfsd/trace.h | 2 -- + 3 files changed, 2 insertions(+), 26 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index fc0fcb3321537..1d3d13b78be0e 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -183,12 +183,6 @@ nfsd_file_alloc(struct inode *inode, unsigned int may, unsigned int hashval, + nf->nf_hashval = hashval; + refcount_set(&nf->nf_ref, 1); + nf->nf_may = may & NFSD_FILE_MAY_MASK; +- if (may & NFSD_MAY_NOT_BREAK_LEASE) { +- if (may & NFSD_MAY_WRITE) +- __set_bit(NFSD_FILE_BREAK_WRITE, &nf->nf_flags); +- if (may & NFSD_MAY_READ) +- __set_bit(NFSD_FILE_BREAK_READ, &nf->nf_flags); +- } + nf->nf_mark = NULL; + trace_nfsd_file_alloc(nf); + } +@@ -957,21 +951,7 @@ nfsd_do_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + + this_cpu_inc(nfsd_file_cache_hits); + +- if (!(may_flags & NFSD_MAY_NOT_BREAK_LEASE)) { +- bool write = (may_flags & NFSD_MAY_WRITE); +- +- if (test_bit(NFSD_FILE_BREAK_READ, &nf->nf_flags) || +- (test_bit(NFSD_FILE_BREAK_WRITE, &nf->nf_flags) && write)) { +- status = nfserrno(nfsd_open_break_lease( +- file_inode(nf->nf_file), may_flags)); +- if (status == nfs_ok) { +- clear_bit(NFSD_FILE_BREAK_READ, &nf->nf_flags); +- if (write) +- clear_bit(NFSD_FILE_BREAK_WRITE, +- &nf->nf_flags); +- } +- } +- } ++ status = nfserrno(nfsd_open_break_lease(file_inode(nf->nf_file), may_flags)); + out: + if (status == nfs_ok) { + *pnf = nf; +diff --git a/fs/nfsd/filecache.h b/fs/nfsd/filecache.h +index 1da0c79a55804..c9e3c6eb4776e 100644 +--- a/fs/nfsd/filecache.h ++++ b/fs/nfsd/filecache.h +@@ -37,9 +37,7 @@ struct nfsd_file { + struct net *nf_net; + #define NFSD_FILE_HASHED (0) + #define NFSD_FILE_PENDING (1) +-#define NFSD_FILE_BREAK_READ (2) +-#define NFSD_FILE_BREAK_WRITE (3) +-#define NFSD_FILE_REFERENCED (4) ++#define NFSD_FILE_REFERENCED (2) + unsigned long nf_flags; + struct inode *nf_inode; + unsigned int nf_hashval; +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index 8ccce4ac66b4e..5c2292a1892cc 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -707,8 +707,6 @@ DEFINE_CLID_EVENT(confirmed_r); + __print_flags(val, "|", \ + { 1 << NFSD_FILE_HASHED, "HASHED" }, \ + { 1 << NFSD_FILE_PENDING, "PENDING" }, \ +- { 1 << NFSD_FILE_BREAK_READ, "BREAK_READ" }, \ +- { 1 << NFSD_FILE_BREAK_WRITE, "BREAK_WRITE" }, \ + { 1 << NFSD_FILE_REFERENCED, "REFERENCED"}) + + DECLARE_EVENT_CLASS(nfsd_file_class, +-- +2.43.0 + diff --git a/queue-5.10/nfsd-enforce-filehandle-check-for-source-file-in-cop.patch b/queue-5.10/nfsd-enforce-filehandle-check-for-source-file-in-cop.patch new file mode 100644 index 00000000000..ef88f66644b --- /dev/null +++ b/queue-5.10/nfsd-enforce-filehandle-check-for-source-file-in-cop.patch @@ -0,0 +1,43 @@ +From 00bb32189db59af989b5031df2e5ed88a6f4cd4a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 19 Aug 2022 15:16:36 -0400 +Subject: NFSD enforce filehandle check for source file in COPY + +From: Olga Kornievskaia + +[ Upstream commit 754035ff79a14886e68c0c9f6fa80adb21f12b53 ] + +If the passed in filehandle for the source file in the COPY operation +is not a regular file, the server MUST return NFS4ERR_WRONG_TYPE. + +Signed-off-by: Olga Kornievskaia +Reviewed-by: Jeff Layton +[ cel: adjusted to apply to v5.10.y ] +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 0431b979748b8..ebfe39d313119 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -1758,7 +1758,13 @@ static int nfsd4_do_async_copy(void *data) + filp = nfs42_ssc_open(copy->ss_mnt, ©->c_fh, + ©->stateid); + if (IS_ERR(filp)) { +- nfserr = nfserr_offload_denied; ++ switch (PTR_ERR(filp)) { ++ case -EBADF: ++ nfserr = nfserr_wrong_type; ++ break; ++ default: ++ nfserr = nfserr_offload_denied; ++ } + /* ss_mnt will be unmounted by the laundromat */ + goto do_callback; + } +-- +2.43.0 + diff --git a/queue-5.10/nfsd-enhance-inter-server-copy-cleanup.patch b/queue-5.10/nfsd-enhance-inter-server-copy-cleanup.patch new file mode 100644 index 00000000000..0f06a024244 --- /dev/null +++ b/queue-5.10/nfsd-enhance-inter-server-copy-cleanup.patch @@ -0,0 +1,345 @@ +From 579aa030c96bad392b8599cc49d214c570635355 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 18 Dec 2022 16:55:53 -0800 +Subject: NFSD: enhance inter-server copy cleanup + +From: Dai Ngo + +[ Upstream commit df24ac7a2e3a9d0bc68f1756a880e50bfe4b4522 ] + +Currently nfsd4_setup_inter_ssc returns the vfsmount of the source +server's export when the mount completes. After the copy is done +nfsd4_cleanup_inter_ssc is called with the vfsmount of the source +server and it searches nfsd_ssc_mount_list for a matching entry +to do the clean up. + +The problems with this approach are (1) the need to search the +nfsd_ssc_mount_list and (2) the code has to handle the case where +the matching entry is not found which looks ugly. + +The enhancement is instead of nfsd4_setup_inter_ssc returning the +vfsmount, it returns the nfsd4_ssc_umount_item which has the +vfsmount embedded in it. When nfsd4_cleanup_inter_ssc is called +it's passed with the nfsd4_ssc_umount_item directly to do the +clean up so no searching is needed and there is no need to handle +the 'not found' case. + +Signed-off-by: Dai Ngo +Signed-off-by: Chuck Lever +[ cel: adjusted whitespace and variable/function names ] +Reviewed-by: Olga Kornievskaia +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 111 ++++++++++++++++------------------------ + fs/nfsd/xdr4.h | 2 +- + include/linux/nfs_ssc.h | 2 +- + 3 files changed, 46 insertions(+), 69 deletions(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 4ab063a2ac84e..5e175133b7bc7 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -1295,15 +1295,15 @@ extern void nfs_sb_deactive(struct super_block *sb); + * setup a work entry in the ssc delayed unmount list. + */ + static __be32 nfsd4_ssc_setup_dul(struct nfsd_net *nn, char *ipaddr, +- struct nfsd4_ssc_umount_item **retwork, struct vfsmount **ss_mnt) ++ struct nfsd4_ssc_umount_item **nsui) + { + struct nfsd4_ssc_umount_item *ni = NULL; + struct nfsd4_ssc_umount_item *work = NULL; + struct nfsd4_ssc_umount_item *tmp; + DEFINE_WAIT(wait); ++ __be32 status = 0; + +- *ss_mnt = NULL; +- *retwork = NULL; ++ *nsui = NULL; + work = kzalloc(sizeof(*work), GFP_KERNEL); + try_again: + spin_lock(&nn->nfsd_ssc_lock); +@@ -1327,12 +1327,12 @@ static __be32 nfsd4_ssc_setup_dul(struct nfsd_net *nn, char *ipaddr, + finish_wait(&nn->nfsd_ssc_waitq, &wait); + goto try_again; + } +- *ss_mnt = ni->nsui_vfsmount; ++ *nsui = ni; + refcount_inc(&ni->nsui_refcnt); + spin_unlock(&nn->nfsd_ssc_lock); + kfree(work); + +- /* return vfsmount in ss_mnt */ ++ /* return vfsmount in (*nsui)->nsui_vfsmount */ + return 0; + } + if (work) { +@@ -1340,31 +1340,32 @@ static __be32 nfsd4_ssc_setup_dul(struct nfsd_net *nn, char *ipaddr, + refcount_set(&work->nsui_refcnt, 2); + work->nsui_busy = true; + list_add_tail(&work->nsui_list, &nn->nfsd_ssc_mount_list); +- *retwork = work; +- } ++ *nsui = work; ++ } else ++ status = nfserr_resource; + spin_unlock(&nn->nfsd_ssc_lock); +- return 0; ++ return status; + } + +-static void nfsd4_ssc_update_dul_work(struct nfsd_net *nn, +- struct nfsd4_ssc_umount_item *work, struct vfsmount *ss_mnt) ++static void nfsd4_ssc_update_dul(struct nfsd_net *nn, ++ struct nfsd4_ssc_umount_item *nsui, ++ struct vfsmount *ss_mnt) + { +- /* set nsui_vfsmount, clear busy flag and wakeup waiters */ + spin_lock(&nn->nfsd_ssc_lock); +- work->nsui_vfsmount = ss_mnt; +- work->nsui_busy = false; ++ nsui->nsui_vfsmount = ss_mnt; ++ nsui->nsui_busy = false; + wake_up_all(&nn->nfsd_ssc_waitq); + spin_unlock(&nn->nfsd_ssc_lock); + } + +-static void nfsd4_ssc_cancel_dul_work(struct nfsd_net *nn, +- struct nfsd4_ssc_umount_item *work) ++static void nfsd4_ssc_cancel_dul(struct nfsd_net *nn, ++ struct nfsd4_ssc_umount_item *nsui) + { + spin_lock(&nn->nfsd_ssc_lock); +- list_del(&work->nsui_list); ++ list_del(&nsui->nsui_list); + wake_up_all(&nn->nfsd_ssc_waitq); + spin_unlock(&nn->nfsd_ssc_lock); +- kfree(work); ++ kfree(nsui); + } + + /* +@@ -1372,7 +1373,7 @@ static void nfsd4_ssc_cancel_dul_work(struct nfsd_net *nn, + */ + static __be32 + nfsd4_interssc_connect(struct nl4_server *nss, struct svc_rqst *rqstp, +- struct vfsmount **mount) ++ struct nfsd4_ssc_umount_item **nsui) + { + struct file_system_type *type; + struct vfsmount *ss_mnt; +@@ -1383,7 +1384,6 @@ nfsd4_interssc_connect(struct nl4_server *nss, struct svc_rqst *rqstp, + char *ipaddr, *dev_name, *raw_data; + int len, raw_len; + __be32 status = nfserr_inval; +- struct nfsd4_ssc_umount_item *work = NULL; + struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); + + naddr = &nss->u.nl4_addr; +@@ -1391,6 +1391,7 @@ nfsd4_interssc_connect(struct nl4_server *nss, struct svc_rqst *rqstp, + naddr->addr_len, + (struct sockaddr *)&tmp_addr, + sizeof(tmp_addr)); ++ *nsui = NULL; + if (tmp_addrlen == 0) + goto out_err; + +@@ -1433,10 +1434,10 @@ nfsd4_interssc_connect(struct nl4_server *nss, struct svc_rqst *rqstp, + goto out_free_rawdata; + snprintf(dev_name, len + 5, "%s%s%s:/", startsep, ipaddr, endsep); + +- status = nfsd4_ssc_setup_dul(nn, ipaddr, &work, &ss_mnt); ++ status = nfsd4_ssc_setup_dul(nn, ipaddr, nsui); + if (status) + goto out_free_devname; +- if (ss_mnt) ++ if ((*nsui)->nsui_vfsmount) + goto out_done; + + /* Use an 'internal' mount: SB_KERNMOUNT -> MNT_INTERNAL */ +@@ -1444,15 +1445,12 @@ nfsd4_interssc_connect(struct nl4_server *nss, struct svc_rqst *rqstp, + module_put(type->owner); + if (IS_ERR(ss_mnt)) { + status = nfserr_nodev; +- if (work) +- nfsd4_ssc_cancel_dul_work(nn, work); ++ nfsd4_ssc_cancel_dul(nn, *nsui); + goto out_free_devname; + } +- if (work) +- nfsd4_ssc_update_dul_work(nn, work, ss_mnt); ++ nfsd4_ssc_update_dul(nn, *nsui, ss_mnt); + out_done: + status = 0; +- *mount = ss_mnt; + + out_free_devname: + kfree(dev_name); +@@ -1476,7 +1474,7 @@ nfsd4_interssc_connect(struct nl4_server *nss, struct svc_rqst *rqstp, + static __be32 + nfsd4_setup_inter_ssc(struct svc_rqst *rqstp, + struct nfsd4_compound_state *cstate, +- struct nfsd4_copy *copy, struct vfsmount **mount) ++ struct nfsd4_copy *copy) + { + struct svc_fh *s_fh = NULL; + stateid_t *s_stid = ©->cp_src_stateid; +@@ -1489,7 +1487,7 @@ nfsd4_setup_inter_ssc(struct svc_rqst *rqstp, + if (status) + goto out; + +- status = nfsd4_interssc_connect(copy->cp_src, rqstp, mount); ++ status = nfsd4_interssc_connect(copy->cp_src, rqstp, ©->ss_nsui); + if (status) + goto out; + +@@ -1507,45 +1505,27 @@ nfsd4_setup_inter_ssc(struct svc_rqst *rqstp, + } + + static void +-nfsd4_cleanup_inter_ssc(struct vfsmount *ss_mnt, struct file *filp, ++nfsd4_cleanup_inter_ssc(struct nfsd4_ssc_umount_item *nsui, struct file *filp, + struct nfsd_file *dst) + { +- bool found = false; +- long timeout; +- struct nfsd4_ssc_umount_item *tmp; +- struct nfsd4_ssc_umount_item *ni = NULL; + struct nfsd_net *nn = net_generic(dst->nf_net, nfsd_net_id); ++ long timeout = msecs_to_jiffies(nfsd4_ssc_umount_timeout); + + nfs42_ssc_close(filp); + nfsd_file_put(dst); + fput(filp); + +- if (!nn) { +- mntput(ss_mnt); +- return; +- } + spin_lock(&nn->nfsd_ssc_lock); +- timeout = msecs_to_jiffies(nfsd4_ssc_umount_timeout); +- list_for_each_entry_safe(ni, tmp, &nn->nfsd_ssc_mount_list, nsui_list) { +- if (ni->nsui_vfsmount->mnt_sb == ss_mnt->mnt_sb) { +- list_del(&ni->nsui_list); +- /* +- * vfsmount can be shared by multiple exports, +- * decrement refcnt. If the count drops to 1 it +- * will be unmounted when nsui_expire expires. +- */ +- refcount_dec(&ni->nsui_refcnt); +- ni->nsui_expire = jiffies + timeout; +- list_add_tail(&ni->nsui_list, &nn->nfsd_ssc_mount_list); +- found = true; +- break; +- } +- } ++ list_del(&nsui->nsui_list); ++ /* ++ * vfsmount can be shared by multiple exports, ++ * decrement refcnt. If the count drops to 1 it ++ * will be unmounted when nsui_expire expires. ++ */ ++ refcount_dec(&nsui->nsui_refcnt); ++ nsui->nsui_expire = jiffies + timeout; ++ list_add_tail(&nsui->nsui_list, &nn->nfsd_ssc_mount_list); + spin_unlock(&nn->nfsd_ssc_lock); +- if (!found) { +- mntput(ss_mnt); +- return; +- } + } + + #else /* CONFIG_NFSD_V4_2_INTER_SSC */ +@@ -1553,15 +1533,13 @@ nfsd4_cleanup_inter_ssc(struct vfsmount *ss_mnt, struct file *filp, + static __be32 + nfsd4_setup_inter_ssc(struct svc_rqst *rqstp, + struct nfsd4_compound_state *cstate, +- struct nfsd4_copy *copy, +- struct vfsmount **mount) ++ struct nfsd4_copy *copy) + { +- *mount = NULL; + return nfserr_inval; + } + + static void +-nfsd4_cleanup_inter_ssc(struct vfsmount *ss_mnt, struct file *filp, ++nfsd4_cleanup_inter_ssc(struct nfsd4_ssc_umount_item *nsui, struct file *filp, + struct nfsd_file *dst) + { + } +@@ -1702,7 +1680,7 @@ static void dup_copy_fields(struct nfsd4_copy *src, struct nfsd4_copy *dst) + memcpy(dst->cp_src, src->cp_src, sizeof(struct nl4_server)); + memcpy(&dst->stateid, &src->stateid, sizeof(src->stateid)); + memcpy(&dst->c_fh, &src->c_fh, sizeof(src->c_fh)); +- dst->ss_mnt = src->ss_mnt; ++ dst->ss_nsui = src->ss_nsui; + } + + static void cleanup_async_copy(struct nfsd4_copy *copy) +@@ -1751,8 +1729,8 @@ static int nfsd4_do_async_copy(void *data) + if (nfsd4_ssc_is_inter(copy)) { + struct file *filp; + +- filp = nfs42_ssc_open(copy->ss_mnt, ©->c_fh, +- ©->stateid); ++ filp = nfs42_ssc_open(copy->ss_nsui->nsui_vfsmount, ++ ©->c_fh, ©->stateid); + if (IS_ERR(filp)) { + switch (PTR_ERR(filp)) { + case -EBADF: +@@ -1766,7 +1744,7 @@ static int nfsd4_do_async_copy(void *data) + } + nfserr = nfsd4_do_copy(copy, filp, copy->nf_dst->nf_file, + false); +- nfsd4_cleanup_inter_ssc(copy->ss_mnt, filp, copy->nf_dst); ++ nfsd4_cleanup_inter_ssc(copy->ss_nsui, filp, copy->nf_dst); + } else { + nfserr = nfsd4_do_copy(copy, copy->nf_src->nf_file, + copy->nf_dst->nf_file, false); +@@ -1792,8 +1770,7 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + status = nfserr_notsupp; + goto out; + } +- status = nfsd4_setup_inter_ssc(rqstp, cstate, copy, +- ©->ss_mnt); ++ status = nfsd4_setup_inter_ssc(rqstp, cstate, copy); + if (status) + return nfserr_offload_denied; + } else { +diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h +index 24934cf90a84f..a034b9b62137c 100644 +--- a/fs/nfsd/xdr4.h ++++ b/fs/nfsd/xdr4.h +@@ -571,7 +571,7 @@ struct nfsd4_copy { + struct task_struct *copy_task; + refcount_t refcount; + +- struct vfsmount *ss_mnt; ++ struct nfsd4_ssc_umount_item *ss_nsui; + struct nfs_fh c_fh; + nfs4_stateid stateid; + }; +diff --git a/include/linux/nfs_ssc.h b/include/linux/nfs_ssc.h +index 75843c00f326a..22265b1ff0800 100644 +--- a/include/linux/nfs_ssc.h ++++ b/include/linux/nfs_ssc.h +@@ -53,6 +53,7 @@ static inline void nfs42_ssc_close(struct file *filep) + if (nfs_ssc_client_tbl.ssc_nfs4_ops) + (*nfs_ssc_client_tbl.ssc_nfs4_ops->sco_close)(filep); + } ++#endif + + struct nfsd4_ssc_umount_item { + struct list_head nsui_list; +@@ -66,7 +67,6 @@ struct nfsd4_ssc_umount_item { + struct vfsmount *nsui_vfsmount; + char nsui_ipaddr[RPC_MAX_ADDRBUFLEN + 1]; + }; +-#endif + + /* + * NFS_FS +-- +2.43.0 + diff --git a/queue-5.10/nfsd-enhance-the-nfsd_cb_setup-tracepoint.patch b/queue-5.10/nfsd-enhance-the-nfsd_cb_setup-tracepoint.patch new file mode 100644 index 00000000000..ead4879ee60 --- /dev/null +++ b/queue-5.10/nfsd-enhance-the-nfsd_cb_setup-tracepoint.patch @@ -0,0 +1,83 @@ +From cd0aee284e78193ccdb4dc75ec0c89ae881618cc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 14 May 2021 15:57:02 -0400 +Subject: NFSD: Enhance the nfsd_cb_setup tracepoint + +From: Chuck Lever + +[ Upstream commit 9f57c6062bf3ce2c6ab9ba60040b34e8134ef259 ] + +Display the transport protocol and authentication flavor so admins +can see what they might be getting wrong. + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4callback.c | 3 ++- + fs/nfsd/trace.h | 27 ++++++++++++++++++++++++++- + 2 files changed, 28 insertions(+), 2 deletions(-) + +diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c +index 2a2eb6184bdae..fe1f36b70fa03 100644 +--- a/fs/nfsd/nfs4callback.c ++++ b/fs/nfsd/nfs4callback.c +@@ -941,7 +941,8 @@ static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *c + clp->cl_cb_conn.cb_xprt = conn->cb_xprt; + clp->cl_cb_client = client; + clp->cl_cb_cred = cred; +- trace_nfsd_cb_setup(clp); ++ trace_nfsd_cb_setup(clp, rpc_peeraddr2str(client, RPC_DISPLAY_NETID), ++ args.authflavor); + return 0; + } + +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index afffb4912acbc..86e0656bdb779 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -910,7 +910,6 @@ DEFINE_EVENT(nfsd_cb_class, nfsd_cb_##name, \ + TP_PROTO(const struct nfs4_client *clp), \ + TP_ARGS(clp)) + +-DEFINE_NFSD_CB_EVENT(setup); + DEFINE_NFSD_CB_EVENT(state); + DEFINE_NFSD_CB_EVENT(lost); + DEFINE_NFSD_CB_EVENT(shutdown); +@@ -931,6 +930,32 @@ TRACE_DEFINE_ENUM(RPC_AUTH_GSS_KRB5P); + { RPC_AUTH_GSS_KRB5I, "krb5i" }, \ + { RPC_AUTH_GSS_KRB5P, "krb5p" }) + ++TRACE_EVENT(nfsd_cb_setup, ++ TP_PROTO(const struct nfs4_client *clp, ++ const char *netid, ++ rpc_authflavor_t authflavor ++ ), ++ TP_ARGS(clp, netid, authflavor), ++ TP_STRUCT__entry( ++ __field(u32, cl_boot) ++ __field(u32, cl_id) ++ __field(unsigned long, authflavor) ++ __array(unsigned char, addr, sizeof(struct sockaddr_in6)) ++ __array(unsigned char, netid, 8) ++ ), ++ TP_fast_assign( ++ __entry->cl_boot = clp->cl_clientid.cl_boot; ++ __entry->cl_id = clp->cl_clientid.cl_id; ++ strlcpy(__entry->netid, netid, sizeof(__entry->netid)); ++ __entry->authflavor = authflavor; ++ memcpy(__entry->addr, &clp->cl_cb_conn.cb_addr, ++ sizeof(struct sockaddr_in6)); ++ ), ++ TP_printk("addr=%pISpc client %08x:%08x proto=%s flavor=%s", ++ __entry->addr, __entry->cl_boot, __entry->cl_id, ++ __entry->netid, show_nfsd_authflavor(__entry->authflavor)) ++); ++ + TRACE_EVENT(nfsd_cb_setup_err, + TP_PROTO( + const struct nfs4_client *clp, +-- +2.43.0 + diff --git a/queue-5.10/nfsd-ensure-nf_inode-is-never-dereferenced.patch b/queue-5.10/nfsd-ensure-nf_inode-is-never-dereferenced.patch new file mode 100644 index 00000000000..66d12a6fdb7 --- /dev/null +++ b/queue-5.10/nfsd-ensure-nf_inode-is-never-dereferenced.patch @@ -0,0 +1,86 @@ +From cdabd2d5fedeaf698cad292d1dcd118627330334 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 Jul 2022 14:27:09 -0400 +Subject: NFSD: Ensure nf_inode is never dereferenced + +From: Chuck Lever + +[ Upstream commit 427f5f83a3191cbf024c5aea6e5b601cdf88d895 ] + +The documenting comment for struct nf_file states: + +/* + * A representation of a file that has been opened by knfsd. These are hashed + * in the hashtable by inode pointer value. Note that this object doesn't + * hold a reference to the inode by itself, so the nf_inode pointer should + * never be dereferenced, only used for comparison. + */ + +Replace the two existing dereferences to make the comment always +true. + +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 5 ++--- + fs/nfsd/filecache.h | 2 +- + fs/nfsd/nfs4state.c | 2 +- + 3 files changed, 4 insertions(+), 5 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index 7ad27655db699..55478d411e5a0 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -227,12 +227,11 @@ nfsd_file_mark_put(struct nfsd_file_mark *nfm) + } + + static struct nfsd_file_mark * +-nfsd_file_mark_find_or_create(struct nfsd_file *nf) ++nfsd_file_mark_find_or_create(struct nfsd_file *nf, struct inode *inode) + { + int err; + struct fsnotify_mark *mark; + struct nfsd_file_mark *nfm = NULL, *new; +- struct inode *inode = nf->nf_inode; + + do { + fsnotify_group_lock(nfsd_file_fsnotify_group); +@@ -1143,7 +1142,7 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + + open_file: + trace_nfsd_file_alloc(nf); +- nf->nf_mark = nfsd_file_mark_find_or_create(nf); ++ nf->nf_mark = nfsd_file_mark_find_or_create(nf, key.inode); + if (nf->nf_mark) { + if (open) { + status = nfsd_open_verified(rqstp, fhp, may_flags, +diff --git a/fs/nfsd/filecache.h b/fs/nfsd/filecache.h +index 28145f1628923..8e8c0c47d67df 100644 +--- a/fs/nfsd/filecache.h ++++ b/fs/nfsd/filecache.h +@@ -39,7 +39,7 @@ struct nfsd_file { + #define NFSD_FILE_PENDING (1) + #define NFSD_FILE_REFERENCED (2) + unsigned long nf_flags; +- struct inode *nf_inode; ++ struct inode *nf_inode; /* don't deref */ + refcount_t nf_ref; + unsigned char nf_may; + struct nfsd_file_mark *nf_mark; +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index c4c1e35d3eb7a..16e5bd54d92c2 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -2577,7 +2577,7 @@ static void nfs4_show_fname(struct seq_file *s, struct nfsd_file *f) + + static void nfs4_show_superblock(struct seq_file *s, struct nfsd_file *f) + { +- struct inode *inode = f->nf_inode; ++ struct inode *inode = file_inode(f->nf_file); + + seq_printf(s, "superblock: \"%02x:%02x:%ld\"", + MAJOR(inode->i_sb->s_dev), +-- +2.43.0 + diff --git a/queue-5.10/nfsd-extra-checks-when-freeing-delegation-stateids.patch b/queue-5.10/nfsd-extra-checks-when-freeing-delegation-stateids.patch new file mode 100644 index 00000000000..43e64d27f0b --- /dev/null +++ b/queue-5.10/nfsd-extra-checks-when-freeing-delegation-stateids.patch @@ -0,0 +1,42 @@ +From cb8f1c1d629a604a2141c1ac2583b8b79142ea32 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Sep 2022 14:41:02 -0400 +Subject: nfsd: extra checks when freeing delegation stateids + +From: Jeff Layton + +[ Upstream commit 895ddf5ed4c54ea9e3533606d7a8b4e4f27f95ef ] + +We've had some reports of problems in the refcounting for delegation +stateids that we've yet to track down. Add some extra checks to ensure +that we've removed the object from various lists before freeing it. + +Link: https://bugzilla.redhat.com/show_bug.cgi?id=2127067 +Signed-off-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index fc6188d70796d..948ef17178158 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -1071,7 +1071,12 @@ static struct nfs4_ol_stateid * nfs4_alloc_open_stateid(struct nfs4_client *clp) + + static void nfs4_free_deleg(struct nfs4_stid *stid) + { +- WARN_ON(!list_empty(&stid->sc_cp_list)); ++ struct nfs4_delegation *dp = delegstateid(stid); ++ ++ WARN_ON_ONCE(!list_empty(&stid->sc_cp_list)); ++ WARN_ON_ONCE(!list_empty(&dp->dl_perfile)); ++ WARN_ON_ONCE(!list_empty(&dp->dl_perclnt)); ++ WARN_ON_ONCE(!list_empty(&dp->dl_recall_lru)); + kmem_cache_free(deleg_slab, stid); + atomic_long_dec(&num_delegations); + } +-- +2.43.0 + diff --git a/queue-5.10/nfsd-extract-the-svcxdr_init_encode-helper.patch b/queue-5.10/nfsd-extract-the-svcxdr_init_encode-helper.patch new file mode 100644 index 00000000000..1deb9110b4c --- /dev/null +++ b/queue-5.10/nfsd-extract-the-svcxdr_init_encode-helper.patch @@ -0,0 +1,683 @@ +From c9baf1d3e6482c416b7587e8dcd33d0228332893 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 27 Oct 2020 15:53:42 -0400 +Subject: NFSD: Extract the svcxdr_init_encode() helper + +From: Chuck Lever + +[ Upstream commit bddfdbcddbe267519cd36aeb115fdf8620980111 ] + +NFSD initializes an encode xdr_stream only after the RPC layer has +already inserted the RPC Reply header. Thus it behaves differently +than xdr_init_encode does, which assumes the passed-in xdr_buf is +entirely devoid of content. + +nfs4proc.c has this server-side stream initialization helper, but +it is visible only to the NFSv4 code. Move this helper to a place +that can be accessed by NFSv2 and NFSv3 server XDR functions. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 31 +++-------- + fs/nfsd/nfs4state.c | 6 +- + fs/nfsd/nfs4xdr.c | 110 ++++++++++++++++++------------------- + fs/nfsd/nfssvc.c | 4 +- + fs/nfsd/xdr4.h | 2 +- + include/linux/sunrpc/svc.h | 25 +++++++++ + 6 files changed, 94 insertions(+), 84 deletions(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 0acf7af9aab8f..2fba0808d975c 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -2256,25 +2256,6 @@ static bool need_wrongsec_check(struct svc_rqst *rqstp) + return !(nextd->op_flags & OP_HANDLES_WRONGSEC); + } + +-static void svcxdr_init_encode(struct svc_rqst *rqstp, +- struct nfsd4_compoundres *resp) +-{ +- struct xdr_stream *xdr = &resp->xdr; +- struct xdr_buf *buf = &rqstp->rq_res; +- struct kvec *head = buf->head; +- +- xdr->buf = buf; +- xdr->iov = head; +- xdr->p = head->iov_base + head->iov_len; +- xdr->end = head->iov_base + PAGE_SIZE - rqstp->rq_auth_slack; +- /* Tail and page_len should be zero at this point: */ +- buf->len = buf->head[0].iov_len; +- xdr_reset_scratch_buffer(xdr); +- xdr->page_ptr = buf->pages - 1; +- buf->buflen = PAGE_SIZE * (1 + rqstp->rq_page_end - buf->pages) +- - rqstp->rq_auth_slack; +-} +- + #ifdef CONFIG_NFSD_V4_2_INTER_SSC + static void + check_if_stalefh_allowed(struct nfsd4_compoundargs *args) +@@ -2329,10 +2310,14 @@ nfsd4_proc_compound(struct svc_rqst *rqstp) + struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); + __be32 status; + +- svcxdr_init_encode(rqstp, resp); +- resp->tagp = resp->xdr.p; ++ resp->xdr = &rqstp->rq_res_stream; ++ ++ /* reserve space for: NFS status code */ ++ xdr_reserve_space(resp->xdr, XDR_UNIT); ++ ++ resp->tagp = resp->xdr->p; + /* reserve space for: taglen, tag, and opcnt */ +- xdr_reserve_space(&resp->xdr, 8 + args->taglen); ++ xdr_reserve_space(resp->xdr, XDR_UNIT * 2 + args->taglen); + resp->taglen = args->taglen; + resp->tag = args->tag; + resp->rqstp = rqstp; +@@ -2438,7 +2423,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp) + encode_op: + if (op->status == nfserr_replay_me) { + op->replay = &cstate->replay_owner->so_replay; +- nfsd4_encode_replay(&resp->xdr, op); ++ nfsd4_encode_replay(resp->xdr, op); + status = op->status = op->replay->rp_status; + } else { + nfsd4_encode_operation(resp, op); +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index c2eba93ab5138..914f60cee3226 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -2925,7 +2925,7 @@ gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_r + static void + nfsd4_store_cache_entry(struct nfsd4_compoundres *resp) + { +- struct xdr_buf *buf = resp->xdr.buf; ++ struct xdr_buf *buf = resp->xdr->buf; + struct nfsd4_slot *slot = resp->cstate.slot; + unsigned int base; + +@@ -2995,7 +2995,7 @@ nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp, + struct nfsd4_sequence *seq) + { + struct nfsd4_slot *slot = resp->cstate.slot; +- struct xdr_stream *xdr = &resp->xdr; ++ struct xdr_stream *xdr = resp->xdr; + __be32 *p; + __be32 status; + +@@ -3740,7 +3740,7 @@ nfsd4_sequence(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + { + struct nfsd4_sequence *seq = &u->sequence; + struct nfsd4_compoundres *resp = rqstp->rq_resp; +- struct xdr_stream *xdr = &resp->xdr; ++ struct xdr_stream *xdr = resp->xdr; + struct nfsd4_session *session; + struct nfs4_client *clp; + struct nfsd4_slot *slot; +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 8d5fdae568aeb..262c6fec56aa6 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -3595,7 +3595,7 @@ nfsd4_encode_stateid(struct xdr_stream *xdr, stateid_t *sid) + static __be32 + nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_access *access) + { +- struct xdr_stream *xdr = &resp->xdr; ++ struct xdr_stream *xdr = resp->xdr; + __be32 *p; + + p = xdr_reserve_space(xdr, 8); +@@ -3608,7 +3608,7 @@ nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_ + + static __be32 nfsd4_encode_bind_conn_to_session(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_bind_conn_to_session *bcts) + { +- struct xdr_stream *xdr = &resp->xdr; ++ struct xdr_stream *xdr = resp->xdr; + __be32 *p; + + p = xdr_reserve_space(xdr, NFS4_MAX_SESSIONID_LEN + 8); +@@ -3625,7 +3625,7 @@ static __be32 nfsd4_encode_bind_conn_to_session(struct nfsd4_compoundres *resp, + static __be32 + nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_close *close) + { +- struct xdr_stream *xdr = &resp->xdr; ++ struct xdr_stream *xdr = resp->xdr; + + return nfsd4_encode_stateid(xdr, &close->cl_stateid); + } +@@ -3634,7 +3634,7 @@ nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_c + static __be32 + nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_commit *commit) + { +- struct xdr_stream *xdr = &resp->xdr; ++ struct xdr_stream *xdr = resp->xdr; + __be32 *p; + + p = xdr_reserve_space(xdr, NFS4_VERIFIER_SIZE); +@@ -3648,7 +3648,7 @@ nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_ + static __be32 + nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_create *create) + { +- struct xdr_stream *xdr = &resp->xdr; ++ struct xdr_stream *xdr = resp->xdr; + __be32 *p; + + p = xdr_reserve_space(xdr, 20); +@@ -3663,7 +3663,7 @@ static __be32 + nfsd4_encode_getattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_getattr *getattr) + { + struct svc_fh *fhp = getattr->ga_fhp; +- struct xdr_stream *xdr = &resp->xdr; ++ struct xdr_stream *xdr = resp->xdr; + + return nfsd4_encode_fattr(xdr, fhp, fhp->fh_export, fhp->fh_dentry, + getattr->ga_bmval, resp->rqstp, 0); +@@ -3672,7 +3672,7 @@ nfsd4_encode_getattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4 + static __be32 + nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, struct svc_fh **fhpp) + { +- struct xdr_stream *xdr = &resp->xdr; ++ struct xdr_stream *xdr = resp->xdr; + struct svc_fh *fhp = *fhpp; + unsigned int len; + __be32 *p; +@@ -3727,7 +3727,7 @@ nfsd4_encode_lock_denied(struct xdr_stream *xdr, struct nfsd4_lock_denied *ld) + static __be32 + nfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lock *lock) + { +- struct xdr_stream *xdr = &resp->xdr; ++ struct xdr_stream *xdr = resp->xdr; + + if (!nfserr) + nfserr = nfsd4_encode_stateid(xdr, &lock->lk_resp_stateid); +@@ -3740,7 +3740,7 @@ nfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lo + static __be32 + nfsd4_encode_lockt(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lockt *lockt) + { +- struct xdr_stream *xdr = &resp->xdr; ++ struct xdr_stream *xdr = resp->xdr; + + if (nfserr == nfserr_denied) + nfsd4_encode_lock_denied(xdr, &lockt->lt_denied); +@@ -3750,7 +3750,7 @@ nfsd4_encode_lockt(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_l + static __be32 + nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_locku *locku) + { +- struct xdr_stream *xdr = &resp->xdr; ++ struct xdr_stream *xdr = resp->xdr; + + return nfsd4_encode_stateid(xdr, &locku->lu_stateid); + } +@@ -3759,7 +3759,7 @@ nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_l + static __be32 + nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_link *link) + { +- struct xdr_stream *xdr = &resp->xdr; ++ struct xdr_stream *xdr = resp->xdr; + __be32 *p; + + p = xdr_reserve_space(xdr, 20); +@@ -3773,7 +3773,7 @@ nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_li + static __be32 + nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open *open) + { +- struct xdr_stream *xdr = &resp->xdr; ++ struct xdr_stream *xdr = resp->xdr; + __be32 *p; + + nfserr = nfsd4_encode_stateid(xdr, &open->op_stateid); +@@ -3867,7 +3867,7 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_op + static __be32 + nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_confirm *oc) + { +- struct xdr_stream *xdr = &resp->xdr; ++ struct xdr_stream *xdr = resp->xdr; + + return nfsd4_encode_stateid(xdr, &oc->oc_resp_stateid); + } +@@ -3875,7 +3875,7 @@ nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, __be32 nfserr, struct + static __be32 + nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_downgrade *od) + { +- struct xdr_stream *xdr = &resp->xdr; ++ struct xdr_stream *xdr = resp->xdr; + + return nfsd4_encode_stateid(xdr, &od->od_stateid); + } +@@ -3885,7 +3885,7 @@ static __be32 nfsd4_encode_splice_read( + struct nfsd4_read *read, + struct file *file, unsigned long maxcount) + { +- struct xdr_stream *xdr = &resp->xdr; ++ struct xdr_stream *xdr = resp->xdr; + struct xdr_buf *buf = xdr->buf; + int status, space_left; + u32 eof; +@@ -3951,7 +3951,7 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp, + struct nfsd4_read *read, + struct file *file, unsigned long maxcount) + { +- struct xdr_stream *xdr = &resp->xdr; ++ struct xdr_stream *xdr = resp->xdr; + u32 eof; + int starting_len = xdr->buf->len - 8; + __be32 nfserr; +@@ -3990,7 +3990,7 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr, + struct nfsd4_read *read) + { + unsigned long maxcount; +- struct xdr_stream *xdr = &resp->xdr; ++ struct xdr_stream *xdr = resp->xdr; + struct file *file; + int starting_len = xdr->buf->len; + __be32 *p; +@@ -4004,7 +4004,7 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr, + WARN_ON_ONCE(test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags)); + return nfserr_resource; + } +- if (resp->xdr.buf->page_len && ++ if (resp->xdr->buf->page_len && + test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags)) { + WARN_ON_ONCE(1); + return nfserr_serverfault; +@@ -4034,7 +4034,7 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd + int maxcount; + __be32 wire_count; + int zero = 0; +- struct xdr_stream *xdr = &resp->xdr; ++ struct xdr_stream *xdr = resp->xdr; + int length_offset = xdr->buf->len; + int status; + __be32 *p; +@@ -4086,7 +4086,7 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4 + int bytes_left; + loff_t offset; + __be64 wire_offset; +- struct xdr_stream *xdr = &resp->xdr; ++ struct xdr_stream *xdr = resp->xdr; + int starting_len = xdr->buf->len; + __be32 *p; + +@@ -4097,8 +4097,8 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4 + /* XXX: Following NFSv3, we ignore the READDIR verifier for now. */ + *p++ = cpu_to_be32(0); + *p++ = cpu_to_be32(0); +- resp->xdr.buf->head[0].iov_len = ((char *)resp->xdr.p) +- - (char *)resp->xdr.buf->head[0].iov_base; ++ xdr->buf->head[0].iov_len = (char *)xdr->p - ++ (char *)xdr->buf->head[0].iov_base; + + /* + * Number of bytes left for directory entries allowing for the +@@ -4173,7 +4173,7 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4 + static __be32 + nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_remove *remove) + { +- struct xdr_stream *xdr = &resp->xdr; ++ struct xdr_stream *xdr = resp->xdr; + __be32 *p; + + p = xdr_reserve_space(xdr, 20); +@@ -4186,7 +4186,7 @@ nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_ + static __be32 + nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_rename *rename) + { +- struct xdr_stream *xdr = &resp->xdr; ++ struct xdr_stream *xdr = resp->xdr; + __be32 *p; + + p = xdr_reserve_space(xdr, 40); +@@ -4269,7 +4269,7 @@ static __be32 + nfsd4_encode_secinfo(struct nfsd4_compoundres *resp, __be32 nfserr, + struct nfsd4_secinfo *secinfo) + { +- struct xdr_stream *xdr = &resp->xdr; ++ struct xdr_stream *xdr = resp->xdr; + + return nfsd4_do_encode_secinfo(xdr, secinfo->si_exp); + } +@@ -4278,7 +4278,7 @@ static __be32 + nfsd4_encode_secinfo_no_name(struct nfsd4_compoundres *resp, __be32 nfserr, + struct nfsd4_secinfo_no_name *secinfo) + { +- struct xdr_stream *xdr = &resp->xdr; ++ struct xdr_stream *xdr = resp->xdr; + + return nfsd4_do_encode_secinfo(xdr, secinfo->sin_exp); + } +@@ -4290,7 +4290,7 @@ nfsd4_encode_secinfo_no_name(struct nfsd4_compoundres *resp, __be32 nfserr, + static __be32 + nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setattr *setattr) + { +- struct xdr_stream *xdr = &resp->xdr; ++ struct xdr_stream *xdr = resp->xdr; + __be32 *p; + + p = xdr_reserve_space(xdr, 16); +@@ -4314,7 +4314,7 @@ nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4 + static __be32 + nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setclientid *scd) + { +- struct xdr_stream *xdr = &resp->xdr; ++ struct xdr_stream *xdr = resp->xdr; + __be32 *p; + + if (!nfserr) { +@@ -4338,7 +4338,7 @@ nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct n + static __be32 + nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_write *write) + { +- struct xdr_stream *xdr = &resp->xdr; ++ struct xdr_stream *xdr = resp->xdr; + __be32 *p; + + p = xdr_reserve_space(xdr, 16); +@@ -4355,7 +4355,7 @@ static __be32 + nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr, + struct nfsd4_exchange_id *exid) + { +- struct xdr_stream *xdr = &resp->xdr; ++ struct xdr_stream *xdr = resp->xdr; + __be32 *p; + char *major_id; + char *server_scope; +@@ -4433,7 +4433,7 @@ static __be32 + nfsd4_encode_create_session(struct nfsd4_compoundres *resp, __be32 nfserr, + struct nfsd4_create_session *sess) + { +- struct xdr_stream *xdr = &resp->xdr; ++ struct xdr_stream *xdr = resp->xdr; + __be32 *p; + + p = xdr_reserve_space(xdr, 24); +@@ -4486,7 +4486,7 @@ static __be32 + nfsd4_encode_sequence(struct nfsd4_compoundres *resp, __be32 nfserr, + struct nfsd4_sequence *seq) + { +- struct xdr_stream *xdr = &resp->xdr; ++ struct xdr_stream *xdr = resp->xdr; + __be32 *p; + + p = xdr_reserve_space(xdr, NFS4_MAX_SESSIONID_LEN + 20); +@@ -4509,7 +4509,7 @@ static __be32 + nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, __be32 nfserr, + struct nfsd4_test_stateid *test_stateid) + { +- struct xdr_stream *xdr = &resp->xdr; ++ struct xdr_stream *xdr = resp->xdr; + struct nfsd4_test_stateid_id *stateid, *next; + __be32 *p; + +@@ -4530,7 +4530,7 @@ static __be32 + nfsd4_encode_getdeviceinfo(struct nfsd4_compoundres *resp, __be32 nfserr, + struct nfsd4_getdeviceinfo *gdev) + { +- struct xdr_stream *xdr = &resp->xdr; ++ struct xdr_stream *xdr = resp->xdr; + const struct nfsd4_layout_ops *ops; + u32 starting_len = xdr->buf->len, needed_len; + __be32 *p; +@@ -4583,7 +4583,7 @@ static __be32 + nfsd4_encode_layoutget(struct nfsd4_compoundres *resp, __be32 nfserr, + struct nfsd4_layoutget *lgp) + { +- struct xdr_stream *xdr = &resp->xdr; ++ struct xdr_stream *xdr = resp->xdr; + const struct nfsd4_layout_ops *ops; + __be32 *p; + +@@ -4610,7 +4610,7 @@ static __be32 + nfsd4_encode_layoutcommit(struct nfsd4_compoundres *resp, __be32 nfserr, + struct nfsd4_layoutcommit *lcp) + { +- struct xdr_stream *xdr = &resp->xdr; ++ struct xdr_stream *xdr = resp->xdr; + __be32 *p; + + p = xdr_reserve_space(xdr, 4); +@@ -4631,7 +4631,7 @@ static __be32 + nfsd4_encode_layoutreturn(struct nfsd4_compoundres *resp, __be32 nfserr, + struct nfsd4_layoutreturn *lrp) + { +- struct xdr_stream *xdr = &resp->xdr; ++ struct xdr_stream *xdr = resp->xdr; + __be32 *p; + + p = xdr_reserve_space(xdr, 4); +@@ -4649,7 +4649,7 @@ nfsd42_encode_write_res(struct nfsd4_compoundres *resp, + struct nfsd42_write_res *write, bool sync) + { + __be32 *p; +- p = xdr_reserve_space(&resp->xdr, 4); ++ p = xdr_reserve_space(resp->xdr, 4); + if (!p) + return nfserr_resource; + +@@ -4658,11 +4658,11 @@ nfsd42_encode_write_res(struct nfsd4_compoundres *resp, + else { + __be32 nfserr; + *p++ = cpu_to_be32(1); +- nfserr = nfsd4_encode_stateid(&resp->xdr, &write->cb_stateid); ++ nfserr = nfsd4_encode_stateid(resp->xdr, &write->cb_stateid); + if (nfserr) + return nfserr; + } +- p = xdr_reserve_space(&resp->xdr, 8 + 4 + NFS4_VERIFIER_SIZE); ++ p = xdr_reserve_space(resp->xdr, 8 + 4 + NFS4_VERIFIER_SIZE); + if (!p) + return nfserr_resource; + +@@ -4676,7 +4676,7 @@ nfsd42_encode_write_res(struct nfsd4_compoundres *resp, + static __be32 + nfsd42_encode_nl4_server(struct nfsd4_compoundres *resp, struct nl4_server *ns) + { +- struct xdr_stream *xdr = &resp->xdr; ++ struct xdr_stream *xdr = resp->xdr; + struct nfs42_netaddr *addr; + __be32 *p; + +@@ -4724,7 +4724,7 @@ nfsd4_encode_copy(struct nfsd4_compoundres *resp, __be32 nfserr, + if (nfserr) + return nfserr; + +- p = xdr_reserve_space(&resp->xdr, 4 + 4); ++ p = xdr_reserve_space(resp->xdr, 4 + 4); + *p++ = xdr_one; /* cr_consecutive */ + *p++ = cpu_to_be32(copy->cp_synchronous); + return 0; +@@ -4734,7 +4734,7 @@ static __be32 + nfsd4_encode_offload_status(struct nfsd4_compoundres *resp, __be32 nfserr, + struct nfsd4_offload_status *os) + { +- struct xdr_stream *xdr = &resp->xdr; ++ struct xdr_stream *xdr = resp->xdr; + __be32 *p; + + p = xdr_reserve_space(xdr, 8 + 4); +@@ -4751,7 +4751,7 @@ nfsd4_encode_read_plus_data(struct nfsd4_compoundres *resp, + unsigned long *maxcount, u32 *eof, + loff_t *pos) + { +- struct xdr_stream *xdr = &resp->xdr; ++ struct xdr_stream *xdr = resp->xdr; + struct file *file = read->rd_nf->nf_file; + int starting_len = xdr->buf->len; + loff_t hole_pos; +@@ -4810,7 +4810,7 @@ nfsd4_encode_read_plus_hole(struct nfsd4_compoundres *resp, + count = data_pos - read->rd_offset; + + /* Content type, offset, byte count */ +- p = xdr_reserve_space(&resp->xdr, 4 + 8 + 8); ++ p = xdr_reserve_space(resp->xdr, 4 + 8 + 8); + if (!p) + return nfserr_resource; + +@@ -4828,7 +4828,7 @@ nfsd4_encode_read_plus(struct nfsd4_compoundres *resp, __be32 nfserr, + struct nfsd4_read *read) + { + unsigned long maxcount, count; +- struct xdr_stream *xdr = &resp->xdr; ++ struct xdr_stream *xdr = resp->xdr; + struct file *file; + int starting_len = xdr->buf->len; + int last_segment = xdr->buf->len; +@@ -4899,7 +4899,7 @@ static __be32 + nfsd4_encode_copy_notify(struct nfsd4_compoundres *resp, __be32 nfserr, + struct nfsd4_copy_notify *cn) + { +- struct xdr_stream *xdr = &resp->xdr; ++ struct xdr_stream *xdr = resp->xdr; + __be32 *p; + + if (nfserr) +@@ -4935,7 +4935,7 @@ nfsd4_encode_seek(struct nfsd4_compoundres *resp, __be32 nfserr, + { + __be32 *p; + +- p = xdr_reserve_space(&resp->xdr, 4 + 8); ++ p = xdr_reserve_space(resp->xdr, 4 + 8); + *p++ = cpu_to_be32(seek->seek_eof); + p = xdr_encode_hyper(p, seek->seek_pos); + +@@ -4996,7 +4996,7 @@ static __be32 + nfsd4_encode_getxattr(struct nfsd4_compoundres *resp, __be32 nfserr, + struct nfsd4_getxattr *getxattr) + { +- struct xdr_stream *xdr = &resp->xdr; ++ struct xdr_stream *xdr = resp->xdr; + __be32 *p, err; + + p = xdr_reserve_space(xdr, 4); +@@ -5020,7 +5020,7 @@ static __be32 + nfsd4_encode_setxattr(struct nfsd4_compoundres *resp, __be32 nfserr, + struct nfsd4_setxattr *setxattr) + { +- struct xdr_stream *xdr = &resp->xdr; ++ struct xdr_stream *xdr = resp->xdr; + __be32 *p; + + p = xdr_reserve_space(xdr, 20); +@@ -5061,7 +5061,7 @@ static __be32 + nfsd4_encode_listxattrs(struct nfsd4_compoundres *resp, __be32 nfserr, + struct nfsd4_listxattrs *listxattrs) + { +- struct xdr_stream *xdr = &resp->xdr; ++ struct xdr_stream *xdr = resp->xdr; + u32 cookie_offset, count_offset, eof; + u32 left, xdrleft, slen, count; + u32 xdrlen, offset; +@@ -5172,7 +5172,7 @@ static __be32 + nfsd4_encode_removexattr(struct nfsd4_compoundres *resp, __be32 nfserr, + struct nfsd4_removexattr *removexattr) + { +- struct xdr_stream *xdr = &resp->xdr; ++ struct xdr_stream *xdr = resp->xdr; + __be32 *p; + + p = xdr_reserve_space(xdr, 20); +@@ -5312,7 +5312,7 @@ __be32 nfsd4_check_resp_size(struct nfsd4_compoundres *resp, u32 respsize) + void + nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) + { +- struct xdr_stream *xdr = &resp->xdr; ++ struct xdr_stream *xdr = resp->xdr; + struct nfs4_stateowner *so = resp->cstate.replay_owner; + struct svc_rqst *rqstp = resp->rqstp; + const struct nfsd4_operation *opdesc = op->opdesc; +@@ -5441,14 +5441,14 @@ int + nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p) + { + struct nfsd4_compoundres *resp = rqstp->rq_resp; +- struct xdr_buf *buf = resp->xdr.buf; ++ struct xdr_buf *buf = resp->xdr->buf; + + WARN_ON_ONCE(buf->len != buf->head[0].iov_len + buf->page_len + + buf->tail[0].iov_len); + + *p = resp->cstate.status; + +- rqstp->rq_next_page = resp->xdr.page_ptr + 1; ++ rqstp->rq_next_page = resp->xdr->page_ptr + 1; + + p = resp->tagp; + *p++ = htonl(resp->taglen); +diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c +index 6c1d70935ea81..0666ef4b87b7a 100644 +--- a/fs/nfsd/nfssvc.c ++++ b/fs/nfsd/nfssvc.c +@@ -1030,7 +1030,7 @@ int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) + * NFSv4 does some encoding while processing + */ + p = resv->iov_base + resv->iov_len; +- resv->iov_len += sizeof(__be32); ++ svcxdr_init_encode(rqstp); + + *statp = proc->pc_func(rqstp); + if (*statp == rpc_drop_reply || test_bit(RQ_DROPME, &rqstp->rq_flags)) +@@ -1085,7 +1085,7 @@ int nfssvc_decode_voidarg(struct svc_rqst *rqstp, __be32 *p) + */ + int nfssvc_encode_voidres(struct svc_rqst *rqstp, __be32 *p) + { +- return xdr_ressize_check(rqstp, p); ++ return 1; + } + + int nfsd_pool_stats_open(struct inode *inode, struct file *file) +diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h +index c300885ae75dd..fe540a3415c6a 100644 +--- a/fs/nfsd/xdr4.h ++++ b/fs/nfsd/xdr4.h +@@ -698,7 +698,7 @@ struct nfsd4_compoundargs { + + struct nfsd4_compoundres { + /* scratch variables for XDR encode */ +- struct xdr_stream xdr; ++ struct xdr_stream *xdr; + struct svc_rqst * rqstp; + + u32 taglen; +diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h +index 31ee3b6047c30..e91d51ea028bb 100644 +--- a/include/linux/sunrpc/svc.h ++++ b/include/linux/sunrpc/svc.h +@@ -248,6 +248,7 @@ struct svc_rqst { + size_t rq_xprt_hlen; /* xprt header len */ + struct xdr_buf rq_arg; + struct xdr_stream rq_arg_stream; ++ struct xdr_stream rq_res_stream; + struct page *rq_scratch_page; + struct xdr_buf rq_res; + struct page *rq_pages[RPCSVC_MAXPAGES + 1]; +@@ -574,4 +575,28 @@ static inline void svcxdr_init_decode(struct svc_rqst *rqstp) + xdr_set_scratch_page(xdr, rqstp->rq_scratch_page); + } + ++/** ++ * svcxdr_init_encode - Prepare an xdr_stream for svc Reply encoding ++ * @rqstp: controlling server RPC transaction context ++ * ++ */ ++static inline void svcxdr_init_encode(struct svc_rqst *rqstp) ++{ ++ struct xdr_stream *xdr = &rqstp->rq_res_stream; ++ struct xdr_buf *buf = &rqstp->rq_res; ++ struct kvec *resv = buf->head; ++ ++ xdr_reset_scratch_buffer(xdr); ++ ++ xdr->buf = buf; ++ xdr->iov = resv; ++ xdr->p = resv->iov_base + resv->iov_len; ++ xdr->end = resv->iov_base + PAGE_SIZE - rqstp->rq_auth_slack; ++ buf->len = resv->iov_len; ++ xdr->page_ptr = buf->pages - 1; ++ buf->buflen = PAGE_SIZE * (1 + rqstp->rq_page_end - buf->pages); ++ buf->buflen -= rqstp->rq_auth_slack; ++ xdr->rqst = NULL; ++} ++ + #endif /* SUNRPC_SVC_H */ +-- +2.43.0 + diff --git a/queue-5.10/nfsd-find_cpntf_state-cleanup.patch b/queue-5.10/nfsd-find_cpntf_state-cleanup.patch new file mode 100644 index 00000000000..e42d0f016e7 --- /dev/null +++ b/queue-5.10/nfsd-find_cpntf_state-cleanup.patch @@ -0,0 +1,69 @@ +From 210e911599d54c4cac8f078f05b6c672f43cdc74 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 Jan 2021 17:57:42 -0500 +Subject: nfsd: find_cpntf_state cleanup + +From: J. Bruce Fields + +[ Upstream commit 47fdb22dacae78f37701d82a94c16a014186d34e ] + +I think this unusual use of struct compound_state could cause confusion. + +It's not that much more complicated just to open-code this stateid +lookup. + +The only change in behavior should be a different error return in the +case the copy is using a source stateid that is a revoked delegation, +but I doubt that matters. + +Signed-off-by: J. Bruce Fields +[ cel: squashed in fix reported by Coverity ] +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 22 ++++++++++++++-------- + 1 file changed, 14 insertions(+), 8 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index c4e9f807b4a1b..b05598e5bc168 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -5832,21 +5832,27 @@ static __be32 find_cpntf_state(struct nfsd_net *nn, stateid_t *st, + { + __be32 status; + struct nfs4_cpntf_state *cps = NULL; +- struct nfsd4_compound_state cstate; ++ struct nfs4_client *found; + + status = manage_cpntf_state(nn, st, NULL, &cps); + if (status) + return status; + + cps->cpntf_time = ktime_get_boottime_seconds(); +- memset(&cstate, 0, sizeof(cstate)); +- status = set_client(&cps->cp_p_clid, &cstate, nn, true); +- if (status) ++ ++ status = nfserr_expired; ++ found = lookup_clientid(&cps->cp_p_clid, true, nn); ++ if (!found) + goto out; +- status = nfsd4_lookup_stateid(&cstate, &cps->cp_p_stateid, +- NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID, +- stid, nn); +- put_client_renew(cstate.clp); ++ ++ *stid = find_stateid_by_type(found, &cps->cp_p_stateid, ++ NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID); ++ if (*stid) ++ status = nfs_ok; ++ else ++ status = nfserr_bad_stateid; ++ ++ put_client_renew(found); + out: + nfs4_put_cpntf_state(nn, cps); + return status; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-finish-converting-the-nfsv2-getacl-result-encod.patch b/queue-5.10/nfsd-finish-converting-the-nfsv2-getacl-result-encod.patch new file mode 100644 index 00000000000..24873efa9bd --- /dev/null +++ b/queue-5.10/nfsd-finish-converting-the-nfsv2-getacl-result-encod.patch @@ -0,0 +1,56 @@ +From 8b07968e4a4c1c48edc3aa0892a034009d28936b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 16 Oct 2022 11:47:02 -0400 +Subject: NFSD: Finish converting the NFSv2 GETACL result encoder + +From: Chuck Lever + +[ Upstream commit ea5021e911d3479346a75ac9b7d9dcd751b0fb99 ] + +The xdr_stream conversion inadvertently left some code that set the +page_len of the send buffer. The XDR stream encoders should handle +this automatically now. + +This oversight adds garbage past the end of the Reply message. +Clients typically ignore the garbage, but NFSD does not need to send +it, as it leaks stale memory contents onto the wire. + +Fixes: f8cba47344f7 ("NFSD: Update the NFSv2 GETACL result encoder to use struct xdr_stream") +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs2acl.c | 10 ---------- + 1 file changed, 10 deletions(-) + +diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c +index f8179fc8c9bdf..9adf672dedbdd 100644 +--- a/fs/nfsd/nfs2acl.c ++++ b/fs/nfsd/nfs2acl.c +@@ -244,7 +244,6 @@ nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + struct nfsd3_getaclres *resp = rqstp->rq_resp; + struct dentry *dentry = resp->fh.fh_dentry; + struct inode *inode; +- int w; + + if (!svcxdr_encode_stat(xdr, resp->status)) + return false; +@@ -258,15 +257,6 @@ nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + if (xdr_stream_encode_u32(xdr, resp->mask) < 0) + return false; + +- rqstp->rq_res.page_len = w = nfsacl_size( +- (resp->mask & NFS_ACL) ? resp->acl_access : NULL, +- (resp->mask & NFS_DFACL) ? resp->acl_default : NULL); +- while (w > 0) { +- if (!*(rqstp->rq_next_page++)) +- return true; +- w -= PAGE_SIZE; +- } +- + if (!nfs_stream_encode_acl(xdr, inode, resp->acl_access, + resp->mask & NFS_ACL, 0)) + return false; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-finish-converting-the-nfsv3-getacl-result-encod.patch b/queue-5.10/nfsd-finish-converting-the-nfsv3-getacl-result-encod.patch new file mode 100644 index 00000000000..604c947c8e0 --- /dev/null +++ b/queue-5.10/nfsd-finish-converting-the-nfsv3-getacl-result-encod.patch @@ -0,0 +1,73 @@ +From 92f4b9ee8fe49683af9d7ec9f9c81a5480c967ea Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 16 Oct 2022 11:47:08 -0400 +Subject: NFSD: Finish converting the NFSv3 GETACL result encoder + +From: Chuck Lever + +[ Upstream commit 841fd0a3cb490eae5dfd262eccb8c8b11d57f8b8 ] + +For some reason, the NFSv2 GETACL result encoder was fully converted +to use the new nfs_stream_encode_acl(), but the NFSv3 equivalent was +not similarly converted. + +Fixes: 20798dfe249a ("NFSD: Update the NFSv3 GETACL result encoder to use struct xdr_stream") +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3acl.c | 30 ++++++------------------------ + 1 file changed, 6 insertions(+), 24 deletions(-) + +diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c +index 2c451fcd5a3cc..161f831b3a1b7 100644 +--- a/fs/nfsd/nfs3acl.c ++++ b/fs/nfsd/nfs3acl.c +@@ -169,11 +169,7 @@ nfs3svc_encode_getaclres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd3_getaclres *resp = rqstp->rq_resp; + struct dentry *dentry = resp->fh.fh_dentry; +- struct kvec *head = rqstp->rq_res.head; + struct inode *inode; +- unsigned int base; +- int n; +- int w; + + if (!svcxdr_encode_nfsstat3(xdr, resp->status)) + return false; +@@ -185,26 +181,12 @@ nfs3svc_encode_getaclres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + if (xdr_stream_encode_u32(xdr, resp->mask) < 0) + return false; + +- base = (char *)xdr->p - (char *)head->iov_base; +- +- rqstp->rq_res.page_len = w = nfsacl_size( +- (resp->mask & NFS_ACL) ? resp->acl_access : NULL, +- (resp->mask & NFS_DFACL) ? resp->acl_default : NULL); +- while (w > 0) { +- if (!*(rqstp->rq_next_page++)) +- return false; +- w -= PAGE_SIZE; +- } +- +- n = nfsacl_encode(&rqstp->rq_res, base, inode, +- resp->acl_access, +- resp->mask & NFS_ACL, 0); +- if (n > 0) +- n = nfsacl_encode(&rqstp->rq_res, base + n, inode, +- resp->acl_default, +- resp->mask & NFS_DFACL, +- NFS_ACL_DEFAULT); +- if (n <= 0) ++ if (!nfs_stream_encode_acl(xdr, inode, resp->acl_access, ++ resp->mask & NFS_ACL, 0)) ++ return false; ++ if (!nfs_stream_encode_acl(xdr, inode, resp->acl_default, ++ resp->mask & NFS_DFACL, ++ NFS_ACL_DEFAULT)) + return false; + break; + default: +-- +2.43.0 + diff --git a/queue-5.10/nfsd-fix-a-regression-in-nfsd_setattr.patch b/queue-5.10/nfsd-fix-a-regression-in-nfsd_setattr.patch new file mode 100644 index 00000000000..620ec826ec8 --- /dev/null +++ b/queue-5.10/nfsd-fix-a-regression-in-nfsd_setattr.patch @@ -0,0 +1,91 @@ +From b09026d51b65ed6190a6c7aa2882af810ff9af99 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Feb 2024 20:24:50 -0500 +Subject: nfsd: Fix a regression in nfsd_setattr() + +From: Trond Myklebust + +[ Upstream commit 6412e44c40aaf8f1d7320b2099c5bdd6cb9126ac ] + +Commit bb4d53d66e4b ("NFSD: use (un)lock_inode instead of +fh_(un)lock for file operations") broke the NFSv3 pre/post op +attributes behaviour when doing a SETATTR rpc call by stripping out +the calls to fh_fill_pre_attrs() and fh_fill_post_attrs(). + +Fixes: bb4d53d66e4b ("NFSD: use (un)lock_inode instead of fh_(un)lock for file operations") +Signed-off-by: Trond Myklebust +Reviewed-by: Jeff Layton +Reviewed-by: NeilBrown +Message-ID: <20240216012451.22725-1-trondmy@kernel.org> +[ cel: adjusted to apply to v5.10.y ] +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 4 ++++ + fs/nfsd/vfs.c | 6 ++++-- + 2 files changed, 8 insertions(+), 2 deletions(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 8560a11daa47d..2c0de247083a9 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -1107,6 +1107,7 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + }; + struct inode *inode; + __be32 status = nfs_ok; ++ bool save_no_wcc; + int err; + + if (setattr->sa_iattr.ia_valid & ATTR_SIZE) { +@@ -1132,8 +1133,11 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + + if (status) + goto out; ++ save_no_wcc = cstate->current_fh.fh_no_wcc; ++ cstate->current_fh.fh_no_wcc = true; + status = nfsd_setattr(rqstp, &cstate->current_fh, &attrs, + 0, (time64_t)0); ++ cstate->current_fh.fh_no_wcc = save_no_wcc; + if (!status) + status = nfserrno(attrs.na_labelerr); + if (!status) +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index 542a1adbbf2a1..0ea05ddff0d08 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -486,7 +486,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, + int accmode = NFSD_MAY_SATTR; + umode_t ftype = 0; + __be32 err; +- int host_err; ++ int host_err = 0; + bool get_write_count; + bool size_change = (iap->ia_valid & ATTR_SIZE); + int retries; +@@ -544,6 +544,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, + } + + inode_lock(inode); ++ fh_fill_pre_attrs(fhp); + for (retries = 1;;) { + struct iattr attrs; + +@@ -569,13 +570,14 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, + !attr->na_aclerr && attr->na_dpacl && S_ISDIR(inode->i_mode)) + attr->na_aclerr = set_posix_acl(inode, ACL_TYPE_DEFAULT, + attr->na_dpacl); ++ fh_fill_post_attrs(fhp); + inode_unlock(inode); + if (size_change) + put_write_access(inode); + out: + if (!host_err) + host_err = commit_metadata(fhp); +- return nfserrno(host_err); ++ return err != 0 ? err : nfserrno(host_err); + } + + #if defined(CONFIG_NFSD_V4) +-- +2.43.0 + diff --git a/queue-5.10/nfsd-fix-a-warning-for-nfsd_file_close_inode.patch b/queue-5.10/nfsd-fix-a-warning-for-nfsd_file_close_inode.patch new file mode 100644 index 00000000000..29fb3672557 --- /dev/null +++ b/queue-5.10/nfsd-fix-a-warning-for-nfsd_file_close_inode.patch @@ -0,0 +1,32 @@ +From f56d373dd3d069747dfcece69fefa4ca662e1c6c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Sep 2021 15:44:42 -0400 +Subject: nfsd: Fix a warning for nfsd_file_close_inode + +From: Trond Myklebust + +[ Upstream commit 19598141f40dff728dd50799e510805261f48850 ] + +Signed-off-by: Trond Myklebust +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index d0748ff04b92f..87d984e0cdc0c 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -541,7 +541,7 @@ nfsd_file_close_inode_sync(struct inode *inode) + } + + /** +- * nfsd_file_close_inode_sync - attempt to forcibly close a nfsd_file ++ * nfsd_file_close_inode - attempt a delayed close of a nfsd_file + * @inode: inode of the file to attempt to remove + * + * Walk the whole hash bucket, looking for any files that correspond to "inode". +-- +2.43.0 + diff --git a/queue-5.10/nfsd-fix-a-write-performance-regression.patch b/queue-5.10/nfsd-fix-a-write-performance-regression.patch new file mode 100644 index 00000000000..825ff2c9063 --- /dev/null +++ b/queue-5.10/nfsd-fix-a-write-performance-regression.patch @@ -0,0 +1,86 @@ +From 2376f01129994dc452640a08579a30b55a22629d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 31 Mar 2022 09:54:01 -0400 +Subject: nfsd: Fix a write performance regression + +From: Trond Myklebust + +[ Upstream commit 6b8a94332ee4f7d9a8ae0cbac7609f79c212f06c ] + +The call to filemap_flush() in nfsd_file_put() is there to ensure that +we clear out any writes belonging to a NFSv3 client relatively quickly +and avoid situations where the file can't be evicted by the garbage +collector. It also ensures that we detect write errors quickly. + +The problem is this causes a regression in performance for some +workloads. + +So try to improve matters by deferring writeback until we're ready to +close the file, and need to detect errors so that we can force the +client to resend. + +Tested-by: Jan Kara +Fixes: b6669305d35a ("nfsd: Reduce the number of calls to nfsd_file_gc()") +Signed-off-by: Trond Myklebust +Link: https://lore.kernel.org/all/20220330103457.r4xrhy2d6nhtouzk@quack3.lan +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 18 +++++++++++++++--- + 1 file changed, 15 insertions(+), 3 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index cc2831cec6695..496f7b3f75237 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -235,6 +235,13 @@ nfsd_file_check_write_error(struct nfsd_file *nf) + return filemap_check_wb_err(file->f_mapping, READ_ONCE(file->f_wb_err)); + } + ++static void ++nfsd_file_flush(struct nfsd_file *nf) ++{ ++ if (nf->nf_file && vfs_fsync(nf->nf_file, 1) != 0) ++ nfsd_reset_write_verifier(net_generic(nf->nf_net, nfsd_net_id)); ++} ++ + static void + nfsd_file_do_unhash(struct nfsd_file *nf) + { +@@ -302,11 +309,14 @@ nfsd_file_put(struct nfsd_file *nf) + return; + } + +- filemap_flush(nf->nf_file->f_mapping); + is_hashed = test_bit(NFSD_FILE_HASHED, &nf->nf_flags) != 0; +- nfsd_file_put_noref(nf); +- if (is_hashed) ++ if (!is_hashed) { ++ nfsd_file_flush(nf); ++ nfsd_file_put_noref(nf); ++ } else { ++ nfsd_file_put_noref(nf); + nfsd_file_schedule_laundrette(); ++ } + if (atomic_long_read(&nfsd_filecache_count) >= NFSD_FILE_LRU_LIMIT) + nfsd_file_gc(); + } +@@ -327,6 +337,7 @@ nfsd_file_dispose_list(struct list_head *dispose) + while(!list_empty(dispose)) { + nf = list_first_entry(dispose, struct nfsd_file, nf_lru); + list_del(&nf->nf_lru); ++ nfsd_file_flush(nf); + nfsd_file_put_noref(nf); + } + } +@@ -340,6 +351,7 @@ nfsd_file_dispose_list_sync(struct list_head *dispose) + while(!list_empty(dispose)) { + nf = list_first_entry(dispose, struct nfsd_file, nf_lru); + list_del(&nf->nf_lru); ++ nfsd_file_flush(nf); + if (!refcount_dec_and_test(&nf->nf_ref)) + continue; + if (nfsd_file_free(nf)) +-- +2.43.0 + diff --git a/queue-5.10/nfsd-fix-boolreturn.cocci-warning.patch b/queue-5.10/nfsd-fix-boolreturn.cocci-warning.patch new file mode 100644 index 00000000000..f02ebf55826 --- /dev/null +++ b/queue-5.10/nfsd-fix-boolreturn.cocci-warning.patch @@ -0,0 +1,40 @@ +From eb09008fcf249e068cc691ce628f8ee3099f4e90 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 Oct 2021 04:14:22 +0000 +Subject: NFSD:fix boolreturn.cocci warning + +From: Changcheng Deng + +[ Upstream commit 291cd656da04163f4bba67953c1f2f823e0d1231 ] + +./fs/nfsd/nfssvc.c: 1072: 8-9: :WARNING return of 0/1 in function +'nfssvc_decode_voidarg' with return type bool + +Return statements in functions returning bool should use true/false +instead of 1/0. + +Reported-by: Zeal Robot +Signed-off-by: Changcheng Deng +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfssvc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c +index 7df1505425edc..408cff8fe32d3 100644 +--- a/fs/nfsd/nfssvc.c ++++ b/fs/nfsd/nfssvc.c +@@ -1069,7 +1069,7 @@ int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) + */ + bool nfssvc_decode_voidarg(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- return 1; ++ return true; + } + + /** +-- +2.43.0 + diff --git a/queue-5.10/nfsd-fix-comments-about-spinlock-handling-with-deleg.patch b/queue-5.10/nfsd-fix-comments-about-spinlock-handling-with-deleg.patch new file mode 100644 index 00000000000..bbb49c99240 --- /dev/null +++ b/queue-5.10/nfsd-fix-comments-about-spinlock-handling-with-deleg.patch @@ -0,0 +1,40 @@ +From 5bf0dc2192de6bd4f99875b9b50a660e155a1124 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Sep 2022 12:38:45 -0400 +Subject: nfsd: fix comments about spinlock handling with delegations + +From: Jeff Layton + +[ Upstream commit 25fbe1fca14142beae6c882f7906510363d42bff ] + +Signed-off-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 1dc3823f3d124..e9fc5a357fc4d 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -4870,14 +4870,14 @@ static void nfsd_break_one_deleg(struct nfs4_delegation *dp) + * We're assuming the state code never drops its reference + * without first removing the lease. Since we're in this lease + * callback (and since the lease code is serialized by the +- * i_lock) we know the server hasn't removed the lease yet, and ++ * flc_lock) we know the server hasn't removed the lease yet, and + * we know it's safe to take a reference. + */ + refcount_inc(&dp->dl_stid.sc_count); + nfsd4_run_cb(&dp->dl_recall); + } + +-/* Called from break_lease() with i_lock held. */ ++/* Called from break_lease() with flc_lock held. */ + static bool + nfsd_break_deleg_cb(struct file_lock *fl) + { +-- +2.43.0 + diff --git a/queue-5.10/nfsd-fix-courtesy-client-with-deny-mode-handling-in-.patch b/queue-5.10/nfsd-fix-courtesy-client-with-deny-mode-handling-in-.patch new file mode 100644 index 00000000000..30abd90df76 --- /dev/null +++ b/queue-5.10/nfsd-fix-courtesy-client-with-deny-mode-handling-in-.patch @@ -0,0 +1,62 @@ +From ba66fca87c53fc48627d4bb520e986758c08c3f9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 3 Feb 2023 13:18:34 -0500 +Subject: nfsd: fix courtesy client with deny mode handling in + nfs4_upgrade_open +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Jeff Layton + +[ Upstream commit dcd779dc46540e174a6ac8d52fbed23593407317 ] + +The nested if statements here make no sense, as you can never reach +"else" branch in the nested statement. Fix the error handling for +when there is a courtesy client that holds a conflicting deny mode. + +Fixes: 3d6942715180 ("NFSD: add support for share reservation conflict to courteous server") +Reported-by: 張智諺 +Signed-off-by: Jeff Layton +Reviewed-by: Dai Ngo +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 21 +++++++++++---------- + 1 file changed, 11 insertions(+), 10 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 507dd2b11856b..e8e642e5ec8f1 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -5296,16 +5296,17 @@ nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, + /* test and set deny mode */ + spin_lock(&fp->fi_lock); + status = nfs4_file_check_deny(fp, open->op_share_deny); +- if (status == nfs_ok) { +- if (status != nfserr_share_denied) { +- set_deny(open->op_share_deny, stp); +- fp->fi_share_deny |= +- (open->op_share_deny & NFS4_SHARE_DENY_BOTH); +- } else { +- if (nfs4_resolve_deny_conflicts_locked(fp, false, +- stp, open->op_share_deny, false)) +- status = nfserr_jukebox; +- } ++ switch (status) { ++ case nfs_ok: ++ set_deny(open->op_share_deny, stp); ++ fp->fi_share_deny |= ++ (open->op_share_deny & NFS4_SHARE_DENY_BOTH); ++ break; ++ case nfserr_share_denied: ++ if (nfs4_resolve_deny_conflicts_locked(fp, false, ++ stp, open->op_share_deny, false)) ++ status = nfserr_jukebox; ++ break; + } + spin_unlock(&fp->fi_lock); + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-fix-crash-on-copy_notify-with-special-stateid.patch b/queue-5.10/nfsd-fix-crash-on-copy_notify-with-special-stateid.patch new file mode 100644 index 00000000000..5ac2405e77c --- /dev/null +++ b/queue-5.10/nfsd-fix-crash-on-copy_notify-with-special-stateid.patch @@ -0,0 +1,57 @@ +From fb83385f9a11d91a063ae5201c79d307f10f57bd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 5 Jan 2022 14:15:03 -0500 +Subject: nfsd: fix crash on COPY_NOTIFY with special stateid + +From: J. Bruce Fields + +[ Upstream commit 074b07d94e0bb6ddce5690a9b7e2373088e8b33a ] + +RTM says "If the special ONE stateid is passed to +nfs4_preprocess_stateid_op(), it returns status=0 but does not set +*cstid. nfsd4_copy_notify() depends on stid being set if status=0, and +thus can crash if the client sends the right COPY_NOTIFY RPC." + +RFC 7862 says "The cna_src_stateid MUST refer to either open or locking +states provided earlier by the server. If it is invalid, then the +operation MUST fail." + +The RFC doesn't specify an error, and the choice doesn't matter much as +this is clearly illegal client behavior, but bad_stateid seems +reasonable. + +Simplest is just to guarantee that nfs4_preprocess_stateid_op, called +with non-NULL cstid, errors out if it can't return a stateid. + +Reported-by: rtm@csail.mit.edu +Fixes: 624322f1adc5 ("NFSD add COPY_NOTIFY operation") +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Reviewed-by: Olga Kornievskaia +Tested-by: Olga Kornievskaia +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 4161a4854c430..60d5d1cb2cc65 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -6097,7 +6097,11 @@ nfs4_preprocess_stateid_op(struct svc_rqst *rqstp, + return nfserr_grace; + + if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) { +- status = check_special_stateids(net, fhp, stateid, flags); ++ if (cstid) ++ status = nfserr_bad_stateid; ++ else ++ status = check_special_stateids(net, fhp, stateid, ++ flags); + goto done; + } + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-fix-creation-time-serialization-order.patch b/queue-5.10/nfsd-fix-creation-time-serialization-order.patch new file mode 100644 index 00000000000..9298b862ec5 --- /dev/null +++ b/queue-5.10/nfsd-fix-creation-time-serialization-order.patch @@ -0,0 +1,66 @@ +From 8ebbf8f15cc37eec4ce78c005f7da8d9c0833f6d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Jun 2023 17:09:06 -0400 +Subject: nfsd: Fix creation time serialization order + +From: Tavian Barnes + +[ Upstream commit d7dbed457c2ef83709a2a2723a2d58de43623449 ] + +In nfsd4_encode_fattr(), TIME_CREATE was being written out after all +other times. However, they should be written out in an order that +matches the bit flags in bmval1, which in this case are + + #define FATTR4_WORD1_TIME_ACCESS (1UL << 15) + #define FATTR4_WORD1_TIME_CREATE (1UL << 18) + #define FATTR4_WORD1_TIME_DELTA (1UL << 19) + #define FATTR4_WORD1_TIME_METADATA (1UL << 20) + #define FATTR4_WORD1_TIME_MODIFY (1UL << 21) + +so TIME_CREATE should come second. + +I noticed this on a FreeBSD NFSv4.2 client, which supports creation +times. On this client, file times were weirdly permuted. With this +patch applied on the server, times looked normal on the client. + +Fixes: e377a3e698fb ("nfsd: Add support for the birth time attribute") +Link: https://unix.stackexchange.com/q/749605/56202 +Signed-off-by: Tavian Barnes +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index a81938c1e3efb..5a68c62864925 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -3364,6 +3364,11 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, + if (status) + goto out; + } ++ if (bmval1 & FATTR4_WORD1_TIME_CREATE) { ++ status = nfsd4_encode_nfstime4(xdr, &stat.btime); ++ if (status) ++ goto out; ++ } + if (bmval1 & FATTR4_WORD1_TIME_DELTA) { + p = xdr_reserve_space(xdr, 12); + if (!p) +@@ -3380,11 +3385,6 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, + if (status) + goto out; + } +- if (bmval1 & FATTR4_WORD1_TIME_CREATE) { +- status = nfsd4_encode_nfstime4(xdr, &stat.btime); +- if (status) +- goto out; +- } + if (bmval1 & FATTR4_WORD1_MOUNTED_ON_FILEID) { + u64 ino = stat.ino; + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-fix-double-fget-bug-in-__write_ports_addfd.patch b/queue-5.10/nfsd-fix-double-fget-bug-in-__write_ports_addfd.patch new file mode 100644 index 00000000000..7e7a66e4ce5 --- /dev/null +++ b/queue-5.10/nfsd-fix-double-fget-bug-in-__write_ports_addfd.patch @@ -0,0 +1,123 @@ +From c6ec5197b2b24b59e992412fee6c89b4a7a6d0aa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 May 2023 14:35:55 +0300 +Subject: nfsd: fix double fget() bug in __write_ports_addfd() + +From: Dan Carpenter + +[ Upstream commit c034203b6a9dae6751ef4371c18cb77983e30c28 ] + +The bug here is that you cannot rely on getting the same socket +from multiple calls to fget() because userspace can influence +that. This is a kind of double fetch bug. + +The fix is to delete the svc_alien_sock() function and instead do +the checking inside the svc_addsock() function. + +Fixes: 3064639423c4 ("nfsd: check passed socket's net matches NFSd superblock's one") +Signed-off-by: Dan Carpenter +Reviewed-by: NeilBrown +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsctl.c | 7 +------ + include/linux/sunrpc/svcsock.h | 7 +++---- + net/sunrpc/svcsock.c | 24 ++++++------------------ + 3 files changed, 10 insertions(+), 28 deletions(-) + +diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c +index c2577ee7ffb22..76a60e7a75097 100644 +--- a/fs/nfsd/nfsctl.c ++++ b/fs/nfsd/nfsctl.c +@@ -714,16 +714,11 @@ static ssize_t __write_ports_addfd(char *buf, struct net *net, const struct cred + if (err != 0 || fd < 0) + return -EINVAL; + +- if (svc_alien_sock(net, fd)) { +- printk(KERN_ERR "%s: socket net is different to NFSd's one\n", __func__); +- return -EINVAL; +- } +- + err = nfsd_create_serv(net); + if (err != 0) + return err; + +- err = svc_addsock(nn->nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT, cred); ++ err = svc_addsock(nn->nfsd_serv, net, fd, buf, SIMPLE_TRANSACTION_LIMIT, cred); + + if (err >= 0 && + !nn->nfsd_serv->sv_nrthreads && !xchg(&nn->keep_active, 1)) +diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h +index b7ac7fe683067..a366d3eb05315 100644 +--- a/include/linux/sunrpc/svcsock.h ++++ b/include/linux/sunrpc/svcsock.h +@@ -57,10 +57,9 @@ int svc_recv(struct svc_rqst *, long); + int svc_send(struct svc_rqst *); + void svc_drop(struct svc_rqst *); + void svc_sock_update_bufs(struct svc_serv *serv); +-bool svc_alien_sock(struct net *net, int fd); +-int svc_addsock(struct svc_serv *serv, const int fd, +- char *name_return, const size_t len, +- const struct cred *cred); ++int svc_addsock(struct svc_serv *serv, struct net *net, ++ const int fd, char *name_return, const size_t len, ++ const struct cred *cred); + void svc_init_xprt_sock(void); + void svc_cleanup_xprt_sock(void); + struct svc_xprt *svc_sock_create(struct svc_serv *serv, int prot); +diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c +index 90f6231d6ed67..cb0cfcd8a8141 100644 +--- a/net/sunrpc/svcsock.c ++++ b/net/sunrpc/svcsock.c +@@ -1342,25 +1342,10 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv, + return svsk; + } + +-bool svc_alien_sock(struct net *net, int fd) +-{ +- int err; +- struct socket *sock = sockfd_lookup(fd, &err); +- bool ret = false; +- +- if (!sock) +- goto out; +- if (sock_net(sock->sk) != net) +- ret = true; +- sockfd_put(sock); +-out: +- return ret; +-} +-EXPORT_SYMBOL_GPL(svc_alien_sock); +- + /** + * svc_addsock - add a listener socket to an RPC service + * @serv: pointer to RPC service to which to add a new listener ++ * @net: caller's network namespace + * @fd: file descriptor of the new listener + * @name_return: pointer to buffer to fill in with name of listener + * @len: size of the buffer +@@ -1370,8 +1355,8 @@ EXPORT_SYMBOL_GPL(svc_alien_sock); + * Name is terminated with '\n'. On error, returns a negative errno + * value. + */ +-int svc_addsock(struct svc_serv *serv, const int fd, char *name_return, +- const size_t len, const struct cred *cred) ++int svc_addsock(struct svc_serv *serv, struct net *net, const int fd, ++ char *name_return, const size_t len, const struct cred *cred) + { + int err = 0; + struct socket *so = sockfd_lookup(fd, &err); +@@ -1382,6 +1367,9 @@ int svc_addsock(struct svc_serv *serv, const int fd, char *name_return, + + if (!so) + return err; ++ err = -EINVAL; ++ if (sock_net(so->sk) != net) ++ goto out; + err = -EAFNOSUPPORT; + if ((so->sk->sk_family != PF_INET) && (so->sk->sk_family != PF_INET6)) + goto out; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-fix-error-return-code-in-nfsd4_interssc_connect.patch b/queue-5.10/nfsd-fix-error-return-code-in-nfsd4_interssc_connect.patch new file mode 100644 index 00000000000..773bf2dd3a2 --- /dev/null +++ b/queue-5.10/nfsd-fix-error-return-code-in-nfsd4_interssc_connect.patch @@ -0,0 +1,38 @@ +From 429b22747a6b43ad3aede6172f1bb2060c8623db Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 4 Jun 2021 10:12:37 +0000 +Subject: NFSD: Fix error return code in nfsd4_interssc_connect() + +From: Wei Yongjun + +[ Upstream commit 54185267e1fe476875e649bb18e1c4254c123305 ] + +'status' has been overwritten to 0 after nfsd4_ssc_setup_dul(), this +cause 0 will be return in vfs_kern_mount() error case. Fix to return +nfserr_nodev in this error. + +Fixes: f4e44b393389 ("NFSD: delay unmount source's export after inter-server copy completed.") +Reported-by: Hulk Robot +Signed-off-by: Wei Yongjun +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 598b54893f837..f7ddfa204abc4 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -1326,6 +1326,7 @@ nfsd4_interssc_connect(struct nl4_server *nss, struct svc_rqst *rqstp, + ss_mnt = vfs_kern_mount(type, SB_KERNMOUNT, dev_name, raw_data); + module_put(type->owner); + if (IS_ERR(ss_mnt)) { ++ status = nfserr_nodev; + if (work) + nfsd4_ssc_cancel_dul_work(nn, work); + goto out_free_devname; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-fix-error-return-code-in-nfsd_file_cache_init.patch b/queue-5.10/nfsd-fix-error-return-code-in-nfsd_file_cache_init.patch new file mode 100644 index 00000000000..797939f4e84 --- /dev/null +++ b/queue-5.10/nfsd-fix-error-return-code-in-nfsd_file_cache_init.patch @@ -0,0 +1,35 @@ +From d8792712e0a3b4dc4fa3c8080c8425f9a6594c03 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 25 Nov 2020 03:39:33 -0500 +Subject: nfsd: Fix error return code in nfsd_file_cache_init() + +From: Huang Guobin + +[ Upstream commit 231307df246eb29f30092836524ebb1fcb8f5b25 ] + +Fix to return PTR_ERR() error code from the error handling case instead of +0 in function nfsd_file_cache_init(), as done elsewhere in this function. + +Fixes: 65294c1f2c5e7("nfsd: add a new struct file caching facility to nfsd") +Signed-off-by: Huang Guobin +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index e30e1ddc1aceb..d0748ff04b92f 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -684,6 +684,7 @@ nfsd_file_cache_init(void) + if (IS_ERR(nfsd_file_fsnotify_group)) { + pr_err("nfsd: unable to create fsnotify group: %ld\n", + PTR_ERR(nfsd_file_fsnotify_group)); ++ ret = PTR_ERR(nfsd_file_fsnotify_group); + nfsd_file_fsnotify_group = NULL; + goto out_notifier; + } +-- +2.43.0 + diff --git a/queue-5.10/nfsd-fix-exposure-in-nfsd4_decode_bitmap.patch b/queue-5.10/nfsd-fix-exposure-in-nfsd4_decode_bitmap.patch new file mode 100644 index 00000000000..ac09f6aa150 --- /dev/null +++ b/queue-5.10/nfsd-fix-exposure-in-nfsd4_decode_bitmap.patch @@ -0,0 +1,50 @@ +From d7404ded8a62e52b77aab13b6224dbcbf027cb24 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 14 Nov 2021 15:16:04 -0500 +Subject: NFSD: Fix exposure in nfsd4_decode_bitmap() + +From: Chuck Lever + +[ Upstream commit c0019b7db1d7ac62c711cda6b357a659d46428fe ] + +rtm@csail.mit.edu reports: +> nfsd4_decode_bitmap4() will write beyond bmval[bmlen-1] if the RPC +> directs it to do so. This can cause nfsd4_decode_state_protect4_a() +> to write client-supplied data beyond the end of +> nfsd4_exchange_id.spo_must_allow[] when called by +> nfsd4_decode_exchange_id(). + +Rewrite the loops so nfsd4_decode_bitmap() cannot iterate beyond +@bmlen. + +Reported by: rtm@csail.mit.edu +Fixes: d1c263a031e8 ("NFSD: Replace READ* macros in nfsd4_decode_fattr()") +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index ba2ed12df2060..d9758232a398c 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -288,11 +288,8 @@ nfsd4_decode_bitmap4(struct nfsd4_compoundargs *argp, u32 *bmval, u32 bmlen) + p = xdr_inline_decode(argp->xdr, count << 2); + if (!p) + return nfserr_bad_xdr; +- i = 0; +- while (i < count) +- bmval[i++] = be32_to_cpup(p++); +- while (i < bmlen) +- bmval[i++] = 0; ++ for (i = 0; i < bmlen; i++) ++ bmval[i] = (i < count) ? be32_to_cpup(p++) : 0; + + return nfs_ok; + } +-- +2.43.0 + diff --git a/queue-5.10/nfsd-fix-fall-through-warnings-for-clang.patch b/queue-5.10/nfsd-fix-fall-through-warnings-for-clang.patch new file mode 100644 index 00000000000..234d415fa21 --- /dev/null +++ b/queue-5.10/nfsd-fix-fall-through-warnings-for-clang.patch @@ -0,0 +1,49 @@ +From ef59b39a868a5a7632909a5b12af5d0776cff31b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Nov 2020 12:26:40 -0600 +Subject: nfsd: Fix fall-through warnings for Clang + +From: Gustavo A. R. Silva + +[ Upstream commit 76c50eb70d8e1133eaada0013845619c36345fbc ] + +In preparation to enable -Wimplicit-fallthrough for Clang, fix multiple +warnings by explicitly adding a couple of break statements instead of +just letting the code fall through to the next case. + +Link: https://github.com/KSPP/linux/issues/115 +Signed-off-by: Gustavo A. R. Silva +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 1 + + fs/nfsd/nfsctl.c | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index fd0d6e81a2272..ea68dc157ada1 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -3161,6 +3161,7 @@ nfsd4_exchange_id(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + goto out_nolock; + } + new->cl_mach_cred = true; ++ break; + case SP4_NONE: + break; + default: /* checked by xdr code */ +diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c +index 147ed8995a79f..cb73c12925629 100644 +--- a/fs/nfsd/nfsctl.c ++++ b/fs/nfsd/nfsctl.c +@@ -1169,6 +1169,7 @@ static struct inode *nfsd_get_inode(struct super_block *sb, umode_t mode) + inode->i_fop = &simple_dir_operations; + inode->i_op = &simple_dir_inode_operations; + inc_nlink(inode); ++ break; + default: + break; + } +-- +2.43.0 + diff --git a/queue-5.10/nfsd-fix-handling-of-cached-open-files-in-nfsd4_open.patch b/queue-5.10/nfsd-fix-handling-of-cached-open-files-in-nfsd4_open.patch new file mode 100644 index 00000000000..ee86392e459 --- /dev/null +++ b/queue-5.10/nfsd-fix-handling-of-cached-open-files-in-nfsd4_open.patch @@ -0,0 +1,273 @@ +From 2f5619caee557237e6f1b73f02114b8d17f2f7c6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Jan 2023 14:55:56 -0500 +Subject: nfsd: fix handling of cached open files in nfsd4_open codepath + +From: Jeff Layton + +[ Upstream commit 0b3a551fa58b4da941efeb209b3770868e2eddd7 ] + +Commit fb70bf124b05 ("NFSD: Instantiate a struct file when creating a +regular NFSv4 file") added the ability to cache an open fd over a +compound. There are a couple of problems with the way this currently +works: + +It's racy, as a newly-created nfsd_file can end up with its PENDING bit +cleared while the nf is hashed, and the nf_file pointer is still zeroed +out. Other tasks can find it in this state and they expect to see a +valid nf_file, and can oops if nf_file is NULL. + +Also, there is no guarantee that we'll end up creating a new nfsd_file +if one is already in the hash. If an extant entry is in the hash with a +valid nf_file, nfs4_get_vfs_file will clobber its nf_file pointer with +the value of op_file and the old nf_file will leak. + +Fix both issues by making a new nfsd_file_acquirei_opened variant that +takes an optional file pointer. If one is present when this is called, +we'll take a new reference to it instead of trying to open the file. If +the nfsd_file already has a valid nf_file, we'll just ignore the +optional file and pass the nfsd_file back as-is. + +Also rework the tracepoints a bit to allow for an "opened" variant and +don't try to avoid counting acquisitions in the case where we already +have a cached open file. + +Fixes: fb70bf124b05 ("NFSD: Instantiate a struct file when creating a regular NFSv4 file") +Cc: Trond Myklebust +Reported-by: Stanislav Saner +Reported-and-Tested-by: Ruben Vestergaard +Reported-and-Tested-by: Torkil Svensgaard +Signed-off-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 40 ++++++++++++++++++---------------- + fs/nfsd/filecache.h | 5 +++-- + fs/nfsd/nfs4state.c | 16 ++++---------- + fs/nfsd/trace.h | 52 ++++++++++++--------------------------------- + 4 files changed, 42 insertions(+), 71 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index 140094a44cc40..6a62d95d5ce64 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -1070,8 +1070,8 @@ nfsd_file_is_cached(struct inode *inode) + + static __be32 + nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, +- unsigned int may_flags, struct nfsd_file **pnf, +- bool open, bool want_gc) ++ unsigned int may_flags, struct file *file, ++ struct nfsd_file **pnf, bool want_gc) + { + struct nfsd_file_lookup_key key = { + .type = NFSD_FILE_KEY_FULL, +@@ -1146,8 +1146,7 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + status = nfserrno(nfsd_open_break_lease(file_inode(nf->nf_file), may_flags)); + out: + if (status == nfs_ok) { +- if (open) +- this_cpu_inc(nfsd_file_acquisitions); ++ this_cpu_inc(nfsd_file_acquisitions); + *pnf = nf; + } else { + if (refcount_dec_and_test(&nf->nf_ref)) +@@ -1157,20 +1156,23 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + + out_status: + put_cred(key.cred); +- if (open) +- trace_nfsd_file_acquire(rqstp, key.inode, may_flags, nf, status); ++ trace_nfsd_file_acquire(rqstp, key.inode, may_flags, nf, status); + return status; + + open_file: + trace_nfsd_file_alloc(nf); + nf->nf_mark = nfsd_file_mark_find_or_create(nf, key.inode); + if (nf->nf_mark) { +- if (open) { ++ if (file) { ++ get_file(file); ++ nf->nf_file = file; ++ status = nfs_ok; ++ trace_nfsd_file_opened(nf, status); ++ } else { + status = nfsd_open_verified(rqstp, fhp, may_flags, + &nf->nf_file); + trace_nfsd_file_open(nf, status); +- } else +- status = nfs_ok; ++ } + } else + status = nfserr_jukebox; + /* +@@ -1206,7 +1208,7 @@ __be32 + nfsd_file_acquire_gc(struct svc_rqst *rqstp, struct svc_fh *fhp, + unsigned int may_flags, struct nfsd_file **pnf) + { +- return nfsd_file_do_acquire(rqstp, fhp, may_flags, pnf, true, true); ++ return nfsd_file_do_acquire(rqstp, fhp, may_flags, NULL, pnf, true); + } + + /** +@@ -1227,28 +1229,30 @@ __be32 + nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + unsigned int may_flags, struct nfsd_file **pnf) + { +- return nfsd_file_do_acquire(rqstp, fhp, may_flags, pnf, true, false); ++ return nfsd_file_do_acquire(rqstp, fhp, may_flags, NULL, pnf, false); + } + + /** +- * nfsd_file_create - Get a struct nfsd_file, do not open ++ * nfsd_file_acquire_opened - Get a struct nfsd_file using existing open file + * @rqstp: the RPC transaction being executed + * @fhp: the NFS filehandle of the file just created + * @may_flags: NFSD_MAY_ settings for the file ++ * @file: cached, already-open file (may be NULL) + * @pnf: OUT: new or found "struct nfsd_file" object + * +- * The nfsd_file_object returned by this API is reference-counted +- * but not garbage-collected. The object is released immediately +- * one RCU grace period after the final nfsd_file_put(). ++ * Acquire a nfsd_file object that is not GC'ed. If one doesn't already exist, ++ * and @file is non-NULL, use it to instantiate a new nfsd_file instead of ++ * opening a new one. + * + * Returns nfs_ok and sets @pnf on success; otherwise an nfsstat in + * network byte order is returned. + */ + __be32 +-nfsd_file_create(struct svc_rqst *rqstp, struct svc_fh *fhp, +- unsigned int may_flags, struct nfsd_file **pnf) ++nfsd_file_acquire_opened(struct svc_rqst *rqstp, struct svc_fh *fhp, ++ unsigned int may_flags, struct file *file, ++ struct nfsd_file **pnf) + { +- return nfsd_file_do_acquire(rqstp, fhp, may_flags, pnf, false, false); ++ return nfsd_file_do_acquire(rqstp, fhp, may_flags, file, pnf, false); + } + + /* +diff --git a/fs/nfsd/filecache.h b/fs/nfsd/filecache.h +index b7efb2c3ddb18..41516a4263ea5 100644 +--- a/fs/nfsd/filecache.h ++++ b/fs/nfsd/filecache.h +@@ -60,7 +60,8 @@ __be32 nfsd_file_acquire_gc(struct svc_rqst *rqstp, struct svc_fh *fhp, + unsigned int may_flags, struct nfsd_file **nfp); + __be32 nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + unsigned int may_flags, struct nfsd_file **nfp); +-__be32 nfsd_file_create(struct svc_rqst *rqstp, struct svc_fh *fhp, +- unsigned int may_flags, struct nfsd_file **nfp); ++__be32 nfsd_file_acquire_opened(struct svc_rqst *rqstp, struct svc_fh *fhp, ++ unsigned int may_flags, struct file *file, ++ struct nfsd_file **nfp); + int nfsd_file_cache_stats_show(struct seq_file *m, void *v); + #endif /* _FS_NFSD_FILECACHE_H */ +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 4e05ad774c861..5eb3e055fde43 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -5261,18 +5261,10 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp, + if (!fp->fi_fds[oflag]) { + spin_unlock(&fp->fi_lock); + +- if (!open->op_filp) { +- status = nfsd_file_acquire(rqstp, cur_fh, access, &nf); +- if (status != nfs_ok) +- goto out_put_access; +- } else { +- status = nfsd_file_create(rqstp, cur_fh, access, &nf); +- if (status != nfs_ok) +- goto out_put_access; +- nf->nf_file = open->op_filp; +- open->op_filp = NULL; +- trace_nfsd_file_create(rqstp, access, nf); +- } ++ status = nfsd_file_acquire_opened(rqstp, cur_fh, access, ++ open->op_filp, &nf); ++ if (status != nfs_ok) ++ goto out_put_access; + + spin_lock(&fp->fi_lock); + if (!fp->fi_fds[oflag]) { +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index 8db7eecde9e39..0f674982785ce 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -891,43 +891,6 @@ TRACE_EVENT(nfsd_file_acquire, + ) + ); + +-TRACE_EVENT(nfsd_file_create, +- TP_PROTO( +- const struct svc_rqst *rqstp, +- unsigned int may_flags, +- const struct nfsd_file *nf +- ), +- +- TP_ARGS(rqstp, may_flags, nf), +- +- TP_STRUCT__entry( +- __field(const void *, nf_inode) +- __field(const void *, nf_file) +- __field(unsigned long, may_flags) +- __field(unsigned long, nf_flags) +- __field(unsigned long, nf_may) +- __field(unsigned int, nf_ref) +- __field(u32, xid) +- ), +- +- TP_fast_assign( +- __entry->nf_inode = nf->nf_inode; +- __entry->nf_file = nf->nf_file; +- __entry->may_flags = may_flags; +- __entry->nf_flags = nf->nf_flags; +- __entry->nf_may = nf->nf_may; +- __entry->nf_ref = refcount_read(&nf->nf_ref); +- __entry->xid = be32_to_cpu(rqstp->rq_xid); +- ), +- +- TP_printk("xid=0x%x inode=%p may_flags=%s ref=%u nf_flags=%s nf_may=%s nf_file=%p", +- __entry->xid, __entry->nf_inode, +- show_nfsd_may_flags(__entry->may_flags), +- __entry->nf_ref, show_nf_flags(__entry->nf_flags), +- show_nfsd_may_flags(__entry->nf_may), __entry->nf_file +- ) +-); +- + TRACE_EVENT(nfsd_file_insert_err, + TP_PROTO( + const struct svc_rqst *rqstp, +@@ -989,8 +952,8 @@ TRACE_EVENT(nfsd_file_cons_err, + ) + ); + +-TRACE_EVENT(nfsd_file_open, +- TP_PROTO(struct nfsd_file *nf, __be32 status), ++DECLARE_EVENT_CLASS(nfsd_file_open_class, ++ TP_PROTO(const struct nfsd_file *nf, __be32 status), + TP_ARGS(nf, status), + TP_STRUCT__entry( + __field(void *, nf_inode) /* cannot be dereferenced */ +@@ -1014,6 +977,17 @@ TRACE_EVENT(nfsd_file_open, + __entry->nf_file) + ) + ++#define DEFINE_NFSD_FILE_OPEN_EVENT(name) \ ++DEFINE_EVENT(nfsd_file_open_class, name, \ ++ TP_PROTO( \ ++ const struct nfsd_file *nf, \ ++ __be32 status \ ++ ), \ ++ TP_ARGS(nf, status)) ++ ++DEFINE_NFSD_FILE_OPEN_EVENT(nfsd_file_open); ++DEFINE_NFSD_FILE_OPEN_EVENT(nfsd_file_opened); ++ + TRACE_EVENT(nfsd_file_is_cached, + TP_PROTO( + const struct inode *inode, +-- +2.43.0 + diff --git a/queue-5.10/nfsd-fix-handling-of-oversized-nfsv4-compound-reques.patch b/queue-5.10/nfsd-fix-handling-of-oversized-nfsv4-compound-reques.patch new file mode 100644 index 00000000000..9364a7ac8a2 --- /dev/null +++ b/queue-5.10/nfsd-fix-handling-of-oversized-nfsv4-compound-reques.patch @@ -0,0 +1,125 @@ +From f03b587e7151d996431702a1457bbf536955812b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 5 Sep 2022 15:33:32 -0400 +Subject: NFSD: Fix handling of oversized NFSv4 COMPOUND requests + +From: Chuck Lever + +[ Upstream commit 7518a3dc5ea249d4112156ce71b8b184eb786151 ] + +If an NFS server returns NFS4ERR_RESOURCE on the first operation in +an NFSv4 COMPOUND, there's no way for a client to know where the +problem is and then simplify the compound to make forward progress. + +So instead, make NFSD process as many operations in an oversized +COMPOUND as it can and then return NFS4ERR_RESOURCE on the first +operation it did not process. + +pynfs NFSv4.0 COMP6 exercises this case, but checks only for the +COMPOUND status code, not whether the server has processed any +of the operations. + +pynfs NFSv4.1 SEQ6 and SEQ7 exercise the NFSv4.1 case, which detects +too many operations per COMPOUND by checking against the limits +negotiated when the session was created. + +Suggested-by: Bruce Fields +Fixes: 0078117c6d91 ("nfsd: return RESOURCE not GARBAGE_ARGS on too many ops") +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 19 +++++++++++++------ + fs/nfsd/nfs4xdr.c | 12 +++--------- + fs/nfsd/xdr4.h | 3 ++- + 3 files changed, 18 insertions(+), 16 deletions(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 62ffcecf78f7e..c40795d1d98df 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -2623,9 +2623,6 @@ nfsd4_proc_compound(struct svc_rqst *rqstp) + status = nfserr_minor_vers_mismatch; + if (nfsd_minorversion(nn, args->minorversion, NFSD_TEST) <= 0) + goto out; +- status = nfserr_resource; +- if (args->opcnt > NFSD_MAX_OPS_PER_COMPOUND) +- goto out; + + status = nfs41_check_op_ordering(args); + if (status) { +@@ -2638,10 +2635,20 @@ nfsd4_proc_compound(struct svc_rqst *rqstp) + + rqstp->rq_lease_breaker = (void **)&cstate->clp; + +- trace_nfsd_compound(rqstp, args->opcnt); ++ trace_nfsd_compound(rqstp, args->client_opcnt); + while (!status && resp->opcnt < args->opcnt) { + op = &args->ops[resp->opcnt++]; + ++ if (unlikely(resp->opcnt == NFSD_MAX_OPS_PER_COMPOUND)) { ++ /* If there are still more operations to process, ++ * stop here and report NFS4ERR_RESOURCE. */ ++ if (cstate->minorversion == 0 && ++ args->client_opcnt > resp->opcnt) { ++ op->status = nfserr_resource; ++ goto encode_op; ++ } ++ } ++ + /* + * The XDR decode routines may have pre-set op->status; + * for example, if there is a miscellaneous XDR error +@@ -2717,8 +2724,8 @@ nfsd4_proc_compound(struct svc_rqst *rqstp) + status = op->status; + } + +- trace_nfsd_compound_status(args->opcnt, resp->opcnt, status, +- nfsd4_op_name(op->opnum)); ++ trace_nfsd_compound_status(args->client_opcnt, resp->opcnt, ++ status, nfsd4_op_name(op->opnum)); + + nfsd4_cstate_clear_replay(cstate); + nfsd4_increment_op_stats(op->opnum); +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 92e0535ddb922..b9398b7b3539a 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -2359,16 +2359,10 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) + + if (xdr_stream_decode_u32(argp->xdr, &argp->minorversion) < 0) + return false; +- if (xdr_stream_decode_u32(argp->xdr, &argp->opcnt) < 0) ++ if (xdr_stream_decode_u32(argp->xdr, &argp->client_opcnt) < 0) + return false; +- +- /* +- * NFS4ERR_RESOURCE is a more helpful error than GARBAGE_ARGS +- * here, so we return success at the xdr level so that +- * nfsd4_proc can handle this is an NFS-level error. +- */ +- if (argp->opcnt > NFSD_MAX_OPS_PER_COMPOUND) +- return true; ++ argp->opcnt = min_t(u32, argp->client_opcnt, ++ NFSD_MAX_OPS_PER_COMPOUND); + + if (argp->opcnt > ARRAY_SIZE(argp->iops)) { + argp->ops = vcalloc(argp->opcnt, sizeof(*argp->ops)); +diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h +index 14b87141de343..2a699e8ca1baf 100644 +--- a/fs/nfsd/xdr4.h ++++ b/fs/nfsd/xdr4.h +@@ -717,9 +717,10 @@ struct nfsd4_compoundargs { + struct svcxdr_tmpbuf *to_free; + struct svc_rqst *rqstp; + +- u32 taglen; + char * tag; ++ u32 taglen; + u32 minorversion; ++ u32 client_opcnt; + u32 opcnt; + struct nfsd4_op *ops; + struct nfsd4_op iops[8]; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-fix-ia_size-underflow.patch b/queue-5.10/nfsd-fix-ia_size-underflow.patch new file mode 100644 index 00000000000..5fb4e1c2104 --- /dev/null +++ b/queue-5.10/nfsd-fix-ia_size-underflow.patch @@ -0,0 +1,45 @@ +From 32ad1b21278e537488d22401a9f41c23223d894d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 31 Jan 2022 13:01:53 -0500 +Subject: NFSD: Fix ia_size underflow + +From: Chuck Lever + +[ Upstream commit e6faac3f58c7c4176b66f63def17a34232a17b0e ] + +iattr::ia_size is a loff_t, which is a signed 64-bit type. NFSv3 and +NFSv4 both define file size as an unsigned 64-bit type. Thus there +is a range of valid file size values an NFS client can send that is +already larger than Linux can handle. + +Currently decode_fattr4() dumps a full u64 value into ia_size. If +that value happens to be larger than S64_MAX, then ia_size +underflows. I'm about to fix up the NFSv3 behavior as well, so let's +catch the underflow in the common code path: nfsd_setattr(). + +Cc: stable@vger.kernel.org +[ cel: context adjusted, 2f221d6f7b88 has not been applied ] +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/vfs.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index d4b6bc3b4d735..09e4a0af6fb43 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -449,6 +449,10 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, + .ia_size = iap->ia_size, + }; + ++ host_err = -EFBIG; ++ if (iap->ia_size < 0) ++ goto out_unlock; ++ + host_err = notify_change(dentry, &size_attr, NULL); + if (host_err) + goto out_unlock; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-fix-inconsistent-indenting.patch b/queue-5.10/nfsd-fix-inconsistent-indenting.patch new file mode 100644 index 00000000000..b668ba0e132 --- /dev/null +++ b/queue-5.10/nfsd-fix-inconsistent-indenting.patch @@ -0,0 +1,40 @@ +From 272849cedfeb2de1b6026b25ed5e0d92aff1ca1a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Dec 2021 16:35:42 +0800 +Subject: NFSD: Fix inconsistent indenting + +From: Jiapeng Chong + +[ Upstream commit 1e37d0e5bda45881eea1bec4b812def72c7d4aea ] + +Eliminate the follow smatch warning: + +fs/nfsd/nfs4xdr.c:4766 nfsd4_encode_read_plus_hole() warn: inconsistent +indenting. + +Reported-by: Abaci Robot +Signed-off-by: Jiapeng Chong +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index d9758232a398c..638a626af18dc 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -4812,8 +4812,8 @@ nfsd4_encode_read_plus_hole(struct nfsd4_compoundres *resp, + return nfserr_resource; + + *p++ = htonl(NFS4_CONTENT_HOLE); +- p = xdr_encode_hyper(p, read->rd_offset); +- p = xdr_encode_hyper(p, count); ++ p = xdr_encode_hyper(p, read->rd_offset); ++ p = xdr_encode_hyper(p, count); + + *eof = (read->rd_offset + count) >= f_size; + *maxcount = min_t(unsigned long, count, *maxcount); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-fix-kernel-test-robot-warning-in-ssc-code.patch b/queue-5.10/nfsd-fix-kernel-test-robot-warning-in-ssc-code.patch new file mode 100644 index 00000000000..b55c16d47d2 --- /dev/null +++ b/queue-5.10/nfsd-fix-kernel-test-robot-warning-in-ssc-code.patch @@ -0,0 +1,60 @@ +From 0bee4cf4ede264c9fec34d61dfb09f3b1acb6225 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 3 Jun 2021 20:02:26 -0400 +Subject: nfsd: fix kernel test robot warning in SSC code + +From: Dai Ngo + +[ Upstream commit f47dc2d3013c65631bf8903becc7d88dc9d9966e ] + +Fix by initializing pointer nfsd4_ssc_umount_item with NULL instead of 0. +Replace return value of nfsd4_ssc_setup_dul with __be32 instead of int. + +Reported-by: kernel test robot +Signed-off-by: Dai Ngo +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 4 ++-- + fs/nfsd/nfs4state.c | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 573c550e7aceb..598b54893f837 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -1178,7 +1178,7 @@ extern void nfs_sb_deactive(struct super_block *sb); + /* + * setup a work entry in the ssc delayed unmount list. + */ +-static int nfsd4_ssc_setup_dul(struct nfsd_net *nn, char *ipaddr, ++static __be32 nfsd4_ssc_setup_dul(struct nfsd_net *nn, char *ipaddr, + struct nfsd4_ssc_umount_item **retwork, struct vfsmount **ss_mnt) + { + struct nfsd4_ssc_umount_item *ni = 0; +@@ -1395,7 +1395,7 @@ nfsd4_cleanup_inter_ssc(struct vfsmount *ss_mnt, struct nfsd_file *src, + bool found = false; + long timeout; + struct nfsd4_ssc_umount_item *tmp; +- struct nfsd4_ssc_umount_item *ni = 0; ++ struct nfsd4_ssc_umount_item *ni = NULL; + struct nfsd_net *nn = net_generic(dst->nf_net, nfsd_net_id); + + nfs42_ssc_close(src->nf_file); +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index a20cdb1910048..401f0f2743717 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -5556,7 +5556,7 @@ EXPORT_SYMBOL_GPL(nfsd4_ssc_init_umount_work); + */ + static void nfsd4_ssc_shutdown_umount(struct nfsd_net *nn) + { +- struct nfsd4_ssc_umount_item *ni = 0; ++ struct nfsd4_ssc_umount_item *ni = NULL; + struct nfsd4_ssc_umount_item *tmp; + + spin_lock(&nn->nfsd_ssc_lock); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-fix-leaked-reference-count-of-nfsd4_ssc_umount_.patch b/queue-5.10/nfsd-fix-leaked-reference-count-of-nfsd4_ssc_umount_.patch new file mode 100644 index 00000000000..784149f8fe1 --- /dev/null +++ b/queue-5.10/nfsd-fix-leaked-reference-count-of-nfsd4_ssc_umount_.patch @@ -0,0 +1,54 @@ +From 2df7163096fbecfe353c148a632ab5ef4a7c473a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Jan 2023 21:34:13 -0800 +Subject: NFSD: fix leaked reference count of nfsd4_ssc_umount_item + +From: Dai Ngo + +[ Upstream commit 34e8f9ec4c9ac235f917747b23a200a5e0ec857b ] + +The reference count of nfsd4_ssc_umount_item is not decremented +on error conditions. This prevents the laundromat from unmounting +the vfsmount of the source file. + +This patch decrements the reference count of nfsd4_ssc_umount_item +on error. + +Fixes: f4e44b393389 ("NFSD: delay unmount source's export after inter-server copy completed.") +Signed-off-by: Dai Ngo +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 0fe00d6d385a1..fe20fd0933355 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -1813,13 +1813,17 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + release_copy_files(copy); + return status; + out_err: ++ if (nfsd4_ssc_is_inter(copy)) { ++ /* ++ * Source's vfsmount of inter-copy will be unmounted ++ * by the laundromat. Use copy instead of async_copy ++ * since async_copy->ss_nsui might not be set yet. ++ */ ++ refcount_dec(©->ss_nsui->nsui_refcnt); ++ } + if (async_copy) + cleanup_async_copy(async_copy); + status = nfserrno(-ENOMEM); +- /* +- * source's vfsmount of inter-copy will be unmounted +- * by the laundromat +- */ + goto out; + } + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-fix-licensing-header-in-filecache.c.patch b/queue-5.10/nfsd-fix-licensing-header-in-filecache.c.patch new file mode 100644 index 00000000000..624ceff9535 --- /dev/null +++ b/queue-5.10/nfsd-fix-licensing-header-in-filecache.c.patch @@ -0,0 +1,34 @@ +From 093795624d09cd18b2d171d2ff513487a8d111a1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 31 Oct 2022 09:53:26 -0400 +Subject: NFSD: Fix licensing header in filecache.c + +From: Chuck Lever + +[ Upstream commit 3f054211b29c0fa06dfdcab402c795fd7e906be1 ] + +Add a missing SPDX header. + +Signed-off-by: Chuck Lever +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index d681faf48cf85..b43d2d7ac5957 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -1,5 +1,6 @@ ++// SPDX-License-Identifier: GPL-2.0 + /* +- * Open file cache. ++ * The NFSD open file cache. + * + * (c) 2015 - Jeff Layton + * +-- +2.43.0 + diff --git a/queue-5.10/nfsd-fix-net-namespace-logic-in-__nfsd_file_cache_pu.patch b/queue-5.10/nfsd-fix-net-namespace-logic-in-__nfsd_file_cache_pu.patch new file mode 100644 index 00000000000..12f076fe300 --- /dev/null +++ b/queue-5.10/nfsd-fix-net-namespace-logic-in-__nfsd_file_cache_pu.patch @@ -0,0 +1,42 @@ +From 6793683b4a96c1d4c519836ae40ece9fd08e623a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 31 Oct 2022 11:49:21 -0400 +Subject: nfsd: fix net-namespace logic in __nfsd_file_cache_purge + +From: Jeff Layton + +[ Upstream commit d3aefd2b29ff5ffdeb5c06a7d3191a027a18cdb8 ] + +If the namespace doesn't match the one in "net", then we'll continue, +but that doesn't cause another rhashtable_walk_next call, so it will +loop infinitely. + +Fixes: ce502f81ba88 ("NFSD: Convert the filecache to use rhashtable") +Reported-by: Petr Vorel +Link: https://lore.kernel.org/ltp/Y1%2FP8gDAcWC%2F+VR3@pevik/ +Signed-off-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index 0b19eb015c6c8..024adcbe67e95 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -892,9 +892,8 @@ __nfsd_file_cache_purge(struct net *net) + + nf = rhashtable_walk_next(&iter); + while (!IS_ERR_OR_NULL(nf)) { +- if (net && nf->nf_net != net) +- continue; +- nfsd_file_unhash_and_dispose(nf, &dispose); ++ if (!net || nf->nf_net == net) ++ nfsd_file_unhash_and_dispose(nf, &dispose); + nf = rhashtable_walk_next(&iter); + } + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-fix-nfsd_file_unhash_and_dispose.patch b/queue-5.10/nfsd-fix-nfsd_file_unhash_and_dispose.patch new file mode 100644 index 00000000000..8b5366b2ce0 --- /dev/null +++ b/queue-5.10/nfsd-fix-nfsd_file_unhash_and_dispose.patch @@ -0,0 +1,125 @@ +From b0ed50aadaeb6bdd3b9c6de518cf15b4d4bc5343 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 30 Sep 2022 16:56:02 -0400 +Subject: nfsd: fix nfsd_file_unhash_and_dispose + +From: Jeff Layton + +[ Upstream commit 8d0d254b15cc5b7d46d85fb7ab8ecede9575e672 ] + +nfsd_file_unhash_and_dispose() is called for two reasons: + +We're either shutting down and purging the filecache, or we've gotten a +notification about a file delete, so we want to go ahead and unhash it +so that it'll get cleaned up when we close. + +We're either walking the hashtable or doing a lookup in it and we +don't take a reference in either case. What we want to do in both cases +is to try and unhash the object and put it on the dispose list if that +was successful. If it's no longer hashed, then we don't want to touch +it, with the assumption being that something else is already cleaning +up the sentinel reference. + +Instead of trying to selectively decrement the refcount in this +function, just unhash it, and if that was successful, move it to the +dispose list. Then, the disposal routine will just clean that up as +usual. + +Also, just make this a void function, drop the WARN_ON_ONCE, and the +comments about deadlocking since the nature of the purported deadlock +is no longer clear. + +Signed-off-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 36 +++++++----------------------------- + 1 file changed, 7 insertions(+), 29 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index fa8e1546e0206..a0d93e797cdce 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -404,22 +404,15 @@ nfsd_file_unhash(struct nfsd_file *nf) + return false; + } + +-/* +- * Return true if the file was unhashed. +- */ +-static bool ++static void + nfsd_file_unhash_and_dispose(struct nfsd_file *nf, struct list_head *dispose) + { + trace_nfsd_file_unhash_and_dispose(nf); +- if (!nfsd_file_unhash(nf)) +- return false; +- /* keep final reference for nfsd_file_lru_dispose */ +- if (refcount_dec_not_one(&nf->nf_ref)) +- return true; +- +- nfsd_file_lru_remove(nf); +- list_add(&nf->nf_lru, dispose); +- return true; ++ if (nfsd_file_unhash(nf)) { ++ /* caller must call nfsd_file_dispose_list() later */ ++ nfsd_file_lru_remove(nf); ++ list_add(&nf->nf_lru, dispose); ++ } + } + + static void +@@ -561,8 +554,6 @@ nfsd_file_dispose_list_delayed(struct list_head *dispose) + * @lock: LRU list lock (unused) + * @arg: dispose list + * +- * Note this can deadlock with nfsd_file_cache_purge. +- * + * Return values: + * %LRU_REMOVED: @item was removed from the LRU + * %LRU_ROTATE: @item is to be moved to the LRU tail +@@ -747,8 +738,6 @@ nfsd_file_close_inode(struct inode *inode) + * + * Walk the LRU list and close any entries that have not been used since + * the last scan. +- * +- * Note this can deadlock with nfsd_file_cache_purge. + */ + static void + nfsd_file_delayed_close(struct work_struct *work) +@@ -890,16 +879,12 @@ nfsd_file_cache_init(void) + goto out; + } + +-/* +- * Note this can deadlock with nfsd_file_lru_cb. +- */ + static void + __nfsd_file_cache_purge(struct net *net) + { + struct rhashtable_iter iter; + struct nfsd_file *nf; + LIST_HEAD(dispose); +- bool del; + + rhashtable_walk_enter(&nfsd_file_rhash_tbl, &iter); + do { +@@ -909,14 +894,7 @@ __nfsd_file_cache_purge(struct net *net) + while (!IS_ERR_OR_NULL(nf)) { + if (net && nf->nf_net != net) + continue; +- del = nfsd_file_unhash_and_dispose(nf, &dispose); +- +- /* +- * Deadlock detected! Something marked this entry as +- * unhased, but hasn't removed it from the hash list. +- */ +- WARN_ON_ONCE(!del); +- ++ nfsd_file_unhash_and_dispose(nf, &dispose); + nf = rhashtable_walk_next(&iter); + } + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-fix-nfsv3-setattr-create-s-handling-of-large-fi.patch b/queue-5.10/nfsd-fix-nfsv3-setattr-create-s-handling-of-large-fi.patch new file mode 100644 index 00000000000..55ff5213cc0 --- /dev/null +++ b/queue-5.10/nfsd-fix-nfsv3-setattr-create-s-handling-of-large-fi.patch @@ -0,0 +1,44 @@ +From 3bdd1c65ac7609f93617c426b6ffd6b226ad892a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 25 Jan 2022 15:59:57 -0500 +Subject: NFSD: Fix NFSv3 SETATTR/CREATE's handling of large file sizes + +From: Chuck Lever + +[ Upstream commit a648fdeb7c0e17177a2280344d015dba3fbe3314 ] + +iattr::ia_size is a loff_t, so these NFSv3 procedures must be +careful to deal with incoming client size values that are larger +than s64_max without corrupting the value. + +Silently capping the value results in storing a different value +than the client passed in which is unexpected behavior, so remove +the min_t() check in decode_sattr3(). + +Note that RFC 1813 permits only the WRITE procedure to return +NFS3ERR_FBIG. We believe that NFSv3 reference implementations +also return NFS3ERR_FBIG when ia_size is too large. + +Cc: stable@vger.kernel.org +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3xdr.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index 7c45ba4db61be..2e47a07029f1d 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -254,7 +254,7 @@ svcxdr_decode_sattr3(struct svc_rqst *rqstp, struct xdr_stream *xdr, + if (xdr_stream_decode_u64(xdr, &newsize) < 0) + return false; + iap->ia_valid |= ATTR_SIZE; +- iap->ia_size = min_t(u64, newsize, NFS_OFFSET_MAX); ++ iap->ia_size = newsize; + } + if (xdr_stream_decode_u32(xdr, &set_it) < 0) + return false; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-fix-null-dereference-in-nfs3svc_encode_getaclre.patch b/queue-5.10/nfsd-fix-null-dereference-in-nfs3svc_encode_getaclre.patch new file mode 100644 index 00000000000..37d1b9e76a6 --- /dev/null +++ b/queue-5.10/nfsd-fix-null-dereference-in-nfs3svc_encode_getaclre.patch @@ -0,0 +1,54 @@ +From 96da2a81e336e60e8142e01f9d6f26a8a5040395 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 1 Jul 2021 20:06:56 -0400 +Subject: nfsd: fix NULL dereference in nfs3svc_encode_getaclres + +From: J. Bruce Fields + +[ Upstream commit ab1016d39cc052064e32f25ad18ef8767a0ee3b8 ] + +In error cases the dentry may be NULL. + +Before 20798dfe249a, the encoder also checked dentry and +d_really_is_positive(dentry), but that looks like overkill to me--zero +status should be enough to guarantee a positive dentry. + +This isn't the first time we've seen an error-case NULL dereference +hidden in the initialization of a local variable in an xdr encoder. But +I went back through the other recent rewrites and didn't spot any +similar bugs. + +Reported-by: JianHong Yin +Reviewed-by: Chuck Lever III +Fixes: 20798dfe249a ("NFSD: Update the NFSv3 GETACL result encoder...") +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3acl.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c +index cfb686f23e571..5e13e5f7f92b8 100644 +--- a/fs/nfsd/nfs3acl.c ++++ b/fs/nfsd/nfs3acl.c +@@ -170,7 +170,7 @@ static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p) + struct nfsd3_getaclres *resp = rqstp->rq_resp; + struct dentry *dentry = resp->fh.fh_dentry; + struct kvec *head = rqstp->rq_res.head; +- struct inode *inode = d_inode(dentry); ++ struct inode *inode; + unsigned int base; + int n; + int w; +@@ -179,6 +179,7 @@ static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p) + return 0; + switch (resp->status) { + case nfs_ok: ++ inode = d_inode(dentry); + if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) + return 0; + if (xdr_stream_encode_u32(xdr, resp->mask) < 0) +-- +2.43.0 + diff --git a/queue-5.10/nfsd-fix-null-ptr-deref-in-nfsd_fill_super.patch b/queue-5.10/nfsd-fix-null-ptr-deref-in-nfsd_fill_super.patch new file mode 100644 index 00000000000..7cda7416954 --- /dev/null +++ b/queue-5.10/nfsd-fix-null-ptr-deref-in-nfsd_fill_super.patch @@ -0,0 +1,105 @@ +From f6d9f6e1e50a92b443c6ce86bc1de02efacab55a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 21 May 2022 12:08:45 +0800 +Subject: nfsd: Fix null-ptr-deref in nfsd_fill_super() + +From: Zhang Xiaoxu + +[ Upstream commit 6f6f84aa215f7b6665ccbb937db50860f9ec2989 ] + +KASAN report null-ptr-deref as follows: + + BUG: KASAN: null-ptr-deref in nfsd_fill_super+0xc6/0xe0 [nfsd] + Write of size 8 at addr 000000000000005d by task a.out/852 + + CPU: 7 PID: 852 Comm: a.out Not tainted 5.18.0-rc7-dirty #66 + Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.14.0-1.fc33 04/01/2014 + Call Trace: + + dump_stack_lvl+0x34/0x44 + kasan_report+0xab/0x120 + ? nfsd_mkdir+0x71/0x1c0 [nfsd] + ? nfsd_fill_super+0xc6/0xe0 [nfsd] + nfsd_fill_super+0xc6/0xe0 [nfsd] + ? nfsd_mkdir+0x1c0/0x1c0 [nfsd] + get_tree_keyed+0x8e/0x100 + vfs_get_tree+0x41/0xf0 + __do_sys_fsconfig+0x590/0x670 + ? fscontext_read+0x180/0x180 + ? anon_inode_getfd+0x4f/0x70 + do_syscall_64+0x35/0x80 + entry_SYSCALL_64_after_hwframe+0x44/0xae + +This can be reproduce by concurrent operations: + 1. fsopen(nfsd)/fsconfig + 2. insmod/rmmod nfsd + +Since the nfsd file system is registered before than nfsd_net allocated, +the caller may get the file_system_type and use the nfsd_net before it +allocated, then null-ptr-deref occurred. + +So init_nfsd() should call register_filesystem() last. + +Fixes: bd5ae9288d64 ("nfsd: register pernet ops last, unregister first") +Signed-off-by: Zhang Xiaoxu +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsctl.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c +index 55949e60897d5..0621c2faf2424 100644 +--- a/fs/nfsd/nfsctl.c ++++ b/fs/nfsd/nfsctl.c +@@ -1535,25 +1535,25 @@ static int __init init_nfsd(void) + retval = create_proc_exports_entry(); + if (retval) + goto out_free_lockd; +- retval = register_filesystem(&nfsd_fs_type); +- if (retval) +- goto out_free_exports; + retval = register_pernet_subsys(&nfsd_net_ops); + if (retval < 0) +- goto out_free_filesystem; ++ goto out_free_exports; + retval = register_cld_notifier(); + if (retval) + goto out_free_subsys; + retval = nfsd4_create_laundry_wq(); ++ if (retval) ++ goto out_free_cld; ++ retval = register_filesystem(&nfsd_fs_type); + if (retval) + goto out_free_all; + return 0; + out_free_all: ++ nfsd4_destroy_laundry_wq(); ++out_free_cld: + unregister_cld_notifier(); + out_free_subsys: + unregister_pernet_subsys(&nfsd_net_ops); +-out_free_filesystem: +- unregister_filesystem(&nfsd_fs_type); + out_free_exports: + remove_proc_entry("fs/nfs/exports", NULL); + remove_proc_entry("fs/nfs", NULL); +@@ -1571,6 +1571,7 @@ static int __init init_nfsd(void) + + static void __exit exit_nfsd(void) + { ++ unregister_filesystem(&nfsd_fs_type); + nfsd4_destroy_laundry_wq(); + unregister_cld_notifier(); + unregister_pernet_subsys(&nfsd_net_ops); +@@ -1581,7 +1582,6 @@ static void __exit exit_nfsd(void) + nfsd_lockd_shutdown(); + nfsd4_free_slabs(); + nfsd4_exit_pnfs(); +- unregister_filesystem(&nfsd_fs_type); + } + + MODULE_AUTHOR("Olaf Kirch "); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-fix-possible-oops-when-nfsd-pool_stats-is-close.patch b/queue-5.10/nfsd-fix-possible-oops-when-nfsd-pool_stats-is-close.patch new file mode 100644 index 00000000000..1c09f23aa73 --- /dev/null +++ b/queue-5.10/nfsd-fix-possible-oops-when-nfsd-pool_stats-is-close.patch @@ -0,0 +1,54 @@ +From 963610171e9fad72470c5fb0d3e6b22a308b4f92 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 Sep 2023 11:25:00 +1000 +Subject: NFSD: fix possible oops when nfsd/pool_stats is closed. + +From: NeilBrown + +[ Upstream commit 88956eabfdea7d01d550535af120d4ef265b1d02 ] + +If /proc/fs/nfsd/pool_stats is open when the last nfsd thread exits, then +when the file is closed a NULL pointer is dereferenced. +This is because nfsd_pool_stats_release() assumes that the +pointer to the svc_serv cannot become NULL while a reference is held. + +This used to be the case but a recent patch split nfsd_last_thread() out +from nfsd_put(), and clearing the pointer is done in nfsd_last_thread(). + +This is easily reproduced by running + rpc.nfsd 8 ; ( rpc.nfsd 0;true) < /proc/fs/nfsd/pool_stats + +Fortunately nfsd_pool_stats_release() has easy access to the svc_serv +pointer, and so can call svc_put() on it directly. + +Fixes: 9f28a971ee9f ("nfsd: separate nfsd_last_thread() from nfsd_put()") +Signed-off-by: NeilBrown +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfssvc.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c +index ee5713fca1870..2a1dd580dfb94 100644 +--- a/fs/nfsd/nfssvc.c ++++ b/fs/nfsd/nfssvc.c +@@ -1084,11 +1084,12 @@ int nfsd_pool_stats_open(struct inode *inode, struct file *file) + + int nfsd_pool_stats_release(struct inode *inode, struct file *file) + { ++ struct seq_file *seq = file->private_data; ++ struct svc_serv *serv = seq->private; + int ret = seq_release(inode, file); +- struct net *net = inode->i_sb->s_fs_info; + + mutex_lock(&nfsd_mutex); +- nfsd_put(net); ++ svc_put(serv); + mutex_unlock(&nfsd_mutex); + return ret; + } +-- +2.43.0 + diff --git a/queue-5.10/nfsd-fix-potential-use-after-free-in-nfsd_file_put.patch b/queue-5.10/nfsd-fix-potential-use-after-free-in-nfsd_file_put.patch new file mode 100644 index 00000000000..2eb48433373 --- /dev/null +++ b/queue-5.10/nfsd-fix-potential-use-after-free-in-nfsd_file_put.patch @@ -0,0 +1,44 @@ +From 68bfd75749583bb37a073b7d719d34990e1771c1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 May 2022 19:49:01 -0400 +Subject: NFSD: Fix potential use-after-free in nfsd_file_put() + +From: Chuck Lever + +[ Upstream commit b6c71c66b0ad8f2b59d9bc08c7a5079b110bec01 ] + +nfsd_file_put_noref() can free @nf, so don't dereference @nf +immediately upon return from nfsd_file_put_noref(). + +Suggested-by: Trond Myklebust +Fixes: 999397926ab3 ("nfsd: Clean up nfsd_file_put()") +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index 11c096b447401..fc0fcb3321537 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -308,11 +308,12 @@ nfsd_file_put(struct nfsd_file *nf) + if (test_bit(NFSD_FILE_HASHED, &nf->nf_flags) == 0) { + nfsd_file_flush(nf); + nfsd_file_put_noref(nf); +- } else { ++ } else if (nf->nf_file) { + nfsd_file_put_noref(nf); +- if (nf->nf_file) +- nfsd_file_schedule_laundrette(); +- } ++ nfsd_file_schedule_laundrette(); ++ } else ++ nfsd_file_put_noref(nf); ++ + if (atomic_long_read(&nfsd_filecache_count) >= NFSD_FILE_LRU_LIMIT) + nfsd_file_gc(); + } +-- +2.43.0 + diff --git a/queue-5.10/nfsd-fix-problem-of-commit-and-nfs4err_delay-in-infi.patch b/queue-5.10/nfsd-fix-problem-of-commit-and-nfs4err_delay-in-infi.patch new file mode 100644 index 00000000000..5317a541c47 --- /dev/null +++ b/queue-5.10/nfsd-fix-problem-of-commit-and-nfs4err_delay-in-infi.patch @@ -0,0 +1,48 @@ +From 608ba128419e38bace64454866f092fce75534be Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 19 Apr 2023 10:53:18 -0700 +Subject: NFSD: Fix problem of COMMIT and NFS4ERR_DELAY in infinite loop + +From: Dai Ngo + +[ Upstream commit 147abcacee33781e75588869e944ddb07528a897 ] + +The following request sequence to the same file causes the NFS client and +server getting into an infinite loop with COMMIT and NFS4ERR_DELAY: + +OPEN +REMOVE +WRITE +COMMIT + +Problem reported by recall11, recall12, recall14, recall20, recall22, +recall40, recall42, recall48, recall50 of nfstest suite. + +This patch restores the handling of race condition in nfsd_file_do_acquire +with unlink to that prior of the regression. + +Fixes: ac3a2585f018 ("nfsd: rework refcounting in filecache") +Signed-off-by: Dai Ngo +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index 6b8706f23eaf0..615ea8324911e 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -1098,8 +1098,6 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + * then unhash. + */ + if (status != nfs_ok || inode->i_nlink == 0) +- status = nfserr_jukebox; +- if (status != nfs_ok) + nfsd_file_unhash(nf); + clear_and_wake_up_bit(NFSD_FILE_PENDING, &nf->nf_flags); + if (status == nfs_ok) +-- +2.43.0 + diff --git a/queue-5.10/nfsd-fix-problems-with-cleanup-on-errors-in-nfsd4_co.patch b/queue-5.10/nfsd-fix-problems-with-cleanup-on-errors-in-nfsd4_co.patch new file mode 100644 index 00000000000..8707a34e216 --- /dev/null +++ b/queue-5.10/nfsd-fix-problems-with-cleanup-on-errors-in-nfsd4_co.patch @@ -0,0 +1,97 @@ +From 473481b342e96b7bd369fdba15a993a2e3dcadf2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 31 Jan 2023 11:12:29 -0800 +Subject: NFSD: fix problems with cleanup on errors in nfsd4_copy + +From: Dai Ngo + +[ Upstream commit 81e722978ad21072470b73d8f6a50ad62c7d5b7d ] + +When nfsd4_copy fails to allocate memory for async_copy->cp_src, or +nfs4_init_copy_state fails, it calls cleanup_async_copy to do the +cleanup for the async_copy which causes page fault since async_copy +is not yet initialized. + +This patche rearranges the order of initializing the fields in +async_copy and adds checks in cleanup_async_copy to skip un-initialized +fields. + +Fixes: ce0887ac96d3 ("NFSD add nfs4 inter ssc to nfsd4_copy") +Fixes: 87689df69491 ("NFSD: Shrink size of struct nfsd4_copy") +Signed-off-by: Dai Ngo +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 12 ++++++++---- + fs/nfsd/nfs4state.c | 5 +++-- + 2 files changed, 11 insertions(+), 6 deletions(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index fe20fd0933355..9c51c10bcf080 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -1687,9 +1687,12 @@ static void cleanup_async_copy(struct nfsd4_copy *copy) + { + nfs4_free_copy_state(copy); + release_copy_files(copy); +- spin_lock(©->cp_clp->async_lock); +- list_del(©->copies); +- spin_unlock(©->cp_clp->async_lock); ++ if (copy->cp_clp) { ++ spin_lock(©->cp_clp->async_lock); ++ if (!list_empty(©->copies)) ++ list_del_init(©->copies); ++ spin_unlock(©->cp_clp->async_lock); ++ } + nfs4_put_copy(copy); + } + +@@ -1786,12 +1789,13 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + async_copy = kzalloc(sizeof(struct nfsd4_copy), GFP_KERNEL); + if (!async_copy) + goto out_err; ++ INIT_LIST_HEAD(&async_copy->copies); ++ refcount_set(&async_copy->refcount, 1); + async_copy->cp_src = kmalloc(sizeof(*async_copy->cp_src), GFP_KERNEL); + if (!async_copy->cp_src) + goto out_err; + if (!nfs4_init_copy_state(nn, copy)) + goto out_err; +- refcount_set(&async_copy->refcount, 1); + memcpy(©->cp_res.cb_stateid, ©->cp_stateid.cs_stid, + sizeof(copy->cp_res.cb_stateid)); + dup_copy_fields(copy, async_copy); +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index f57137ef306bd..507dd2b11856b 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -990,7 +990,6 @@ static int nfs4_init_cp_state(struct nfsd_net *nn, copy_stateid_t *stid, + + stid->cs_stid.si_opaque.so_clid.cl_boot = (u32)nn->boot_time; + stid->cs_stid.si_opaque.so_clid.cl_id = nn->s2s_cp_cl_id; +- stid->cs_type = cs_type; + + idr_preload(GFP_KERNEL); + spin_lock(&nn->s2s_cp_lock); +@@ -1001,6 +1000,7 @@ static int nfs4_init_cp_state(struct nfsd_net *nn, copy_stateid_t *stid, + idr_preload_end(); + if (new_id < 0) + return 0; ++ stid->cs_type = cs_type; + return 1; + } + +@@ -1034,7 +1034,8 @@ void nfs4_free_copy_state(struct nfsd4_copy *copy) + { + struct nfsd_net *nn; + +- WARN_ON_ONCE(copy->cp_stateid.cs_type != NFS4_COPY_STID); ++ if (copy->cp_stateid.cs_type != NFS4_COPY_STID) ++ return; + nn = net_generic(copy->cp_clp->net, nfsd_net_id); + spin_lock(&nn->s2s_cp_lock); + idr_remove(&nn->s2s_cp_stateids, +-- +2.43.0 + diff --git a/queue-5.10/nfsd-fix-readdir-buffer-overflow.patch b/queue-5.10/nfsd-fix-readdir-buffer-overflow.patch new file mode 100644 index 00000000000..5678af722ee --- /dev/null +++ b/queue-5.10/nfsd-fix-readdir-buffer-overflow.patch @@ -0,0 +1,112 @@ +From 307b88729ec1885a0e787c5811dc25c09e034702 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Dec 2021 11:12:11 -0500 +Subject: NFSD: Fix READDIR buffer overflow + +From: Chuck Lever + +[ Upstream commit 53b1119a6e5028b125f431a0116ba73510d82a72 ] + +If a client sends a READDIR count argument that is too small (say, +zero), then the buffer size calculation in the new init_dirlist +helper functions results in an underflow, allowing the XDR stream +functions to write beyond the actual buffer. + +This calculation has always been suspect. NFSD has never sanity- +checked the READDIR count argument, but the old entry encoders +managed the problem correctly. + +With the commits below, entry encoding changed, exposing the +underflow to the pointer arithmetic in xdr_reserve_space(). + +Modern NFS clients attempt to retrieve as much data as possible +for each READDIR request. Also, we have no unit tests that +exercise the behavior of READDIR at the lower bound of @count +values. Thus this case was missed during testing. + +Reported-by: Anatoly Trosinenko +Fixes: f5dcccd647da ("NFSD: Update the NFSv2 READDIR entry encoder to use struct xdr_stream") +Fixes: 7f87fc2d34d4 ("NFSD: Update NFSv3 READDIR entry encoders to use struct xdr_stream") +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3proc.c | 11 ++++------- + fs/nfsd/nfsproc.c | 8 ++++---- + 2 files changed, 8 insertions(+), 11 deletions(-) + +diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c +index 5abb5c8e2cd21..d26271c60ab44 100644 +--- a/fs/nfsd/nfs3proc.c ++++ b/fs/nfsd/nfs3proc.c +@@ -443,22 +443,19 @@ nfsd3_proc_link(struct svc_rqst *rqstp) + + static void nfsd3_init_dirlist_pages(struct svc_rqst *rqstp, + struct nfsd3_readdirres *resp, +- int count) ++ u32 count) + { + struct xdr_buf *buf = &resp->dirlist; + struct xdr_stream *xdr = &resp->xdr; + +- count = min_t(u32, count, svc_max_payload(rqstp)); ++ count = clamp(count, (u32)(XDR_UNIT * 2), svc_max_payload(rqstp)); + + memset(buf, 0, sizeof(*buf)); + + /* Reserve room for the NULL ptr & eof flag (-2 words) */ + buf->buflen = count - XDR_UNIT * 2; + buf->pages = rqstp->rq_next_page; +- while (count > 0) { +- rqstp->rq_next_page++; +- count -= PAGE_SIZE; +- } ++ rqstp->rq_next_page += (buf->buflen + PAGE_SIZE - 1) >> PAGE_SHIFT; + + /* This is xdr_init_encode(), but it assumes that + * the head kvec has already been consumed. */ +@@ -467,7 +464,7 @@ static void nfsd3_init_dirlist_pages(struct svc_rqst *rqstp, + xdr->page_ptr = buf->pages; + xdr->iov = NULL; + xdr->p = page_address(*buf->pages); +- xdr->end = xdr->p + (PAGE_SIZE >> 2); ++ xdr->end = (void *)xdr->p + min_t(u32, buf->buflen, PAGE_SIZE); + xdr->rqst = NULL; + } + +diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c +index 5a84aed17e705..8ee329bc3815d 100644 +--- a/fs/nfsd/nfsproc.c ++++ b/fs/nfsd/nfsproc.c +@@ -556,17 +556,17 @@ nfsd_proc_rmdir(struct svc_rqst *rqstp) + + static void nfsd_init_dirlist_pages(struct svc_rqst *rqstp, + struct nfsd_readdirres *resp, +- int count) ++ u32 count) + { + struct xdr_buf *buf = &resp->dirlist; + struct xdr_stream *xdr = &resp->xdr; + +- count = min_t(u32, count, PAGE_SIZE); ++ count = clamp(count, (u32)(XDR_UNIT * 2), svc_max_payload(rqstp)); + + memset(buf, 0, sizeof(*buf)); + + /* Reserve room for the NULL ptr & eof flag (-2 words) */ +- buf->buflen = count - sizeof(__be32) * 2; ++ buf->buflen = count - XDR_UNIT * 2; + buf->pages = rqstp->rq_next_page; + rqstp->rq_next_page++; + +@@ -577,7 +577,7 @@ static void nfsd_init_dirlist_pages(struct svc_rqst *rqstp, + xdr->page_ptr = buf->pages; + xdr->iov = NULL; + xdr->p = page_address(*buf->pages); +- xdr->end = xdr->p + (PAGE_SIZE >> 2); ++ xdr->end = (void *)xdr->p + min_t(u32, buf->buflen, PAGE_SIZE); + xdr->rqst = NULL; + } + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-fix-reads-with-a-non-zero-offset-that-don-t-end.patch b/queue-5.10/nfsd-fix-reads-with-a-non-zero-offset-that-don-t-end.patch new file mode 100644 index 00000000000..9a0b58dfbe2 --- /dev/null +++ b/queue-5.10/nfsd-fix-reads-with-a-non-zero-offset-that-don-t-end.patch @@ -0,0 +1,50 @@ +From d21e7ca65bb1b8f679bbc20672487addca00b417 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 23 Nov 2022 14:14:32 -0500 +Subject: NFSD: Fix reads with a non-zero offset that don't end on a page + boundary +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Chuck Lever + +[ Upstream commit ac8db824ead0de2e9111337c401409d010fba2f0 ] + +This was found when virtual machines with nfs-mounted qcow2 disks +failed to boot properly. + +Reported-by: Anders Blomdell +Suggested-by: Al Viro +Link: https://bugzilla.redhat.com/show_bug.cgi?id=2142132 +Fixes: bfbfb6182ad1 ("nfsd_splice_actor(): handle compound pages") +[ cel: "‘for’ loop initial declarations are only allowed in C99 or C11 mode" ] +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/vfs.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index e29034b1e6128..4ff626c912cc3 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -888,11 +888,11 @@ nfsd_splice_actor(struct pipe_inode_info *pipe, struct pipe_buffer *buf, + struct svc_rqst *rqstp = sd->u.data; + struct page *page = buf->page; // may be a compound one + unsigned offset = buf->offset; +- int i; ++ struct page *last_page; + +- page += offset / PAGE_SIZE; +- for (i = sd->len; i > 0; i -= PAGE_SIZE) +- svc_rqst_replace_page(rqstp, page++); ++ last_page = page + (offset + sd->len - 1) / PAGE_SIZE; ++ for (page += offset / PAGE_SIZE; page <= last_page; page++) ++ svc_rqst_replace_page(rqstp, page); + if (rqstp->rq_res.page_len == 0) // first call + rqstp->rq_res.page_base = offset % PAGE_SIZE; + rqstp->rq_res.page_len += sd->len; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-fix-regression-with-setting-acls.patch b/queue-5.10/nfsd-fix-regression-with-setting-acls.patch new file mode 100644 index 00000000000..6d2a3df6401 --- /dev/null +++ b/queue-5.10/nfsd-fix-regression-with-setting-acls.patch @@ -0,0 +1,85 @@ +From 35850d46e15cf52f7e67df32d589681968d1b88e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Sep 2022 12:08:40 +1000 +Subject: NFSD: fix regression with setting ACLs. + +From: NeilBrown + +[ Upstream commit 00801cd92d91e94aa04d687f9bb9a9104e7c3d46 ] + +A recent patch moved ACL setting into nfsd_setattr(). +Unfortunately it didn't work as nfsd_setattr() aborts early if +iap->ia_valid is 0. + +Remove this test, and instead avoid calling notify_change() when +ia_valid is 0. + +This means that nfsd_setattr() will now *always* lock the inode. +Previously it didn't if only a ATTR_MODE change was requested on a +symlink (see Commit 15b7a1b86d66 ("[PATCH] knfsd: fix setattr-on-symlink +error return")). I don't think this change really matters. + +Fixes: c0cbe70742f4 ("NFSD: add posix ACLs to struct nfsd_attrs") +Signed-off-by: NeilBrown +Reviewed-by: Jeff Layton +[ cel: backported to 5.10.y, prior to idmapped mounts ] +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/vfs.c | 19 +++++++++---------- + 1 file changed, 9 insertions(+), 10 deletions(-) + +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index 5a7fee4ee2079..95f2e4549c034 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -299,6 +299,10 @@ commit_metadata(struct svc_fh *fhp) + static void + nfsd_sanitize_attrs(struct inode *inode, struct iattr *iap) + { ++ /* Ignore mode updates on symlinks */ ++ if (S_ISLNK(inode->i_mode)) ++ iap->ia_valid &= ~ATTR_MODE; ++ + /* sanitize the mode change */ + if (iap->ia_valid & ATTR_MODE) { + iap->ia_mode &= S_IALLUGO; +@@ -366,7 +370,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, + int accmode = NFSD_MAY_SATTR; + umode_t ftype = 0; + __be32 err; +- int host_err; ++ int host_err = 0; + bool get_write_count; + bool size_change = (iap->ia_valid & ATTR_SIZE); + +@@ -404,13 +408,6 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, + dentry = fhp->fh_dentry; + inode = d_inode(dentry); + +- /* Ignore any mode updates on symlinks */ +- if (S_ISLNK(inode->i_mode)) +- iap->ia_valid &= ~ATTR_MODE; +- +- if (!iap->ia_valid) +- return 0; +- + nfsd_sanitize_attrs(inode, iap); + + if (check_guard && guardtime != inode->i_ctime.tv_sec) +@@ -461,8 +458,10 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, + goto out_unlock; + } + +- iap->ia_valid |= ATTR_CTIME; +- host_err = notify_change(dentry, iap, NULL); ++ if (iap->ia_valid) { ++ iap->ia_valid |= ATTR_CTIME; ++ host_err = notify_change(dentry, iap, NULL); ++ } + + out_unlock: + if (attr->na_seclabel && attr->na_seclabel->len) +-- +2.43.0 + diff --git a/queue-5.10/nfsd-fix-release_lockowner.patch b/queue-5.10/nfsd-fix-release_lockowner.patch new file mode 100644 index 00000000000..017bee57bf9 --- /dev/null +++ b/queue-5.10/nfsd-fix-release_lockowner.patch @@ -0,0 +1,149 @@ +From aee76342109daa8253aae7ff919d67757c6f7516 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 22 Jan 2024 14:58:16 +1100 +Subject: nfsd: fix RELEASE_LOCKOWNER + +From: NeilBrown + +[ Upstream commit edcf9725150e42beeca42d085149f4c88fa97afd ] + +The test on so_count in nfsd4_release_lockowner() is nonsense and +harmful. Revert to using check_for_locks(), changing that to not sleep. + +First: harmful. +As is documented in the kdoc comment for nfsd4_release_lockowner(), the +test on so_count can transiently return a false positive resulting in a +return of NFS4ERR_LOCKS_HELD when in fact no locks are held. This is +clearly a protocol violation and with the Linux NFS client it can cause +incorrect behaviour. + +If RELEASE_LOCKOWNER is sent while some other thread is still +processing a LOCK request which failed because, at the time that request +was received, the given owner held a conflicting lock, then the nfsd +thread processing that LOCK request can hold a reference (conflock) to +the lock owner that causes nfsd4_release_lockowner() to return an +incorrect error. + +The Linux NFS client ignores that NFS4ERR_LOCKS_HELD error because it +never sends NFS4_RELEASE_LOCKOWNER without first releasing any locks, so +it knows that the error is impossible. It assumes the lock owner was in +fact released so it feels free to use the same lock owner identifier in +some later locking request. + +When it does reuse a lock owner identifier for which a previous RELEASE +failed, it will naturally use a lock_seqid of zero. However the server, +which didn't release the lock owner, will expect a larger lock_seqid and +so will respond with NFS4ERR_BAD_SEQID. + +So clearly it is harmful to allow a false positive, which testing +so_count allows. + +The test is nonsense because ... well... it doesn't mean anything. + +so_count is the sum of three different counts. +1/ the set of states listed on so_stateids +2/ the set of active vfs locks owned by any of those states +3/ various transient counts such as for conflicting locks. + +When it is tested against '2' it is clear that one of these is the +transient reference obtained by find_lockowner_str_locked(). It is not +clear what the other one is expected to be. + +In practice, the count is often 2 because there is precisely one state +on so_stateids. If there were more, this would fail. + +In my testing I see two circumstances when RELEASE_LOCKOWNER is called. +In one case, CLOSE is called before RELEASE_LOCKOWNER. That results in +all the lock states being removed, and so the lockowner being discarded +(it is removed when there are no more references which usually happens +when the lock state is discarded). When nfsd4_release_lockowner() finds +that the lock owner doesn't exist, it returns success. + +The other case shows an so_count of '2' and precisely one state listed +in so_stateid. It appears that the Linux client uses a separate lock +owner for each file resulting in one lock state per lock owner, so this +test on '2' is safe. For another client it might not be safe. + +So this patch changes check_for_locks() to use the (newish) +find_any_file_locked() so that it doesn't take a reference on the +nfs4_file and so never calls nfsd_file_put(), and so never sleeps. With +this check is it safe to restore the use of check_for_locks() rather +than testing so_count against the mysterious '2'. + +Fixes: ce3c4ad7f4ce ("NFSD: Fix possible sleep during nfsd4_release_lockowner()") +Signed-off-by: NeilBrown +Reviewed-by: Jeff Layton +Cc: stable@vger.kernel.org # v6.2+ +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 26 +++++++++++++++----------- + 1 file changed, 15 insertions(+), 11 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index e8e642e5ec8f1..c073cc23c5285 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -7836,14 +7836,16 @@ check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner) + { + struct file_lock *fl; + int status = false; +- struct nfsd_file *nf = find_any_file(fp); ++ struct nfsd_file *nf; + struct inode *inode; + struct file_lock_context *flctx; + ++ spin_lock(&fp->fi_lock); ++ nf = find_any_file_locked(fp); + if (!nf) { + /* Any valid lock stateid should have some sort of access */ + WARN_ON_ONCE(1); +- return status; ++ goto out; + } + + inode = locks_inode(nf->nf_file); +@@ -7859,7 +7861,8 @@ check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner) + } + spin_unlock(&flctx->flc_lock); + } +- nfsd_file_put(nf); ++out: ++ spin_unlock(&fp->fi_lock); + return status; + } + +@@ -7869,10 +7872,8 @@ check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner) + * @cstate: NFSv4 COMPOUND state + * @u: RELEASE_LOCKOWNER arguments + * +- * The lockowner's so_count is bumped when a lock record is added +- * or when copying a conflicting lock. The latter case is brief, +- * but can lead to fleeting false positives when looking for +- * locks-in-use. ++ * Check if theree are any locks still held and if not - free the lockowner ++ * and any lock state that is owned. + * + * Return values: + * %nfs_ok: lockowner released or not found +@@ -7908,10 +7909,13 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, + spin_unlock(&clp->cl_lock); + return nfs_ok; + } +- if (atomic_read(&lo->lo_owner.so_count) != 2) { +- spin_unlock(&clp->cl_lock); +- nfs4_put_stateowner(&lo->lo_owner); +- return nfserr_locks_held; ++ ++ list_for_each_entry(stp, &lo->lo_owner.so_stateids, st_perstateowner) { ++ if (check_for_locks(stp->st_stid.sc_file, lo)) { ++ spin_unlock(&clp->cl_lock); ++ nfs4_put_stateowner(&lo->lo_owner); ++ return nfserr_locks_held; ++ } + } + unhash_lockowner_locked(lo); + while (!list_empty(&lo->lo_owner.so_stateids)) { +-- +2.43.0 + diff --git a/queue-5.10/nfsd-fix-returned-readdir-offset-cookie.patch b/queue-5.10/nfsd-fix-returned-readdir-offset-cookie.patch new file mode 100644 index 00000000000..27e24e19ccf --- /dev/null +++ b/queue-5.10/nfsd-fix-returned-readdir-offset-cookie.patch @@ -0,0 +1,57 @@ +From cb2ffbc9de877cf02b8f5cd68562c3afaf6f65a4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 10 Nov 2020 10:24:39 -0500 +Subject: NFSD: Fix returned READDIR offset cookie + +From: Chuck Lever + +[ Upstream commit 0a8f37fb34a96267c656f7254e69bb9a2fc89fe4 ] + +Code inspection shows that the server's NFSv3 READDIR implementation +handles offset cookies slightly differently than the NFSv2 READDIR, +NFSv3 READDIRPLUS, and NFSv4 READDIR implementations, +and there doesn't seem to be any need for this difference. + +As a clean up, I copied the logic from nfsd3_proc_readdirplus(). + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3proc.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c +index 71db0ed3c49ed..8cffd9852ef04 100644 +--- a/fs/nfsd/nfs3proc.c ++++ b/fs/nfsd/nfs3proc.c +@@ -449,6 +449,7 @@ nfsd3_proc_readdir(struct svc_rqst *rqstp) + struct nfsd3_readdirargs *argp = rqstp->rq_argp; + struct nfsd3_readdirres *resp = rqstp->rq_resp; + int count = 0; ++ loff_t offset; + struct page **p; + caddr_t page_addr = NULL; + +@@ -467,7 +468,9 @@ nfsd3_proc_readdir(struct svc_rqst *rqstp) + resp->common.err = nfs_ok; + resp->buffer = argp->buffer; + resp->rqstp = rqstp; +- resp->status = nfsd_readdir(rqstp, &resp->fh, (loff_t *)&argp->cookie, ++ offset = argp->cookie; ++ ++ resp->status = nfsd_readdir(rqstp, &resp->fh, &offset, + &resp->common, nfs3svc_encode_entry); + memcpy(resp->verf, argp->verf, 8); + count = 0; +@@ -483,8 +486,6 @@ nfsd3_proc_readdir(struct svc_rqst *rqstp) + } + resp->count = count >> 2; + if (resp->offset) { +- loff_t offset = argp->cookie; +- + if (unlikely(resp->offset1)) { + /* we ended up with offset on a page boundary */ + *resp->offset = htonl(offset >> 32); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-fix-space-and-spelling-mistake.patch b/queue-5.10/nfsd-fix-space-and-spelling-mistake.patch new file mode 100644 index 00000000000..d7b055a5661 --- /dev/null +++ b/queue-5.10/nfsd-fix-space-and-spelling-mistake.patch @@ -0,0 +1,44 @@ +From 1467c6e11f8d4d6da7050cb2b2a73fabc81c7ec8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 23 Jun 2022 16:20:05 +0800 +Subject: NFSD: Fix space and spelling mistake + +From: Zhang Jiaming + +[ Upstream commit f532c9ff103897be0e2a787c0876683c3dc39ed3 ] + +Add a blank space after ','. +Change 'succesful' to 'successful'. + +Signed-off-by: Zhang Jiaming +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index adbac1e77e9e2..cb4a037266709 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -828,7 +828,7 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + goto out_umask; + status = nfsd_create(rqstp, &cstate->current_fh, + create->cr_name, create->cr_namelen, +- &create->cr_iattr,S_IFCHR, rdev, &resfh); ++ &create->cr_iattr, S_IFCHR, rdev, &resfh); + break; + + case NF4SOCK: +@@ -2703,7 +2703,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp) + if (op->opdesc->op_flags & OP_MODIFIES_SOMETHING) { + /* + * Don't execute this op if we couldn't encode a +- * succesful reply: ++ * successful reply: + */ + u32 plen = op->opdesc->op_rsize_bop(rqstp, op); + /* +-- +2.43.0 + diff --git a/queue-5.10/nfsd-fix-sparse-warning-in-nfssvc.c.patch b/queue-5.10/nfsd-fix-sparse-warning-in-nfssvc.c.patch new file mode 100644 index 00000000000..7ecaa10b796 --- /dev/null +++ b/queue-5.10/nfsd-fix-sparse-warning-in-nfssvc.c.patch @@ -0,0 +1,73 @@ +From 5aa5d7ccb46e324a0e4c13b7a76ae4d748d6fa49 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 18 Dec 2020 12:28:23 -0500 +Subject: NFSD: Fix sparse warning in nfssvc.c + +From: Chuck Lever + +[ Upstream commit d6c9e4368cc6a61bf25c9c72437ced509c854563 ] + +fs/nfsd/nfssvc.c:36:6: warning: symbol 'inter_copy_offload_enable' was not declared. Should it be static? + +The parameter was added by commit ce0887ac96d3 ("NFSD add nfs4 inter +ssc to nfsd4_copy"). Relocate it into the source file that uses it, +and make it static. This approach is similar to the +nfs4_disable_idmapping, cltrack_prog, and cltrack_legacy_disable +module parameters. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 5 +++++ + fs/nfsd/nfssvc.c | 6 ------ + fs/nfsd/xdr4.h | 1 - + 3 files changed, 5 insertions(+), 7 deletions(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 6b06f0ad05615..1ef98398362a5 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -50,6 +50,11 @@ + #include "pnfs.h" + #include "trace.h" + ++static bool inter_copy_offload_enable; ++module_param(inter_copy_offload_enable, bool, 0644); ++MODULE_PARM_DESC(inter_copy_offload_enable, ++ "Enable inter server to server copy offload. Default: false"); ++ + #ifdef CONFIG_NFSD_V4_SECURITY_LABEL + #include + +diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c +index 3fb9607d67a37..423410cc02145 100644 +--- a/fs/nfsd/nfssvc.c ++++ b/fs/nfsd/nfssvc.c +@@ -33,12 +33,6 @@ + + #define NFSDDBG_FACILITY NFSDDBG_SVC + +-bool inter_copy_offload_enable; +-EXPORT_SYMBOL_GPL(inter_copy_offload_enable); +-module_param(inter_copy_offload_enable, bool, 0644); +-MODULE_PARM_DESC(inter_copy_offload_enable, +- "Enable inter server to server copy offload. Default: false"); +- + extern struct svc_program nfsd_program; + static int nfsd(void *vrqstp); + #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) +diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h +index a60ff5ce1a375..c300885ae75dd 100644 +--- a/fs/nfsd/xdr4.h ++++ b/fs/nfsd/xdr4.h +@@ -568,7 +568,6 @@ struct nfsd4_copy { + struct nfs_fh c_fh; + nfs4_stateid stateid; + }; +-extern bool inter_copy_offload_enable; + + struct nfsd4_seek { + /* request */ +-- +2.43.0 + diff --git a/queue-5.10/nfsd-fix-sparse-warning.patch b/queue-5.10/nfsd-fix-sparse-warning.patch new file mode 100644 index 00000000000..90a684115c4 --- /dev/null +++ b/queue-5.10/nfsd-fix-sparse-warning.patch @@ -0,0 +1,35 @@ +From 70b079a7e791e561ccb9542578b4eeb3ff1e0908 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 13 Oct 2021 16:44:20 -0400 +Subject: NFSD: Fix sparse warning + +From: Chuck Lever + +[ Upstream commit c2f1c4bd20621175c581f298b4943df0cffbd841 ] + +/home/cel/src/linux/linux/fs/nfsd/nfs4proc.c:1539:24: warning: incorrect type in assignment (different base types) +/home/cel/src/linux/linux/fs/nfsd/nfs4proc.c:1539:24: expected restricted __be32 [usertype] status +/home/cel/src/linux/linux/fs/nfsd/nfs4proc.c:1539:24: got int + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 52f3f35533791..eaf2f95d059ca 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -1508,7 +1508,7 @@ static ssize_t _nfsd_copy_file_range(struct nfsd4_copy *copy) + u64 bytes_total = copy->cp_count; + u64 src_pos = copy->cp_src_pos; + u64 dst_pos = copy->cp_dst_pos; +- __be32 status; ++ int status; + + /* See RFC 7862 p.67: */ + if (bytes_total == 0) +-- +2.43.0 + diff --git a/queue-5.10/nfsd-fix-strncpy-fortify-warning.patch b/queue-5.10/nfsd-fix-strncpy-fortify-warning.patch new file mode 100644 index 00000000000..5a88ae19935 --- /dev/null +++ b/queue-5.10/nfsd-fix-strncpy-fortify-warning.patch @@ -0,0 +1,58 @@ +From 846676b5abe7d626e27d6a61b43151b45464a230 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 Jul 2022 14:40:03 -0400 +Subject: NFSD: Fix strncpy() fortify warning +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Chuck Lever + +[ Upstream commit 5304877936c0a67e1a01464d113bae4c81eacdb6 ] + +In function ‘strncpy’, + inlined from ‘nfsd4_ssc_setup_dul’ at /home/cel/src/linux/manet/fs/nfsd/nfs4proc.c:1392:3, + inlined from ‘nfsd4_interssc_connect’ at /home/cel/src/linux/manet/fs/nfsd/nfs4proc.c:1489:11: +/home/cel/src/linux/manet/include/linux/fortify-string.h:52:33: warning: ‘__builtin_strncpy’ specified bound 63 equals destination size [-Wstringop-truncation] + 52 | #define __underlying_strncpy __builtin_strncpy + | ^ +/home/cel/src/linux/manet/include/linux/fortify-string.h:89:16: note: in expansion of macro ‘__underlying_strncpy’ + 89 | return __underlying_strncpy(p, q, size); + | ^~~~~~~~~~~~~~~~~~~~ + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 2 +- + include/linux/nfs_ssc.h | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 08c2eaca4f24e..1b49b4e2803c7 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -1391,7 +1391,7 @@ static __be32 nfsd4_ssc_setup_dul(struct nfsd_net *nn, char *ipaddr, + return 0; + } + if (work) { +- strncpy(work->nsui_ipaddr, ipaddr, sizeof(work->nsui_ipaddr)); ++ strlcpy(work->nsui_ipaddr, ipaddr, sizeof(work->nsui_ipaddr) - 1); + refcount_set(&work->nsui_refcnt, 2); + work->nsui_busy = true; + list_add_tail(&work->nsui_list, &nn->nfsd_ssc_mount_list); +diff --git a/include/linux/nfs_ssc.h b/include/linux/nfs_ssc.h +index 222ae8883e854..75843c00f326a 100644 +--- a/include/linux/nfs_ssc.h ++++ b/include/linux/nfs_ssc.h +@@ -64,7 +64,7 @@ struct nfsd4_ssc_umount_item { + refcount_t nsui_refcnt; + unsigned long nsui_expire; + struct vfsmount *nsui_vfsmount; +- char nsui_ipaddr[RPC_MAX_ADDRBUFLEN]; ++ char nsui_ipaddr[RPC_MAX_ADDRBUFLEN + 1]; + }; + #endif + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-fix-the-behavior-of-read-near-offset_max.patch b/queue-5.10/nfsd-fix-the-behavior-of-read-near-offset_max.patch new file mode 100644 index 00000000000..14bc129f198 --- /dev/null +++ b/queue-5.10/nfsd-fix-the-behavior-of-read-near-offset_max.patch @@ -0,0 +1,122 @@ +From d4fd9408fd45502d3b7256922faee3f9c7917855 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 4 Feb 2022 15:19:34 -0500 +Subject: NFSD: Fix the behavior of READ near OFFSET_MAX + +From: Chuck Lever + +[ Upstream commit 0cb4d23ae08c48f6bf3c29a8e5c4a74b8388b960 ] + +Dan Aloni reports: +> Due to commit 8cfb9015280d ("NFS: Always provide aligned buffers to +> the RPC read layers") on the client, a read of 0xfff is aligned up +> to server rsize of 0x1000. +> +> As a result, in a test where the server has a file of size +> 0x7fffffffffffffff, and the client tries to read from the offset +> 0x7ffffffffffff000, the read causes loff_t overflow in the server +> and it returns an NFS code of EINVAL to the client. The client as +> a result indefinitely retries the request. + +The Linux NFS client does not handle NFS?ERR_INVAL, even though all +NFS specifications permit servers to return that status code for a +READ. + +Instead of NFS?ERR_INVAL, have out-of-range READ requests succeed +and return a short result. Set the EOF flag in the result to prevent +the client from retrying the READ request. This behavior appears to +be consistent with Solaris NFS servers. + +Note that NFSv3 and NFSv4 use u64 offset values on the wire. These +must be converted to loff_t internally before use -- an implicit +type cast is not adequate for this purpose. Otherwise VFS checks +against sb->s_maxbytes do not work properly. + +Reported-by: Dan Aloni +Cc: stable@vger.kernel.org +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3proc.c | 8 ++++++-- + fs/nfsd/nfs4proc.c | 8 ++++++-- + fs/nfsd/nfs4xdr.c | 8 ++------ + 3 files changed, 14 insertions(+), 10 deletions(-) + +diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c +index 1515c32e08db2..b540489ea240d 100644 +--- a/fs/nfsd/nfs3proc.c ++++ b/fs/nfsd/nfs3proc.c +@@ -150,13 +150,17 @@ nfsd3_proc_read(struct svc_rqst *rqstp) + unsigned int len; + int v; + +- argp->count = min_t(u32, argp->count, max_blocksize); +- + dprintk("nfsd: READ(3) %s %lu bytes at %Lu\n", + SVCFH_fmt(&argp->fh), + (unsigned long) argp->count, + (unsigned long long) argp->offset); + ++ argp->count = min_t(u32, argp->count, max_blocksize); ++ if (argp->offset > (u64)OFFSET_MAX) ++ argp->offset = (u64)OFFSET_MAX; ++ if (argp->offset + argp->count > (u64)OFFSET_MAX) ++ argp->count = (u64)OFFSET_MAX - argp->offset; ++ + v = 0; + len = argp->count; + resp->pages = rqstp->rq_next_page; +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 451190813302e..f3d6bd2bfa4f7 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -782,12 +782,16 @@ nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + __be32 status; + + read->rd_nf = NULL; +- if (read->rd_offset >= OFFSET_MAX) +- return nfserr_inval; + + trace_nfsd_read_start(rqstp, &cstate->current_fh, + read->rd_offset, read->rd_length); + ++ read->rd_length = min_t(u32, read->rd_length, svc_max_payload(rqstp)); ++ if (read->rd_offset > (u64)OFFSET_MAX) ++ read->rd_offset = (u64)OFFSET_MAX; ++ if (read->rd_offset + read->rd_length > (u64)OFFSET_MAX) ++ read->rd_length = (u64)OFFSET_MAX - read->rd_offset; ++ + /* + * If we do a zero copy read, then a client will see read data + * that reflects the state of the file *after* performing the +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index adf97d72bda80..be0995bb9459a 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -3997,10 +3997,8 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr, + } + xdr_commit_encode(xdr); + +- maxcount = svc_max_payload(resp->rqstp); +- maxcount = min_t(unsigned long, maxcount, ++ maxcount = min_t(unsigned long, read->rd_length, + (xdr->buf->buflen - xdr->buf->len)); +- maxcount = min_t(unsigned long, maxcount, read->rd_length); + + if (file->f_op->splice_read && + test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags)) +@@ -4834,10 +4832,8 @@ nfsd4_encode_read_plus(struct nfsd4_compoundres *resp, __be32 nfserr, + return nfserr_resource; + xdr_commit_encode(xdr); + +- maxcount = svc_max_payload(resp->rqstp); +- maxcount = min_t(unsigned long, maxcount, ++ maxcount = min_t(unsigned long, read->rd_length, + (xdr->buf->buflen - xdr->buf->len)); +- maxcount = min_t(unsigned long, maxcount, read->rd_length); + count = maxcount; + + eof = read->rd_offset >= i_size_read(file_inode(file)); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-fix-the-filecache-lru-shrinker.patch b/queue-5.10/nfsd-fix-the-filecache-lru-shrinker.patch new file mode 100644 index 00000000000..bf7db64782f --- /dev/null +++ b/queue-5.10/nfsd-fix-the-filecache-lru-shrinker.patch @@ -0,0 +1,57 @@ +From f423373a995091f18aab84052d3dabd09f2cae9e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 Jul 2022 14:25:24 -0400 +Subject: NFSD: Fix the filecache LRU shrinker + +From: Chuck Lever + +[ Upstream commit edead3a55804739b2e4af0f35e9c7326264e7b22 ] + +Without LRU item rotation, the shrinker visits only a few items on +the end of the LRU list, and those would always be long-term OPEN +files for NFSv4 workloads. That makes the filecache shrinker +completely ineffective. + +Adopt the same strategy as the inode LRU by using LRU_ROTATE. + +Suggested-by: Dave Chinner +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index 5c9e3ff6397b0..849c010c6ef61 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -445,6 +445,7 @@ nfsd_file_dispose_list_delayed(struct list_head *dispose) + * + * Return values: + * %LRU_REMOVED: @item was removed from the LRU ++ * %LRU_ROTATE: @item is to be moved to the LRU tail + * %LRU_SKIP: @item cannot be evicted + */ + static enum lru_status +@@ -483,7 +484,7 @@ nfsd_file_lru_cb(struct list_head *item, struct list_lru_one *lru, + + if (test_and_clear_bit(NFSD_FILE_REFERENCED, &nf->nf_flags)) { + trace_nfsd_file_gc_referenced(nf); +- return LRU_SKIP; ++ return LRU_ROTATE; + } + + if (!test_and_clear_bit(NFSD_FILE_HASHED, &nf->nf_flags)) { +@@ -525,7 +526,7 @@ nfsd_file_gc(void) + unsigned long ret; + + ret = list_lru_walk(&nfsd_file_lru, nfsd_file_lru_cb, +- &dispose, LONG_MAX); ++ &dispose, list_lru_count(&nfsd_file_lru)); + trace_nfsd_file_gc_removed(ret, list_lru_count(&nfsd_file_lru)); + nfsd_file_gc_dispose_list(&dispose); + } +-- +2.43.0 + diff --git a/queue-5.10/nfsd-fix-typo-accesible.patch b/queue-5.10/nfsd-fix-typo-accesible.patch new file mode 100644 index 00000000000..79be44206a7 --- /dev/null +++ b/queue-5.10/nfsd-fix-typo-accesible.patch @@ -0,0 +1,53 @@ +From 5cff015f8f326703f54026ee4ce20a9acbb39b87 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Mar 2021 21:22:21 +0100 +Subject: nfsd: Fix typo "accesible" + +From: Ricardo Ribalda + +[ Upstream commit 34a624931b8c12b435b5009edc5897e4630107bc ] + +Trivial fix. + +Cc: linux-nfs@vger.kernel.org +Signed-off-by: Ricardo Ribalda +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/Kconfig | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/fs/nfsd/Kconfig b/fs/nfsd/Kconfig +index d6cff5fbe705b..5fa38ad9e7e3f 100644 +--- a/fs/nfsd/Kconfig ++++ b/fs/nfsd/Kconfig +@@ -99,7 +99,7 @@ config NFSD_BLOCKLAYOUT + help + This option enables support for the exporting pNFS block layouts + in the kernel's NFS server. The pNFS block layout enables NFS +- clients to directly perform I/O to block devices accesible to both ++ clients to directly perform I/O to block devices accessible to both + the server and the clients. See RFC 5663 for more details. + + If unsure, say N. +@@ -113,7 +113,7 @@ config NFSD_SCSILAYOUT + help + This option enables support for the exporting pNFS SCSI layouts + in the kernel's NFS server. The pNFS SCSI layout enables NFS +- clients to directly perform I/O to SCSI devices accesible to both ++ clients to directly perform I/O to SCSI devices accessible to both + the server and the clients. See draft-ietf-nfsv4-scsi-layout for + more details. + +@@ -127,7 +127,7 @@ config NFSD_FLEXFILELAYOUT + This option enables support for the exporting pNFS Flex File + layouts in the kernel's NFS server. The pNFS Flex File layout + enables NFS clients to directly perform I/O to NFSv3 devices +- accesible to both the server and the clients. See ++ accessible to both the server and the clients. See + draft-ietf-nfsv4-flex-files for more details. + + Warning, this server implements the bare minimum functionality +-- +2.43.0 + diff --git a/queue-5.10/nfsd-fix-up-nfsd-to-ensure-that-timeout-errors-don-t.patch b/queue-5.10/nfsd-fix-up-nfsd-to-ensure-that-timeout-errors-don-t.patch new file mode 100644 index 00000000000..974c721deef --- /dev/null +++ b/queue-5.10/nfsd-fix-up-nfsd-to-ensure-that-timeout-errors-don-t.patch @@ -0,0 +1,52 @@ +From add9302cb2594401b7622c40f1cbc62755e57148 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Nov 2020 17:03:18 -0500 +Subject: nfsd: Fix up nfsd to ensure that timeout errors don't result in + ESTALE + +From: Trond Myklebust + +[ Upstream commit 2e19d10c1438241de32467637a2a411971547991 ] + +If the underlying filesystem times out, then we want knfsd to return +NFSERR_JUKEBOX/DELAY rather than NFSERR_STALE. + +Signed-off-by: Trond Myklebust +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsfh.c | 16 ++++++++++++---- + 1 file changed, 12 insertions(+), 4 deletions(-) + +diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c +index 9c29a523f4848..e80a7525561d0 100644 +--- a/fs/nfsd/nfsfh.c ++++ b/fs/nfsd/nfsfh.c +@@ -268,12 +268,20 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp) + if (fileid_type == FILEID_ROOT) + dentry = dget(exp->ex_path.dentry); + else { +- dentry = exportfs_decode_fh(exp->ex_path.mnt, fid, +- data_left, fileid_type, +- nfsd_acceptable, exp); +- if (IS_ERR_OR_NULL(dentry)) ++ dentry = exportfs_decode_fh_raw(exp->ex_path.mnt, fid, ++ data_left, fileid_type, ++ nfsd_acceptable, exp); ++ if (IS_ERR_OR_NULL(dentry)) { + trace_nfsd_set_fh_dentry_badhandle(rqstp, fhp, + dentry ? PTR_ERR(dentry) : -ESTALE); ++ switch (PTR_ERR(dentry)) { ++ case -ENOMEM: ++ case -ETIMEDOUT: ++ break; ++ default: ++ dentry = ERR_PTR(-ESTALE); ++ } ++ } + } + if (dentry == NULL) + goto out; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-fix-up-the-filecache-laundrette-scheduling.patch b/queue-5.10/nfsd-fix-up-the-filecache-laundrette-scheduling.patch new file mode 100644 index 00000000000..60f671cdb27 --- /dev/null +++ b/queue-5.10/nfsd-fix-up-the-filecache-laundrette-scheduling.patch @@ -0,0 +1,58 @@ +From 82567283e893f9494eaec6acf227c26fb2c072f0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 2 Nov 2022 14:44:50 -0400 +Subject: nfsd: fix up the filecache laundrette scheduling + +From: Jeff Layton + +[ Upstream commit 22ae4c114f77b55a4c5036e8f70409a0799a08f8 ] + +We don't really care whether there are hashed entries when it comes to +scheduling the laundrette. They might all be non-gc entries, after all. +We only want to schedule it if there are entries on the LRU. + +Switch to using list_lru_count, and move the check into +nfsd_file_gc_worker. The other callsite in nfsd_file_put doesn't need to +count entries, since it only schedules the laundrette after adding an +entry to the LRU. + +Signed-off-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 12 +++++------- + 1 file changed, 5 insertions(+), 7 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index fb7ada3f7410e..522e900a88605 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -210,12 +210,9 @@ static const struct rhashtable_params nfsd_file_rhash_params = { + static void + nfsd_file_schedule_laundrette(void) + { +- if ((atomic_read(&nfsd_file_rhash_tbl.nelems) == 0) || +- test_bit(NFSD_FILE_CACHE_UP, &nfsd_file_flags) == 0) +- return; +- +- queue_delayed_work(system_wq, &nfsd_filecache_laundrette, +- NFSD_LAUNDRETTE_DELAY); ++ if (test_bit(NFSD_FILE_CACHE_UP, &nfsd_file_flags)) ++ queue_delayed_work(system_wq, &nfsd_filecache_laundrette, ++ NFSD_LAUNDRETTE_DELAY); + } + + static void +@@ -665,7 +662,8 @@ static void + nfsd_file_gc_worker(struct work_struct *work) + { + nfsd_file_gc(); +- nfsd_file_schedule_laundrette(); ++ if (list_lru_count(&nfsd_file_lru)) ++ nfsd_file_schedule_laundrette(); + } + + static unsigned long +-- +2.43.0 + diff --git a/queue-5.10/nfsd-fix-use-after-free-in-nfsd4_ssc_setup_dul.patch b/queue-5.10/nfsd-fix-use-after-free-in-nfsd4_ssc_setup_dul.patch new file mode 100644 index 00000000000..bf81c773dad --- /dev/null +++ b/queue-5.10/nfsd-fix-use-after-free-in-nfsd4_ssc_setup_dul.patch @@ -0,0 +1,38 @@ +From 65e5efd77aaf5b26995d8e97c8ccd4ca28a6709d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 12 Jan 2023 00:24:53 +0800 +Subject: NFSD: fix use-after-free in nfsd4_ssc_setup_dul() + +From: Xingyuan Mo + +[ Upstream commit e6cf91b7b47ff82b624bdfe2fdcde32bb52e71dd ] + +If signal_pending() returns true, schedule_timeout() will not be executed, +causing the waiting task to remain in the wait queue. +Fixed by adding a call to finish_wait(), which ensures that the waiting +task will always be removed from the wait queue. + +Fixes: f4e44b393389 ("NFSD: delay unmount source's export after inter-server copy completed.") +Signed-off-by: Xingyuan Mo +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index a89f98fa3a9d0..4ab063a2ac84e 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -1320,6 +1320,7 @@ static __be32 nfsd4_ssc_setup_dul(struct nfsd_net *nn, char *ipaddr, + /* allow 20secs for mount/unmount for now - revisit */ + if (signal_pending(current) || + (schedule_timeout(20*HZ) == 0)) { ++ finish_wait(&nn->nfsd_ssc_waitq, &wait); + kfree(work); + return nfserr_eagain; + } +-- +2.43.0 + diff --git a/queue-5.10/nfsd-fix-use-after-free-in-nfsd_file_do_acquire-trac.patch b/queue-5.10/nfsd-fix-use-after-free-in-nfsd_file_do_acquire-trac.patch new file mode 100644 index 00000000000..9b835a1810a --- /dev/null +++ b/queue-5.10/nfsd-fix-use-after-free-in-nfsd_file_do_acquire-trac.patch @@ -0,0 +1,41 @@ +From e4d91cbca62771a7311659c5a7321f94b51e8c23 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 5 Nov 2022 09:49:26 -0400 +Subject: nfsd: fix use-after-free in nfsd_file_do_acquire tracepoint + +From: Jeff Layton + +[ Upstream commit bdd6b5624c62d0acd350d07564f1c82fe649235f ] + +When we fail to insert into the hashtable with a non-retryable error, +we'll free the object and then goto out_status. If the tracepoint is +enabled, it'll end up accessing the freed object when it tries to +grab the fields out of it. + +Set nf to NULL after freeing it to avoid the issue. + +Fixes: 243a5263014a ("nfsd: rework hashtable handling in nfsd_do_file_acquire") +Reported-by: kernel test robot +Reported-by: Dan Carpenter +Signed-off-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index 024adcbe67e95..dceb522f5cee9 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -1075,6 +1075,7 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + goto open_file; + + nfsd_file_slab_free(&nf->nf_rcu); ++ nf = NULL; + if (ret == -EEXIST) + goto retry; + trace_nfsd_file_insert_err(rqstp, key.inode, may_flags, ret); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-fix-using-the-correct-variable-for-sizeof.patch b/queue-5.10/nfsd-fix-using-the-correct-variable-for-sizeof.patch new file mode 100644 index 00000000000..e77a37df61d --- /dev/null +++ b/queue-5.10/nfsd-fix-using-the-correct-variable-for-sizeof.patch @@ -0,0 +1,36 @@ +From a74f2bc3679003f3930ac2914261875307ae9be6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 19 Mar 2022 21:27:04 +0100 +Subject: nfsd: fix using the correct variable for sizeof() + +From: Jakob Koschel + +[ Upstream commit 4fc5f5346592cdc91689455d83885b0af65d71b8 ] + +While the original code is valid, it is not the obvious choice for the +sizeof() call and in preparation to limit the scope of the list iterator +variable the sizeof should be changed to the size of the destination. + +Signed-off-by: Jakob Koschel +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4layouts.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/nfsd/nfs4layouts.c b/fs/nfsd/nfs4layouts.c +index 2673019d30ecd..7018d209b784a 100644 +--- a/fs/nfsd/nfs4layouts.c ++++ b/fs/nfsd/nfs4layouts.c +@@ -421,7 +421,7 @@ nfsd4_insert_layout(struct nfsd4_layoutget *lgp, struct nfs4_layout_stateid *ls) + new = kmem_cache_alloc(nfs4_layout_cache, GFP_KERNEL); + if (!new) + return nfserr_jukebox; +- memcpy(&new->lo_seg, seg, sizeof(lp->lo_seg)); ++ memcpy(&new->lo_seg, seg, sizeof(new->lo_seg)); + new->lo_state = ls; + + spin_lock(&fp->fi_lock); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-fix-whitespace.patch b/queue-5.10/nfsd-fix-whitespace.patch new file mode 100644 index 00000000000..0a62f1d8b30 --- /dev/null +++ b/queue-5.10/nfsd-fix-whitespace.patch @@ -0,0 +1,84 @@ +From 9b3c96ddfcafd1165a7746d54c57fce152b24a49 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 21 Mar 2022 16:41:32 -0400 +Subject: NFSD: Fix whitespace + +From: Chuck Lever + +[ Upstream commit 26320d7e317c37404c811603d50d811132aef78c ] + +Clean up: Pull case arms back one tab stop to conform every other +switch statement in fs/nfsd/nfs4proc.c. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 50 +++++++++++++++++++++++----------------------- + 1 file changed, 25 insertions(+), 25 deletions(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index c21cfaabf873a..90a12ccf96713 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -600,33 +600,33 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + goto out; + + switch (open->op_claim_type) { +- case NFS4_OPEN_CLAIM_DELEGATE_CUR: +- case NFS4_OPEN_CLAIM_NULL: +- status = do_open_lookup(rqstp, cstate, open, &resfh); +- if (status) +- goto out; +- break; +- case NFS4_OPEN_CLAIM_PREVIOUS: +- status = nfs4_check_open_reclaim(cstate->clp); +- if (status) +- goto out; +- open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; +- reclaim = true; +- fallthrough; +- case NFS4_OPEN_CLAIM_FH: +- case NFS4_OPEN_CLAIM_DELEG_CUR_FH: +- status = do_open_fhandle(rqstp, cstate, open); +- if (status) +- goto out; +- resfh = &cstate->current_fh; +- break; +- case NFS4_OPEN_CLAIM_DELEG_PREV_FH: +- case NFS4_OPEN_CLAIM_DELEGATE_PREV: +- status = nfserr_notsupp; ++ case NFS4_OPEN_CLAIM_DELEGATE_CUR: ++ case NFS4_OPEN_CLAIM_NULL: ++ status = do_open_lookup(rqstp, cstate, open, &resfh); ++ if (status) + goto out; +- default: +- status = nfserr_inval; ++ break; ++ case NFS4_OPEN_CLAIM_PREVIOUS: ++ status = nfs4_check_open_reclaim(cstate->clp); ++ if (status) + goto out; ++ open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; ++ reclaim = true; ++ fallthrough; ++ case NFS4_OPEN_CLAIM_FH: ++ case NFS4_OPEN_CLAIM_DELEG_CUR_FH: ++ status = do_open_fhandle(rqstp, cstate, open); ++ if (status) ++ goto out; ++ resfh = &cstate->current_fh; ++ break; ++ case NFS4_OPEN_CLAIM_DELEG_PREV_FH: ++ case NFS4_OPEN_CLAIM_DELEGATE_PREV: ++ status = nfserr_notsupp; ++ goto out; ++ default: ++ status = nfserr_inval; ++ goto out; + } + /* + * nfsd4_process_open2() does the actual opening of the file. If +-- +2.43.0 + diff --git a/queue-5.10/nfsd-fix-zero-length-nfsv3-writes.patch b/queue-5.10/nfsd-fix-zero-length-nfsv3-writes.patch new file mode 100644 index 00000000000..57fd17fc44d --- /dev/null +++ b/queue-5.10/nfsd-fix-zero-length-nfsv3-writes.patch @@ -0,0 +1,92 @@ +From 7a9647a0fcf1078d2ad9c2fe51d4d8f3124fd97a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 21 Dec 2021 11:52:06 -0500 +Subject: NFSD: Fix zero-length NFSv3 WRITEs + +From: Chuck Lever + +[ Upstream commit 6a2f774424bfdcc2df3e17de0cefe74a4269cad5 ] + +The Linux NFS server currently responds to a zero-length NFSv3 WRITE +request with NFS3ERR_IO. It responds to a zero-length NFSv4 WRITE +with NFS4_OK and count of zero. + +RFC 1813 says of the WRITE procedure's @count argument: + +count + The number of bytes of data to be written. If count is + 0, the WRITE will succeed and return a count of 0, + barring errors due to permissions checking. + +RFC 8881 has similar language for NFSv4, though NFSv4 removed the +explicit @count argument because that value is already contained in +the opaque payload array. + +The synthetic client pynfs's WRT4 and WRT15 tests do emit zero- +length WRITEs to exercise this spec requirement. Commit fdec6114ee1f +("nfsd4: zero-length WRITE should succeed") addressed the same +problem there with the same fix. + +But interestingly the Linux NFS client does not appear to emit zero- +length WRITEs, instead squelching them. I'm not aware of a test that +can generate such WRITEs for NFSv3, so I wrote a naive C program to +generate a zero-length WRITE and test this fix. + +Fixes: 8154ef2776aa ("NFSD: Clean up legacy NFS WRITE argument XDR decoders") +Reported-by: Trond Myklebust +Signed-off-by: Chuck Lever +Cc: stable@vger.kernel.org +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3proc.c | 6 +----- + fs/nfsd/nfsproc.c | 5 ----- + 2 files changed, 1 insertion(+), 10 deletions(-) + +diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c +index d26271c60ab44..1515c32e08db2 100644 +--- a/fs/nfsd/nfs3proc.c ++++ b/fs/nfsd/nfs3proc.c +@@ -207,15 +207,11 @@ nfsd3_proc_write(struct svc_rqst *rqstp) + fh_copy(&resp->fh, &argp->fh); + resp->committed = argp->stable; + nvecs = svc_fill_write_vector(rqstp, &argp->payload); +- if (!nvecs) { +- resp->status = nfserr_io; +- goto out; +- } ++ + resp->status = nfsd_write(rqstp, &resp->fh, argp->offset, + rqstp->rq_vec, nvecs, &cnt, + resp->committed, resp->verf); + resp->count = cnt; +-out: + return rpc_success; + } + +diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c +index 8ee329bc3815d..0a2bab7ef33c9 100644 +--- a/fs/nfsd/nfsproc.c ++++ b/fs/nfsd/nfsproc.c +@@ -235,10 +235,6 @@ nfsd_proc_write(struct svc_rqst *rqstp) + argp->len, argp->offset); + + nvecs = svc_fill_write_vector(rqstp, &argp->payload); +- if (!nvecs) { +- resp->status = nfserr_io; +- goto out; +- } + + resp->status = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh), + argp->offset, rqstp->rq_vec, nvecs, +@@ -247,7 +243,6 @@ nfsd_proc_write(struct svc_rqst *rqstp) + resp->status = fh_getattr(&resp->fh, &resp->stat); + else if (resp->status == nfserr_jukebox) + return rpc_drop_reply; +-out: + return rpc_success; + } + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-flesh-out-a-documenting-comment-for-filecache.c.patch b/queue-5.10/nfsd-flesh-out-a-documenting-comment-for-filecache.c.patch new file mode 100644 index 00000000000..a5424f921c6 --- /dev/null +++ b/queue-5.10/nfsd-flesh-out-a-documenting-comment-for-filecache.c.patch @@ -0,0 +1,59 @@ +From eea58b91a46a6b7e04e85fd2c256c04c37dfd587 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 1 Nov 2022 13:30:46 -0400 +Subject: NFSD: Flesh out a documenting comment for filecache.c + +From: Chuck Lever + +[ Upstream commit b3276c1f5b268ff56622e9e125b792b4c3dc03ac ] + +Record what we've learned recently about the NFSD filecache in a +documenting comment so our future selves don't forget what all this +is for. + +Signed-off-by: Chuck Lever +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 24 ++++++++++++++++++++++++ + 1 file changed, 24 insertions(+) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index 13a25503b80e1..d681faf48cf85 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -2,6 +2,30 @@ + * Open file cache. + * + * (c) 2015 - Jeff Layton ++ * ++ * An nfsd_file object is a per-file collection of open state that binds ++ * together: ++ * - a struct file * ++ * - a user credential ++ * - a network namespace ++ * - a read-ahead context ++ * - monitoring for writeback errors ++ * ++ * nfsd_file objects are reference-counted. Consumers acquire a new ++ * object via the nfsd_file_acquire API. They manage their interest in ++ * the acquired object, and hence the object's reference count, via ++ * nfsd_file_get and nfsd_file_put. There are two varieties of nfsd_file ++ * object: ++ * ++ * * non-garbage-collected: When a consumer wants to precisely control ++ * the lifetime of a file's open state, it acquires a non-garbage- ++ * collected nfsd_file. The final nfsd_file_put releases the open ++ * state immediately. ++ * ++ * * garbage-collected: When a consumer does not control the lifetime ++ * of open state, it acquires a garbage-collected nfsd_file. The ++ * final nfsd_file_put allows the open state to linger for a period ++ * during which it may be re-used. + */ + + #include +-- +2.43.0 + diff --git a/queue-5.10/nfsd-grant-read-delegations-to-clients-holding-write.patch b/queue-5.10/nfsd-grant-read-delegations-to-clients-holding-write.patch new file mode 100644 index 00000000000..8d155097c38 --- /dev/null +++ b/queue-5.10/nfsd-grant-read-delegations-to-clients-holding-write.patch @@ -0,0 +1,156 @@ +From a5c472cc3be9f7451dc3a71a095c1a46b6ae0a75 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Apr 2021 14:00:18 -0400 +Subject: nfsd: grant read delegations to clients holding writes + +From: J. Bruce Fields + +[ Upstream commit aba2072f452346d56a462718bcde93d697383148 ] + +It's OK to grant a read delegation to a client that holds a write, +as long as it's the only client holding the write. + +We originally tried to do this in commit 94415b06eb8a ("nfsd4: a +client's own opens needn't prevent delegations"), which had to be +reverted in commit 6ee65a773096 ("Revert "nfsd4: a client's own +opens needn't prevent delegations""). + +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/locks.c | 3 ++ + fs/nfsd/nfs4state.c | 82 +++++++++++++++++++++++++++++++++++++-------- + 2 files changed, 71 insertions(+), 14 deletions(-) + +diff --git a/fs/locks.c b/fs/locks.c +index 873f97504bddf..101867933e4d3 100644 +--- a/fs/locks.c ++++ b/fs/locks.c +@@ -1808,6 +1808,9 @@ check_conflicting_open(struct file *filp, const long arg, int flags) + + if (flags & FL_LAYOUT) + return 0; ++ if (flags & FL_DELEG) ++ /* We leave these checks to the caller */ ++ return 0; + + if (arg == F_RDLCK) + return inode_is_open_for_write(inode) ? -EAGAIN : 0; +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 9c8dacf0f2b86..fd0d6e81a2272 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -5030,6 +5030,65 @@ static struct file_lock *nfs4_alloc_init_lease(struct nfs4_delegation *dp, + return fl; + } + ++static int nfsd4_check_conflicting_opens(struct nfs4_client *clp, ++ struct nfs4_file *fp) ++{ ++ struct nfs4_ol_stateid *st; ++ struct file *f = fp->fi_deleg_file->nf_file; ++ struct inode *ino = locks_inode(f); ++ int writes; ++ ++ writes = atomic_read(&ino->i_writecount); ++ if (!writes) ++ return 0; ++ /* ++ * There could be multiple filehandles (hence multiple ++ * nfs4_files) referencing this file, but that's not too ++ * common; let's just give up in that case rather than ++ * trying to go look up all the clients using that other ++ * nfs4_file as well: ++ */ ++ if (fp->fi_aliased) ++ return -EAGAIN; ++ /* ++ * If there's a close in progress, make sure that we see it ++ * clear any fi_fds[] entries before we see it decrement ++ * i_writecount: ++ */ ++ smp_mb__after_atomic(); ++ ++ if (fp->fi_fds[O_WRONLY]) ++ writes--; ++ if (fp->fi_fds[O_RDWR]) ++ writes--; ++ if (writes > 0) ++ return -EAGAIN; /* There may be non-NFSv4 writers */ ++ /* ++ * It's possible there are non-NFSv4 write opens in progress, ++ * but if they haven't incremented i_writecount yet then they ++ * also haven't called break lease yet; so, they'll break this ++ * lease soon enough. So, all that's left to check for is NFSv4 ++ * opens: ++ */ ++ spin_lock(&fp->fi_lock); ++ list_for_each_entry(st, &fp->fi_stateids, st_perfile) { ++ if (st->st_openstp == NULL /* it's an open */ && ++ access_permit_write(st) && ++ st->st_stid.sc_client != clp) { ++ spin_unlock(&fp->fi_lock); ++ return -EAGAIN; ++ } ++ } ++ spin_unlock(&fp->fi_lock); ++ /* ++ * There's a small chance that we could be racing with another ++ * NFSv4 open. However, any open that hasn't added itself to ++ * the fi_stateids list also hasn't called break_lease yet; so, ++ * they'll break this lease soon enough. ++ */ ++ return 0; ++} ++ + static struct nfs4_delegation * + nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh, + struct nfs4_file *fp, struct nfs4_clnt_odstate *odstate) +@@ -5049,9 +5108,12 @@ nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh, + + nf = find_readable_file(fp); + if (!nf) { +- /* We should always have a readable file here */ +- WARN_ON_ONCE(1); +- return ERR_PTR(-EBADF); ++ /* ++ * We probably could attempt another open and get a read ++ * delegation, but for now, don't bother until the ++ * client actually sends us one. ++ */ ++ return ERR_PTR(-EAGAIN); + } + spin_lock(&state_lock); + spin_lock(&fp->fi_lock); +@@ -5086,6 +5148,9 @@ nfs4_set_delegation(struct nfs4_client *clp, struct svc_fh *fh, + locks_free_lock(fl); + if (status) + goto out_clnt_odstate; ++ status = nfsd4_check_conflicting_opens(clp, fp); ++ if (status) ++ goto out_unlock; + + spin_lock(&state_lock); + spin_lock(&fp->fi_lock); +@@ -5167,17 +5232,6 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, + goto out_no_deleg; + if (!cb_up || !(oo->oo_flags & NFS4_OO_CONFIRMED)) + goto out_no_deleg; +- /* +- * Also, if the file was opened for write or +- * create, there's a good chance the client's +- * about to write to it, resulting in an +- * immediate recall (since we don't support +- * write delegations): +- */ +- if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE) +- goto out_no_deleg; +- if (open->op_create == NFS4_OPEN_CREATE) +- goto out_no_deleg; + break; + default: + goto out_no_deleg; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-handle-errors-better-in-write_ports_addfd.patch b/queue-5.10/nfsd-handle-errors-better-in-write_ports_addfd.patch new file mode 100644 index 00000000000..f142c08046f --- /dev/null +++ b/queue-5.10/nfsd-handle-errors-better-in-write_ports_addfd.patch @@ -0,0 +1,36 @@ +From 0069eef7fef07dc9e1788a4fab1d42860aaa9473 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Nov 2021 15:51:25 +1100 +Subject: NFSD: handle errors better in write_ports_addfd() + +From: NeilBrown + +[ Upstream commit 89b24336f03a8ba560e96b0c47a8434a7fa48e3c ] + +If write_ports_add() fails, we shouldn't destroy the serv, unless we had +only just created it. So if there are any permanent sockets already +attached, leave the serv in place. + +Signed-off-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsctl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c +index d0761ca8cb542..162866cfe83a2 100644 +--- a/fs/nfsd/nfsctl.c ++++ b/fs/nfsd/nfsctl.c +@@ -742,7 +742,7 @@ static ssize_t __write_ports_addfd(char *buf, struct net *net, const struct cred + return err; + + err = svc_addsock(nn->nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT, cred); +- if (err < 0) { ++ if (err < 0 && list_empty(&nn->nfsd_serv->sv_permsocks)) { + nfsd_destroy(net); + return err; + } +-- +2.43.0 + diff --git a/queue-5.10/nfsd-hash-nfs4_files-by-inode-number.patch b/queue-5.10/nfsd-hash-nfs4_files-by-inode-number.patch new file mode 100644 index 00000000000..0d4b0e05644 --- /dev/null +++ b/queue-5.10/nfsd-hash-nfs4_files-by-inode-number.patch @@ -0,0 +1,141 @@ +From 259f56e3920fb017437d21898eeaed75fc5862ac Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Apr 2021 14:00:15 -0400 +Subject: nfsd: hash nfs4_files by inode number + +From: J. Bruce Fields + +[ Upstream commit f9b60e2209213fdfcc504ba25a404977c5d08b77 ] + +The nfs4_file structure is per-filehandle, not per-inode, because the +spec requires open and other state to be per filehandle. + +But it will turn out to be convenient for nfs4_files associated with the +same inode to be hashed to the same bucket, so let's hash on the inode +instead of the filehandle. + +Filehandle aliasing is rare, so that shouldn't have much performance +impact. + +(If you have a ton of exported filesystems, though, and all of them have +a root with inode number 2, could that get you an overlong hash chain? +Perhaps this (and the v4 open file cache) should be hashed on the inode +pointer instead.) + +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 27 ++++++++++++--------------- + fs/nfsd/state.h | 1 - + 2 files changed, 12 insertions(+), 16 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index a42a505b3e417..8d2d6e90bfc5e 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -554,14 +554,12 @@ static unsigned int ownerstr_hashval(struct xdr_netobj *ownername) + #define FILE_HASH_BITS 8 + #define FILE_HASH_SIZE (1 << FILE_HASH_BITS) + +-static unsigned int nfsd_fh_hashval(struct knfsd_fh *fh) ++static unsigned int file_hashval(struct svc_fh *fh) + { +- return jhash2(fh->fh_base.fh_pad, XDR_QUADLEN(fh->fh_size), 0); +-} ++ struct inode *inode = d_inode(fh->fh_dentry); + +-static unsigned int file_hashval(struct knfsd_fh *fh) +-{ +- return nfsd_fh_hashval(fh) & (FILE_HASH_SIZE - 1); ++ /* XXX: why not (here & in file cache) use inode? */ ++ return (unsigned int)hash_long(inode->i_ino, FILE_HASH_BITS); + } + + static struct hlist_head file_hashtbl[FILE_HASH_SIZE]; +@@ -4106,7 +4104,7 @@ static struct nfs4_file *nfsd4_alloc_file(void) + } + + /* OPEN Share state helper functions */ +-static void nfsd4_init_file(struct knfsd_fh *fh, unsigned int hashval, ++static void nfsd4_init_file(struct svc_fh *fh, unsigned int hashval, + struct nfs4_file *fp) + { + lockdep_assert_held(&state_lock); +@@ -4116,7 +4114,7 @@ static void nfsd4_init_file(struct knfsd_fh *fh, unsigned int hashval, + INIT_LIST_HEAD(&fp->fi_stateids); + INIT_LIST_HEAD(&fp->fi_delegations); + INIT_LIST_HEAD(&fp->fi_clnt_odstate); +- fh_copy_shallow(&fp->fi_fhandle, fh); ++ fh_copy_shallow(&fp->fi_fhandle, &fh->fh_handle); + fp->fi_deleg_file = NULL; + fp->fi_had_conflict = false; + fp->fi_share_deny = 0; +@@ -4460,13 +4458,13 @@ move_to_close_lru(struct nfs4_ol_stateid *s, struct net *net) + + /* search file_hashtbl[] for file */ + static struct nfs4_file * +-find_file_locked(struct knfsd_fh *fh, unsigned int hashval) ++find_file_locked(struct svc_fh *fh, unsigned int hashval) + { + struct nfs4_file *fp; + + hlist_for_each_entry_rcu(fp, &file_hashtbl[hashval], fi_hash, + lockdep_is_held(&state_lock)) { +- if (fh_match(&fp->fi_fhandle, fh)) { ++ if (fh_match(&fp->fi_fhandle, &fh->fh_handle)) { + if (refcount_inc_not_zero(&fp->fi_ref)) + return fp; + } +@@ -4474,8 +4472,7 @@ find_file_locked(struct knfsd_fh *fh, unsigned int hashval) + return NULL; + } + +-struct nfs4_file * +-find_file(struct knfsd_fh *fh) ++static struct nfs4_file * find_file(struct svc_fh *fh) + { + struct nfs4_file *fp; + unsigned int hashval = file_hashval(fh); +@@ -4487,7 +4484,7 @@ find_file(struct knfsd_fh *fh) + } + + static struct nfs4_file * +-find_or_add_file(struct nfs4_file *new, struct knfsd_fh *fh) ++find_or_add_file(struct nfs4_file *new, struct svc_fh *fh) + { + struct nfs4_file *fp; + unsigned int hashval = file_hashval(fh); +@@ -4519,7 +4516,7 @@ nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type) + struct nfs4_file *fp; + __be32 ret = nfs_ok; + +- fp = find_file(¤t_fh->fh_handle); ++ fp = find_file(current_fh); + if (!fp) + return ret; + /* Check for conflicting share reservations */ +@@ -5208,7 +5205,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf + * and check for delegations in the process of being recalled. + * If not found, create the nfs4_file struct + */ +- fp = find_or_add_file(open->op_file, ¤t_fh->fh_handle); ++ fp = find_or_add_file(open->op_file, current_fh); + if (fp != open->op_file) { + status = nfs4_check_deleg(cl, open, &dp); + if (status) +diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h +index 54cab651ac1d0..61a2d95d79233 100644 +--- a/fs/nfsd/state.h ++++ b/fs/nfsd/state.h +@@ -669,7 +669,6 @@ extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(struct xdr_netobj name + struct xdr_netobj princhash, struct nfsd_net *nn); + extern bool nfs4_has_reclaimed_state(struct xdr_netobj name, struct nfsd_net *nn); + +-struct nfs4_file *find_file(struct knfsd_fh *fh); + void put_nfs4_file(struct nfs4_file *fi); + extern void nfs4_put_copy(struct nfsd4_copy *copy); + extern struct nfsd4_copy * +-- +2.43.0 + diff --git a/queue-5.10/nfsd-have-legacy-nfsd-write-decoders-use-xdr_stream_.patch b/queue-5.10/nfsd-have-legacy-nfsd-write-decoders-use-xdr_stream_.patch new file mode 100644 index 00000000000..9ee4ea14233 --- /dev/null +++ b/queue-5.10/nfsd-have-legacy-nfsd-write-decoders-use-xdr_stream_.patch @@ -0,0 +1,214 @@ +From ecf1763d5630412d2835c650af53b4b67f70979d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Sep 2021 17:06:21 -0400 +Subject: NFSD: Have legacy NFSD WRITE decoders use xdr_stream_subsegment() + +From: Chuck Lever + +[ Upstream commit dae9a6cab8009e526570e7477ce858dcdfeb256e ] + +Refactor. + +Now that the NFSv2 and NFSv3 XDR decoders have been converted to +use xdr_streams, the WRITE decoder functions can use +xdr_stream_subsegment() to extract the WRITE payload into its own +xdr_buf, just as the NFSv4 WRITE XDR decoder currently does. + +That makes it possible to pass the first kvec, pages array + length, +page_base, and total payload length via a single function parameter. + +The payload's page_base is not yet assigned or used, but will be in +subsequent patches. + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +[ cel: adjusted to apply to v5.10.y ] +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3proc.c | 3 +-- + fs/nfsd/nfs3xdr.c | 12 ++---------- + fs/nfsd/nfs4proc.c | 3 +-- + fs/nfsd/nfsproc.c | 3 +-- + fs/nfsd/nfsxdr.c | 9 +-------- + fs/nfsd/xdr.h | 2 +- + fs/nfsd/xdr3.h | 2 +- + include/linux/sunrpc/svc.h | 3 +-- + net/sunrpc/svc.c | 11 ++++++----- + 9 files changed, 15 insertions(+), 33 deletions(-) + +diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c +index be1ed33e424e0..5abb5c8e2cd21 100644 +--- a/fs/nfsd/nfs3proc.c ++++ b/fs/nfsd/nfs3proc.c +@@ -206,8 +206,7 @@ nfsd3_proc_write(struct svc_rqst *rqstp) + + fh_copy(&resp->fh, &argp->fh); + resp->committed = argp->stable; +- nvecs = svc_fill_write_vector(rqstp, rqstp->rq_arg.pages, +- &argp->first, cnt); ++ nvecs = svc_fill_write_vector(rqstp, &argp->payload); + if (!nvecs) { + resp->status = nfserr_io; + goto out; +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index 3d37923afb06c..267e56f218af7 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -621,9 +621,6 @@ nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p) + struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd3_writeargs *args = rqstp->rq_argp; + u32 max_blocksize = svc_max_payload(rqstp); +- struct kvec *head = rqstp->rq_arg.head; +- struct kvec *tail = rqstp->rq_arg.tail; +- size_t remaining; + + if (!svcxdr_decode_nfs_fh3(xdr, &args->fh)) + return 0; +@@ -641,17 +638,12 @@ nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p) + /* request sanity */ + if (args->count != args->len) + return 0; +- remaining = head->iov_len + rqstp->rq_arg.page_len + tail->iov_len; +- remaining -= xdr_stream_pos(xdr); +- if (remaining < xdr_align_size(args->len)) +- return 0; + if (args->count > max_blocksize) { + args->count = max_blocksize; + args->len = max_blocksize; + } +- +- args->first.iov_base = xdr->p; +- args->first.iov_len = head->iov_len - xdr_stream_pos(xdr); ++ if (!xdr_stream_subsegment(xdr, &args->payload, args->count)) ++ return 0; + + return 1; + } +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index ebb6d8471e8d7..d2ee1ba7ddc65 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -1034,8 +1034,7 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + + write->wr_how_written = write->wr_stable_how; + +- nvecs = svc_fill_write_vector(rqstp, write->wr_payload.pages, +- write->wr_payload.head, write->wr_buflen); ++ nvecs = svc_fill_write_vector(rqstp, &write->wr_payload); + WARN_ON_ONCE(nvecs > ARRAY_SIZE(rqstp->rq_vec)); + + status = nfsd_vfs_write(rqstp, &cstate->current_fh, nf, +diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c +index 78bdfdc253fd3..5a84aed17e705 100644 +--- a/fs/nfsd/nfsproc.c ++++ b/fs/nfsd/nfsproc.c +@@ -234,8 +234,7 @@ nfsd_proc_write(struct svc_rqst *rqstp) + SVCFH_fmt(&argp->fh), + argp->len, argp->offset); + +- nvecs = svc_fill_write_vector(rqstp, rqstp->rq_arg.pages, +- &argp->first, cnt); ++ nvecs = svc_fill_write_vector(rqstp, &argp->payload); + if (!nvecs) { + resp->status = nfserr_io; + goto out; +diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c +index 082449c7d0dbf..ddcc18adfeb1a 100644 +--- a/fs/nfsd/nfsxdr.c ++++ b/fs/nfsd/nfsxdr.c +@@ -325,10 +325,7 @@ nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p) + { + struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd_writeargs *args = rqstp->rq_argp; +- struct kvec *head = rqstp->rq_arg.head; +- struct kvec *tail = rqstp->rq_arg.tail; + u32 beginoffset, totalcount; +- size_t remaining; + + if (!svcxdr_decode_fhandle(xdr, &args->fh)) + return 0; +@@ -346,12 +343,8 @@ nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p) + return 0; + if (args->len > NFSSVC_MAXBLKSIZE_V2) + return 0; +- remaining = head->iov_len + rqstp->rq_arg.page_len + tail->iov_len; +- remaining -= xdr_stream_pos(xdr); +- if (remaining < xdr_align_size(args->len)) ++ if (!xdr_stream_subsegment(xdr, &args->payload, args->len)) + return 0; +- args->first.iov_base = xdr->p; +- args->first.iov_len = head->iov_len - xdr_stream_pos(xdr); + + return 1; + } +diff --git a/fs/nfsd/xdr.h b/fs/nfsd/xdr.h +index c67ad02b9a028..863a35f24910a 100644 +--- a/fs/nfsd/xdr.h ++++ b/fs/nfsd/xdr.h +@@ -33,7 +33,7 @@ struct nfsd_writeargs { + svc_fh fh; + __u32 offset; + __u32 len; +- struct kvec first; ++ struct xdr_buf payload; + }; + + struct nfsd_createargs { +diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h +index 933008382bbeb..712c117300cb7 100644 +--- a/fs/nfsd/xdr3.h ++++ b/fs/nfsd/xdr3.h +@@ -40,7 +40,7 @@ struct nfsd3_writeargs { + __u32 count; + int stable; + __u32 len; +- struct kvec first; ++ struct xdr_buf payload; + }; + + struct nfsd3_createargs { +diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h +index dd3daadbc0e5c..b0986e969c2f4 100644 +--- a/include/linux/sunrpc/svc.h ++++ b/include/linux/sunrpc/svc.h +@@ -531,8 +531,7 @@ int svc_encode_result_payload(struct svc_rqst *rqstp, + unsigned int offset, + unsigned int length); + unsigned int svc_fill_write_vector(struct svc_rqst *rqstp, +- struct page **pages, +- struct kvec *first, size_t total); ++ struct xdr_buf *payload); + char *svc_fill_symlink_pathname(struct svc_rqst *rqstp, + struct kvec *first, void *p, + size_t total); +diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c +index 0d3c3ca2830a8..54f66f66beb59 100644 +--- a/net/sunrpc/svc.c ++++ b/net/sunrpc/svc.c +@@ -1654,16 +1654,17 @@ EXPORT_SYMBOL_GPL(svc_encode_result_payload); + /** + * svc_fill_write_vector - Construct data argument for VFS write call + * @rqstp: svc_rqst to operate on +- * @pages: list of pages containing data payload +- * @first: buffer containing first section of write payload +- * @total: total number of bytes of write payload ++ * @payload: xdr_buf containing only the write data payload + * + * Fills in rqstp::rq_vec, and returns the number of elements. + */ +-unsigned int svc_fill_write_vector(struct svc_rqst *rqstp, struct page **pages, +- struct kvec *first, size_t total) ++unsigned int svc_fill_write_vector(struct svc_rqst *rqstp, ++ struct xdr_buf *payload) + { ++ struct page **pages = payload->pages; ++ struct kvec *first = payload->head; + struct kvec *vec = rqstp->rq_vec; ++ size_t total = payload->len; + unsigned int i; + + /* Some types of transport can present the write payload +-- +2.43.0 + diff --git a/queue-5.10/nfsd-helper-for-laundromat-expiry-calculations.patch b/queue-5.10/nfsd-helper-for-laundromat-expiry-calculations.patch new file mode 100644 index 00000000000..caa91911043 --- /dev/null +++ b/queue-5.10/nfsd-helper-for-laundromat-expiry-calculations.patch @@ -0,0 +1,140 @@ +From 65362449c2d5dc94e8341f9594be59960d3a6a77 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 2 Mar 2021 10:46:23 -0500 +Subject: nfsd: helper for laundromat expiry calculations + +From: J. Bruce Fields + +[ Upstream commit 7f7e7a4006f74b031718055a0751c70c2e3d5e7e ] + +We do this same logic repeatedly, and it's easy to get the sense of the +comparison wrong. + +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 49 +++++++++++++++++++++++++-------------------- + 1 file changed, 27 insertions(+), 22 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 914f60cee3226..0afc14b3e4593 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -5385,6 +5385,22 @@ static bool clients_still_reclaiming(struct nfsd_net *nn) + return true; + } + ++struct laundry_time { ++ time64_t cutoff; ++ time64_t new_timeo; ++}; ++ ++static bool state_expired(struct laundry_time *lt, time64_t last_refresh) ++{ ++ time64_t time_remaining; ++ ++ if (last_refresh < lt->cutoff) ++ return true; ++ time_remaining = last_refresh - lt->cutoff; ++ lt->new_timeo = min(lt->new_timeo, time_remaining); ++ return false; ++} ++ + static time64_t + nfs4_laundromat(struct nfsd_net *nn) + { +@@ -5394,14 +5410,16 @@ nfs4_laundromat(struct nfsd_net *nn) + struct nfs4_ol_stateid *stp; + struct nfsd4_blocked_lock *nbl; + struct list_head *pos, *next, reaplist; +- time64_t cutoff = ktime_get_boottime_seconds() - nn->nfsd4_lease; +- time64_t t, new_timeo = nn->nfsd4_lease; ++ struct laundry_time lt = { ++ .cutoff = ktime_get_boottime_seconds() - nn->nfsd4_lease, ++ .new_timeo = nn->nfsd4_lease ++ }; + struct nfs4_cpntf_state *cps; + copy_stateid_t *cps_t; + int i; + + if (clients_still_reclaiming(nn)) { +- new_timeo = 0; ++ lt.new_timeo = 0; + goto out; + } + nfsd4_end_grace(nn); +@@ -5411,7 +5429,7 @@ nfs4_laundromat(struct nfsd_net *nn) + idr_for_each_entry(&nn->s2s_cp_stateids, cps_t, i) { + cps = container_of(cps_t, struct nfs4_cpntf_state, cp_stateid); + if (cps->cp_stateid.sc_type == NFS4_COPYNOTIFY_STID && +- cps->cpntf_time < cutoff) ++ state_expired(<, cps->cpntf_time)) + _free_cpntf_state_locked(nn, cps); + } + spin_unlock(&nn->s2s_cp_lock); +@@ -5419,11 +5437,8 @@ nfs4_laundromat(struct nfsd_net *nn) + spin_lock(&nn->client_lock); + list_for_each_safe(pos, next, &nn->client_lru) { + clp = list_entry(pos, struct nfs4_client, cl_lru); +- if (clp->cl_time > cutoff) { +- t = clp->cl_time - cutoff; +- new_timeo = min(new_timeo, t); ++ if (!state_expired(<, clp->cl_time)) + break; +- } + if (mark_client_expired_locked(clp)) { + trace_nfsd_clid_expired(&clp->cl_clientid); + continue; +@@ -5440,11 +5455,8 @@ nfs4_laundromat(struct nfsd_net *nn) + spin_lock(&state_lock); + list_for_each_safe(pos, next, &nn->del_recall_lru) { + dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); +- if (dp->dl_time > cutoff) { +- t = dp->dl_time - cutoff; +- new_timeo = min(new_timeo, t); ++ if (!state_expired(<, dp->dl_time)) + break; +- } + WARN_ON(!unhash_delegation_locked(dp)); + list_add(&dp->dl_recall_lru, &reaplist); + } +@@ -5460,11 +5472,8 @@ nfs4_laundromat(struct nfsd_net *nn) + while (!list_empty(&nn->close_lru)) { + oo = list_first_entry(&nn->close_lru, struct nfs4_openowner, + oo_close_lru); +- if (oo->oo_time > cutoff) { +- t = oo->oo_time - cutoff; +- new_timeo = min(new_timeo, t); ++ if (!state_expired(<, oo->oo_time)) + break; +- } + list_del_init(&oo->oo_close_lru); + stp = oo->oo_last_closed_stid; + oo->oo_last_closed_stid = NULL; +@@ -5490,11 +5499,8 @@ nfs4_laundromat(struct nfsd_net *nn) + while (!list_empty(&nn->blocked_locks_lru)) { + nbl = list_first_entry(&nn->blocked_locks_lru, + struct nfsd4_blocked_lock, nbl_lru); +- if (nbl->nbl_time > cutoff) { +- t = nbl->nbl_time - cutoff; +- new_timeo = min(new_timeo, t); ++ if (!state_expired(<, nbl->nbl_time)) + break; +- } + list_move(&nbl->nbl_lru, &reaplist); + list_del_init(&nbl->nbl_list); + } +@@ -5507,8 +5513,7 @@ nfs4_laundromat(struct nfsd_net *nn) + free_blocked_lock(nbl); + } + out: +- new_timeo = max_t(time64_t, new_timeo, NFSD_LAUNDROMAT_MINTIMEOUT); +- return new_timeo; ++ return max_t(time64_t, lt.new_timeo, NFSD_LAUNDROMAT_MINTIMEOUT); + } + + static struct workqueue_struct *laundry_wq; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-hook-up-the-filecache-stat-file.patch b/queue-5.10/nfsd-hook-up-the-filecache-stat-file.patch new file mode 100644 index 00000000000..f41895d7ae8 --- /dev/null +++ b/queue-5.10/nfsd-hook-up-the-filecache-stat-file.patch @@ -0,0 +1,65 @@ +From c9290962f8a98d2e26bc6a6fe38351d12a9475d8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 Jul 2022 14:24:58 -0400 +Subject: NFSD: Hook up the filecache stat file + +From: Chuck Lever + +[ Upstream commit 2e6c6e4c4375bfd3defa5b1ff3604d9f33d1c936 ] + +There has always been the capability of exporting filecache metrics +via /proc, but it was never hooked up. Let's surface these metrics +to enable better observability of the filecache. + +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsctl.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c +index 66c352bf61b1d..7002edbf26870 100644 +--- a/fs/nfsd/nfsctl.c ++++ b/fs/nfsd/nfsctl.c +@@ -25,6 +25,7 @@ + #include "state.h" + #include "netns.h" + #include "pnfs.h" ++#include "filecache.h" + + /* + * We have a single directory with several nodes in it. +@@ -45,6 +46,7 @@ enum { + NFSD_Ports, + NFSD_MaxBlkSize, + NFSD_MaxConnections, ++ NFSD_Filecache, + NFSD_SupportedEnctypes, + /* + * The below MUST come last. Otherwise we leave a hole in nfsd_files[] +@@ -229,6 +231,13 @@ static const struct file_operations reply_cache_stats_operations = { + .release = single_release, + }; + ++static const struct file_operations filecache_ops = { ++ .open = nfsd_file_cache_stats_open, ++ .read = seq_read, ++ .llseek = seq_lseek, ++ .release = single_release, ++}; ++ + /*----------------------------------------------------------------------------*/ + /* + * payload - write methods +@@ -1370,6 +1379,7 @@ static int nfsd_fill_super(struct super_block *sb, struct fs_context *fc) + [NFSD_Ports] = {"portlist", &transaction_ops, S_IWUSR|S_IRUGO}, + [NFSD_MaxBlkSize] = {"max_block_size", &transaction_ops, S_IWUSR|S_IRUGO}, + [NFSD_MaxConnections] = {"max_connections", &transaction_ops, S_IWUSR|S_IRUGO}, ++ [NFSD_Filecache] = {"filecache", &filecache_ops, S_IRUGO}, + #if defined(CONFIG_SUNRPC_GSS) || defined(CONFIG_SUNRPC_GSS_MODULE) + [NFSD_SupportedEnctypes] = {"supported_krb5_enctypes", &supported_enctypes_ops, S_IRUGO}, + #endif /* CONFIG_SUNRPC_GSS or CONFIG_SUNRPC_GSS_MODULE */ +-- +2.43.0 + diff --git a/queue-5.10/nfsd-ignore-requests-to-disable-unsupported-versions.patch b/queue-5.10/nfsd-ignore-requests-to-disable-unsupported-versions.patch new file mode 100644 index 00000000000..9a86aca4353 --- /dev/null +++ b/queue-5.10/nfsd-ignore-requests-to-disable-unsupported-versions.patch @@ -0,0 +1,40 @@ +From 8844467a5e8f94226937ace0c0620a6eafe555c1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 18 Oct 2022 07:47:54 -0400 +Subject: nfsd: ignore requests to disable unsupported versions + +From: Jeff Layton + +[ Upstream commit 8e823bafff2308753d430566256c83d8085952da ] + +The kernel currently errors out if you attempt to enable or disable a +version that it doesn't recognize. Change it to ignore attempts to +disable an unrecognized version. If we don't support it, then there is +no harm in doing so. + +Signed-off-by: Jeff Layton +Reviewed-by: Tom Talpey +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsctl.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c +index dc74a947a440c..68ed42fd29fc8 100644 +--- a/fs/nfsd/nfsctl.c ++++ b/fs/nfsd/nfsctl.c +@@ -601,7 +601,9 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size) + } + break; + default: +- return -EINVAL; ++ /* Ignore requests to disable non-existent versions */ ++ if (cmd == NFSD_SET) ++ return -EINVAL; + } + vers += len + 1; + } while ((len = qword_get(&mesg, vers, size)) > 0); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-improve-stateid-access-bitmask-documentation.patch b/queue-5.10/nfsd-improve-stateid-access-bitmask-documentation.patch new file mode 100644 index 00000000000..5ffb2a80c8f --- /dev/null +++ b/queue-5.10/nfsd-improve-stateid-access-bitmask-documentation.patch @@ -0,0 +1,73 @@ +From 05afac7f9575834d01e48919563a4ea64cfa0365 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Dec 2021 17:32:21 -0500 +Subject: nfsd: improve stateid access bitmask documentation + +From: J. Bruce Fields + +[ Upstream commit 3dcd1d8aab00c5d3a0a3725253c86440b1a0f5a7 ] + +The use of the bitmaps is confusing. Add a cross-reference to make it +easier to find the existing comment. Add an updated reference with URL +to make it quicker to look up. And a bit more editorializing about the +value of this. + +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 14 ++++++++++---- + fs/nfsd/state.h | 4 ++++ + 2 files changed, 14 insertions(+), 4 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 0b39ed1568d40..3b8c5f2283975 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -360,11 +360,13 @@ static const struct nfsd4_callback_ops nfsd4_cb_notify_lock_ops = { + * st_{access,deny}_bmap field of the stateid, in order to track not + * only what share bits are currently in force, but also what + * combinations of share bits previous opens have used. This allows us +- * to enforce the recommendation of rfc 3530 14.2.19 that the server +- * return an error if the client attempt to downgrade to a combination +- * of share bits not explicable by closing some of its previous opens. ++ * to enforce the recommendation in ++ * https://datatracker.ietf.org/doc/html/rfc7530#section-16.19.4 that ++ * the server return an error if the client attempt to downgrade to a ++ * combination of share bits not explicable by closing some of its ++ * previous opens. + * +- * XXX: This enforcement is actually incomplete, since we don't keep ++ * This enforcement is arguably incomplete, since we don't keep + * track of access/deny bit combinations; so, e.g., we allow: + * + * OPEN allow read, deny write +@@ -372,6 +374,10 @@ static const struct nfsd4_callback_ops nfsd4_cb_notify_lock_ops = { + * DOWNGRADE allow read, deny none + * + * which we should reject. ++ * ++ * But you could also argue that our current code is already overkill, ++ * since it only exists to return NFS4ERR_INVAL on incorrect client ++ * behavior. + */ + static unsigned int + bmap_to_share_mode(unsigned long bmap) +diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h +index e73bdbb1634ab..6eb3c7157214b 100644 +--- a/fs/nfsd/state.h ++++ b/fs/nfsd/state.h +@@ -568,6 +568,10 @@ struct nfs4_ol_stateid { + struct list_head st_locks; + struct nfs4_stateowner *st_stateowner; + struct nfs4_clnt_odstate *st_clnt_odstate; ++/* ++ * These bitmasks use 3 separate bits for READ, ALLOW, and BOTH; see the ++ * comment above bmap_to_share_mode() for explanation: ++ */ + unsigned char st_access_bmap; + unsigned char st_deny_bmap; + struct nfs4_ol_stateid *st_openstp; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-increase-nfsd_max_ops_per_compound.patch b/queue-5.10/nfsd-increase-nfsd_max_ops_per_compound.patch new file mode 100644 index 00000000000..d2a6e25f614 --- /dev/null +++ b/queue-5.10/nfsd-increase-nfsd_max_ops_per_compound.patch @@ -0,0 +1,82 @@ +From a2383531cc84b202a40a9395976b872183cb4a92 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 2 Sep 2022 18:18:16 -0400 +Subject: NFSD: Increase NFSD_MAX_OPS_PER_COMPOUND + +From: Chuck Lever + +[ Upstream commit 80e591ce636f3ae6855a0ca26963da1fdd6d4508 ] + +When attempting an NFSv4 mount, a Solaris NFSv4 client builds a +single large COMPOUND that chains a series of LOOKUPs to get to the +pseudo filesystem root directory that is to be mounted. The Linux +NFS server's current maximum of 16 operations per NFSv4 COMPOUND is +not large enough to ensure that this works for paths that are more +than a few components deep. + +Since NFSD_MAX_OPS_PER_COMPOUND is mostly a sanity check, and most +NFSv4 COMPOUNDS are between 3 and 6 operations (thus they do not +trigger any re-allocation of the operation array on the server), +increasing this maximum should result in little to no impact. + +The ops array can get large now, so allocate it via vmalloc() to +help ensure memory fragmentation won't cause an allocation failure. + +Link: https://bugzilla.kernel.org/show_bug.cgi?id=216383 +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 7 ++++--- + fs/nfsd/state.h | 2 +- + 2 files changed, 5 insertions(+), 4 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 5476541530ead..92e0535ddb922 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -42,6 +42,8 @@ + #include + #include + #include ++#include ++ + #include + + #include "idmap.h" +@@ -2369,10 +2371,9 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) + return true; + + if (argp->opcnt > ARRAY_SIZE(argp->iops)) { +- argp->ops = kzalloc(argp->opcnt * sizeof(*argp->ops), GFP_KERNEL); ++ argp->ops = vcalloc(argp->opcnt, sizeof(*argp->ops)); + if (!argp->ops) { + argp->ops = argp->iops; +- dprintk("nfsd: couldn't allocate room for COMPOUND\n"); + return false; + } + } +@@ -5402,7 +5403,7 @@ void nfsd4_release_compoundargs(struct svc_rqst *rqstp) + struct nfsd4_compoundargs *args = rqstp->rq_argp; + + if (args->ops != args->iops) { +- kfree(args->ops); ++ vfree(args->ops); + args->ops = args->iops; + } + while (args->to_free) { +diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h +index ae596dbf86675..5d28beb290fef 100644 +--- a/fs/nfsd/state.h ++++ b/fs/nfsd/state.h +@@ -175,7 +175,7 @@ static inline struct nfs4_delegation *delegstateid(struct nfs4_stid *s) + /* Maximum number of slots per session. 160 is useful for long haul TCP */ + #define NFSD_MAX_SLOTS_PER_SESSION 160 + /* Maximum number of operations per session compound */ +-#define NFSD_MAX_OPS_PER_COMPOUND 16 ++#define NFSD_MAX_OPS_PER_COMPOUND 50 + /* Maximum session per slot cache size */ + #define NFSD_SLOT_CACHE_SIZE 2048 + /* Maximum number of NFSD_SLOT_CACHE_SIZE slots per session */ +-- +2.43.0 + diff --git a/queue-5.10/nfsd-initialize-pointer-ni-with-null-and-not-plain-i.patch b/queue-5.10/nfsd-initialize-pointer-ni-with-null-and-not-plain-i.patch new file mode 100644 index 00000000000..7dc68e8d99f --- /dev/null +++ b/queue-5.10/nfsd-initialize-pointer-ni-with-null-and-not-plain-i.patch @@ -0,0 +1,50 @@ +From adcd2a291f5e32593f46f83698786ab387012c6d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 25 Sep 2021 23:58:41 +0100 +Subject: NFSD: Initialize pointer ni with NULL and not plain integer 0 + +From: Colin Ian King + +[ Upstream commit 8e70bf27fd20cc17e87150327a640e546bfbee64 ] + +Pointer ni is being initialized with plain integer zero. Fix +this by initializing with NULL. + +Signed-off-by: Colin Ian King +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 2 +- + fs/nfsd/nfs4state.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index d55d9b9dbafb1..ebb6d8471e8d7 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -1181,7 +1181,7 @@ extern void nfs_sb_deactive(struct super_block *sb); + static __be32 nfsd4_ssc_setup_dul(struct nfsd_net *nn, char *ipaddr, + struct nfsd4_ssc_umount_item **retwork, struct vfsmount **ss_mnt) + { +- struct nfsd4_ssc_umount_item *ni = 0; ++ struct nfsd4_ssc_umount_item *ni = NULL; + struct nfsd4_ssc_umount_item *work = NULL; + struct nfsd4_ssc_umount_item *tmp; + DEFINE_WAIT(wait); +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 68562564be6b2..0b39ed1568d40 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -5573,7 +5573,7 @@ static void nfsd4_ssc_shutdown_umount(struct nfsd_net *nn) + static void nfsd4_ssc_expire_umount(struct nfsd_net *nn) + { + bool do_wakeup = false; +- struct nfsd4_ssc_umount_item *ni = 0; ++ struct nfsd4_ssc_umount_item *ni = NULL; + struct nfsd4_ssc_umount_item *tmp; + + spin_lock(&nn->nfsd_ssc_lock); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-instantiate-a-struct-file-when-creating-a-regul.patch b/queue-5.10/nfsd-instantiate-a-struct-file-when-creating-a-regul.patch new file mode 100644 index 00000000000..ee7ccc46785 --- /dev/null +++ b/queue-5.10/nfsd-instantiate-a-struct-file-when-creating-a-regul.patch @@ -0,0 +1,318 @@ +From bc94af8ea3d4e3736b8c5e8d23d593da3a98a8aa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 30 Mar 2022 10:30:54 -0400 +Subject: NFSD: Instantiate a struct file when creating a regular NFSv4 file + +From: Chuck Lever + +[ Upstream commit fb70bf124b051d4ded4ce57511dfec6d3ebf2b43 ] + +There have been reports of races that cause NFSv4 OPEN(CREATE) to +return an error even though the requested file was created. NFSv4 +does not provide a status code for this case. + +To mitigate some of these problems, reorganize the NFSv4 +OPEN(CREATE) logic to allocate resources before the file is actually +created, and open the new file while the parent directory is still +locked. + +Two new APIs are added: + ++ Add an API that works like nfsd_file_acquire() but does not open +the underlying file. The OPEN(CREATE) path can use this API when it +already has an open file. + ++ Add an API that is kin to dentry_open(). NFSD needs to create a +file and grab an open "struct file *" atomically. The +alloc_empty_file() has to be done before the inode create. If it +fails (for example, because the NFS server has exceeded its +max_files limit), we avoid creating the file and can still return +an error to the NFS client. + +BugLink: https://bugzilla.linux-nfs.org/show_bug.cgi?id=382 +Signed-off-by: Chuck Lever +Tested-by: JianHong Yin +[ cel: backported to 5.10.y, prior to idmapped mounts ] +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 51 ++++++++++++++++++++++++++++++++++++++------- + fs/nfsd/filecache.h | 2 ++ + fs/nfsd/nfs4proc.c | 43 ++++++++++++++++++++++++++++++++++---- + fs/nfsd/nfs4state.c | 16 +++++++++++--- + fs/nfsd/xdr4.h | 1 + + fs/open.c | 41 ++++++++++++++++++++++++++++++++++++ + include/linux/fs.h | 2 ++ + 7 files changed, 142 insertions(+), 14 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index 3c297ccfcc59d..db9c68a3c1f3b 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -898,9 +898,9 @@ nfsd_file_is_cached(struct inode *inode) + return ret; + } + +-__be32 +-nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, +- unsigned int may_flags, struct nfsd_file **pnf) ++static __be32 ++nfsd_do_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, ++ unsigned int may_flags, struct nfsd_file **pnf, bool open) + { + __be32 status; + struct net *net = SVC_NET(rqstp); +@@ -995,10 +995,13 @@ nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + nfsd_file_gc(); + + nf->nf_mark = nfsd_file_mark_find_or_create(nf); +- if (nf->nf_mark) +- status = nfsd_open_verified(rqstp, fhp, may_flags, +- &nf->nf_file); +- else ++ if (nf->nf_mark) { ++ if (open) ++ status = nfsd_open_verified(rqstp, fhp, may_flags, ++ &nf->nf_file); ++ else ++ status = nfs_ok; ++ } else + status = nfserr_jukebox; + /* + * If construction failed, or we raced with a call to unlink() +@@ -1018,6 +1021,40 @@ nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + goto out; + } + ++/** ++ * nfsd_file_acquire - Get a struct nfsd_file with an open file ++ * @rqstp: the RPC transaction being executed ++ * @fhp: the NFS filehandle of the file to be opened ++ * @may_flags: NFSD_MAY_ settings for the file ++ * @pnf: OUT: new or found "struct nfsd_file" object ++ * ++ * Returns nfs_ok and sets @pnf on success; otherwise an nfsstat in ++ * network byte order is returned. ++ */ ++__be32 ++nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, ++ unsigned int may_flags, struct nfsd_file **pnf) ++{ ++ return nfsd_do_file_acquire(rqstp, fhp, may_flags, pnf, true); ++} ++ ++/** ++ * nfsd_file_create - Get a struct nfsd_file, do not open ++ * @rqstp: the RPC transaction being executed ++ * @fhp: the NFS filehandle of the file just created ++ * @may_flags: NFSD_MAY_ settings for the file ++ * @pnf: OUT: new or found "struct nfsd_file" object ++ * ++ * Returns nfs_ok and sets @pnf on success; otherwise an nfsstat in ++ * network byte order is returned. ++ */ ++__be32 ++nfsd_file_create(struct svc_rqst *rqstp, struct svc_fh *fhp, ++ unsigned int may_flags, struct nfsd_file **pnf) ++{ ++ return nfsd_do_file_acquire(rqstp, fhp, may_flags, pnf, false); ++} ++ + /* + * Note that fields may be added, removed or reordered in the future. Programs + * scraping this file for info should test the labels to ensure they're +diff --git a/fs/nfsd/filecache.h b/fs/nfsd/filecache.h +index 435ceab27897a..1da0c79a55804 100644 +--- a/fs/nfsd/filecache.h ++++ b/fs/nfsd/filecache.h +@@ -59,5 +59,7 @@ void nfsd_file_close_inode_sync(struct inode *inode); + bool nfsd_file_is_cached(struct inode *inode); + __be32 nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + unsigned int may_flags, struct nfsd_file **nfp); ++__be32 nfsd_file_create(struct svc_rqst *rqstp, struct svc_fh *fhp, ++ unsigned int may_flags, struct nfsd_file **nfp); + int nfsd_file_cache_stats_open(struct inode *, struct file *); + #endif /* _FS_NFSD_FILECACHE_H */ +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index adb64c9259bd8..166ebb126d37b 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -243,6 +243,37 @@ static inline bool nfsd4_create_is_exclusive(int createmode) + createmode == NFS4_CREATE_EXCLUSIVE4_1; + } + ++static __be32 ++nfsd4_vfs_create(struct svc_fh *fhp, struct dentry *child, ++ struct nfsd4_open *open) ++{ ++ struct file *filp; ++ struct path path; ++ int oflags; ++ ++ oflags = O_CREAT | O_LARGEFILE; ++ switch (open->op_share_access & NFS4_SHARE_ACCESS_BOTH) { ++ case NFS4_SHARE_ACCESS_WRITE: ++ oflags |= O_WRONLY; ++ break; ++ case NFS4_SHARE_ACCESS_BOTH: ++ oflags |= O_RDWR; ++ break; ++ default: ++ oflags |= O_RDONLY; ++ } ++ ++ path.mnt = fhp->fh_export->ex_path.mnt; ++ path.dentry = child; ++ filp = dentry_create(&path, oflags, open->op_iattr.ia_mode, ++ current_cred()); ++ if (IS_ERR(filp)) ++ return nfserrno(PTR_ERR(filp)); ++ ++ open->op_filp = filp; ++ return nfs_ok; ++} ++ + /* + * Implement NFSv4's unchecked, guarded, and exclusive create + * semantics for regular files. Open state for this new file is +@@ -355,11 +386,9 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp, + if (!IS_POSIXACL(inode)) + iap->ia_mode &= ~current_umask(); + +- host_err = vfs_create(inode, child, iap->ia_mode, true); +- if (host_err < 0) { +- status = nfserrno(host_err); ++ status = nfsd4_vfs_create(fhp, child, open); ++ if (status != nfs_ok) + goto out; +- } + open->op_created = true; + + /* A newly created file already has a file size of zero. */ +@@ -517,6 +546,8 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + (int)open->op_fnamelen, open->op_fname, + open->op_openowner); + ++ open->op_filp = NULL; ++ + /* This check required by spec. */ + if (open->op_create && open->op_claim_type != NFS4_OPEN_CLAIM_NULL) + return nfserr_inval; +@@ -613,6 +644,10 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + if (reclaim && !status) + nn->somebody_reclaimed = true; + out: ++ if (open->op_filp) { ++ fput(open->op_filp); ++ open->op_filp = NULL; ++ } + if (resfh && resfh != &cstate->current_fh) { + fh_dup2(&cstate->current_fh, resfh); + fh_put(resfh); +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 9116496b476aa..9f972ca09eec7 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -5110,9 +5110,19 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp, + + if (!fp->fi_fds[oflag]) { + spin_unlock(&fp->fi_lock); +- status = nfsd_file_acquire(rqstp, cur_fh, access, &nf); +- if (status) +- goto out_put_access; ++ ++ if (!open->op_filp) { ++ status = nfsd_file_acquire(rqstp, cur_fh, access, &nf); ++ if (status != nfs_ok) ++ goto out_put_access; ++ } else { ++ status = nfsd_file_create(rqstp, cur_fh, access, &nf); ++ if (status != nfs_ok) ++ goto out_put_access; ++ nf->nf_file = open->op_filp; ++ open->op_filp = NULL; ++ } ++ + spin_lock(&fp->fi_lock); + if (!fp->fi_fds[oflag]) { + fp->fi_fds[oflag] = nf; +diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h +index 4a298ac5515df..448b687943cd3 100644 +--- a/fs/nfsd/xdr4.h ++++ b/fs/nfsd/xdr4.h +@@ -273,6 +273,7 @@ struct nfsd4_open { + bool op_truncate; /* used during processing */ + bool op_created; /* used during processing */ + struct nfs4_openowner *op_openowner; /* used during processing */ ++ struct file *op_filp; /* used during processing */ + struct nfs4_file *op_file; /* used during processing */ + struct nfs4_ol_stateid *op_stp; /* used during processing */ + struct nfs4_clnt_odstate *op_odstate; /* used during processing */ +diff --git a/fs/open.c b/fs/open.c +index 9f56ebacfbefe..d69312a2d434b 100644 +--- a/fs/open.c ++++ b/fs/open.c +@@ -954,6 +954,47 @@ struct file *dentry_open(const struct path *path, int flags, + } + EXPORT_SYMBOL(dentry_open); + ++/** ++ * dentry_create - Create and open a file ++ * @path: path to create ++ * @flags: O_ flags ++ * @mode: mode bits for new file ++ * @cred: credentials to use ++ * ++ * Caller must hold the parent directory's lock, and have prepared ++ * a negative dentry, placed in @path->dentry, for the new file. ++ * ++ * Caller sets @path->mnt to the vfsmount of the filesystem where ++ * the new file is to be created. The parent directory and the ++ * negative dentry must reside on the same filesystem instance. ++ * ++ * On success, returns a "struct file *". Otherwise a ERR_PTR ++ * is returned. ++ */ ++struct file *dentry_create(const struct path *path, int flags, umode_t mode, ++ const struct cred *cred) ++{ ++ struct file *f; ++ int error; ++ ++ validate_creds(cred); ++ f = alloc_empty_file(flags, cred); ++ if (IS_ERR(f)) ++ return f; ++ ++ error = vfs_create(d_inode(path->dentry->d_parent), ++ path->dentry, mode, true); ++ if (!error) ++ error = vfs_open(path, f); ++ ++ if (unlikely(error)) { ++ fput(f); ++ return ERR_PTR(error); ++ } ++ return f; ++} ++EXPORT_SYMBOL(dentry_create); ++ + struct file *open_with_fake_path(const struct path *path, int flags, + struct inode *inode, const struct cred *cred) + { +diff --git a/include/linux/fs.h b/include/linux/fs.h +index 3e9105b3cc767..7e7098bf2c57e 100644 +--- a/include/linux/fs.h ++++ b/include/linux/fs.h +@@ -2618,6 +2618,8 @@ extern struct file *filp_open(const char *, int, umode_t); + extern struct file *file_open_root(struct dentry *, struct vfsmount *, + const char *, int, umode_t); + extern struct file * dentry_open(const struct path *, int, const struct cred *); ++extern struct file *dentry_create(const struct path *path, int flags, ++ umode_t mode, const struct cred *cred); + extern struct file * open_with_fake_path(const struct path *, int, + struct inode*, const struct cred *); + static inline struct file *file_clone_open(struct file *file) +-- +2.43.0 + diff --git a/queue-5.10/nfsd-introduce-struct-nfsd_attrs.patch b/queue-5.10/nfsd-introduce-struct-nfsd_attrs.patch new file mode 100644 index 00000000000..98600c7cc25 --- /dev/null +++ b/queue-5.10/nfsd-introduce-struct-nfsd_attrs.patch @@ -0,0 +1,434 @@ +From c71f8691d388fb7d44acbc0f76bdbc8e4a3206ec Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 Jul 2022 16:45:30 +1000 +Subject: NFSD: introduce struct nfsd_attrs + +From: NeilBrown + +[ Upstream commit 7fe2a71dda349a1afa75781f0cc7975be9784d15 ] + +The attributes that nfsd might want to set on a file include 'struct +iattr' as well as an ACL and security label. +The latter two are passed around quite separately from the first, in +part because they are only needed for NFSv4. This leads to some +clumsiness in the code, such as the attributes NOT being set in +nfsd_create_setattr(). + +We need to keep the directory locked until all attributes are set to +ensure the file is never visibile without all its attributes. This need +combined with the inconsistent handling of attributes leads to more +clumsiness. + +As a first step towards tidying this up, introduce 'struct nfsd_attrs'. +This is passed (by reference) to vfs.c functions that work with +attributes, and is assembled by the various nfs*proc functions which +call them. As yet only iattr is included, but future patches will +expand this. + +Signed-off-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3proc.c | 20 ++++++++++++++++---- + fs/nfsd/nfs4proc.c | 23 ++++++++++++++++------- + fs/nfsd/nfs4state.c | 5 ++++- + fs/nfsd/nfsproc.c | 17 +++++++++++++---- + fs/nfsd/vfs.c | 24 ++++++++++++++---------- + fs/nfsd/vfs.h | 12 ++++++++---- + 6 files changed, 71 insertions(+), 30 deletions(-) + +diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c +index e314545bbdb2e..7b81d871f0d3c 100644 +--- a/fs/nfsd/nfs3proc.c ++++ b/fs/nfsd/nfs3proc.c +@@ -67,12 +67,15 @@ nfsd3_proc_setattr(struct svc_rqst *rqstp) + { + struct nfsd3_sattrargs *argp = rqstp->rq_argp; + struct nfsd3_attrstat *resp = rqstp->rq_resp; ++ struct nfsd_attrs attrs = { ++ .na_iattr = &argp->attrs, ++ }; + + dprintk("nfsd: SETATTR(3) %s\n", + SVCFH_fmt(&argp->fh)); + + fh_copy(&resp->fh, &argp->fh); +- resp->status = nfsd_setattr(rqstp, &resp->fh, &argp->attrs, ++ resp->status = nfsd_setattr(rqstp, &resp->fh, &attrs, + argp->check_guard, argp->guardtime); + return rpc_success; + } +@@ -233,6 +236,9 @@ nfsd3_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp, + { + struct iattr *iap = &argp->attrs; + struct dentry *parent, *child; ++ struct nfsd_attrs attrs = { ++ .na_iattr = iap, ++ }; + __u32 v_mtime, v_atime; + struct inode *inode; + __be32 status; +@@ -331,7 +337,7 @@ nfsd3_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp, + } + + set_attr: +- status = nfsd_create_setattr(rqstp, fhp, resfhp, iap); ++ status = nfsd_create_setattr(rqstp, fhp, resfhp, &attrs); + + out: + fh_unlock(fhp); +@@ -368,6 +374,9 @@ nfsd3_proc_mkdir(struct svc_rqst *rqstp) + { + struct nfsd3_createargs *argp = rqstp->rq_argp; + struct nfsd3_diropres *resp = rqstp->rq_resp; ++ struct nfsd_attrs attrs = { ++ .na_iattr = &argp->attrs, ++ }; + + dprintk("nfsd: MKDIR(3) %s %.*s\n", + SVCFH_fmt(&argp->fh), +@@ -378,7 +387,7 @@ nfsd3_proc_mkdir(struct svc_rqst *rqstp) + fh_copy(&resp->dirfh, &argp->fh); + fh_init(&resp->fh, NFS3_FHSIZE); + resp->status = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len, +- &argp->attrs, S_IFDIR, 0, &resp->fh); ++ &attrs, S_IFDIR, 0, &resp->fh); + fh_unlock(&resp->dirfh); + return rpc_success; + } +@@ -428,6 +437,9 @@ nfsd3_proc_mknod(struct svc_rqst *rqstp) + { + struct nfsd3_mknodargs *argp = rqstp->rq_argp; + struct nfsd3_diropres *resp = rqstp->rq_resp; ++ struct nfsd_attrs attrs = { ++ .na_iattr = &argp->attrs, ++ }; + int type; + dev_t rdev = 0; + +@@ -453,7 +465,7 @@ nfsd3_proc_mknod(struct svc_rqst *rqstp) + + type = nfs3_ftypes[argp->ftype]; + resp->status = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len, +- &argp->attrs, type, rdev, &resp->fh); ++ &attrs, type, rdev, &resp->fh); + fh_unlock(&resp->dirfh); + out: + return rpc_success; +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 7685bbe9d78dd..f8a157e4bc708 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -286,6 +286,9 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp, + struct svc_fh *resfhp, struct nfsd4_open *open) + { + struct iattr *iap = &open->op_iattr; ++ struct nfsd_attrs attrs = { ++ .na_iattr = iap, ++ }; + struct dentry *parent, *child; + __u32 v_mtime, v_atime; + struct inode *inode; +@@ -404,7 +407,7 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp, + } + + set_attr: +- status = nfsd_create_setattr(rqstp, fhp, resfhp, iap); ++ status = nfsd_create_setattr(rqstp, fhp, resfhp, &attrs); + + out: + fh_unlock(fhp); +@@ -787,6 +790,9 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + union nfsd4_op_u *u) + { + struct nfsd4_create *create = &u->create; ++ struct nfsd_attrs attrs = { ++ .na_iattr = &create->cr_iattr, ++ }; + struct svc_fh resfh; + __be32 status; + dev_t rdev; +@@ -818,7 +824,7 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + goto out_umask; + status = nfsd_create(rqstp, &cstate->current_fh, + create->cr_name, create->cr_namelen, +- &create->cr_iattr, S_IFBLK, rdev, &resfh); ++ &attrs, S_IFBLK, rdev, &resfh); + break; + + case NF4CHR: +@@ -829,26 +835,26 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + goto out_umask; + status = nfsd_create(rqstp, &cstate->current_fh, + create->cr_name, create->cr_namelen, +- &create->cr_iattr, S_IFCHR, rdev, &resfh); ++ &attrs, S_IFCHR, rdev, &resfh); + break; + + case NF4SOCK: + status = nfsd_create(rqstp, &cstate->current_fh, + create->cr_name, create->cr_namelen, +- &create->cr_iattr, S_IFSOCK, 0, &resfh); ++ &attrs, S_IFSOCK, 0, &resfh); + break; + + case NF4FIFO: + status = nfsd_create(rqstp, &cstate->current_fh, + create->cr_name, create->cr_namelen, +- &create->cr_iattr, S_IFIFO, 0, &resfh); ++ &attrs, S_IFIFO, 0, &resfh); + break; + + case NF4DIR: + create->cr_iattr.ia_valid &= ~ATTR_SIZE; + status = nfsd_create(rqstp, &cstate->current_fh, + create->cr_name, create->cr_namelen, +- &create->cr_iattr, S_IFDIR, 0, &resfh); ++ &attrs, S_IFDIR, 0, &resfh); + break; + + default: +@@ -1142,6 +1148,9 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + union nfsd4_op_u *u) + { + struct nfsd4_setattr *setattr = &u->setattr; ++ struct nfsd_attrs attrs = { ++ .na_iattr = &setattr->sa_iattr, ++ }; + __be32 status = nfs_ok; + int err; + +@@ -1174,7 +1183,7 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + &setattr->sa_label); + if (status) + goto out; +- status = nfsd_setattr(rqstp, &cstate->current_fh, &setattr->sa_iattr, ++ status = nfsd_setattr(rqstp, &cstate->current_fh, &attrs, + 0, (time64_t)0); + out: + fh_drop_write(&cstate->current_fh); +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index b3ab112695837..2b6c9f1b9de88 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -5077,11 +5077,14 @@ nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh, + .ia_valid = ATTR_SIZE, + .ia_size = 0, + }; ++ struct nfsd_attrs attrs = { ++ .na_iattr = &iattr, ++ }; + if (!open->op_truncate) + return 0; + if (!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE)) + return nfserr_inval; +- return nfsd_setattr(rqstp, fh, &iattr, 0, (time64_t)0); ++ return nfsd_setattr(rqstp, fh, &attrs, 0, (time64_t)0); + } + + static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp, +diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c +index b8ddf21e70ea0..f061f229d5ff0 100644 +--- a/fs/nfsd/nfsproc.c ++++ b/fs/nfsd/nfsproc.c +@@ -51,6 +51,9 @@ nfsd_proc_setattr(struct svc_rqst *rqstp) + struct nfsd_sattrargs *argp = rqstp->rq_argp; + struct nfsd_attrstat *resp = rqstp->rq_resp; + struct iattr *iap = &argp->attrs; ++ struct nfsd_attrs attrs = { ++ .na_iattr = iap, ++ }; + struct svc_fh *fhp; + + dprintk("nfsd: SETATTR %s, valid=%x, size=%ld\n", +@@ -100,7 +103,7 @@ nfsd_proc_setattr(struct svc_rqst *rqstp) + } + } + +- resp->status = nfsd_setattr(rqstp, fhp, iap, 0, (time64_t)0); ++ resp->status = nfsd_setattr(rqstp, fhp, &attrs, 0, (time64_t)0); + if (resp->status != nfs_ok) + goto out; + +@@ -260,6 +263,9 @@ nfsd_proc_create(struct svc_rqst *rqstp) + svc_fh *dirfhp = &argp->fh; + svc_fh *newfhp = &resp->fh; + struct iattr *attr = &argp->attrs; ++ struct nfsd_attrs attrs = { ++ .na_iattr = attr, ++ }; + struct inode *inode; + struct dentry *dchild; + int type, mode; +@@ -385,7 +391,7 @@ nfsd_proc_create(struct svc_rqst *rqstp) + if (!inode) { + /* File doesn't exist. Create it and set attrs */ + resp->status = nfsd_create_locked(rqstp, dirfhp, argp->name, +- argp->len, attr, type, rdev, ++ argp->len, &attrs, type, rdev, + newfhp); + } else if (type == S_IFREG) { + dprintk("nfsd: existing %s, valid=%x, size=%ld\n", +@@ -396,7 +402,7 @@ nfsd_proc_create(struct svc_rqst *rqstp) + */ + attr->ia_valid &= ATTR_SIZE; + if (attr->ia_valid) +- resp->status = nfsd_setattr(rqstp, newfhp, attr, 0, ++ resp->status = nfsd_setattr(rqstp, newfhp, &attrs, 0, + (time64_t)0); + } + +@@ -511,6 +517,9 @@ nfsd_proc_mkdir(struct svc_rqst *rqstp) + { + struct nfsd_createargs *argp = rqstp->rq_argp; + struct nfsd_diropres *resp = rqstp->rq_resp; ++ struct nfsd_attrs attrs = { ++ .na_iattr = &argp->attrs, ++ }; + + dprintk("nfsd: MKDIR %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name); + +@@ -522,7 +531,7 @@ nfsd_proc_mkdir(struct svc_rqst *rqstp) + argp->attrs.ia_valid &= ~ATTR_SIZE; + fh_init(&resp->fh, NFS_FHSIZE); + resp->status = nfsd_create(rqstp, &argp->fh, argp->name, argp->len, +- &argp->attrs, S_IFDIR, 0, &resp->fh); ++ &attrs, S_IFDIR, 0, &resp->fh); + fh_put(&argp->fh); + if (resp->status != nfs_ok) + goto out; +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index 5c8dc1a05e57e..c86c3a8e42329 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -362,11 +362,13 @@ nfsd_get_write_access(struct svc_rqst *rqstp, struct svc_fh *fhp, + * Set various file attributes. After this call fhp needs an fh_put. + */ + __be32 +-nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, ++nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, ++ struct nfsd_attrs *attr, + int check_guard, time64_t guardtime) + { + struct dentry *dentry; + struct inode *inode; ++ struct iattr *iap = attr->na_iattr; + int accmode = NFSD_MAY_SATTR; + umode_t ftype = 0; + __be32 err; +@@ -1221,14 +1223,15 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, u64 offset, + * @rqstp: RPC transaction being executed + * @fhp: NFS filehandle of parent directory + * @resfhp: NFS filehandle of new object +- * @iap: requested attributes of new object ++ * @attrs: requested attributes of new object + * + * Returns nfs_ok on success, or an nfsstat in network byte order. + */ + __be32 + nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, +- struct svc_fh *resfhp, struct iattr *iap) ++ struct svc_fh *resfhp, struct nfsd_attrs *attrs) + { ++ struct iattr *iap = attrs->na_iattr; + __be32 status; + + /* +@@ -1249,7 +1252,7 @@ nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, + * if the attributes have not changed. + */ + if (iap->ia_valid) +- status = nfsd_setattr(rqstp, resfhp, iap, 0, (time64_t)0); ++ status = nfsd_setattr(rqstp, resfhp, attrs, 0, (time64_t)0); + else + status = nfserrno(commit_metadata(resfhp)); + +@@ -1288,11 +1291,12 @@ nfsd_check_ignore_resizing(struct iattr *iap) + /* The parent directory should already be locked: */ + __be32 + nfsd_create_locked(struct svc_rqst *rqstp, struct svc_fh *fhp, +- char *fname, int flen, struct iattr *iap, +- int type, dev_t rdev, struct svc_fh *resfhp) ++ char *fname, int flen, struct nfsd_attrs *attrs, ++ int type, dev_t rdev, struct svc_fh *resfhp) + { + struct dentry *dentry, *dchild; + struct inode *dirp; ++ struct iattr *iap = attrs->na_iattr; + __be32 err; + int host_err; + +@@ -1365,7 +1369,7 @@ nfsd_create_locked(struct svc_rqst *rqstp, struct svc_fh *fhp, + if (host_err < 0) + goto out_nfserr; + +- err = nfsd_create_setattr(rqstp, fhp, resfhp, iap); ++ err = nfsd_create_setattr(rqstp, fhp, resfhp, attrs); + + out: + dput(dchild); +@@ -1384,8 +1388,8 @@ nfsd_create_locked(struct svc_rqst *rqstp, struct svc_fh *fhp, + */ + __be32 + nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, +- char *fname, int flen, struct iattr *iap, +- int type, dev_t rdev, struct svc_fh *resfhp) ++ char *fname, int flen, struct nfsd_attrs *attrs, ++ int type, dev_t rdev, struct svc_fh *resfhp) + { + struct dentry *dentry, *dchild = NULL; + __be32 err; +@@ -1417,7 +1421,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, + dput(dchild); + if (err) + return err; +- return nfsd_create_locked(rqstp, fhp, fname, flen, iap, type, ++ return nfsd_create_locked(rqstp, fhp, fname, flen, attrs, type, + rdev, resfhp); + } + +diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h +index 26347d76f44a0..d8b1a36fca956 100644 +--- a/fs/nfsd/vfs.h ++++ b/fs/nfsd/vfs.h +@@ -42,6 +42,10 @@ struct nfsd_file; + typedef int (*nfsd_filldir_t)(void *, const char *, int, loff_t, u64, unsigned); + + /* nfsd/vfs.c */ ++struct nfsd_attrs { ++ struct iattr *na_iattr; /* input */ ++}; ++ + int nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp, + struct svc_export **expp); + __be32 nfsd_lookup(struct svc_rqst *, struct svc_fh *, +@@ -50,7 +54,7 @@ __be32 nfsd_lookup_dentry(struct svc_rqst *, struct svc_fh *, + const char *, unsigned int, + struct svc_export **, struct dentry **); + __be32 nfsd_setattr(struct svc_rqst *, struct svc_fh *, +- struct iattr *, int, time64_t); ++ struct nfsd_attrs *, int, time64_t); + int nfsd_mountpoint(struct dentry *, struct svc_export *); + #ifdef CONFIG_NFSD_V4 + __be32 nfsd4_set_nfs4_label(struct svc_rqst *, struct svc_fh *, +@@ -63,14 +67,14 @@ __be32 nfsd4_clone_file_range(struct svc_rqst *rqstp, + u64 count, bool sync); + #endif /* CONFIG_NFSD_V4 */ + __be32 nfsd_create_locked(struct svc_rqst *, struct svc_fh *, +- char *name, int len, struct iattr *attrs, ++ char *name, int len, struct nfsd_attrs *attrs, + int type, dev_t rdev, struct svc_fh *res); + __be32 nfsd_create(struct svc_rqst *, struct svc_fh *, +- char *name, int len, struct iattr *attrs, ++ char *name, int len, struct nfsd_attrs *attrs, + int type, dev_t rdev, struct svc_fh *res); + __be32 nfsd_access(struct svc_rqst *, struct svc_fh *, u32 *, u32 *); + __be32 nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, +- struct svc_fh *resfhp, struct iattr *iap); ++ struct svc_fh *resfhp, struct nfsd_attrs *iap); + __be32 nfsd_commit(struct svc_rqst *rqst, struct svc_fh *fhp, + u64 offset, u32 count, __be32 *verf); + #ifdef CONFIG_NFSD_V4 +-- +2.43.0 + diff --git a/queue-5.10/nfsd-invoke-svc_encode_result_payload-in-read-nfsd-e.patch b/queue-5.10/nfsd-invoke-svc_encode_result_payload-in-read-nfsd-e.patch new file mode 100644 index 00000000000..e6ec727414c --- /dev/null +++ b/queue-5.10/nfsd-invoke-svc_encode_result_payload-in-read-nfsd-e.patch @@ -0,0 +1,249 @@ +From 95b9e93785e76fe0fe5847d62e9ebfb02d04b225 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Nov 2020 10:24:19 -0500 +Subject: NFSD: Invoke svc_encode_result_payload() in "read" NFSD encoders + +From: Chuck Lever + +[ Upstream commit 76e5492b161f555c0fb69cad9eb39a7d8467f5fe ] + +Have the NFSD encoders annotate the boundaries of every +direct-data-placement eligible result data payload. Then change +svcrdma to use that annotation instead of the xdr->page_len +when handling Write chunks. + +For NFSv4 on RDMA, that enables the ability to recognize multiple +result payloads per compound. This is a pre-requisite for supporting +multiple Write chunks per RPC transaction. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3xdr.c | 7 +++++ + fs/nfsd/nfs4xdr.c | 41 +++++++++++++++++++-------- + fs/nfsd/nfsxdr.c | 6 ++++ + net/sunrpc/xprtrdma/svc_rdma_sendto.c | 24 +++++----------- + 4 files changed, 49 insertions(+), 29 deletions(-) + +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index 716566da400e1..27b24823f7c42 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -707,6 +707,7 @@ int + nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p) + { + struct nfsd3_readlinkres *resp = rqstp->rq_resp; ++ struct kvec *head = rqstp->rq_res.head; + + *p++ = resp->status; + p = encode_post_op_attr(rqstp, p, &resp->fh); +@@ -720,6 +721,8 @@ nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p) + *p = 0; + rqstp->rq_res.tail[0].iov_len = 4 - (resp->len&3); + } ++ if (svc_encode_result_payload(rqstp, head->iov_len, resp->len)) ++ return 0; + return 1; + } else + return xdr_ressize_check(rqstp, p); +@@ -730,6 +733,7 @@ int + nfs3svc_encode_readres(struct svc_rqst *rqstp, __be32 *p) + { + struct nfsd3_readres *resp = rqstp->rq_resp; ++ struct kvec *head = rqstp->rq_res.head; + + *p++ = resp->status; + p = encode_post_op_attr(rqstp, p, &resp->fh); +@@ -746,6 +750,9 @@ nfs3svc_encode_readres(struct svc_rqst *rqstp, __be32 *p) + *p = 0; + rqstp->rq_res.tail[0].iov_len = 4 - (resp->count & 3); + } ++ if (svc_encode_result_payload(rqstp, head->iov_len, ++ resp->count)) ++ return 0; + return 1; + } else + return xdr_ressize_check(rqstp, p); +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 9971d3c295731..4b3344296ed0e 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -3770,8 +3770,8 @@ static __be32 nfsd4_encode_splice_read( + { + struct xdr_stream *xdr = &resp->xdr; + struct xdr_buf *buf = xdr->buf; ++ int status, space_left; + u32 eof; +- int space_left; + __be32 nfserr; + __be32 *p = xdr->p - 2; + +@@ -3782,14 +3782,13 @@ static __be32 nfsd4_encode_splice_read( + nfserr = nfsd_splice_read(read->rd_rqstp, read->rd_fhp, + file, read->rd_offset, &maxcount, &eof); + read->rd_length = maxcount; +- if (nfserr) { +- /* +- * nfsd_splice_actor may have already messed with the +- * page length; reset it so as not to confuse +- * xdr_truncate_encode: +- */ +- buf->page_len = 0; +- return nfserr; ++ if (nfserr) ++ goto out_err; ++ status = svc_encode_result_payload(read->rd_rqstp, ++ buf->head[0].iov_len, maxcount); ++ if (status) { ++ nfserr = nfserrno(status); ++ goto out_err; + } + + *(p++) = htonl(eof); +@@ -3820,6 +3819,15 @@ static __be32 nfsd4_encode_splice_read( + xdr->end = (__be32 *)((void *)xdr->end + space_left); + + return 0; ++ ++out_err: ++ /* ++ * nfsd_splice_actor may have already messed with the ++ * page length; reset it so as not to confuse ++ * xdr_truncate_encode in our caller. ++ */ ++ buf->page_len = 0; ++ return nfserr; + } + + static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp, +@@ -3911,6 +3919,7 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd + int zero = 0; + struct xdr_stream *xdr = &resp->xdr; + int length_offset = xdr->buf->len; ++ int status; + __be32 *p; + + p = xdr_reserve_space(xdr, 4); +@@ -3931,9 +3940,13 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd + (char *)p, &maxcount); + if (nfserr == nfserr_isdir) + nfserr = nfserr_inval; +- if (nfserr) { +- xdr_truncate_encode(xdr, length_offset); +- return nfserr; ++ if (nfserr) ++ goto out_err; ++ status = svc_encode_result_payload(readlink->rl_rqstp, length_offset, ++ maxcount); ++ if (status) { ++ nfserr = nfserrno(status); ++ goto out_err; + } + + wire_count = htonl(maxcount); +@@ -3943,6 +3956,10 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd + write_bytes_to_xdr_buf(xdr->buf, length_offset + 4 + maxcount, + &zero, 4 - (maxcount&3)); + return 0; ++ ++out_err: ++ xdr_truncate_encode(xdr, length_offset); ++ return nfserr; + } + + static __be32 +diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c +index 8a288c8fcd57c..9e00a902113e3 100644 +--- a/fs/nfsd/nfsxdr.c ++++ b/fs/nfsd/nfsxdr.c +@@ -469,6 +469,7 @@ int + nfssvc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p) + { + struct nfsd_readlinkres *resp = rqstp->rq_resp; ++ struct kvec *head = rqstp->rq_res.head; + + *p++ = resp->status; + if (resp->status != nfs_ok) +@@ -483,6 +484,8 @@ nfssvc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p) + *p = 0; + rqstp->rq_res.tail[0].iov_len = 4 - (resp->len&3); + } ++ if (svc_encode_result_payload(rqstp, head->iov_len, resp->len)) ++ return 0; + return 1; + } + +@@ -490,6 +493,7 @@ int + nfssvc_encode_readres(struct svc_rqst *rqstp, __be32 *p) + { + struct nfsd_readres *resp = rqstp->rq_resp; ++ struct kvec *head = rqstp->rq_res.head; + + *p++ = resp->status; + if (resp->status != nfs_ok) +@@ -507,6 +511,8 @@ nfssvc_encode_readres(struct svc_rqst *rqstp, __be32 *p) + *p = 0; + rqstp->rq_res.tail[0].iov_len = 4 - (resp->count&3); + } ++ if (svc_encode_result_payload(rqstp, head->iov_len, resp->count)) ++ return 0; + return 1; + } + +diff --git a/net/sunrpc/xprtrdma/svc_rdma_sendto.c b/net/sunrpc/xprtrdma/svc_rdma_sendto.c +index c8411b4f3492a..d6436c13d5c47 100644 +--- a/net/sunrpc/xprtrdma/svc_rdma_sendto.c ++++ b/net/sunrpc/xprtrdma/svc_rdma_sendto.c +@@ -448,7 +448,6 @@ static ssize_t svc_rdma_encode_write_chunk(__be32 *src, + * svc_rdma_encode_write_list - Encode RPC Reply's Write chunk list + * @rctxt: Reply context with information about the RPC Call + * @sctxt: Send context for the RPC Reply +- * @length: size in bytes of the payload in the first Write chunk + * + * The client provides a Write chunk list in the Call message. Fill + * in the segments in the first Write chunk in the Reply's transport +@@ -465,12 +464,12 @@ static ssize_t svc_rdma_encode_write_chunk(__be32 *src, + */ + static ssize_t + svc_rdma_encode_write_list(const struct svc_rdma_recv_ctxt *rctxt, +- struct svc_rdma_send_ctxt *sctxt, +- unsigned int length) ++ struct svc_rdma_send_ctxt *sctxt) + { + ssize_t len, ret; + +- ret = svc_rdma_encode_write_chunk(rctxt->rc_write_list, sctxt, length); ++ ret = svc_rdma_encode_write_chunk(rctxt->rc_write_list, sctxt, ++ rctxt->rc_read_payload_length); + if (ret < 0) + return ret; + len = ret; +@@ -923,21 +922,12 @@ int svc_rdma_sendto(struct svc_rqst *rqstp) + goto err0; + if (wr_lst) { + /* XXX: Presume the client sent only one Write chunk */ +- unsigned long offset; +- unsigned int length; +- +- if (rctxt->rc_read_payload_length) { +- offset = rctxt->rc_read_payload_offset; +- length = rctxt->rc_read_payload_length; +- } else { +- offset = xdr->head[0].iov_len; +- length = xdr->page_len; +- } +- ret = svc_rdma_send_write_chunk(rdma, wr_lst, xdr, offset, +- length); ++ ret = svc_rdma_send_write_chunk(rdma, wr_lst, xdr, ++ rctxt->rc_read_payload_offset, ++ rctxt->rc_read_payload_length); + if (ret < 0) + goto err2; +- if (svc_rdma_encode_write_list(rctxt, sctxt, length) < 0) ++ if (svc_rdma_encode_write_list(rctxt, sctxt) < 0) + goto err0; + } else { + if (xdr_stream_encode_item_absent(&sctxt->sc_stream) < 0) +-- +2.43.0 + diff --git a/queue-5.10/nfsd-keep-track-of-the-number-of-courtesy-clients-in.patch b/queue-5.10/nfsd-keep-track-of-the-number-of-courtesy-clients-in.patch new file mode 100644 index 00000000000..f9e3eec4f53 --- /dev/null +++ b/queue-5.10/nfsd-keep-track-of-the-number-of-courtesy-clients-in.patch @@ -0,0 +1,100 @@ +From 03ecbad30ad8e865101f87235489d4c280cd9418 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 14 Sep 2022 08:54:25 -0700 +Subject: NFSD: keep track of the number of courtesy clients in the system + +From: Dai Ngo + +[ Upstream commit 3a4ea23d86a317c4b68b9a69d51f7e84e1e04357 ] + +Add counter nfs4_courtesy_client_count to nfsd_net to keep track +of the number of courtesy clients in the system. + +Signed-off-by: Dai Ngo +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/netns.h | 2 ++ + fs/nfsd/nfs4state.c | 17 ++++++++++++++++- + 2 files changed, 18 insertions(+), 1 deletion(-) + +diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h +index ffe17743cc74b..55c7006d6109a 100644 +--- a/fs/nfsd/netns.h ++++ b/fs/nfsd/netns.h +@@ -192,6 +192,8 @@ struct nfsd_net { + + atomic_t nfs4_client_count; + int nfs4_max_clients; ++ ++ atomic_t nfsd_courtesy_clients; + }; + + /* Simple check to find out if a given net was properly initialized */ +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 2bb78ab4f6c31..9930c5f9440c7 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -160,6 +160,13 @@ static bool is_client_expired(struct nfs4_client *clp) + return clp->cl_time == 0; + } + ++static void nfsd4_dec_courtesy_client_count(struct nfsd_net *nn, ++ struct nfs4_client *clp) ++{ ++ if (clp->cl_state != NFSD4_ACTIVE) ++ atomic_add_unless(&nn->nfsd_courtesy_clients, -1, 0); ++} ++ + static __be32 get_client_locked(struct nfs4_client *clp) + { + struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); +@@ -169,6 +176,7 @@ static __be32 get_client_locked(struct nfs4_client *clp) + if (is_client_expired(clp)) + return nfserr_expired; + atomic_inc(&clp->cl_rpc_users); ++ nfsd4_dec_courtesy_client_count(nn, clp); + clp->cl_state = NFSD4_ACTIVE; + return nfs_ok; + } +@@ -190,6 +198,7 @@ renew_client_locked(struct nfs4_client *clp) + + list_move_tail(&clp->cl_lru, &nn->client_lru); + clp->cl_time = ktime_get_boottime_seconds(); ++ nfsd4_dec_courtesy_client_count(nn, clp); + clp->cl_state = NFSD4_ACTIVE; + } + +@@ -2248,6 +2257,7 @@ __destroy_client(struct nfs4_client *clp) + if (clp->cl_cb_conn.cb_xprt) + svc_xprt_put(clp->cl_cb_conn.cb_xprt); + atomic_add_unless(&nn->nfs4_client_count, -1, 0); ++ nfsd4_dec_courtesy_client_count(nn, clp); + free_client(clp); + wake_up_all(&expiry_wq); + } +@@ -4375,6 +4385,8 @@ void nfsd4_init_leases_net(struct nfsd_net *nn) + max_clients = (u64)si.totalram * si.mem_unit / (1024 * 1024 * 1024); + max_clients *= NFS4_CLIENTS_PER_GB; + nn->nfs4_max_clients = max_t(int, max_clients, NFS4_CLIENTS_PER_GB); ++ ++ atomic_set(&nn->nfsd_courtesy_clients, 0); + } + + static void init_nfs4_replay(struct nfs4_replay *rp) +@@ -5928,8 +5940,11 @@ nfs4_get_client_reaplist(struct nfsd_net *nn, struct list_head *reaplist, + goto exp_client; + if (!state_expired(lt, clp->cl_time)) + break; +- if (!atomic_read(&clp->cl_rpc_users)) ++ if (!atomic_read(&clp->cl_rpc_users)) { ++ if (clp->cl_state == NFSD4_ACTIVE) ++ atomic_inc(&nn->nfsd_courtesy_clients); + clp->cl_state = NFSD4_COURTESY; ++ } + if (!client_has_state(clp)) + goto exp_client; + if (!nfs4_anylock_blockers(clp)) +-- +2.43.0 + diff --git a/queue-5.10/nfsd-keep-track-of-the-number-of-v4-clients-in-the-s.patch b/queue-5.10/nfsd-keep-track-of-the-number-of-v4-clients-in-the-s.patch new file mode 100644 index 00000000000..6fbeaf990c1 --- /dev/null +++ b/queue-5.10/nfsd-keep-track-of-the-number-of-v4-clients-in-the-s.patch @@ -0,0 +1,92 @@ +From faab332b8421f0c5fe76ce864bc2755cb4097dd0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 15 Jul 2022 16:54:52 -0700 +Subject: NFSD: keep track of the number of v4 clients in the system + +From: Dai Ngo + +[ Upstream commit 0926c39515aa065a296e97dfc8790026f1e53f86 ] + +Add counter nfs4_client_count to keep track of the total number +of v4 clients, including courtesy clients, in the system. + +Signed-off-by: Dai Ngo +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/netns.h | 2 ++ + fs/nfsd/nfs4state.c | 10 ++++++++-- + 2 files changed, 10 insertions(+), 2 deletions(-) + +diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h +index 1b1a962a18041..ce864f001a3ee 100644 +--- a/fs/nfsd/netns.h ++++ b/fs/nfsd/netns.h +@@ -189,6 +189,8 @@ struct nfsd_net { + struct nfsd_fcache_disposal *fcache_disposal; + + siphash_key_t siphash_key; ++ ++ atomic_t nfs4_client_count; + }; + + /* Simple check to find out if a given net was properly initialized */ +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 76a77329cf368..5003d73fa9287 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -2066,7 +2066,8 @@ STALE_CLIENTID(clientid_t *clid, struct nfsd_net *nn) + * This type of memory management is somewhat inefficient, but we use it + * anyway since SETCLIENTID is not a common operation. + */ +-static struct nfs4_client *alloc_client(struct xdr_netobj name) ++static struct nfs4_client *alloc_client(struct xdr_netobj name, ++ struct nfsd_net *nn) + { + struct nfs4_client *clp; + int i; +@@ -2089,6 +2090,7 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name) + atomic_set(&clp->cl_rpc_users, 0); + clp->cl_cb_state = NFSD4_CB_UNKNOWN; + clp->cl_state = NFSD4_ACTIVE; ++ atomic_inc(&nn->nfs4_client_count); + atomic_set(&clp->cl_delegs_in_recall, 0); + INIT_LIST_HEAD(&clp->cl_idhash); + INIT_LIST_HEAD(&clp->cl_openowners); +@@ -2196,6 +2198,7 @@ static __be32 mark_client_expired_locked(struct nfs4_client *clp) + static void + __destroy_client(struct nfs4_client *clp) + { ++ struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); + int i; + struct nfs4_openowner *oo; + struct nfs4_delegation *dp; +@@ -2239,6 +2242,7 @@ __destroy_client(struct nfs4_client *clp) + nfsd4_shutdown_callback(clp); + if (clp->cl_cb_conn.cb_xprt) + svc_xprt_put(clp->cl_cb_conn.cb_xprt); ++ atomic_add_unless(&nn->nfs4_client_count, -1, 0); + free_client(clp); + wake_up_all(&expiry_wq); + } +@@ -2865,7 +2869,7 @@ static struct nfs4_client *create_client(struct xdr_netobj name, + struct nfsd_net *nn = net_generic(net, nfsd_net_id); + struct dentry *dentries[ARRAY_SIZE(client_files)]; + +- clp = alloc_client(name); ++ clp = alloc_client(name, nn); + if (clp == NULL) + return NULL; + +@@ -4357,6 +4361,8 @@ void nfsd4_init_leases_net(struct nfsd_net *nn) + nn->clientid_base = prandom_u32(); + nn->clientid_counter = nn->clientid_base + 1; + nn->s2s_cp_cl_id = nn->clientid_counter++; ++ ++ atomic_set(&nn->nfs4_client_count, 0); + } + + static void init_nfs4_replay(struct nfs4_replay *rp) +-- +2.43.0 + diff --git a/queue-5.10/nfsd-leave-open-files-out-of-the-filecache-lru.patch b/queue-5.10/nfsd-leave-open-files-out-of-the-filecache-lru.patch new file mode 100644 index 00000000000..30235e588b7 --- /dev/null +++ b/queue-5.10/nfsd-leave-open-files-out-of-the-filecache-lru.patch @@ -0,0 +1,160 @@ +From f8adc3c63a4838d36d1c133dd7f639d9ba288835 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 Jul 2022 14:25:17 -0400 +Subject: NFSD: Leave open files out of the filecache LRU + +From: Chuck Lever + +[ Upstream commit 4a0e73e635e3f36b616ad5c943e3d23debe4632f ] + +There have been reports of problems when running fstests generic/531 +against Linux NFS servers with NFSv4. The NFS server that hosts the +test's SCRATCH_DEV suffers from CPU soft lock-ups during the test. +Analysis shows that: + +fs/nfsd/filecache.c + 482 ret = list_lru_walk(&nfsd_file_lru, + 483 nfsd_file_lru_cb, + 484 &head, LONG_MAX); + +causes nfsd_file_gc() to walk the entire length of the filecache LRU +list every time it is called (which is quite frequently). The walk +holds a spinlock the entire time that prevents other nfsd threads +from accessing the filecache. + +What's more, for NFSv4 workloads, none of the items that are visited +during this walk may be evicted, since they are all files that are +held OPEN by NFS clients. + +Address this by ensuring that open files are not kept on the LRU +list. + +Reported-by: Frank van der Linden +Reported-by: Wang Yugui +Link: https://bugzilla.linux-nfs.org/show_bug.cgi?id=386 +Suggested-by: Trond Myklebust +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 24 +++++++++++++++++++----- + fs/nfsd/trace.h | 2 ++ + 2 files changed, 21 insertions(+), 5 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index a995a744a7481..5c9e3ff6397b0 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -262,6 +262,7 @@ nfsd_file_flush(struct nfsd_file *nf) + + static void nfsd_file_lru_add(struct nfsd_file *nf) + { ++ set_bit(NFSD_FILE_REFERENCED, &nf->nf_flags); + if (list_lru_add(&nfsd_file_lru, &nf->nf_lru)) + trace_nfsd_file_lru_add(nf); + } +@@ -291,7 +292,6 @@ nfsd_file_unhash(struct nfsd_file *nf) + { + if (test_and_clear_bit(NFSD_FILE_HASHED, &nf->nf_flags)) { + nfsd_file_do_unhash(nf); +- nfsd_file_lru_remove(nf); + return true; + } + return false; +@@ -312,6 +312,7 @@ nfsd_file_unhash_and_release_locked(struct nfsd_file *nf, struct list_head *disp + if (refcount_dec_not_one(&nf->nf_ref)) + return true; + ++ nfsd_file_lru_remove(nf); + list_add(&nf->nf_lru, dispose); + return true; + } +@@ -323,6 +324,7 @@ nfsd_file_put_noref(struct nfsd_file *nf) + + if (refcount_dec_and_test(&nf->nf_ref)) { + WARN_ON(test_bit(NFSD_FILE_HASHED, &nf->nf_flags)); ++ nfsd_file_lru_remove(nf); + nfsd_file_free(nf); + } + } +@@ -332,7 +334,7 @@ nfsd_file_put(struct nfsd_file *nf) + { + might_sleep(); + +- set_bit(NFSD_FILE_REFERENCED, &nf->nf_flags); ++ nfsd_file_lru_add(nf); + if (test_bit(NFSD_FILE_HASHED, &nf->nf_flags) == 0) { + nfsd_file_flush(nf); + nfsd_file_put_noref(nf); +@@ -432,8 +434,18 @@ nfsd_file_dispose_list_delayed(struct list_head *dispose) + } + } + +-/* ++/** ++ * nfsd_file_lru_cb - Examine an entry on the LRU list ++ * @item: LRU entry to examine ++ * @lru: controlling LRU ++ * @lock: LRU list lock (unused) ++ * @arg: dispose list ++ * + * Note this can deadlock with nfsd_file_cache_purge. ++ * ++ * Return values: ++ * %LRU_REMOVED: @item was removed from the LRU ++ * %LRU_SKIP: @item cannot be evicted + */ + static enum lru_status + nfsd_file_lru_cb(struct list_head *item, struct list_lru_one *lru, +@@ -455,8 +467,9 @@ nfsd_file_lru_cb(struct list_head *item, struct list_lru_one *lru, + * That order is deliberate to ensure that we can do this locklessly. + */ + if (refcount_read(&nf->nf_ref) > 1) { ++ list_lru_isolate(lru, &nf->nf_lru); + trace_nfsd_file_gc_in_use(nf); +- return LRU_SKIP; ++ return LRU_REMOVED; + } + + /* +@@ -1013,6 +1026,7 @@ nfsd_do_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + goto retry; + } + ++ nfsd_file_lru_remove(nf); + this_cpu_inc(nfsd_file_cache_hits); + + status = nfserrno(nfsd_open_break_lease(file_inode(nf->nf_file), may_flags)); +@@ -1034,7 +1048,6 @@ nfsd_do_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + refcount_inc(&nf->nf_ref); + __set_bit(NFSD_FILE_HASHED, &nf->nf_flags); + __set_bit(NFSD_FILE_PENDING, &nf->nf_flags); +- nfsd_file_lru_add(nf); + hlist_add_head_rcu(&nf->nf_node, &nfsd_file_hashtbl[hashval].nfb_head); + ++nfsd_file_hashtbl[hashval].nfb_count; + nfsd_file_hashtbl[hashval].nfb_maxcount = max(nfsd_file_hashtbl[hashval].nfb_maxcount, +@@ -1059,6 +1072,7 @@ nfsd_do_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + */ + if (status != nfs_ok || inode->i_nlink == 0) { + bool do_free; ++ nfsd_file_lru_remove(nf); + spin_lock(&nfsd_file_hashtbl[hashval].nfb_lock); + do_free = nfsd_file_unhash(nf); + spin_unlock(&nfsd_file_hashtbl[hashval].nfb_lock); +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index b1aa28c062ac5..5919cdcf137b8 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -892,7 +892,9 @@ DEFINE_EVENT(nfsd_file_gc_class, name, \ + TP_ARGS(nf)) + + DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_lru_add); ++DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_lru_add_disposed); + DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_lru_del); ++DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_lru_del_disposed); + DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_gc_in_use); + DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_gc_writeback); + DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_gc_referenced); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-limit-the-number-of-v4-clients-to-1024-per-1gb-.patch b/queue-5.10/nfsd-limit-the-number-of-v4-clients-to-1024-per-1gb-.patch new file mode 100644 index 00000000000..9f3f98954af --- /dev/null +++ b/queue-5.10/nfsd-limit-the-number-of-v4-clients-to-1024-per-1gb-.patch @@ -0,0 +1,135 @@ +From 7bee796e56b88fab0a5d9cadefda792d623e5b02 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 15 Jul 2022 16:54:53 -0700 +Subject: NFSD: limit the number of v4 clients to 1024 per 1GB of system memory + +From: Dai Ngo + +[ Upstream commit 4271c2c0887562318a0afef97d32d8a71cbe0743 ] + +Currently there is no limit on how many v4 clients are supported +by the system. This can be a problem in systems with small memory +configuration to function properly when a very large number of +clients exist that creates memory shortage conditions. + +This patch enforces a limit of 1024 NFSv4 clients, including courtesy +clients, per 1GB of system memory. When the number of the clients +reaches the limit, requests that create new clients are returned +with NFS4ERR_DELAY and the laundromat is kicked start to trim old +clients. Due to the overhead of the upcall to remove the client +record, the maximun number of clients the laundromat removes on +each run is limited to 128. This is done to ensure the laundromat +can still process the other tasks in a timely manner. + +Since there is now a limit of the number of clients, the 24-hr +idle time limit of courtesy client is no longer needed and was +removed. + +Signed-off-by: Dai Ngo +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/netns.h | 1 + + fs/nfsd/nfs4state.c | 27 +++++++++++++++++++++------ + fs/nfsd/nfsd.h | 2 ++ + 3 files changed, 24 insertions(+), 6 deletions(-) + +diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h +index ce864f001a3ee..ffe17743cc74b 100644 +--- a/fs/nfsd/netns.h ++++ b/fs/nfsd/netns.h +@@ -191,6 +191,7 @@ struct nfsd_net { + siphash_key_t siphash_key; + + atomic_t nfs4_client_count; ++ int nfs4_max_clients; + }; + + /* Simple check to find out if a given net was properly initialized */ +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 5003d73fa9287..1babc08fcb88f 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -2072,6 +2072,10 @@ static struct nfs4_client *alloc_client(struct xdr_netobj name, + struct nfs4_client *clp; + int i; + ++ if (atomic_read(&nn->nfs4_client_count) >= nn->nfs4_max_clients) { ++ mod_delayed_work(laundry_wq, &nn->laundromat_work, 0); ++ return NULL; ++ } + clp = kmem_cache_zalloc(client_slab, GFP_KERNEL); + if (clp == NULL) + return NULL; +@@ -4353,6 +4357,9 @@ nfsd4_init_slabs(void) + + void nfsd4_init_leases_net(struct nfsd_net *nn) + { ++ struct sysinfo si; ++ u64 max_clients; ++ + nn->nfsd4_lease = 90; /* default lease time */ + nn->nfsd4_grace = 90; + nn->somebody_reclaimed = false; +@@ -4363,6 +4370,10 @@ void nfsd4_init_leases_net(struct nfsd_net *nn) + nn->s2s_cp_cl_id = nn->clientid_counter++; + + atomic_set(&nn->nfs4_client_count, 0); ++ si_meminfo(&si); ++ max_clients = (u64)si.totalram * si.mem_unit / (1024 * 1024 * 1024); ++ max_clients *= NFS4_CLIENTS_PER_GB; ++ nn->nfs4_max_clients = max_t(int, max_clients, NFS4_CLIENTS_PER_GB); + } + + static void init_nfs4_replay(struct nfs4_replay *rp) +@@ -5828,9 +5839,12 @@ static void + nfs4_get_client_reaplist(struct nfsd_net *nn, struct list_head *reaplist, + struct laundry_time *lt) + { ++ unsigned int maxreap, reapcnt = 0; + struct list_head *pos, *next; + struct nfs4_client *clp; + ++ maxreap = (atomic_read(&nn->nfs4_client_count) >= nn->nfs4_max_clients) ? ++ NFSD_CLIENT_MAX_TRIM_PER_RUN : 0; + INIT_LIST_HEAD(reaplist); + spin_lock(&nn->client_lock); + list_for_each_safe(pos, next, &nn->client_lru) { +@@ -5841,14 +5855,15 @@ nfs4_get_client_reaplist(struct nfsd_net *nn, struct list_head *reaplist, + break; + if (!atomic_read(&clp->cl_rpc_users)) + clp->cl_state = NFSD4_COURTESY; +- if (!client_has_state(clp) || +- ktime_get_boottime_seconds() >= +- (clp->cl_time + NFSD_COURTESY_CLIENT_TIMEOUT)) ++ if (!client_has_state(clp)) + goto exp_client; +- if (nfs4_anylock_blockers(clp)) { ++ if (!nfs4_anylock_blockers(clp)) ++ if (reapcnt >= maxreap) ++ continue; + exp_client: +- if (!mark_client_expired_locked(clp)) +- list_add(&clp->cl_lru, reaplist); ++ if (!mark_client_expired_locked(clp)) { ++ list_add(&clp->cl_lru, reaplist); ++ reapcnt++; + } + } + spin_unlock(&nn->client_lock); +diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h +index ef8087691138a..57a468ed85c35 100644 +--- a/fs/nfsd/nfsd.h ++++ b/fs/nfsd/nfsd.h +@@ -341,6 +341,8 @@ void nfsd_lockd_shutdown(void); + + #define NFSD_LAUNDROMAT_MINTIMEOUT 1 /* seconds */ + #define NFSD_COURTESY_CLIENT_TIMEOUT (24 * 60 * 60) /* seconds */ ++#define NFSD_CLIENT_MAX_TRIM_PER_RUN 128 ++#define NFS4_CLIENTS_PER_GB 1024 + + /* + * The following attributes are currently not supported by the NFSv4 server: +-- +2.43.0 + diff --git a/queue-5.10/nfsd-log-client-tracking-type-log-message-as-info-in.patch b/queue-5.10/nfsd-log-client-tracking-type-log-message-as-info-in.patch new file mode 100644 index 00000000000..e24080fb18e --- /dev/null +++ b/queue-5.10/nfsd-log-client-tracking-type-log-message-as-info-in.patch @@ -0,0 +1,75 @@ +From 16098058a6756fe068b9cb1752beb89e29798465 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 12 Mar 2021 22:03:00 +0100 +Subject: nfsd: Log client tracking type log message as info instead of warning +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Paul Menzel + +[ Upstream commit f988a7b71d1e66e63f79cd59c763875347943a7a ] + +`printk()`, by default, uses the log level warning, which leaves the +user reading + + NFSD: Using UMH upcall client tracking operations. + +wondering what to do about it (`dmesg --level=warn`). + +Several client tracking methods are tried, and expected to fail. That’s +why a message is printed only on success. It might be interesting for +users to know the chosen method, so use info-level instead of +debug-level. + +Cc: linux-nfs@vger.kernel.org +Signed-off-by: Paul Menzel +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4recover.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c +index 83c4e68839537..d08c1a8c9254b 100644 +--- a/fs/nfsd/nfs4recover.c ++++ b/fs/nfsd/nfs4recover.c +@@ -626,7 +626,7 @@ nfsd4_legacy_tracking_init(struct net *net) + status = nfsd4_load_reboot_recovery_data(net); + if (status) + goto err; +- printk("NFSD: Using legacy client tracking operations.\n"); ++ pr_info("NFSD: Using legacy client tracking operations.\n"); + return 0; + + err: +@@ -1030,7 +1030,7 @@ nfsd4_init_cld_pipe(struct net *net) + + status = __nfsd4_init_cld_pipe(net); + if (!status) +- printk("NFSD: Using old nfsdcld client tracking operations.\n"); ++ pr_info("NFSD: Using old nfsdcld client tracking operations.\n"); + return status; + } + +@@ -1607,7 +1607,7 @@ nfsd4_cld_tracking_init(struct net *net) + nfs4_release_reclaim(nn); + goto err_remove; + } else +- printk("NFSD: Using nfsdcld client tracking operations.\n"); ++ pr_info("NFSD: Using nfsdcld client tracking operations.\n"); + return 0; + + err_remove: +@@ -1866,7 +1866,7 @@ nfsd4_umh_cltrack_init(struct net *net) + ret = nfsd4_umh_cltrack_upcall("init", NULL, grace_start, NULL); + kfree(grace_start); + if (!ret) +- printk("NFSD: Using UMH upcall client tracking operations.\n"); ++ pr_info("NFSD: Using UMH upcall client tracking operations.\n"); + return ret; + } + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-make-a-copy-of-struct-iattr-before-calling-noti.patch b/queue-5.10/nfsd-make-a-copy-of-struct-iattr-before-calling-noti.patch new file mode 100644 index 00000000000..05d9eb88307 --- /dev/null +++ b/queue-5.10/nfsd-make-a-copy-of-struct-iattr-before-calling-noti.patch @@ -0,0 +1,50 @@ +From 822efa290a95ff27076c27d21909cee2a14d22cb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 17 May 2023 12:26:44 -0400 +Subject: nfsd: make a copy of struct iattr before calling notify_change + +From: Jeff Layton + +[ Upstream commit d53d70084d27f56bcdf5074328f2c9ec861be596 ] + +notify_change can modify the iattr structure. In particular it can +end up setting ATTR_MODE when ATTR_KILL_SUID is already set, causing +a BUG() if the same iattr is passed to notify_change more than once. + +Make a copy of the struct iattr before calling notify_change. + +Reported-by: Zhi Li +Link: https://bugzilla.redhat.com/show_bug.cgi?id=2207969 +Tested-by: Zhi Li +Fixes: 34b91dda7124 ("NFSD: Make nfsd4_setattr() wait before returning NFS4ERR_DELAY") +Signed-off-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/vfs.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index abc682854507b..542a1adbbf2a1 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -545,7 +545,15 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, + + inode_lock(inode); + for (retries = 1;;) { +- host_err = __nfsd_setattr(dentry, iap); ++ struct iattr attrs; ++ ++ /* ++ * notify_change() can alter its iattr argument, making ++ * @iap unsuitable for submission multiple times. Make a ++ * copy for every loop iteration. ++ */ ++ attrs = *iap; ++ host_err = __nfsd_setattr(dentry, &attrs); + if (host_err != -EAGAIN || !retries--) + break; + if (!nfsd_wait_for_delegreturn(rqstp, inode)) +-- +2.43.0 + diff --git a/queue-5.10/nfsd-make-it-possible-to-use-svc_set_num_threads_syn.patch b/queue-5.10/nfsd-make-it-possible-to-use-svc_set_num_threads_syn.patch new file mode 100644 index 00000000000..dd006f7a75a --- /dev/null +++ b/queue-5.10/nfsd-make-it-possible-to-use-svc_set_num_threads_syn.patch @@ -0,0 +1,190 @@ +From 542f2f52433837769a1b17b9907302b9b4653b31 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Nov 2021 15:51:25 +1100 +Subject: NFSD: Make it possible to use svc_set_num_threads_sync + +From: NeilBrown + +[ Upstream commit 3409e4f1e8f239f0ed81be0b068ecf4e73e2e826 ] + +nfsd cannot currently use svc_set_num_threads_sync. It instead +uses svc_set_num_threads which does *not* wait for threads to all +exit, and has a separate mechanism (nfsd_shutdown_complete) to wait +for completion. + +The reason that nfsd is unlike other services is that nfsd threads can +exit separately from svc_set_num_threads being called - they die on +receipt of SIGKILL. Also, when the last thread exits, the service must +be shut down (sockets closed). + +For this, the nfsd_mutex needs to be taken, and as that mutex needs to +be held while svc_set_num_threads is called, the one cannot wait for +the other. + +This patch changes the nfsd thread so that it can drop the ref on the +service without blocking on nfsd_mutex, so that svc_set_num_threads_sync +can be used: + - if it can drop a non-last reference, it does that. This does not + trigger shutdown and does not require a mutex. This will likely + happen for all but the last thread signalled, and for all threads + being shut down by nfsd_shutdown_threads() + - if it can get the mutex without blocking (trylock), it does that + and then drops the reference. This will likely happen for the + last thread killed by SIGKILL + - Otherwise there might be an unrelated task holding the mutex, + possibly in another network namespace, or nfsd_shutdown_threads() + might be just about to get a reference on the service, after which + we can drop ours safely. + We cannot conveniently get wakeup notifications on these events, + and we are unlikely to need to, so we sleep briefly and check again. + +With this we can discard nfsd_shutdown_complete and +nfsd_complete_shutdown(), and switch to svc_set_num_threads_sync. + +Signed-off-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/netns.h | 3 --- + fs/nfsd/nfssvc.c | 41 +++++++++++++++++++------------------- + include/linux/sunrpc/svc.h | 13 ++++++++++++ + 3 files changed, 33 insertions(+), 24 deletions(-) + +diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h +index 08bcd8f23b013..1fd59eb0730bb 100644 +--- a/fs/nfsd/netns.h ++++ b/fs/nfsd/netns.h +@@ -134,9 +134,6 @@ struct nfsd_net { + wait_queue_head_t ntf_wq; + atomic_t ntf_refcnt; + +- /* Allow umount to wait for nfsd state cleanup */ +- struct completion nfsd_shutdown_complete; +- + /* + * clientid and stateid data for construction of net unique COPY + * stateids. +diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c +index eb8cc4d914fee..6b10415e4006b 100644 +--- a/fs/nfsd/nfssvc.c ++++ b/fs/nfsd/nfssvc.c +@@ -593,20 +593,10 @@ static const struct svc_serv_ops nfsd_thread_sv_ops = { + .svo_shutdown = nfsd_last_thread, + .svo_function = nfsd, + .svo_enqueue_xprt = svc_xprt_do_enqueue, +- .svo_setup = svc_set_num_threads, ++ .svo_setup = svc_set_num_threads_sync, + .svo_module = THIS_MODULE, + }; + +-static void nfsd_complete_shutdown(struct net *net) +-{ +- struct nfsd_net *nn = net_generic(net, nfsd_net_id); +- +- WARN_ON(!mutex_is_locked(&nfsd_mutex)); +- +- nn->nfsd_serv = NULL; +- complete(&nn->nfsd_shutdown_complete); +-} +- + void nfsd_shutdown_threads(struct net *net) + { + struct nfsd_net *nn = net_generic(net, nfsd_net_id); +@@ -624,8 +614,6 @@ void nfsd_shutdown_threads(struct net *net) + serv->sv_ops->svo_setup(serv, NULL, 0); + nfsd_put(net); + mutex_unlock(&nfsd_mutex); +- /* Wait for shutdown of nfsd_serv to complete */ +- wait_for_completion(&nn->nfsd_shutdown_complete); + } + + bool i_am_nfsd(void) +@@ -650,7 +638,6 @@ int nfsd_create_serv(struct net *net) + &nfsd_thread_sv_ops); + if (nn->nfsd_serv == NULL) + return -ENOMEM; +- init_completion(&nn->nfsd_shutdown_complete); + + nn->nfsd_serv->sv_maxconn = nn->max_connections; + error = svc_bind(nn->nfsd_serv, net); +@@ -659,7 +646,7 @@ int nfsd_create_serv(struct net *net) + * been set up yet. + */ + svc_put(nn->nfsd_serv); +- nfsd_complete_shutdown(net); ++ nn->nfsd_serv = NULL; + return error; + } + +@@ -715,7 +702,7 @@ void nfsd_put(struct net *net) + if (kref_put(&nn->nfsd_serv->sv_refcnt, nfsd_noop)) { + svc_shutdown_net(nn->nfsd_serv, net); + svc_destroy(&nn->nfsd_serv->sv_refcnt); +- nfsd_complete_shutdown(net); ++ nn->nfsd_serv = NULL; + } + } + +@@ -743,7 +730,7 @@ int nfsd_set_nrthreads(int n, int *nthreads, struct net *net) + if (tot > NFSD_MAXSERVS) { + /* total too large: scale down requested numbers */ + for (i = 0; i < n && tot > 0; i++) { +- int new = nthreads[i] * NFSD_MAXSERVS / tot; ++ int new = nthreads[i] * NFSD_MAXSERVS / tot; + tot -= (nthreads[i] - new); + nthreads[i] = new; + } +@@ -989,10 +976,22 @@ nfsd(void *vrqstp) + /* Release the thread */ + svc_exit_thread(rqstp); + +- /* Now if needed we call svc_destroy in appropriate context */ +- mutex_lock(&nfsd_mutex); +- nfsd_put(net); +- mutex_unlock(&nfsd_mutex); ++ /* We need to drop a ref, but may not drop the last reference ++ * without holding nfsd_mutex, and we cannot wait for nfsd_mutex as that ++ * could deadlock with nfsd_shutdown_threads() waiting for us. ++ * So three options are: ++ * - drop a non-final reference, ++ * - get the mutex without waiting ++ * - sleep briefly andd try the above again ++ */ ++ while (!svc_put_not_last(nn->nfsd_serv)) { ++ if (mutex_trylock(&nfsd_mutex)) { ++ nfsd_put(net); ++ mutex_unlock(&nfsd_mutex); ++ break; ++ } ++ msleep(20); ++ } + + /* Release module */ + module_put_and_kthread_exit(0); +diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h +index 6829c4ee36544..2768d61b8aed5 100644 +--- a/include/linux/sunrpc/svc.h ++++ b/include/linux/sunrpc/svc.h +@@ -141,6 +141,19 @@ static inline void svc_put(struct svc_serv *serv) + kref_put(&serv->sv_refcnt, svc_destroy); + } + ++/** ++ * svc_put_not_last - decrement non-final reference count on SUNRPC serv ++ * @serv: the svc_serv to have count decremented ++ * ++ * Returns: %true is refcount was decremented. ++ * ++ * If the refcount is 1, it is not decremented and instead failure is reported. ++ */ ++static inline bool svc_put_not_last(struct svc_serv *serv) ++{ ++ return refcount_dec_not_one(&serv->sv_refcnt.refcount); ++} ++ + /* + * Maximum payload size supported by a kernel RPC server. + * This is use to determine the max number of pages nfsd is +-- +2.43.0 + diff --git a/queue-5.10/nfsd-make-nfs4_put_copy-static.patch b/queue-5.10/nfsd-make-nfs4_put_copy-static.patch new file mode 100644 index 00000000000..c33a47608b9 --- /dev/null +++ b/queue-5.10/nfsd-make-nfs4_put_copy-static.patch @@ -0,0 +1,46 @@ +From db5dcc7eea2b1a1e7bb335e12e4f45162c10f4cb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 Jul 2022 14:40:35 -0400 +Subject: NFSD: Make nfs4_put_copy() static + +From: Chuck Lever + +[ Upstream commit 8ea6e2c90bb0eb74a595a12e23a1dff9abbc760a ] + +Clean up: All call sites are in fs/nfsd/nfs4proc.c. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 2 +- + fs/nfsd/state.h | 1 - + 2 files changed, 1 insertion(+), 2 deletions(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 7fb1ef7c4383e..64879350ccbda 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -1287,7 +1287,7 @@ nfsd4_clone(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + return status; + } + +-void nfs4_put_copy(struct nfsd4_copy *copy) ++static void nfs4_put_copy(struct nfsd4_copy *copy) + { + if (!refcount_dec_and_test(©->refcount)) + return; +diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h +index f3d6313914ed0..ae596dbf86675 100644 +--- a/fs/nfsd/state.h ++++ b/fs/nfsd/state.h +@@ -703,7 +703,6 @@ extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(struct xdr_netobj name + extern bool nfs4_has_reclaimed_state(struct xdr_netobj name, struct nfsd_net *nn); + + void put_nfs4_file(struct nfs4_file *fi); +-extern void nfs4_put_copy(struct nfsd4_copy *copy); + extern struct nfsd4_copy * + find_async_copy(struct nfs4_client *clp, stateid_t *staetid); + extern void nfs4_put_cpntf_state(struct nfsd_net *nn, +-- +2.43.0 + diff --git a/queue-5.10/nfsd-make-nfsd4_ops-opnum-a-u32.patch b/queue-5.10/nfsd-make-nfsd4_ops-opnum-a-u32.patch new file mode 100644 index 00000000000..cff1a57b719 --- /dev/null +++ b/queue-5.10/nfsd-make-nfsd4_ops-opnum-a-u32.patch @@ -0,0 +1,73 @@ +From 31e62857e46e95e4813cfbe74435d605d11b91b7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 22 Nov 2020 12:49:52 -0500 +Subject: NFSD: Make nfsd4_ops::opnum a u32 + +From: Chuck Lever + +[ Upstream commit 3a237b4af5b7b0e77588e120554077cab3341943 ] + +Avoid passing a "pointer to int" argument to xdr_stream_decode_u32. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 2 +- + fs/nfsd/nfs4xdr.c | 7 +++---- + fs/nfsd/xdr4.h | 2 +- + 3 files changed, 5 insertions(+), 6 deletions(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index a038d1e182ff3..6b06f0ad05615 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -3272,7 +3272,7 @@ int nfsd4_max_reply(struct svc_rqst *rqstp, struct nfsd4_op *op) + void warn_on_nonidempotent_op(struct nfsd4_op *op) + { + if (OPDESC(op)->op_flags & OP_MODIFIES_SOMETHING) { +- pr_err("unable to encode reply to nonidempotent op %d (%s)\n", ++ pr_err("unable to encode reply to nonidempotent op %u (%s)\n", + op->opnum, nfsd4_op_name(op->opnum)); + WARN_ON_ONCE(1); + } +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index bf8eacab64952..085191b4b3aa5 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -2419,9 +2419,8 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) + op = &argp->ops[i]; + op->replay = NULL; + +- READ_BUF(4); +- op->opnum = be32_to_cpup(p++); +- ++ if (xdr_stream_decode_u32(argp->xdr, &op->opnum) < 0) ++ return nfserr_bad_xdr; + if (nfsd4_opnum_in_range(argp, op)) { + op->status = nfsd4_dec_ops[op->opnum](argp, &op->u); + if (op->status != nfs_ok) +@@ -5395,7 +5394,7 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) + if (op->status && opdesc && + !(opdesc->op_flags & OP_NONTRIVIAL_ERROR_ENCODE)) + goto status; +- BUG_ON(op->opnum < 0 || op->opnum >= ARRAY_SIZE(nfsd4_enc_ops) || ++ BUG_ON(op->opnum >= ARRAY_SIZE(nfsd4_enc_ops) || + !nfsd4_enc_ops[op->opnum]); + encoder = nfsd4_enc_ops[op->opnum]; + op->status = encoder(resp, op->status, &op->u); +diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h +index facc5762bf831..2c31f3a7d7c74 100644 +--- a/fs/nfsd/xdr4.h ++++ b/fs/nfsd/xdr4.h +@@ -615,7 +615,7 @@ struct nfsd4_copy_notify { + }; + + struct nfsd4_op { +- int opnum; ++ u32 opnum; + const struct nfsd4_operation * opdesc; + __be32 status; + union nfsd4_op_u { +-- +2.43.0 + diff --git a/queue-5.10/nfsd-make-nfsd4_remove-wait-before-returning-nfs4err.patch b/queue-5.10/nfsd-make-nfsd4_remove-wait-before-returning-nfs4err.patch new file mode 100644 index 00000000000..0b2a3d1d906 --- /dev/null +++ b/queue-5.10/nfsd-make-nfsd4_remove-wait-before-returning-nfs4err.patch @@ -0,0 +1,52 @@ +From b3a3ac3401589ea50dc03bdf2df0e450a1dd6b1b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Sep 2022 18:14:25 -0400 +Subject: NFSD: Make nfsd4_remove() wait before returning NFS4ERR_DELAY + +From: Chuck Lever + +[ Upstream commit 5f5f8b6d655fd947e899b1771c2f7cb581a06764 ] + +nfsd_unlink() can kick off a CB_RECALL (via +vfs_unlink() -> leases_conflict()) if a delegation is present. +Before returning NFS4ERR_DELAY, give the client holding that +delegation a chance to return it and then retry the nfsd_unlink() +again, once. + +Link: https://bugzilla.linux-nfs.org/show_bug.cgi?id=354 +Tested-by: Igor Mammedov +Reviewed-by: Jeff Layton +[ cel: backported to 5.10.y, prior to idmapped mounts ] +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/vfs.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index 5684845d95119..e29034b1e6128 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -1803,9 +1803,18 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, + + fh_fill_pre_attrs(fhp); + if (type != S_IFDIR) { ++ int retries; ++ + if (rdentry->d_sb->s_export_op->flags & EXPORT_OP_CLOSE_BEFORE_UNLINK) + nfsd_close_cached_files(rdentry); +- host_err = vfs_unlink(dirp, rdentry, NULL); ++ ++ for (retries = 1;;) { ++ host_err = vfs_unlink(dirp, rdentry, NULL); ++ if (host_err != -EAGAIN || !retries--) ++ break; ++ if (!nfsd_wait_for_delegreturn(rqstp, rinode)) ++ break; ++ } + } else { + host_err = vfs_rmdir(dirp, rdentry); + } +-- +2.43.0 + diff --git a/queue-5.10/nfsd-make-nfsd4_rename-wait-before-returning-nfs4err.patch b/queue-5.10/nfsd-make-nfsd4_rename-wait-before-returning-nfs4err.patch new file mode 100644 index 00000000000..80a7e1ba660 --- /dev/null +++ b/queue-5.10/nfsd-make-nfsd4_rename-wait-before-returning-nfs4err.patch @@ -0,0 +1,53 @@ +From 102cde287ca3151fd09bd8177dadd0606e5a1ead Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Sep 2022 18:14:19 -0400 +Subject: NFSD: Make nfsd4_rename() wait before returning NFS4ERR_DELAY + +From: Chuck Lever + +[ Upstream commit 68c522afd0b1936b48a03a4c8b81261e7597c62d ] + +nfsd_rename() can kick off a CB_RECALL (via +vfs_rename() -> leases_conflict()) if a delegation is present. +Before returning NFS4ERR_DELAY, give the client holding that +delegation a chance to return it and then retry the nfsd_rename() +again, once. + +This version of the patch handles renaming an existing file, +but does not deal with renaming onto an existing file. That +case will still always trigger an NFS4ERR_DELAY. + +Link: https://bugzilla.linux-nfs.org/show_bug.cgi?id=354 +Tested-by: Igor Mammedov +Signed-off-by: Chuck Lever +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/vfs.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index dc79db261d6a2..5684845d95119 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -1711,7 +1711,15 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, + .new_dir = tdir, + .new_dentry = ndentry, + }; +- host_err = vfs_rename(&rd); ++ int retries; ++ ++ for (retries = 1;;) { ++ host_err = vfs_rename(&rd); ++ if (host_err != -EAGAIN || !retries--) ++ break; ++ if (!nfsd_wait_for_delegreturn(rqstp, d_inode(odentry))) ++ break; ++ } + if (!host_err) { + host_err = commit_metadata(tfhp); + if (!host_err) +-- +2.43.0 + diff --git a/queue-5.10/nfsd-make-nfsd4_run_cb-a-bool-return-function.patch b/queue-5.10/nfsd-make-nfsd4_run_cb-a-bool-return-function.patch new file mode 100644 index 00000000000..bc7bb344014 --- /dev/null +++ b/queue-5.10/nfsd-make-nfsd4_run_cb-a-bool-return-function.patch @@ -0,0 +1,96 @@ +From 70f3862779aecba6dfd1383bd6ad8fbe32fc8b8a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Sep 2022 14:41:01 -0400 +Subject: nfsd: make nfsd4_run_cb a bool return function + +From: Jeff Layton + +[ Upstream commit b95239ca4954a0d48b19c09ce7e8f31b453b4216 ] + +queue_work can return false and not queue anything, if the work is +already queued. If that happens in the case of a CB_RECALL, we'll have +taken an extra reference to the stid that will never be put. Ensure we +throw a warning in that case. + +Signed-off-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4callback.c | 14 ++++++++++++-- + fs/nfsd/nfs4state.c | 5 ++--- + fs/nfsd/state.h | 2 +- + 3 files changed, 15 insertions(+), 6 deletions(-) + +diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c +index face8908a40b1..39989c14c8a1e 100644 +--- a/fs/nfsd/nfs4callback.c ++++ b/fs/nfsd/nfs4callback.c +@@ -1373,11 +1373,21 @@ void nfsd4_init_cb(struct nfsd4_callback *cb, struct nfs4_client *clp, + cb->cb_holds_slot = false; + } + +-void nfsd4_run_cb(struct nfsd4_callback *cb) ++/** ++ * nfsd4_run_cb - queue up a callback job to run ++ * @cb: callback to queue ++ * ++ * Kick off a callback to do its thing. Returns false if it was already ++ * on a queue, true otherwise. ++ */ ++bool nfsd4_run_cb(struct nfsd4_callback *cb) + { + struct nfs4_client *clp = cb->cb_clp; ++ bool queued; + + nfsd41_cb_inflight_begin(clp); +- if (!nfsd4_queue_cb(cb)) ++ queued = nfsd4_queue_cb(cb); ++ if (!queued) + nfsd41_cb_inflight_end(clp); ++ return queued; + } +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index e9fc5a357fc4d..fc6188d70796d 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -4874,14 +4874,13 @@ static void nfsd_break_one_deleg(struct nfs4_delegation *dp) + * we know it's safe to take a reference. + */ + refcount_inc(&dp->dl_stid.sc_count); +- nfsd4_run_cb(&dp->dl_recall); ++ WARN_ON_ONCE(!nfsd4_run_cb(&dp->dl_recall)); + } + + /* Called from break_lease() with flc_lock held. */ + static bool + nfsd_break_deleg_cb(struct file_lock *fl) + { +- bool ret = false; + struct nfs4_delegation *dp = (struct nfs4_delegation *)fl->fl_owner; + struct nfs4_file *fp = dp->dl_stid.sc_file; + struct nfs4_client *clp = dp->dl_stid.sc_client; +@@ -4907,7 +4906,7 @@ nfsd_break_deleg_cb(struct file_lock *fl) + fp->fi_had_conflict = true; + nfsd_break_one_deleg(dp); + spin_unlock(&fp->fi_lock); +- return ret; ++ return false; + } + + /** +diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h +index b3477087a9fc3..e2daef3cc0034 100644 +--- a/fs/nfsd/state.h ++++ b/fs/nfsd/state.h +@@ -692,7 +692,7 @@ extern void nfsd4_probe_callback_sync(struct nfs4_client *clp); + extern void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *); + extern void nfsd4_init_cb(struct nfsd4_callback *cb, struct nfs4_client *clp, + const struct nfsd4_callback_ops *ops, enum nfsd4_cb_op op); +-extern void nfsd4_run_cb(struct nfsd4_callback *cb); ++extern bool nfsd4_run_cb(struct nfsd4_callback *cb); + extern int nfsd4_create_callback_queue(void); + extern void nfsd4_destroy_callback_queue(void); + extern void nfsd4_shutdown_callback(struct nfs4_client *); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-make-nfsd4_setattr-wait-before-returning-nfs4er.patch b/queue-5.10/nfsd-make-nfsd4_setattr-wait-before-returning-nfs4er.patch new file mode 100644 index 00000000000..7311982cc57 --- /dev/null +++ b/queue-5.10/nfsd-make-nfsd4_setattr-wait-before-returning-nfs4er.patch @@ -0,0 +1,54 @@ +From 8576b08945891abc687a49a8f1fb6729c2670baf Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Sep 2022 18:14:13 -0400 +Subject: NFSD: Make nfsd4_setattr() wait before returning NFS4ERR_DELAY + +From: Chuck Lever + +[ Upstream commit 34b91dda7124fc3259e4b2ae53e0c933dedfec01 ] + +nfsd_setattr() can kick off a CB_RECALL (via +notify_change() -> break_lease()) if a delegation is present. Before +returning NFS4ERR_DELAY, give the client holding that delegation a +chance to return it and then retry the nfsd_setattr() again, once. + +Link: https://bugzilla.linux-nfs.org/show_bug.cgi?id=354 +Tested-by: Igor Mammedov +Signed-off-by: Chuck Lever +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/vfs.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index e32b0c807ea9d..dc79db261d6a2 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -426,6 +426,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, + int host_err; + bool get_write_count; + bool size_change = (iap->ia_valid & ATTR_SIZE); ++ int retries; + + if (iap->ia_valid & ATTR_SIZE) { + accmode |= NFSD_MAY_WRITE|NFSD_MAY_OWNER_OVERRIDE; +@@ -480,7 +481,13 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, + } + + inode_lock(inode); +- host_err = __nfsd_setattr(dentry, iap); ++ for (retries = 1;;) { ++ host_err = __nfsd_setattr(dentry, iap); ++ if (host_err != -EAGAIN || !retries--) ++ break; ++ if (!nfsd_wait_for_delegreturn(rqstp, inode)) ++ break; ++ } + if (attr->na_seclabel && attr->na_seclabel->len) + attr->na_labelerr = security_inode_setsecctx(dentry, + attr->na_seclabel->data, attr->na_seclabel->len); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-make-nfsd_stats.th_cnt-atomic_t.patch b/queue-5.10/nfsd-make-nfsd_stats.th_cnt-atomic_t.patch new file mode 100644 index 00000000000..64b20d0e078 --- /dev/null +++ b/queue-5.10/nfsd-make-nfsd_stats.th_cnt-atomic_t.patch @@ -0,0 +1,87 @@ +From 8ba0a4c5c7c3e36775a5f0210865404b50d1e3d5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Nov 2021 15:51:25 +1100 +Subject: nfsd: make nfsd_stats.th_cnt atomic_t + +From: NeilBrown + +[ Upstream commit 9b6c8c9bebccd5fb785c306b948c08874a88874d ] + +This allows us to move the updates for th_cnt out of the mutex. +This is a step towards reducing mutex coverage in nfsd(). + +Signed-off-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfssvc.c | 6 +++--- + fs/nfsd/stats.c | 2 +- + fs/nfsd/stats.h | 4 +--- + 3 files changed, 5 insertions(+), 7 deletions(-) + +diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c +index 141d884fee4f4..32f2c46a38323 100644 +--- a/fs/nfsd/nfssvc.c ++++ b/fs/nfsd/nfssvc.c +@@ -57,7 +57,7 @@ static __be32 nfsd_init_request(struct svc_rqst *, + /* + * nfsd_mutex protects nn->nfsd_serv -- both the pointer itself and the members + * of the svc_serv struct. In particular, ->sv_nrthreads but also to some +- * extent ->sv_temp_socks and ->sv_permsocks. It also protects nfsdstats.th_cnt ++ * extent ->sv_temp_socks and ->sv_permsocks. + * + * If (out side the lock) nn->nfsd_serv is non-NULL, then it must point to a + * properly initialised 'struct svc_serv' with ->sv_nrthreads > 0 (unless +@@ -955,8 +955,8 @@ nfsd(void *vrqstp) + allow_signal(SIGINT); + allow_signal(SIGQUIT); + +- nfsdstats.th_cnt++; + mutex_unlock(&nfsd_mutex); ++ atomic_inc(&nfsdstats.th_cnt); + + set_freezable(); + +@@ -983,8 +983,8 @@ nfsd(void *vrqstp) + /* Clear signals before calling svc_exit_thread() */ + flush_signals(current); + ++ atomic_dec(&nfsdstats.th_cnt); + mutex_lock(&nfsd_mutex); +- nfsdstats.th_cnt --; + + out: + /* Take an extra ref so that the svc_put in svc_exit_thread() +diff --git a/fs/nfsd/stats.c b/fs/nfsd/stats.c +index 1d3b881e73821..a8c5a02a84f04 100644 +--- a/fs/nfsd/stats.c ++++ b/fs/nfsd/stats.c +@@ -45,7 +45,7 @@ static int nfsd_proc_show(struct seq_file *seq, void *v) + percpu_counter_sum_positive(&nfsdstats.counter[NFSD_STATS_IO_WRITE])); + + /* thread usage: */ +- seq_printf(seq, "th %u 0", nfsdstats.th_cnt); ++ seq_printf(seq, "th %u 0", atomic_read(&nfsdstats.th_cnt)); + + /* deprecated thread usage histogram stats */ + for (i = 0; i < 10; i++) +diff --git a/fs/nfsd/stats.h b/fs/nfsd/stats.h +index 51ecda852e23b..9b43dc3d99913 100644 +--- a/fs/nfsd/stats.h ++++ b/fs/nfsd/stats.h +@@ -29,11 +29,9 @@ enum { + struct nfsd_stats { + struct percpu_counter counter[NFSD_STATS_COUNTERS_NUM]; + +- /* Protected by nfsd_mutex */ +- unsigned int th_cnt; /* number of available threads */ ++ atomic_t th_cnt; /* number of available threads */ + }; + +- + extern struct nfsd_stats nfsdstats; + + extern struct svc_stat nfsd_svcstats; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-map-ebadf.patch b/queue-5.10/nfsd-map-ebadf.patch new file mode 100644 index 00000000000..b02ae4a0dc5 --- /dev/null +++ b/queue-5.10/nfsd-map-ebadf.patch @@ -0,0 +1,72 @@ +From c076f6ead20e8f9834c4a560bd253d46685fc9c7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 18 Dec 2021 20:37:54 -0500 +Subject: nfsd: map EBADF + +From: Peng Tao + +[ Upstream commit b3d0db706c77d02055910fcfe2f6eb5155ff9d5e ] + +Now that we have open file cache, it is possible that another client +deletes the file and DP will not know about it. Then IO to MDS would +fail with BADSTATEID and knfsd would start state recovery, which +should fail as well and then nfs read/write will fail with EBADF. +And it triggers a WARN() in nfserrno(). + +-----------[ cut here ]------------ +WARNING: CPU: 0 PID: 13529 at fs/nfsd/nfsproc.c:758 nfserrno+0x58/0x70 [nfsd]() +nfsd: non-standard errno: -9 +modules linked in: nfsv3 nfs_layout_flexfiles rpcsec_gss_krb5 nfsv4 dns_resolver nfs fscache ip6t_rpfilter ip6t_REJECT nf_reject_ipv6 xt_connt +pata_acpi floppy +CPU: 0 PID: 13529 Comm: nfsd Tainted: G W 4.1.5-00307-g6e6579b #7 +Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 09/30/2014 + 0000000000000000 00000000464e6c9c ffff88079085fba8 ffffffff81789936 + 0000000000000000 ffff88079085fc00 ffff88079085fbe8 ffffffff810a08ea + ffff88079085fbe8 ffff88080f45c900 ffff88080f627d50 ffff880790c46a48 + all Trace: + [] dump_stack+0x45/0x57 + [] warn_slowpath_common+0x8a/0xc0 + [] warn_slowpath_fmt+0x55/0x70 + [] ? splice_direct_to_actor+0x148/0x230 + [] ? fsid_source+0x60/0x60 [nfsd] + [] nfserrno+0x58/0x70 [nfsd] + [] nfsd_finish_read+0x97/0xb0 [nfsd] + [] nfsd_splice_read+0x76/0xa0 [nfsd] + [] nfsd_read+0xc1/0xd0 [nfsd] + [] ? svc_tcp_adjust_wspace+0x12/0x30 [sunrpc] + [] nfsd3_proc_read+0xba/0x150 [nfsd] + [] nfsd_dispatch+0xc3/0x210 [nfsd] + [] ? svc_tcp_adjust_wspace+0x12/0x30 [sunrpc] + [] svc_process_common+0x453/0x6f0 [sunrpc] + [] svc_process+0x113/0x1b0 [sunrpc] + [] nfsd+0xff/0x170 [nfsd] + [] ? nfsd_destroy+0x80/0x80 [nfsd] + [] kthread+0xd8/0xf0 + [] ? kthread_create_on_node+0x1b0/0x1b0 + [] ret_from_fork+0x42/0x70 + [] ? kthread_create_on_node+0x1b0/0x1b0 + +Signed-off-by: Peng Tao +Signed-off-by: Lance Shelton +Signed-off-by: Trond Myklebust +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsproc.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c +index 0a2bab7ef33c9..de4b97cdbd2bc 100644 +--- a/fs/nfsd/nfsproc.c ++++ b/fs/nfsd/nfsproc.c +@@ -845,6 +845,7 @@ nfserrno (int errno) + { nfserr_io, -EIO }, + { nfserr_nxio, -ENXIO }, + { nfserr_fbig, -E2BIG }, ++ { nfserr_stale, -EBADF }, + { nfserr_acces, -EACCES }, + { nfserr_exist, -EEXIST }, + { nfserr_xdev, -EXDEV }, +-- +2.43.0 + diff --git a/queue-5.10/nfsd-minor-nfsd4_change_attribute-cleanup.patch b/queue-5.10/nfsd-minor-nfsd4_change_attribute-cleanup.patch new file mode 100644 index 00000000000..e732e98e6b0 --- /dev/null +++ b/queue-5.10/nfsd-minor-nfsd4_change_attribute-cleanup.patch @@ -0,0 +1,77 @@ +From 8841a1def8d09900433192ada564a1c73b88408a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Nov 2020 17:46:16 -0500 +Subject: nfsd: minor nfsd4_change_attribute cleanup + +From: J. Bruce Fields + +[ Upstream commit 4b03d99794eeed27650597a886247c6427ce1055 ] + +Minor cleanup, no change in behavior. + +Also pull out a common helper that'll be useful elsewhere. + +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsfh.h | 13 +++++-------- + include/linux/iversion.h | 13 +++++++++++++ + 2 files changed, 18 insertions(+), 8 deletions(-) + +diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h +index 39d764b129fa3..45bd776290d52 100644 +--- a/fs/nfsd/nfsfh.h ++++ b/fs/nfsd/nfsfh.h +@@ -259,19 +259,16 @@ fh_clear_wcc(struct svc_fh *fhp) + static inline u64 nfsd4_change_attribute(struct kstat *stat, + struct inode *inode) + { +- u64 chattr; +- + if (IS_I_VERSION(inode)) { ++ u64 chattr; ++ + chattr = stat->ctime.tv_sec; + chattr <<= 30; + chattr += stat->ctime.tv_nsec; + chattr += inode_query_iversion(inode); +- } else { +- chattr = stat->ctime.tv_sec; +- chattr <<= 32; +- chattr += stat->ctime.tv_nsec; +- } +- return chattr; ++ return chattr; ++ } else ++ return time_to_chattr(&stat->ctime); + } + + extern void fill_pre_wcc(struct svc_fh *fhp); +diff --git a/include/linux/iversion.h b/include/linux/iversion.h +index 2917ef990d435..3bfebde5a1a6d 100644 +--- a/include/linux/iversion.h ++++ b/include/linux/iversion.h +@@ -328,6 +328,19 @@ inode_query_iversion(struct inode *inode) + return cur >> I_VERSION_QUERIED_SHIFT; + } + ++/* ++ * For filesystems without any sort of change attribute, the best we can ++ * do is fake one up from the ctime: ++ */ ++static inline u64 time_to_chattr(struct timespec64 *t) ++{ ++ u64 chattr = t->tv_sec; ++ ++ chattr <<= 32; ++ chattr += t->tv_nsec; ++ return chattr; ++} ++ + /** + * inode_eq_iversion_raw - check whether the raw i_version counter has changed + * @inode: inode to check +-- +2.43.0 + diff --git a/queue-5.10/nfsd-modernize-nfsd4_release_lockowner.patch b/queue-5.10/nfsd-modernize-nfsd4_release_lockowner.patch new file mode 100644 index 00000000000..b43a7df0e68 --- /dev/null +++ b/queue-5.10/nfsd-modernize-nfsd4_release_lockowner.patch @@ -0,0 +1,85 @@ +From 6d6c53387e7fed92f3a0b86ae3d1372083bf13ab Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 22 May 2022 12:07:18 -0400 +Subject: NFSD: Modernize nfsd4_release_lockowner() + +From: Chuck Lever + +[ Upstream commit bd8fdb6e545f950f4654a9a10d7e819ad48146e5 ] + +Refactor: Use existing helpers that other lock operations use. This +change removes several automatic variables, so re-organize the +variable declarations for readability. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 36 +++++++++++------------------------- + 1 file changed, 11 insertions(+), 25 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index e0ce0412d7dea..1c32765e86b1f 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -7562,16 +7562,13 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, + union nfsd4_op_u *u) + { + struct nfsd4_release_lockowner *rlockowner = &u->release_lockowner; ++ struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); + clientid_t *clid = &rlockowner->rl_clientid; +- struct nfs4_stateowner *sop; +- struct nfs4_lockowner *lo = NULL; + struct nfs4_ol_stateid *stp; +- struct xdr_netobj *owner = &rlockowner->rl_owner; +- unsigned int hashval = ownerstr_hashval(owner); +- __be32 status; +- struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); ++ struct nfs4_lockowner *lo; + struct nfs4_client *clp; +- LIST_HEAD (reaplist); ++ LIST_HEAD(reaplist); ++ __be32 status; + + dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n", + clid->cl_boot, clid->cl_id); +@@ -7579,30 +7576,19 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, + status = set_client(clid, cstate, nn); + if (status) + return status; +- + clp = cstate->clp; +- /* Find the matching lock stateowner */ +- spin_lock(&clp->cl_lock); +- list_for_each_entry(sop, &clp->cl_ownerstr_hashtbl[hashval], +- so_strhash) { + +- if (sop->so_is_open_owner || !same_owner_str(sop, owner)) +- continue; +- +- if (atomic_read(&sop->so_count) != 1) { +- spin_unlock(&clp->cl_lock); +- return nfserr_locks_held; +- } +- +- lo = lockowner(sop); +- nfs4_get_stateowner(sop); +- break; +- } ++ spin_lock(&clp->cl_lock); ++ lo = find_lockowner_str_locked(clp, &rlockowner->rl_owner); + if (!lo) { + spin_unlock(&clp->cl_lock); + return status; + } +- ++ if (atomic_read(&lo->lo_owner.so_count) != 2) { ++ spin_unlock(&clp->cl_lock); ++ nfs4_put_stateowner(&lo->lo_owner); ++ return nfserr_locks_held; ++ } + unhash_lockowner_locked(lo); + while (!list_empty(&lo->lo_owner.so_stateids)) { + stp = list_first_entry(&lo->lo_owner.so_stateids, +-- +2.43.0 + diff --git a/queue-5.10/nfsd-move-copy-offload-callback-arguments-into-a-sep.patch b/queue-5.10/nfsd-move-copy-offload-callback-arguments-into-a-sep.patch new file mode 100644 index 00000000000..31fdca47725 --- /dev/null +++ b/queue-5.10/nfsd-move-copy-offload-callback-arguments-into-a-sep.patch @@ -0,0 +1,233 @@ +From 8fd7a92cdbc78fcdc0854ccbff824db96f025f2f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 Jul 2022 14:41:18 -0400 +Subject: NFSD: Move copy offload callback arguments into a separate structure + +From: Chuck Lever + +[ Upstream commit a11ada99ce93a79393dc6683d22f7915748c8f6b ] + +Refactor so that CB_OFFLOAD arguments can be passed without +allocating a whole struct nfsd4_copy object. On my system (x86_64) +this removes another 96 bytes from struct nfsd4_copy. + +[ cel: adjusted to apply to v5.10.y ] +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4callback.c | 37 +++++++++++++++++------------------ + fs/nfsd/nfs4proc.c | 44 +++++++++++++++++++++--------------------- + fs/nfsd/xdr4.h | 11 +++++++---- + 3 files changed, 47 insertions(+), 45 deletions(-) + +diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c +index e1272a7f45220..face8908a40b1 100644 +--- a/fs/nfsd/nfs4callback.c ++++ b/fs/nfsd/nfs4callback.c +@@ -679,7 +679,7 @@ static int nfs4_xdr_dec_cb_notify_lock(struct rpc_rqst *rqstp, + * case NFS4_OK: + * write_response4 coa_resok4; + * default: +- * length4 coa_bytes_copied; ++ * length4 coa_bytes_copied; + * }; + * struct CB_OFFLOAD4args { + * nfs_fh4 coa_fh; +@@ -688,21 +688,22 @@ static int nfs4_xdr_dec_cb_notify_lock(struct rpc_rqst *rqstp, + * }; + */ + static void encode_offload_info4(struct xdr_stream *xdr, +- __be32 nfserr, +- const struct nfsd4_copy *cp) ++ const struct nfsd4_cb_offload *cbo) + { + __be32 *p; + + p = xdr_reserve_space(xdr, 4); +- *p++ = nfserr; +- if (!nfserr) { ++ *p = cbo->co_nfserr; ++ switch (cbo->co_nfserr) { ++ case nfs_ok: + p = xdr_reserve_space(xdr, 4 + 8 + 4 + NFS4_VERIFIER_SIZE); + p = xdr_encode_empty_array(p); +- p = xdr_encode_hyper(p, cp->cp_res.wr_bytes_written); +- *p++ = cpu_to_be32(cp->cp_res.wr_stable_how); +- p = xdr_encode_opaque_fixed(p, cp->cp_res.wr_verifier.data, ++ p = xdr_encode_hyper(p, cbo->co_res.wr_bytes_written); ++ *p++ = cpu_to_be32(cbo->co_res.wr_stable_how); ++ p = xdr_encode_opaque_fixed(p, cbo->co_res.wr_verifier.data, + NFS4_VERIFIER_SIZE); +- } else { ++ break; ++ default: + p = xdr_reserve_space(xdr, 8); + /* We always return success if bytes were written */ + p = xdr_encode_hyper(p, 0); +@@ -710,18 +711,16 @@ static void encode_offload_info4(struct xdr_stream *xdr, + } + + static void encode_cb_offload4args(struct xdr_stream *xdr, +- __be32 nfserr, +- const struct knfsd_fh *fh, +- const struct nfsd4_copy *cp, ++ const struct nfsd4_cb_offload *cbo, + struct nfs4_cb_compound_hdr *hdr) + { + __be32 *p; + + p = xdr_reserve_space(xdr, 4); +- *p++ = cpu_to_be32(OP_CB_OFFLOAD); +- encode_nfs_fh4(xdr, fh); +- encode_stateid4(xdr, &cp->cp_res.cb_stateid); +- encode_offload_info4(xdr, nfserr, cp); ++ *p = cpu_to_be32(OP_CB_OFFLOAD); ++ encode_nfs_fh4(xdr, &cbo->co_fh); ++ encode_stateid4(xdr, &cbo->co_res.cb_stateid); ++ encode_offload_info4(xdr, cbo); + + hdr->nops++; + } +@@ -731,8 +730,8 @@ static void nfs4_xdr_enc_cb_offload(struct rpc_rqst *req, + const void *data) + { + const struct nfsd4_callback *cb = data; +- const struct nfsd4_copy *cp = +- container_of(cb, struct nfsd4_copy, cp_cb); ++ const struct nfsd4_cb_offload *cbo = ++ container_of(cb, struct nfsd4_cb_offload, co_cb); + struct nfs4_cb_compound_hdr hdr = { + .ident = 0, + .minorversion = cb->cb_clp->cl_minorversion, +@@ -740,7 +739,7 @@ static void nfs4_xdr_enc_cb_offload(struct rpc_rqst *req, + + encode_cb_compound4args(xdr, &hdr); + encode_cb_sequence4args(xdr, cb, &hdr); +- encode_cb_offload4args(xdr, cp->nfserr, &cp->fh, cp, &hdr); ++ encode_cb_offload4args(xdr, cbo, &hdr); + encode_cb_nops(&hdr); + } + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 332fd1d0b188d..fdde7eca8d438 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -1635,9 +1635,10 @@ nfsd4_cleanup_intra_ssc(struct nfsd_file *src, struct nfsd_file *dst) + + static void nfsd4_cb_offload_release(struct nfsd4_callback *cb) + { +- struct nfsd4_copy *copy = container_of(cb, struct nfsd4_copy, cp_cb); ++ struct nfsd4_cb_offload *cbo = ++ container_of(cb, struct nfsd4_cb_offload, co_cb); + +- nfs4_put_copy(copy); ++ kfree(cbo); + } + + static int nfsd4_cb_offload_done(struct nfsd4_callback *cb, +@@ -1753,25 +1754,23 @@ static void cleanup_async_copy(struct nfsd4_copy *copy) + nfs4_put_copy(copy); + } + +-static void nfsd4_send_cb_offload(struct nfsd4_copy *copy) ++static void nfsd4_send_cb_offload(struct nfsd4_copy *copy, __be32 nfserr) + { +- struct nfsd4_copy *cb_copy; ++ struct nfsd4_cb_offload *cbo; + +- cb_copy = kzalloc(sizeof(struct nfsd4_copy), GFP_KERNEL); +- if (!cb_copy) ++ cbo = kzalloc(sizeof(*cbo), GFP_KERNEL); ++ if (!cbo) + return; + +- refcount_set(&cb_copy->refcount, 1); +- memcpy(&cb_copy->cp_res, ©->cp_res, sizeof(copy->cp_res)); +- cb_copy->cp_clp = copy->cp_clp; +- cb_copy->nfserr = copy->nfserr; +- memcpy(&cb_copy->fh, ©->fh, sizeof(copy->fh)); ++ memcpy(&cbo->co_res, ©->cp_res, sizeof(copy->cp_res)); ++ memcpy(&cbo->co_fh, ©->fh, sizeof(copy->fh)); ++ cbo->co_nfserr = nfserr; + +- nfsd4_init_cb(&cb_copy->cp_cb, cb_copy->cp_clp, +- &nfsd4_cb_offload_ops, NFSPROC4_CLNT_CB_OFFLOAD); +- trace_nfsd_cb_offload(copy->cp_clp, ©->cp_res.cb_stateid, +- ©->fh, copy->cp_count, copy->nfserr); +- nfsd4_run_cb(&cb_copy->cp_cb); ++ nfsd4_init_cb(&cbo->co_cb, copy->cp_clp, &nfsd4_cb_offload_ops, ++ NFSPROC4_CLNT_CB_OFFLOAD); ++ trace_nfsd_cb_offload(copy->cp_clp, &cbo->co_res.cb_stateid, ++ &cbo->co_fh, copy->cp_count, nfserr); ++ nfsd4_run_cb(&cbo->co_cb); + } + + /** +@@ -1784,6 +1783,7 @@ static void nfsd4_send_cb_offload(struct nfsd4_copy *copy) + static int nfsd4_do_async_copy(void *data) + { + struct nfsd4_copy *copy = (struct nfsd4_copy *)data; ++ __be32 nfserr; + + if (nfsd4_ssc_is_inter(copy)) { + struct file *filp; +@@ -1791,21 +1791,21 @@ static int nfsd4_do_async_copy(void *data) + filp = nfs42_ssc_open(copy->ss_mnt, ©->c_fh, + ©->stateid); + if (IS_ERR(filp)) { +- copy->nfserr = nfserr_offload_denied; ++ nfserr = nfserr_offload_denied; + /* ss_mnt will be unmounted by the laundromat */ + goto do_callback; + } +- copy->nfserr = nfsd4_do_copy(copy, filp, +- copy->nf_dst->nf_file, false); ++ nfserr = nfsd4_do_copy(copy, filp, copy->nf_dst->nf_file, ++ false); + nfsd4_cleanup_inter_ssc(copy->ss_mnt, filp, copy->nf_dst); + } else { +- copy->nfserr = nfsd4_do_copy(copy, copy->nf_src->nf_file, +- copy->nf_dst->nf_file, false); ++ nfserr = nfsd4_do_copy(copy, copy->nf_src->nf_file, ++ copy->nf_dst->nf_file, false); + nfsd4_cleanup_intra_ssc(copy->nf_src, copy->nf_dst); + } + + do_callback: +- nfsd4_send_cb_offload(copy); ++ nfsd4_send_cb_offload(copy, nfserr); + cleanup_async_copy(copy); + return 0; + } +diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h +index 1f6ac92bcf856..3b9e60249aea9 100644 +--- a/fs/nfsd/xdr4.h ++++ b/fs/nfsd/xdr4.h +@@ -533,6 +533,13 @@ struct nfsd42_write_res { + stateid_t cb_stateid; + }; + ++struct nfsd4_cb_offload { ++ struct nfsd4_callback co_cb; ++ struct nfsd42_write_res co_res; ++ __be32 co_nfserr; ++ struct knfsd_fh co_fh; ++}; ++ + struct nfsd4_copy { + /* request */ + stateid_t cp_src_stateid; +@@ -550,10 +557,6 @@ struct nfsd4_copy { + + /* response */ + struct nfsd42_write_res cp_res; +- +- /* for cb_offload */ +- struct nfsd4_callback cp_cb; +- __be32 nfserr; + struct knfsd_fh fh; + + struct nfs4_client *cp_clp; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-move-create-destroy-of-laundry_wq-to-init_nfsd-.patch b/queue-5.10/nfsd-move-create-destroy-of-laundry_wq-to-init_nfsd-.patch new file mode 100644 index 00000000000..8ef15c46fc8 --- /dev/null +++ b/queue-5.10/nfsd-move-create-destroy-of-laundry_wq-to-init_nfsd-.patch @@ -0,0 +1,129 @@ +From bdb7598acc8b650c62629b60de51dfcc03f9791c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 May 2022 14:19:23 -0700 +Subject: NFSD: move create/destroy of laundry_wq to init_nfsd and exit_nfsd + +From: Dai Ngo + +[ Upstream commit d76cc46b37e123e8d245cc3490978dbda56f979d ] + +This patch moves create/destroy of laundry_wq from nfs4_state_start +and nfs4_state_shutdown_net to init_nfsd and exit_nfsd to prevent +the laundromat from being freed while a thread is processing a +conflicting lock. + +Reviewed-by: J. Bruce Fields +Signed-off-by: Dai Ngo +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 28 ++++++++++++++++------------ + fs/nfsd/nfsctl.c | 4 ++++ + fs/nfsd/nfsd.h | 4 ++++ + 3 files changed, 24 insertions(+), 12 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 4ba0a70d8990f..30ea1c7b6b9fd 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -127,6 +127,21 @@ static const struct nfsd4_callback_ops nfsd4_cb_notify_lock_ops; + + static struct workqueue_struct *laundry_wq; + ++int nfsd4_create_laundry_wq(void) ++{ ++ int rc = 0; ++ ++ laundry_wq = alloc_workqueue("%s", WQ_UNBOUND, 0, "nfsd4"); ++ if (laundry_wq == NULL) ++ rc = -ENOMEM; ++ return rc; ++} ++ ++void nfsd4_destroy_laundry_wq(void) ++{ ++ destroy_workqueue(laundry_wq); ++} ++ + static bool is_session_dead(struct nfsd4_session *ses) + { + return ses->se_flags & NFS4_SESSION_DEAD; +@@ -7775,22 +7790,12 @@ nfs4_state_start(void) + { + int ret; + +- laundry_wq = alloc_workqueue("%s", WQ_UNBOUND, 0, "nfsd4"); +- if (laundry_wq == NULL) { +- ret = -ENOMEM; +- goto out; +- } + ret = nfsd4_create_callback_queue(); + if (ret) +- goto out_free_laundry; ++ return ret; + + set_max_delegations(); + return 0; +- +-out_free_laundry: +- destroy_workqueue(laundry_wq); +-out: +- return ret; + } + + void +@@ -7827,7 +7832,6 @@ nfs4_state_shutdown_net(struct net *net) + void + nfs4_state_shutdown(void) + { +- destroy_workqueue(laundry_wq); + nfsd4_destroy_callback_queue(); + } + +diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c +index 16920e4512bde..322a208878f2c 100644 +--- a/fs/nfsd/nfsctl.c ++++ b/fs/nfsd/nfsctl.c +@@ -1542,6 +1542,9 @@ static int __init init_nfsd(void) + if (retval < 0) + goto out_free_filesystem; + retval = register_cld_notifier(); ++ if (retval) ++ goto out_free_all; ++ retval = nfsd4_create_laundry_wq(); + if (retval) + goto out_free_all; + return 0; +@@ -1566,6 +1569,7 @@ static int __init init_nfsd(void) + + static void __exit exit_nfsd(void) + { ++ nfsd4_destroy_laundry_wq(); + unregister_cld_notifier(); + unregister_pernet_subsys(&nfsd_net_ops); + nfsd_drc_slab_free(); +diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h +index 23996c6ca75e3..847b482155ae9 100644 +--- a/fs/nfsd/nfsd.h ++++ b/fs/nfsd/nfsd.h +@@ -162,6 +162,8 @@ void nfs4_state_shutdown_net(struct net *net); + int nfs4_reset_recoverydir(char *recdir); + char * nfs4_recoverydir(void); + bool nfsd4_spo_must_allow(struct svc_rqst *rqstp); ++int nfsd4_create_laundry_wq(void); ++void nfsd4_destroy_laundry_wq(void); + #else + static inline int nfsd4_init_slabs(void) { return 0; } + static inline void nfsd4_free_slabs(void) { } +@@ -175,6 +177,8 @@ static inline bool nfsd4_spo_must_allow(struct svc_rqst *rqstp) + { + return false; + } ++static inline int nfsd4_create_laundry_wq(void) { return 0; }; ++static inline void nfsd4_destroy_laundry_wq(void) {}; + #endif + + /* +-- +2.43.0 + diff --git a/queue-5.10/nfsd-move-documenting-comment-for-nfsd4_process_open.patch b/queue-5.10/nfsd-move-documenting-comment-for-nfsd4_process_open.patch new file mode 100644 index 00000000000..ec30bc537cd --- /dev/null +++ b/queue-5.10/nfsd-move-documenting-comment-for-nfsd4_process_open.patch @@ -0,0 +1,63 @@ +From de8cfa81919760315af08d23e49ec6e398fe4f92 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 23 Mar 2022 13:55:37 -0400 +Subject: NFSD: Move documenting comment for nfsd4_process_open2() + +From: Chuck Lever + +[ Upstream commit 7e2ce0cc15a509b859199235a2bad9cece00f67a ] + +Clean up nfsd4_open() by converting a large comment at the only +call site for nfsd4_process_open2() to a kerneldoc comment in +front of that function. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 6 +----- + fs/nfsd/nfs4state.c | 12 ++++++++++++ + 2 files changed, 13 insertions(+), 5 deletions(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 90a12ccf96713..d62d962ed2f13 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -628,11 +628,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + status = nfserr_inval; + goto out; + } +- /* +- * nfsd4_process_open2() does the actual opening of the file. If +- * successful, it (1) truncates the file if open->op_truncate was +- * set, (2) sets open->op_stateid, (3) sets open->op_delegation. +- */ ++ + status = nfsd4_process_open2(rqstp, resfh, open); + WARN(status && open->op_created, + "nfsd4_process_open2 failed to open newly-created file! status=%u\n", +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 9f972ca09eec7..e0ce0412d7dea 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -5465,6 +5465,18 @@ static void nfsd4_deleg_xgrade_none_ext(struct nfsd4_open *open, + */ + } + ++/** ++ * nfsd4_process_open2 - finish open processing ++ * @rqstp: the RPC transaction being executed ++ * @current_fh: NFSv4 COMPOUND's current filehandle ++ * @open: OPEN arguments ++ * ++ * If successful, (1) truncate the file if open->op_truncate was ++ * set, (2) set open->op_stateid, (3) set open->op_delegation. ++ * ++ * Returns %nfs_ok on success; otherwise an nfs4stat value in ++ * network byte order is returned. ++ */ + __be32 + nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open) + { +-- +2.43.0 + diff --git a/queue-5.10/nfsd-move-filehandle-format-declarations-out-of-uapi.patch b/queue-5.10/nfsd-move-filehandle-format-declarations-out-of-uapi.patch new file mode 100644 index 00000000000..b6c826c4c9b --- /dev/null +++ b/queue-5.10/nfsd-move-filehandle-format-declarations-out-of-uapi.patch @@ -0,0 +1,292 @@ +From ba0b086f054cb6645b3f75062feb4e97159cc0d3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Sep 2021 11:14:47 +1000 +Subject: NFSD: move filehandle format declarations out of "uapi". + +From: NeilBrown + +[ Upstream commit ef5825e3cf0d0af657f5fb4dd86d750ed42fee0a ] + +A small part of the declaration concerning filehandle format are +currently in the "uapi" include directory: + include/uapi/linux/nfsd/nfsfh.h + +There is a lot more to the filehandle format, including "enum fid_type" +and "enum nfsd_fsid" which are not exported via "uapi". + +This small part of the filehandle definition is of minimal use outside +of the kernel, and I can find no evidence that an other code is using +it. Certainly nfs-utils and wireshark (The most likely candidates) do not +use these declarations. + +So move it out of "uapi" by copying the content from + include/uapi/linux/nfsd/nfsfh.h +into + fs/nfsd/nfsfh.h + +A few unnecessary "#include" directives are not copied, and neither is +the #define of fh_auth, which is annotated as being for userspace only. + +The copyright claims in the uapi file are identical to those in the nfsd +file, so there is no need to copy those. + +The "__u32" style integer types are only needed in "uapi". In +kernel-only code we can use the more familiar "u32" style. + +Signed-off-by: NeilBrown +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsfh.h | 97 ++++++++++++++++++++++++++- + fs/nfsd/vfs.c | 1 + + include/uapi/linux/nfsd/nfsfh.h | 115 -------------------------------- + 3 files changed, 97 insertions(+), 116 deletions(-) + delete mode 100644 include/uapi/linux/nfsd/nfsfh.h + +diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h +index 6106697adc04b..ad47f16676a8c 100644 +--- a/fs/nfsd/nfsfh.h ++++ b/fs/nfsd/nfsfh.h +@@ -10,9 +10,104 @@ + + #include + #include +-#include + #include + #include ++#include ++ ++ ++/* ++ * This is the old "dentry style" Linux NFSv2 file handle. ++ * ++ * The xino and xdev fields are currently used to transport the ++ * ino/dev of the exported inode. ++ */ ++struct nfs_fhbase_old { ++ u32 fb_dcookie; /* dentry cookie - always 0xfeebbaca */ ++ u32 fb_ino; /* our inode number */ ++ u32 fb_dirino; /* dir inode number, 0 for directories */ ++ u32 fb_dev; /* our device */ ++ u32 fb_xdev; ++ u32 fb_xino; ++ u32 fb_generation; ++}; ++ ++/* ++ * This is the new flexible, extensible style NFSv2/v3/v4 file handle. ++ * ++ * The file handle starts with a sequence of four-byte words. ++ * The first word contains a version number (1) and three descriptor bytes ++ * that tell how the remaining 3 variable length fields should be handled. ++ * These three bytes are auth_type, fsid_type and fileid_type. ++ * ++ * All four-byte values are in host-byte-order. ++ * ++ * The auth_type field is deprecated and must be set to 0. ++ * ++ * The fsid_type identifies how the filesystem (or export point) is ++ * encoded. ++ * Current values: ++ * 0 - 4 byte device id (ms-2-bytes major, ls-2-bytes minor), 4byte inode number ++ * NOTE: we cannot use the kdev_t device id value, because kdev_t.h ++ * says we mustn't. We must break it up and reassemble. ++ * 1 - 4 byte user specified identifier ++ * 2 - 4 byte major, 4 byte minor, 4 byte inode number - DEPRECATED ++ * 3 - 4 byte device id, encoded for user-space, 4 byte inode number ++ * 4 - 4 byte inode number and 4 byte uuid ++ * 5 - 8 byte uuid ++ * 6 - 16 byte uuid ++ * 7 - 8 byte inode number and 16 byte uuid ++ * ++ * The fileid_type identified how the file within the filesystem is encoded. ++ * The values for this field are filesystem specific, exccept that ++ * filesystems must not use the values '0' or '0xff'. 'See enum fid_type' ++ * in include/linux/exportfs.h for currently registered values. ++ */ ++struct nfs_fhbase_new { ++ union { ++ struct { ++ u8 fb_version_aux; /* == 1, even => nfs_fhbase_old */ ++ u8 fb_auth_type_aux; ++ u8 fb_fsid_type_aux; ++ u8 fb_fileid_type_aux; ++ u32 fb_auth[1]; ++ /* u32 fb_fsid[0]; floating */ ++ /* u32 fb_fileid[0]; floating */ ++ }; ++ struct { ++ u8 fb_version; /* == 1, even => nfs_fhbase_old */ ++ u8 fb_auth_type; ++ u8 fb_fsid_type; ++ u8 fb_fileid_type; ++ u32 fb_auth_flex[]; /* flexible-array member */ ++ }; ++ }; ++}; ++ ++struct knfsd_fh { ++ unsigned int fh_size; /* significant for NFSv3. ++ * Points to the current size while building ++ * a new file handle ++ */ ++ union { ++ struct nfs_fhbase_old fh_old; ++ u32 fh_pad[NFS4_FHSIZE/4]; ++ struct nfs_fhbase_new fh_new; ++ } fh_base; ++}; ++ ++#define ofh_dcookie fh_base.fh_old.fb_dcookie ++#define ofh_ino fh_base.fh_old.fb_ino ++#define ofh_dirino fh_base.fh_old.fb_dirino ++#define ofh_dev fh_base.fh_old.fb_dev ++#define ofh_xdev fh_base.fh_old.fb_xdev ++#define ofh_xino fh_base.fh_old.fb_xino ++#define ofh_generation fh_base.fh_old.fb_generation ++ ++#define fh_version fh_base.fh_new.fb_version ++#define fh_fsid_type fh_base.fh_new.fb_fsid_type ++#define fh_auth_type fh_base.fh_new.fb_auth_type ++#define fh_fileid_type fh_base.fh_new.fb_fileid_type ++#define fh_fsid fh_base.fh_new.fb_auth_flex + + static inline __u32 ino_t_to_u32(ino_t ino) + { +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index 2c493937dd5ec..05b5f7e241e70 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -244,6 +244,7 @@ nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp, + * returned. Otherwise the covered directory is returned. + * NOTE: this mountpoint crossing is not supported properly by all + * clients and is explicitly disallowed for NFSv3 ++ * NeilBrown + */ + __be32 + nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, +diff --git a/include/uapi/linux/nfsd/nfsfh.h b/include/uapi/linux/nfsd/nfsfh.h +deleted file mode 100644 +index e29e8accc4f4d..0000000000000 +--- a/include/uapi/linux/nfsd/nfsfh.h ++++ /dev/null +@@ -1,115 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +-/* +- * This file describes the layout of the file handles as passed +- * over the wire. +- * +- * Copyright (C) 1995, 1996, 1997 Olaf Kirch +- */ +- +-#ifndef _UAPI_LINUX_NFSD_FH_H +-#define _UAPI_LINUX_NFSD_FH_H +- +-#include +-#include +-#include +-#include +-#include +- +-/* +- * This is the old "dentry style" Linux NFSv2 file handle. +- * +- * The xino and xdev fields are currently used to transport the +- * ino/dev of the exported inode. +- */ +-struct nfs_fhbase_old { +- __u32 fb_dcookie; /* dentry cookie - always 0xfeebbaca */ +- __u32 fb_ino; /* our inode number */ +- __u32 fb_dirino; /* dir inode number, 0 for directories */ +- __u32 fb_dev; /* our device */ +- __u32 fb_xdev; +- __u32 fb_xino; +- __u32 fb_generation; +-}; +- +-/* +- * This is the new flexible, extensible style NFSv2/v3/v4 file handle. +- * +- * The file handle starts with a sequence of four-byte words. +- * The first word contains a version number (1) and three descriptor bytes +- * that tell how the remaining 3 variable length fields should be handled. +- * These three bytes are auth_type, fsid_type and fileid_type. +- * +- * All four-byte values are in host-byte-order. +- * +- * The auth_type field is deprecated and must be set to 0. +- * +- * The fsid_type identifies how the filesystem (or export point) is +- * encoded. +- * Current values: +- * 0 - 4 byte device id (ms-2-bytes major, ls-2-bytes minor), 4byte inode number +- * NOTE: we cannot use the kdev_t device id value, because kdev_t.h +- * says we mustn't. We must break it up and reassemble. +- * 1 - 4 byte user specified identifier +- * 2 - 4 byte major, 4 byte minor, 4 byte inode number - DEPRECATED +- * 3 - 4 byte device id, encoded for user-space, 4 byte inode number +- * 4 - 4 byte inode number and 4 byte uuid +- * 5 - 8 byte uuid +- * 6 - 16 byte uuid +- * 7 - 8 byte inode number and 16 byte uuid +- * +- * The fileid_type identified how the file within the filesystem is encoded. +- * The values for this field are filesystem specific, exccept that +- * filesystems must not use the values '0' or '0xff'. 'See enum fid_type' +- * in include/linux/exportfs.h for currently registered values. +- */ +-struct nfs_fhbase_new { +- union { +- struct { +- __u8 fb_version_aux; /* == 1, even => nfs_fhbase_old */ +- __u8 fb_auth_type_aux; +- __u8 fb_fsid_type_aux; +- __u8 fb_fileid_type_aux; +- __u32 fb_auth[1]; +- /* __u32 fb_fsid[0]; floating */ +- /* __u32 fb_fileid[0]; floating */ +- }; +- struct { +- __u8 fb_version; /* == 1, even => nfs_fhbase_old */ +- __u8 fb_auth_type; +- __u8 fb_fsid_type; +- __u8 fb_fileid_type; +- __u32 fb_auth_flex[]; /* flexible-array member */ +- }; +- }; +-}; +- +-struct knfsd_fh { +- unsigned int fh_size; /* significant for NFSv3. +- * Points to the current size while building +- * a new file handle +- */ +- union { +- struct nfs_fhbase_old fh_old; +- __u32 fh_pad[NFS4_FHSIZE/4]; +- struct nfs_fhbase_new fh_new; +- } fh_base; +-}; +- +-#define ofh_dcookie fh_base.fh_old.fb_dcookie +-#define ofh_ino fh_base.fh_old.fb_ino +-#define ofh_dirino fh_base.fh_old.fb_dirino +-#define ofh_dev fh_base.fh_old.fb_dev +-#define ofh_xdev fh_base.fh_old.fb_xdev +-#define ofh_xino fh_base.fh_old.fb_xino +-#define ofh_generation fh_base.fh_old.fb_generation +- +-#define fh_version fh_base.fh_new.fb_version +-#define fh_fsid_type fh_base.fh_new.fb_fsid_type +-#define fh_auth_type fh_base.fh_new.fb_auth_type +-#define fh_fileid_type fh_base.fh_new.fb_fileid_type +-#define fh_fsid fh_base.fh_new.fb_auth_flex +- +-/* Do not use, provided for userspace compatiblity. */ +-#define fh_auth fh_base.fh_new.fb_auth +- +-#endif /* _UAPI_LINUX_NFSD_FH_H */ +-- +2.43.0 + diff --git a/queue-5.10/nfsd-move-fill_pre_wcc-and-fill_post_wcc.patch b/queue-5.10/nfsd-move-fill_pre_wcc-and-fill_post_wcc.patch new file mode 100644 index 00000000000..8667ba6c111 --- /dev/null +++ b/queue-5.10/nfsd-move-fill_pre_wcc-and-fill_post_wcc.patch @@ -0,0 +1,290 @@ +From c17ed4cb6938896139629d48d40fc2b47b34436e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Dec 2021 14:36:49 -0500 +Subject: NFSD: Move fill_pre_wcc() and fill_post_wcc() + +From: Chuck Lever + +[ Upstream commit fcb5e3fa012351f3b96024c07bc44834c2478213 ] + +These functions are related to file handle processing and have +nothing to do with XDR encoding or decoding. Also they are no longer +NFSv3-specific. As a clean-up, move their definitions to a more +appropriate location. WCC is also an NFSv3-specific term, so rename +them as general-purpose helpers. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3xdr.c | 55 -------------------------------------- + fs/nfsd/nfs4proc.c | 2 +- + fs/nfsd/nfsfh.c | 66 +++++++++++++++++++++++++++++++++++++++++++++- + fs/nfsd/nfsfh.h | 40 ++++++++++++++++++---------- + fs/nfsd/vfs.c | 8 +++--- + 5 files changed, 96 insertions(+), 75 deletions(-) + +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index 84088581bbe09..7c45ba4db61be 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -487,61 +487,6 @@ svcxdr_encode_wcc_data(struct svc_rqst *rqstp, struct xdr_stream *xdr, + return true; + } + +-/* +- * Fill in the pre_op attr for the wcc data +- */ +-void fill_pre_wcc(struct svc_fh *fhp) +-{ +- struct inode *inode; +- struct kstat stat; +- bool v4 = (fhp->fh_maxsize == NFS4_FHSIZE); +- __be32 err; +- +- if (fhp->fh_no_wcc || fhp->fh_pre_saved) +- return; +- inode = d_inode(fhp->fh_dentry); +- err = fh_getattr(fhp, &stat); +- if (err) { +- /* Grab the times from inode anyway */ +- stat.mtime = inode->i_mtime; +- stat.ctime = inode->i_ctime; +- stat.size = inode->i_size; +- } +- if (v4) +- fhp->fh_pre_change = nfsd4_change_attribute(&stat, inode); +- +- fhp->fh_pre_mtime = stat.mtime; +- fhp->fh_pre_ctime = stat.ctime; +- fhp->fh_pre_size = stat.size; +- fhp->fh_pre_saved = true; +-} +- +-/* +- * Fill in the post_op attr for the wcc data +- */ +-void fill_post_wcc(struct svc_fh *fhp) +-{ +- bool v4 = (fhp->fh_maxsize == NFS4_FHSIZE); +- struct inode *inode = d_inode(fhp->fh_dentry); +- __be32 err; +- +- if (fhp->fh_no_wcc) +- return; +- +- if (fhp->fh_post_saved) +- printk("nfsd: inode locked twice during operation.\n"); +- +- err = fh_getattr(fhp, &fhp->fh_post_attr); +- if (err) { +- fhp->fh_post_saved = false; +- fhp->fh_post_attr.ctime = inode->i_ctime; +- } else +- fhp->fh_post_saved = true; +- if (v4) +- fhp->fh_post_change = +- nfsd4_change_attribute(&fhp->fh_post_attr, inode); +-} +- + /* + * XDR decode functions + */ +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index e8ffaa7faced9..451190813302e 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -2523,7 +2523,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp) + goto encode_op; + } + +- fh_clear_wcc(current_fh); ++ fh_clear_pre_post_attrs(current_fh); + + /* If op is non-idempotent */ + if (op->opdesc->op_flags & OP_MODIFIES_SOMETHING) { +diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c +index 34e201b6eb623..3b9751555f8f2 100644 +--- a/fs/nfsd/nfsfh.c ++++ b/fs/nfsd/nfsfh.c +@@ -610,6 +610,70 @@ fh_update(struct svc_fh *fhp) + return nfserr_serverfault; + } + ++#ifdef CONFIG_NFSD_V3 ++ ++/** ++ * fh_fill_pre_attrs - Fill in pre-op attributes ++ * @fhp: file handle to be updated ++ * ++ */ ++void fh_fill_pre_attrs(struct svc_fh *fhp) ++{ ++ bool v4 = (fhp->fh_maxsize == NFS4_FHSIZE); ++ struct inode *inode; ++ struct kstat stat; ++ __be32 err; ++ ++ if (fhp->fh_no_wcc || fhp->fh_pre_saved) ++ return; ++ ++ inode = d_inode(fhp->fh_dentry); ++ err = fh_getattr(fhp, &stat); ++ if (err) { ++ /* Grab the times from inode anyway */ ++ stat.mtime = inode->i_mtime; ++ stat.ctime = inode->i_ctime; ++ stat.size = inode->i_size; ++ } ++ if (v4) ++ fhp->fh_pre_change = nfsd4_change_attribute(&stat, inode); ++ ++ fhp->fh_pre_mtime = stat.mtime; ++ fhp->fh_pre_ctime = stat.ctime; ++ fhp->fh_pre_size = stat.size; ++ fhp->fh_pre_saved = true; ++} ++ ++/** ++ * fh_fill_post_attrs - Fill in post-op attributes ++ * @fhp: file handle to be updated ++ * ++ */ ++void fh_fill_post_attrs(struct svc_fh *fhp) ++{ ++ bool v4 = (fhp->fh_maxsize == NFS4_FHSIZE); ++ struct inode *inode = d_inode(fhp->fh_dentry); ++ __be32 err; ++ ++ if (fhp->fh_no_wcc) ++ return; ++ ++ if (fhp->fh_post_saved) ++ printk("nfsd: inode locked twice during operation.\n"); ++ ++ err = fh_getattr(fhp, &fhp->fh_post_attr); ++ if (err) { ++ fhp->fh_post_saved = false; ++ fhp->fh_post_attr.ctime = inode->i_ctime; ++ } else ++ fhp->fh_post_saved = true; ++ if (v4) ++ fhp->fh_post_change = ++ nfsd4_change_attribute(&fhp->fh_post_attr, inode); ++} ++ ++#endif /* CONFIG_NFSD_V3 */ ++ + /* + * Release a file handle. + */ +@@ -622,7 +686,7 @@ fh_put(struct svc_fh *fhp) + fh_unlock(fhp); + fhp->fh_dentry = NULL; + dput(dentry); +- fh_clear_wcc(fhp); ++ fh_clear_pre_post_attrs(fhp); + } + fh_drop_write(fhp); + if (exp) { +diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h +index d11e4b6870d68..434930d8a946e 100644 +--- a/fs/nfsd/nfsfh.h ++++ b/fs/nfsd/nfsfh.h +@@ -284,12 +284,13 @@ static inline u32 knfsd_fh_hash(const struct knfsd_fh *fh) + #endif + + #ifdef CONFIG_NFSD_V3 +-/* +- * The wcc data stored in current_fh should be cleared +- * between compound ops. ++ ++/** ++ * fh_clear_pre_post_attrs - Reset pre/post attributes ++ * @fhp: file handle to be updated ++ * + */ +-static inline void +-fh_clear_wcc(struct svc_fh *fhp) ++static inline void fh_clear_pre_post_attrs(struct svc_fh *fhp) + { + fhp->fh_post_saved = false; + fhp->fh_pre_saved = false; +@@ -323,13 +324,24 @@ static inline u64 nfsd4_change_attribute(struct kstat *stat, + return time_to_chattr(&stat->ctime); + } + +-extern void fill_pre_wcc(struct svc_fh *fhp); +-extern void fill_post_wcc(struct svc_fh *fhp); +-#else +-#define fh_clear_wcc(ignored) +-#define fill_pre_wcc(ignored) +-#define fill_post_wcc(notused) +-#endif /* CONFIG_NFSD_V3 */ ++extern void fh_fill_pre_attrs(struct svc_fh *fhp); ++extern void fh_fill_post_attrs(struct svc_fh *fhp); ++ ++#else /* !CONFIG_NFSD_V3 */ ++ ++static inline void fh_clear_pre_post_attrs(struct svc_fh *fhp) ++{ ++} ++ ++static inline void fh_fill_pre_attrs(struct svc_fh *fhp) ++{ ++} ++ ++static inline void fh_fill_post_attrs(struct svc_fh *fhp) ++{ ++} ++ ++#endif /* !CONFIG_NFSD_V3 */ + + + /* +@@ -355,7 +367,7 @@ fh_lock_nested(struct svc_fh *fhp, unsigned int subclass) + + inode = d_inode(dentry); + inode_lock_nested(inode, subclass); +- fill_pre_wcc(fhp); ++ fh_fill_pre_attrs(fhp); + fhp->fh_locked = true; + } + +@@ -372,7 +384,7 @@ static inline void + fh_unlock(struct svc_fh *fhp) + { + if (fhp->fh_locked) { +- fill_post_wcc(fhp); ++ fh_fill_post_attrs(fhp); + inode_unlock(d_inode(fhp->fh_dentry)); + fhp->fh_locked = false; + } +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index 77f48779210d0..d4b6bc3b4d735 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -1787,8 +1787,8 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, + * so do it by hand */ + trap = lock_rename(tdentry, fdentry); + ffhp->fh_locked = tfhp->fh_locked = true; +- fill_pre_wcc(ffhp); +- fill_pre_wcc(tfhp); ++ fh_fill_pre_attrs(ffhp); ++ fh_fill_pre_attrs(tfhp); + + odentry = lookup_one_len(fname, fdentry, flen); + host_err = PTR_ERR(odentry); +@@ -1840,8 +1840,8 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, + * were the same, so again we do it by hand. + */ + if (!close_cached) { +- fill_post_wcc(ffhp); +- fill_post_wcc(tfhp); ++ fh_fill_post_attrs(ffhp); ++ fh_fill_post_attrs(tfhp); + } + unlock_rename(tdentry, fdentry); + ffhp->fh_locked = tfhp->fh_locked = false; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-move-from-strlcpy-with-unused-retval-to-strscpy.patch b/queue-5.10/nfsd-move-from-strlcpy-with-unused-retval-to-strscpy.patch new file mode 100644 index 00000000000..b3bbe5b2eb1 --- /dev/null +++ b/queue-5.10/nfsd-move-from-strlcpy-with-unused-retval-to-strscpy.patch @@ -0,0 +1,85 @@ +From 534cbe8d78d181c8847a78f7fa2f79d0b7ec3acb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 18 Aug 2022 23:01:14 +0200 +Subject: NFSD: move from strlcpy with unused retval to strscpy + +From: Wolfram Sang + +[ Upstream commit 72f78ae00a8e5d7abe13abac8305a300f6afd74b ] + +Follow the advice of the below link and prefer 'strscpy' in this +subsystem. Conversion is 1:1 because the return value is not used. +Generated by a coccinelle script. + +Link: https://lore.kernel.org/r/CAHk-=wgfRnXz0W3D37d01q3JFkr_i_uTL=V6A6G1oUZcprmknw@mail.gmail.com/ +Signed-off-by: Wolfram Sang +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4idmap.c | 8 ++++---- + fs/nfsd/nfs4proc.c | 2 +- + fs/nfsd/nfssvc.c | 2 +- + 3 files changed, 6 insertions(+), 6 deletions(-) + +diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c +index f92161ce1f97d..e70a1a2999b7b 100644 +--- a/fs/nfsd/nfs4idmap.c ++++ b/fs/nfsd/nfs4idmap.c +@@ -82,8 +82,8 @@ ent_init(struct cache_head *cnew, struct cache_head *citm) + new->id = itm->id; + new->type = itm->type; + +- strlcpy(new->name, itm->name, sizeof(new->name)); +- strlcpy(new->authname, itm->authname, sizeof(new->authname)); ++ strscpy(new->name, itm->name, sizeof(new->name)); ++ strscpy(new->authname, itm->authname, sizeof(new->authname)); + } + + static void +@@ -548,7 +548,7 @@ idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen + return nfserr_badowner; + memcpy(key.name, name, namelen); + key.name[namelen] = '\0'; +- strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname)); ++ strscpy(key.authname, rqst_authname(rqstp), sizeof(key.authname)); + ret = idmap_lookup(rqstp, nametoid_lookup, &key, nn->nametoid_cache, &item); + if (ret == -ENOENT) + return nfserr_badowner; +@@ -584,7 +584,7 @@ static __be32 idmap_id_to_name(struct xdr_stream *xdr, + int ret; + struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); + +- strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname)); ++ strscpy(key.authname, rqst_authname(rqstp), sizeof(key.authname)); + ret = idmap_lookup(rqstp, idtoname_lookup, &key, nn->idtoname_cache, &item); + if (ret == -ENOENT) + return encode_ascii_id(xdr, id); +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 193b84a0f3a59..0431b979748b8 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -1345,7 +1345,7 @@ static __be32 nfsd4_ssc_setup_dul(struct nfsd_net *nn, char *ipaddr, + return 0; + } + if (work) { +- strlcpy(work->nsui_ipaddr, ipaddr, sizeof(work->nsui_ipaddr) - 1); ++ strscpy(work->nsui_ipaddr, ipaddr, sizeof(work->nsui_ipaddr) - 1); + refcount_set(&work->nsui_refcnt, 2); + work->nsui_busy = true; + list_add_tail(&work->nsui_list, &nn->nfsd_ssc_mount_list); +diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c +index 011c556caa1e7..8b1afde192118 100644 +--- a/fs/nfsd/nfssvc.c ++++ b/fs/nfsd/nfssvc.c +@@ -799,7 +799,7 @@ nfsd_svc(int nrservs, struct net *net, const struct cred *cred) + if (nrservs == 0 && nn->nfsd_serv == NULL) + goto out; + +- strlcpy(nn->nfsd_name, utsname()->nodename, ++ strscpy(nn->nfsd_name, utsname()->nodename, + sizeof(nn->nfsd_name)); + + error = nfsd_create_serv(net); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-move-fsnotify-on-client-creation-outside-spinlo.patch b/queue-5.10/nfsd-move-fsnotify-on-client-creation-outside-spinlo.patch new file mode 100644 index 00000000000..5b67781b172 --- /dev/null +++ b/queue-5.10/nfsd-move-fsnotify-on-client-creation-outside-spinlo.patch @@ -0,0 +1,65 @@ +From 7a117138084de36de4c10eae0ec62f5d567a8a41 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 25 May 2021 14:53:44 -0400 +Subject: nfsd: move fsnotify on client creation outside spinlock + +From: J. Bruce Fields + +[ Upstream commit 934bd07fae7e55232845f909f78873ab8678ca74 ] + +This was causing a "sleeping function called from invalid context" +warning. + +I don't think we need the set_and_test_bit() here; clients move from +unconfirmed to confirmed only once, under the client_lock. + +The (conf == unconf) is a way to check whether we're in that confirming +case, hopefully that's not too obscure. + +Fixes: 472d155a0631 "nfsd: report client confirmation status in "info" file" +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 3dd6e25d5d90f..4e14a9f6dfd39 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -2846,11 +2846,8 @@ move_to_confirmed(struct nfs4_client *clp) + list_move(&clp->cl_idhash, &nn->conf_id_hashtbl[idhashval]); + rb_erase(&clp->cl_namenode, &nn->unconf_name_tree); + add_clp_to_name_tree(clp, &nn->conf_name_tree); +- if (!test_and_set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags)) { +- trace_nfsd_clid_confirmed(&clp->cl_clientid); +- if (clp->cl_nfsd_dentry && clp->cl_nfsd_info_dentry) +- fsnotify_dentry(clp->cl_nfsd_info_dentry, FS_MODIFY); +- } ++ set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); ++ trace_nfsd_clid_confirmed(&clp->cl_clientid); + renew_client_locked(clp); + } + +@@ -3509,6 +3506,8 @@ nfsd4_create_session(struct svc_rqst *rqstp, + /* cache solo and embedded create sessions under the client_lock */ + nfsd4_cache_create_session(cr_ses, cs_slot, status); + spin_unlock(&nn->client_lock); ++ if (conf == unconf) ++ fsnotify_dentry(conf->cl_nfsd_info_dentry, FS_MODIFY); + /* init connection and backchannel */ + nfsd4_init_conn(rqstp, conn, new); + nfsd4_put_session(new); +@@ -4129,6 +4128,8 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, + } + get_client_locked(conf); + spin_unlock(&nn->client_lock); ++ if (conf == unconf) ++ fsnotify_dentry(conf->cl_nfsd_info_dentry, FS_MODIFY); + nfsd4_probe_callback(conf); + spin_lock(&nn->client_lock); + put_client_renew_locked(conf); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-move-nfsd_file_trace_alloc-tracepoint.patch b/queue-5.10/nfsd-move-nfsd_file_trace_alloc-tracepoint.patch new file mode 100644 index 00000000000..690f0b24614 --- /dev/null +++ b/queue-5.10/nfsd-move-nfsd_file_trace_alloc-tracepoint.patch @@ -0,0 +1,85 @@ +From 9d097afa51f18a7f6b6e54f61b0b3cc7425a73fb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 Jul 2022 14:26:49 -0400 +Subject: NFSD: Move nfsd_file_trace_alloc() tracepoint + +From: Chuck Lever + +[ Upstream commit b40a2839470cd62ed68c4a32d72a18ee8975b1ac ] + +Avoid recording the allocation of an nfsd_file item that is +immediately released because a matching item was already +inserted in the hash. + +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 2 +- + fs/nfsd/trace.h | 25 ++++++++++++++++++++++++- + 2 files changed, 25 insertions(+), 2 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index 85813affb8abf..26cfae138b906 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -302,7 +302,6 @@ nfsd_file_alloc(struct nfsd_file_lookup_key *key, unsigned int may) + refcount_set(&nf->nf_ref, 2); + nf->nf_may = key->need; + nf->nf_mark = NULL; +- trace_nfsd_file_alloc(nf); + } + return nf; + } +@@ -1125,6 +1124,7 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + return status; + + open_file: ++ trace_nfsd_file_alloc(nf); + nf->nf_mark = nfsd_file_mark_find_or_create(nf); + if (nf->nf_mark) { + if (open) { +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index ce391ba2f1ca5..22c1fb735f1a7 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -739,12 +739,35 @@ DEFINE_EVENT(nfsd_file_class, name, \ + TP_PROTO(struct nfsd_file *nf), \ + TP_ARGS(nf)) + +-DEFINE_NFSD_FILE_EVENT(nfsd_file_alloc); + DEFINE_NFSD_FILE_EVENT(nfsd_file_put_final); + DEFINE_NFSD_FILE_EVENT(nfsd_file_unhash); + DEFINE_NFSD_FILE_EVENT(nfsd_file_put); + DEFINE_NFSD_FILE_EVENT(nfsd_file_unhash_and_dispose); + ++TRACE_EVENT(nfsd_file_alloc, ++ TP_PROTO( ++ const struct nfsd_file *nf ++ ), ++ TP_ARGS(nf), ++ TP_STRUCT__entry( ++ __field(const void *, nf_inode) ++ __field(unsigned long, nf_flags) ++ __field(unsigned long, nf_may) ++ __field(unsigned int, nf_ref) ++ ), ++ TP_fast_assign( ++ __entry->nf_inode = nf->nf_inode; ++ __entry->nf_flags = nf->nf_flags; ++ __entry->nf_ref = refcount_read(&nf->nf_ref); ++ __entry->nf_may = nf->nf_may; ++ ), ++ TP_printk("inode=%p ref=%u flags=%s may=%s", ++ __entry->nf_inode, __entry->nf_ref, ++ show_nf_flags(__entry->nf_flags), ++ show_nfsd_may_flags(__entry->nf_may) ++ ) ++); ++ + TRACE_EVENT(nfsd_file_acquire, + TP_PROTO( + const struct svc_rqst *rqstp, +-- +2.43.0 + diff --git a/queue-5.10/nfsd-move-nfserrno-to-vfs.c.patch b/queue-5.10/nfsd-move-nfserrno-to-vfs.c.patch new file mode 100644 index 00000000000..2624c8e4308 --- /dev/null +++ b/queue-5.10/nfsd-move-nfserrno-to-vfs.c.patch @@ -0,0 +1,250 @@ +From 64cc0b0d49c2a49ec2cda5d92efa4e8e43a60aae Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 18 Oct 2022 07:47:55 -0400 +Subject: nfsd: move nfserrno() to vfs.c + +From: Jeff Layton + +[ Upstream commit cb12fae1c34b1fa7eaae92c5aadc72d86d7fae19 ] + +nfserrno() is common to all nfs versions, but nfsproc.c is specifically +for NFSv2. Move it to vfs.c, and the prototype to vfs.h. + +While we're in here, remove the #ifdef EDQUOT check in this function. +It's apparently a holdover from the initial merge of the nfsd code in +1997. No other place in the kernel checks that that symbol is defined +before using it, so I think we can dispense with it here. + +Signed-off-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/blocklayout.c | 1 + + fs/nfsd/blocklayoutxdr.c | 1 + + fs/nfsd/export.h | 1 - + fs/nfsd/flexfilelayout.c | 1 + + fs/nfsd/nfs4idmap.c | 1 + + fs/nfsd/nfsproc.c | 62 --------------------------------------- + fs/nfsd/vfs.c | 63 ++++++++++++++++++++++++++++++++++++++++ + fs/nfsd/vfs.h | 1 + + 8 files changed, 68 insertions(+), 63 deletions(-) + +diff --git a/fs/nfsd/blocklayout.c b/fs/nfsd/blocklayout.c +index a07c39c94bbd0..d91a686d2f313 100644 +--- a/fs/nfsd/blocklayout.c ++++ b/fs/nfsd/blocklayout.c +@@ -16,6 +16,7 @@ + #include "blocklayoutxdr.h" + #include "pnfs.h" + #include "filecache.h" ++#include "vfs.h" + + #define NFSDDBG_FACILITY NFSDDBG_PNFS + +diff --git a/fs/nfsd/blocklayoutxdr.c b/fs/nfsd/blocklayoutxdr.c +index 2455dc8be18a8..1ed2f691ebb90 100644 +--- a/fs/nfsd/blocklayoutxdr.c ++++ b/fs/nfsd/blocklayoutxdr.c +@@ -9,6 +9,7 @@ + + #include "nfsd.h" + #include "blocklayoutxdr.h" ++#include "vfs.h" + + #define NFSDDBG_FACILITY NFSDDBG_PNFS + +diff --git a/fs/nfsd/export.h b/fs/nfsd/export.h +index ee0e3aba4a6e5..d03f7f6a8642d 100644 +--- a/fs/nfsd/export.h ++++ b/fs/nfsd/export.h +@@ -115,7 +115,6 @@ struct svc_export * rqst_find_fsidzero_export(struct svc_rqst *); + int exp_rootfh(struct net *, struct auth_domain *, + char *path, struct knfsd_fh *, int maxsize); + __be32 exp_pseudoroot(struct svc_rqst *, struct svc_fh *); +-__be32 nfserrno(int errno); + + static inline void exp_put(struct svc_export *exp) + { +diff --git a/fs/nfsd/flexfilelayout.c b/fs/nfsd/flexfilelayout.c +index 2e2f1d5e9f623..fabc21ed68cea 100644 +--- a/fs/nfsd/flexfilelayout.c ++++ b/fs/nfsd/flexfilelayout.c +@@ -15,6 +15,7 @@ + + #include "flexfilelayoutxdr.h" + #include "pnfs.h" ++#include "vfs.h" + + #define NFSDDBG_FACILITY NFSDDBG_PNFS + +diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c +index e70a1a2999b7b..5e9809aff37eb 100644 +--- a/fs/nfsd/nfs4idmap.c ++++ b/fs/nfsd/nfs4idmap.c +@@ -41,6 +41,7 @@ + #include "idmap.h" + #include "nfsd.h" + #include "netns.h" ++#include "vfs.h" + + /* + * Turn off idmapping when using AUTH_SYS. +diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c +index 78fa5a9edf277..3777b5be4253a 100644 +--- a/fs/nfsd/nfsproc.c ++++ b/fs/nfsd/nfsproc.c +@@ -848,65 +848,3 @@ const struct svc_version nfsd_version2 = { + .vs_dispatch = nfsd_dispatch, + .vs_xdrsize = NFS2_SVC_XDRSIZE, + }; +- +-/* +- * Map errnos to NFS errnos. +- */ +-__be32 +-nfserrno (int errno) +-{ +- static struct { +- __be32 nfserr; +- int syserr; +- } nfs_errtbl[] = { +- { nfs_ok, 0 }, +- { nfserr_perm, -EPERM }, +- { nfserr_noent, -ENOENT }, +- { nfserr_io, -EIO }, +- { nfserr_nxio, -ENXIO }, +- { nfserr_fbig, -E2BIG }, +- { nfserr_stale, -EBADF }, +- { nfserr_acces, -EACCES }, +- { nfserr_exist, -EEXIST }, +- { nfserr_xdev, -EXDEV }, +- { nfserr_mlink, -EMLINK }, +- { nfserr_nodev, -ENODEV }, +- { nfserr_notdir, -ENOTDIR }, +- { nfserr_isdir, -EISDIR }, +- { nfserr_inval, -EINVAL }, +- { nfserr_fbig, -EFBIG }, +- { nfserr_nospc, -ENOSPC }, +- { nfserr_rofs, -EROFS }, +- { nfserr_mlink, -EMLINK }, +- { nfserr_nametoolong, -ENAMETOOLONG }, +- { nfserr_notempty, -ENOTEMPTY }, +-#ifdef EDQUOT +- { nfserr_dquot, -EDQUOT }, +-#endif +- { nfserr_stale, -ESTALE }, +- { nfserr_jukebox, -ETIMEDOUT }, +- { nfserr_jukebox, -ERESTARTSYS }, +- { nfserr_jukebox, -EAGAIN }, +- { nfserr_jukebox, -EWOULDBLOCK }, +- { nfserr_jukebox, -ENOMEM }, +- { nfserr_io, -ETXTBSY }, +- { nfserr_notsupp, -EOPNOTSUPP }, +- { nfserr_toosmall, -ETOOSMALL }, +- { nfserr_serverfault, -ESERVERFAULT }, +- { nfserr_serverfault, -ENFILE }, +- { nfserr_io, -EREMOTEIO }, +- { nfserr_stale, -EOPENSTALE }, +- { nfserr_io, -EUCLEAN }, +- { nfserr_perm, -ENOKEY }, +- { nfserr_no_grace, -ENOGRACE}, +- }; +- int i; +- +- for (i = 0; i < ARRAY_SIZE(nfs_errtbl); i++) { +- if (nfs_errtbl[i].syserr == errno) +- return nfs_errtbl[i].nfserr; +- } +- WARN_ONCE(1, "nfsd: non-standard errno: %d\n", errno); +- return nfserr_io; +-} +- +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index aae81c5cecb94..9bda56fe303cf 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -48,6 +48,69 @@ + + #define NFSDDBG_FACILITY NFSDDBG_FILEOP + ++/** ++ * nfserrno - Map Linux errnos to NFS errnos ++ * @errno: POSIX(-ish) error code to be mapped ++ * ++ * Returns the appropriate (net-endian) nfserr_* (or nfs_ok if errno is 0). If ++ * it's an error we don't expect, log it once and return nfserr_io. ++ */ ++__be32 ++nfserrno (int errno) ++{ ++ static struct { ++ __be32 nfserr; ++ int syserr; ++ } nfs_errtbl[] = { ++ { nfs_ok, 0 }, ++ { nfserr_perm, -EPERM }, ++ { nfserr_noent, -ENOENT }, ++ { nfserr_io, -EIO }, ++ { nfserr_nxio, -ENXIO }, ++ { nfserr_fbig, -E2BIG }, ++ { nfserr_stale, -EBADF }, ++ { nfserr_acces, -EACCES }, ++ { nfserr_exist, -EEXIST }, ++ { nfserr_xdev, -EXDEV }, ++ { nfserr_mlink, -EMLINK }, ++ { nfserr_nodev, -ENODEV }, ++ { nfserr_notdir, -ENOTDIR }, ++ { nfserr_isdir, -EISDIR }, ++ { nfserr_inval, -EINVAL }, ++ { nfserr_fbig, -EFBIG }, ++ { nfserr_nospc, -ENOSPC }, ++ { nfserr_rofs, -EROFS }, ++ { nfserr_mlink, -EMLINK }, ++ { nfserr_nametoolong, -ENAMETOOLONG }, ++ { nfserr_notempty, -ENOTEMPTY }, ++ { nfserr_dquot, -EDQUOT }, ++ { nfserr_stale, -ESTALE }, ++ { nfserr_jukebox, -ETIMEDOUT }, ++ { nfserr_jukebox, -ERESTARTSYS }, ++ { nfserr_jukebox, -EAGAIN }, ++ { nfserr_jukebox, -EWOULDBLOCK }, ++ { nfserr_jukebox, -ENOMEM }, ++ { nfserr_io, -ETXTBSY }, ++ { nfserr_notsupp, -EOPNOTSUPP }, ++ { nfserr_toosmall, -ETOOSMALL }, ++ { nfserr_serverfault, -ESERVERFAULT }, ++ { nfserr_serverfault, -ENFILE }, ++ { nfserr_io, -EREMOTEIO }, ++ { nfserr_stale, -EOPENSTALE }, ++ { nfserr_io, -EUCLEAN }, ++ { nfserr_perm, -ENOKEY }, ++ { nfserr_no_grace, -ENOGRACE}, ++ }; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(nfs_errtbl); i++) { ++ if (nfs_errtbl[i].syserr == errno) ++ return nfs_errtbl[i].nfserr; ++ } ++ WARN_ONCE(1, "nfsd: non-standard errno: %d\n", errno); ++ return nfserr_io; ++} ++ + /* + * Called from nfsd_lookup and encode_dirent. Check if we have crossed + * a mount point. +diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h +index 120521bc7b247..8ddd687f83599 100644 +--- a/fs/nfsd/vfs.h ++++ b/fs/nfsd/vfs.h +@@ -60,6 +60,7 @@ static inline void nfsd_attrs_free(struct nfsd_attrs *attrs) + posix_acl_release(attrs->na_dpacl); + } + ++__be32 nfserrno (int errno); + int nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp, + struct svc_export **expp); + __be32 nfsd_lookup(struct svc_rqst *, struct svc_fh *, +-- +2.43.0 + diff --git a/queue-5.10/nfsd-move-some-commit_metadata-s-outside-the-inode-l.patch b/queue-5.10/nfsd-move-some-commit_metadata-s-outside-the-inode-l.patch new file mode 100644 index 00000000000..7e9b080cc3c --- /dev/null +++ b/queue-5.10/nfsd-move-some-commit_metadata-s-outside-the-inode-l.patch @@ -0,0 +1,59 @@ +From 24c954ebd32a6f54b796919423c694040a990645 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 14 May 2021 18:21:37 -0400 +Subject: nfsd: move some commit_metadata()s outside the inode lock + +From: J. Bruce Fields + +[ Upstream commit eeeadbb9bd5652c47bb9b31aa9ad8b4f1b4aa8b3 ] + +The commit may be time-consuming and there's no need to hold the lock +for it. + +More of these are possible, these were just some easy ones. + +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/vfs.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index 2eb3bfbc8a35f..74b2c6c5ad0b9 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -1626,9 +1626,9 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, + + host_err = vfs_symlink(d_inode(dentry), dnew, path); + err = nfserrno(host_err); ++ fh_unlock(fhp); + if (!err) + err = nfserrno(commit_metadata(fhp)); +- fh_unlock(fhp); + + fh_drop_write(fhp); + +@@ -1693,6 +1693,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, + if (d_really_is_negative(dold)) + goto out_dput; + host_err = vfs_link(dold, dirp, dnew, NULL); ++ fh_unlock(ffhp); + if (!host_err) { + err = nfserrno(commit_metadata(ffhp)); + if (!err) +@@ -1913,10 +1914,10 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, + host_err = vfs_rmdir(dirp, rdentry); + } + ++ fh_unlock(fhp); + if (!host_err) + host_err = commit_metadata(fhp); + dput(rdentry); +- fh_unlock(fhp); + iput(rinode); /* truncate the inode here */ + + out_drop_write: +-- +2.43.0 + diff --git a/queue-5.10/nfsd-move-svc_serv_ops-svo_function-into-struct-svc_.patch b/queue-5.10/nfsd-move-svc_serv_ops-svo_function-into-struct-svc_.patch new file mode 100644 index 00000000000..fa047df8fc2 --- /dev/null +++ b/queue-5.10/nfsd-move-svc_serv_ops-svo_function-into-struct-svc_.patch @@ -0,0 +1,268 @@ +From 838e7ff90b9299b225b27df8a40dc1c24aea4f78 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 16 Feb 2022 12:16:27 -0500 +Subject: NFSD: Move svc_serv_ops::svo_function into struct svc_serv + +From: Chuck Lever + +[ Upstream commit 37902c6313090235c847af89c5515591261ee338 ] + +Hoist svo_function back into svc_serv and remove struct +svc_serv_ops, since the struct is now devoid of fields. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/svc.c | 6 +----- + fs/nfs/callback.c | 43 ++++++++++---------------------------- + fs/nfsd/nfssvc.c | 7 +------ + include/linux/sunrpc/svc.h | 14 ++++--------- + net/sunrpc/svc.c | 37 ++++++++++++++++++++++---------- + 5 files changed, 43 insertions(+), 64 deletions(-) + +diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c +index bfde31124f3af..59ef8a1f843f3 100644 +--- a/fs/lockd/svc.c ++++ b/fs/lockd/svc.c +@@ -349,10 +349,6 @@ static struct notifier_block lockd_inet6addr_notifier = { + }; + #endif + +-static const struct svc_serv_ops lockd_sv_ops = { +- .svo_function = lockd, +-}; +- + static int lockd_get(void) + { + struct svc_serv *serv; +@@ -376,7 +372,7 @@ static int lockd_get(void) + nlm_timeout = LOCKD_DFLT_TIMEO; + nlmsvc_timeout = nlm_timeout * HZ; + +- serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, &lockd_sv_ops); ++ serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, lockd); + if (!serv) { + printk(KERN_WARNING "lockd_up: create service failed\n"); + return -ENOMEM; +diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c +index a494f9e7bd0a0..456af7d230cf1 100644 +--- a/fs/nfs/callback.c ++++ b/fs/nfs/callback.c +@@ -231,29 +231,10 @@ static int nfs_callback_up_net(int minorversion, struct svc_serv *serv, + return ret; + } + +-static const struct svc_serv_ops nfs40_cb_sv_ops = { +- .svo_function = nfs4_callback_svc, +-}; +-#if defined(CONFIG_NFS_V4_1) +-static const struct svc_serv_ops nfs41_cb_sv_ops = { +- .svo_function = nfs41_callback_svc, +-}; +- +-static const struct svc_serv_ops *nfs4_cb_sv_ops[] = { +- [0] = &nfs40_cb_sv_ops, +- [1] = &nfs41_cb_sv_ops, +-}; +-#else +-static const struct svc_serv_ops *nfs4_cb_sv_ops[] = { +- [0] = &nfs40_cb_sv_ops, +- [1] = NULL, +-}; +-#endif +- + static struct svc_serv *nfs_callback_create_svc(int minorversion) + { + struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion]; +- const struct svc_serv_ops *sv_ops; ++ int (*threadfn)(void *data); + struct svc_serv *serv; + + /* +@@ -262,17 +243,6 @@ static struct svc_serv *nfs_callback_create_svc(int minorversion) + if (cb_info->serv) + return svc_get(cb_info->serv); + +- switch (minorversion) { +- case 0: +- sv_ops = nfs4_cb_sv_ops[0]; +- break; +- default: +- sv_ops = nfs4_cb_sv_ops[1]; +- } +- +- if (sv_ops == NULL) +- return ERR_PTR(-ENOTSUPP); +- + /* + * Sanity check: if there's no task, + * we should be the first user ... +@@ -281,7 +251,16 @@ static struct svc_serv *nfs_callback_create_svc(int minorversion) + printk(KERN_WARNING "nfs_callback_create_svc: no kthread, %d users??\n", + cb_info->users); + +- serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, sv_ops); ++ threadfn = nfs4_callback_svc; ++#if defined(CONFIG_NFS_V4_1) ++ if (minorversion) ++ threadfn = nfs41_callback_svc; ++#else ++ if (minorversion) ++ return ERR_PTR(-ENOTSUPP); ++#endif ++ serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, ++ threadfn); + if (!serv) { + printk(KERN_ERR "nfs_callback_create_svc: create service failed\n"); + return ERR_PTR(-ENOMEM); +diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c +index d25d4c12a499a..2f74be98ff2d9 100644 +--- a/fs/nfsd/nfssvc.c ++++ b/fs/nfsd/nfssvc.c +@@ -612,10 +612,6 @@ static int nfsd_get_default_max_blksize(void) + return ret; + } + +-static const struct svc_serv_ops nfsd_thread_sv_ops = { +- .svo_function = nfsd, +-}; +- + void nfsd_shutdown_threads(struct net *net) + { + struct nfsd_net *nn = net_generic(net, nfsd_net_id); +@@ -654,8 +650,7 @@ int nfsd_create_serv(struct net *net) + if (nfsd_max_blksize == 0) + nfsd_max_blksize = nfsd_get_default_max_blksize(); + nfsd_reset_versions(nn); +- serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize, +- &nfsd_thread_sv_ops); ++ serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize, nfsd); + if (serv == NULL) + return -ENOMEM; + +diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h +index c64db9b14a643..3c908ffbbf45f 100644 +--- a/include/linux/sunrpc/svc.h ++++ b/include/linux/sunrpc/svc.h +@@ -52,13 +52,6 @@ struct svc_pool { + unsigned long sp_flags; + } ____cacheline_aligned_in_smp; + +-struct svc_serv; +- +-struct svc_serv_ops { +- /* function for service threads to run */ +- int (*svo_function)(void *); +-}; +- + /* + * RPC service. + * +@@ -91,7 +84,8 @@ struct svc_serv { + + unsigned int sv_nrpools; /* number of thread pools */ + struct svc_pool * sv_pools; /* array of thread pools */ +- const struct svc_serv_ops *sv_ops; /* server operations */ ++ int (*sv_threadfn)(void *data); ++ + #if defined(CONFIG_SUNRPC_BACKCHANNEL) + struct list_head sv_cb_list; /* queue for callback requests + * that arrive over the same +@@ -495,7 +489,7 @@ int svc_rpcb_setup(struct svc_serv *serv, struct net *net); + void svc_rpcb_cleanup(struct svc_serv *serv, struct net *net); + int svc_bind(struct svc_serv *serv, struct net *net); + struct svc_serv *svc_create(struct svc_program *, unsigned int, +- const struct svc_serv_ops *); ++ int (*threadfn)(void *data)); + struct svc_rqst *svc_rqst_alloc(struct svc_serv *serv, + struct svc_pool *pool, int node); + void svc_rqst_replace_page(struct svc_rqst *rqstp, +@@ -503,7 +497,7 @@ void svc_rqst_replace_page(struct svc_rqst *rqstp, + void svc_rqst_free(struct svc_rqst *); + void svc_exit_thread(struct svc_rqst *); + struct svc_serv * svc_create_pooled(struct svc_program *, unsigned int, +- const struct svc_serv_ops *); ++ int (*threadfn)(void *data)); + int svc_set_num_threads(struct svc_serv *, struct svc_pool *, int); + int svc_pool_stats_open(struct svc_serv *serv, struct file *file); + int svc_process(struct svc_rqst *); +diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c +index bdecc902cf998..7f231947347ea 100644 +--- a/net/sunrpc/svc.c ++++ b/net/sunrpc/svc.c +@@ -446,7 +446,7 @@ __svc_init_bc(struct svc_serv *serv) + */ + static struct svc_serv * + __svc_create(struct svc_program *prog, unsigned int bufsize, int npools, +- const struct svc_serv_ops *ops) ++ int (*threadfn)(void *data)) + { + struct svc_serv *serv; + unsigned int vers; +@@ -463,7 +463,7 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools, + bufsize = RPCSVC_MAXPAYLOAD; + serv->sv_max_payload = bufsize? bufsize : 4096; + serv->sv_max_mesg = roundup(serv->sv_max_payload + PAGE_SIZE, PAGE_SIZE); +- serv->sv_ops = ops; ++ serv->sv_threadfn = threadfn; + xdrsize = 0; + while (prog) { + prog->pg_lovers = prog->pg_nvers-1; +@@ -509,22 +509,37 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools, + return serv; + } + +-struct svc_serv * +-svc_create(struct svc_program *prog, unsigned int bufsize, +- const struct svc_serv_ops *ops) ++/** ++ * svc_create - Create an RPC service ++ * @prog: the RPC program the new service will handle ++ * @bufsize: maximum message size for @prog ++ * @threadfn: a function to service RPC requests for @prog ++ * ++ * Returns an instantiated struct svc_serv object or NULL. ++ */ ++struct svc_serv *svc_create(struct svc_program *prog, unsigned int bufsize, ++ int (*threadfn)(void *data)) + { +- return __svc_create(prog, bufsize, /*npools*/1, ops); ++ return __svc_create(prog, bufsize, 1, threadfn); + } + EXPORT_SYMBOL_GPL(svc_create); + +-struct svc_serv * +-svc_create_pooled(struct svc_program *prog, unsigned int bufsize, +- const struct svc_serv_ops *ops) ++/** ++ * svc_create_pooled - Create an RPC service with pooled threads ++ * @prog: the RPC program the new service will handle ++ * @bufsize: maximum message size for @prog ++ * @threadfn: a function to service RPC requests for @prog ++ * ++ * Returns an instantiated struct svc_serv object or NULL. ++ */ ++struct svc_serv *svc_create_pooled(struct svc_program *prog, ++ unsigned int bufsize, ++ int (*threadfn)(void *data)) + { + struct svc_serv *serv; + unsigned int npools = svc_pool_map_get(); + +- serv = __svc_create(prog, bufsize, npools, ops); ++ serv = __svc_create(prog, bufsize, npools, threadfn); + if (!serv) + goto out_err; + return serv; +@@ -734,7 +749,7 @@ svc_start_kthreads(struct svc_serv *serv, struct svc_pool *pool, int nrservs) + if (IS_ERR(rqstp)) + return PTR_ERR(rqstp); + +- task = kthread_create_on_node(serv->sv_ops->svo_function, rqstp, ++ task = kthread_create_on_node(serv->sv_threadfn, rqstp, + node, "%s", serv->sv_name); + if (IS_ERR(task)) { + svc_exit_thread(rqstp); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-narrow-nfsd_mutex-protection-in-nfsd-thread.patch b/queue-5.10/nfsd-narrow-nfsd_mutex-protection-in-nfsd-thread.patch new file mode 100644 index 00000000000..40e19a28d1d --- /dev/null +++ b/queue-5.10/nfsd-narrow-nfsd_mutex-protection-in-nfsd-thread.patch @@ -0,0 +1,67 @@ +From 2fb0fe2185c2917c59eb8967ba34eaf7da2bd91c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Nov 2021 15:51:25 +1100 +Subject: NFSD: narrow nfsd_mutex protection in nfsd thread + +From: NeilBrown + +[ Upstream commit 9d3792aefdcda71d20c2b1ecc589c17ae71eb523 ] + +There is nothing happening in the start of nfsd() that requires +protection by the mutex, so don't take it until shutting down the thread +- which does still require protection - but only for nfsd_put(). + +Signed-off-by: NeilBrown +[ cel: address merge conflict with fd2468fa1301 ] +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfssvc.c | 8 ++------ + 1 file changed, 2 insertions(+), 6 deletions(-) + +diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c +index 16884a90e1ab0..eb8cc4d914fee 100644 +--- a/fs/nfsd/nfssvc.c ++++ b/fs/nfsd/nfssvc.c +@@ -932,9 +932,6 @@ nfsd(void *vrqstp) + struct nfsd_net *nn = net_generic(net, nfsd_net_id); + int err; + +- /* Lock module and set up kernel thread */ +- mutex_lock(&nfsd_mutex); +- + /* At this point, the thread shares current->fs + * with the init process. We need to create files with the + * umask as defined by the client instead of init's umask. */ +@@ -954,7 +951,6 @@ nfsd(void *vrqstp) + allow_signal(SIGINT); + allow_signal(SIGQUIT); + +- mutex_unlock(&nfsd_mutex); + atomic_inc(&nfsdstats.th_cnt); + + set_freezable(); +@@ -983,7 +979,6 @@ nfsd(void *vrqstp) + flush_signals(current); + + atomic_dec(&nfsdstats.th_cnt); +- mutex_lock(&nfsd_mutex); + + out: + /* Take an extra ref so that the svc_put in svc_exit_thread() +@@ -995,10 +990,11 @@ nfsd(void *vrqstp) + svc_exit_thread(rqstp); + + /* Now if needed we call svc_destroy in appropriate context */ ++ mutex_lock(&nfsd_mutex); + nfsd_put(net); ++ mutex_unlock(&nfsd_mutex); + + /* Release module */ +- mutex_unlock(&nfsd_mutex); + module_put_and_kthread_exit(0); + return 0; + } +-- +2.43.0 + diff --git a/queue-5.10/nfsd-never-call-nfsd_file_gc-in-foreground-paths.patch b/queue-5.10/nfsd-never-call-nfsd_file_gc-in-foreground-paths.patch new file mode 100644 index 00000000000..a0db147b5cd --- /dev/null +++ b/queue-5.10/nfsd-never-call-nfsd_file_gc-in-foreground-paths.patch @@ -0,0 +1,87 @@ +From 8850e819998966a0240774130a99bd7f0d8cb7d8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 Jul 2022 14:25:30 -0400 +Subject: NFSD: Never call nfsd_file_gc() in foreground paths + +From: Chuck Lever + +[ Upstream commit 6df19411367a5fb4ef61854cbd1af269c077f917 ] + +The checks in nfsd_file_acquire() and nfsd_file_put() that directly +invoke filecache garbage collection are intended to keep cache +occupancy between a low- and high-watermark. The reason to limit the +capacity of the filecache is to keep filecache lookups reasonably +fast. + +However, invoking garbage collection at those points has some +undesirable negative impacts. Files that are held open by NFSv4 +clients often push the occupancy of the filecache over these +watermarks. At that point: + +- Every call to nfsd_file_acquire() and nfsd_file_put() results in + an LRU walk. This has the same effect on lookup latency as long + chains in the hash table. +- Garbage collection will then run on every nfsd thread, causing a + lot of unnecessary lock contention. +- Limiting cache capacity pushes out files used only by NFSv3 + clients, which are the type of files the filecache is supposed to + help. + +To address those negative impacts, remove the direct calls to the +garbage collector. Subsequent patches will address maintaining +lookup efficiency as cache capacity increases. + +Suggested-by: Wang Yugui +Suggested-by: Dave Chinner +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 10 +--------- + 1 file changed, 1 insertion(+), 9 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index 849c010c6ef61..7a02ff11b9ec1 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -28,8 +28,6 @@ + #define NFSD_LAUNDRETTE_DELAY (2 * HZ) + + #define NFSD_FILE_SHUTDOWN (1) +-#define NFSD_FILE_LRU_THRESHOLD (4096UL) +-#define NFSD_FILE_LRU_LIMIT (NFSD_FILE_LRU_THRESHOLD << 2) + + /* We only care about NFSD_MAY_READ/WRITE for this cache */ + #define NFSD_FILE_MAY_MASK (NFSD_MAY_READ|NFSD_MAY_WRITE) +@@ -65,8 +63,6 @@ static struct fsnotify_group *nfsd_file_fsnotify_group; + static atomic_long_t nfsd_filecache_count; + static struct delayed_work nfsd_filecache_laundrette; + +-static void nfsd_file_gc(void); +- + static void + nfsd_file_schedule_laundrette(void) + { +@@ -343,9 +339,6 @@ nfsd_file_put(struct nfsd_file *nf) + nfsd_file_schedule_laundrette(); + } else + nfsd_file_put_noref(nf); +- +- if (atomic_long_read(&nfsd_filecache_count) >= NFSD_FILE_LRU_LIMIT) +- nfsd_file_gc(); + } + + struct nfsd_file * +@@ -1054,8 +1047,7 @@ nfsd_do_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + nfsd_file_hashtbl[hashval].nfb_maxcount = max(nfsd_file_hashtbl[hashval].nfb_maxcount, + nfsd_file_hashtbl[hashval].nfb_count); + spin_unlock(&nfsd_file_hashtbl[hashval].nfb_lock); +- if (atomic_long_inc_return(&nfsd_filecache_count) >= NFSD_FILE_LRU_THRESHOLD) +- nfsd_file_gc(); ++ atomic_long_inc(&nfsd_filecache_count); + + nf->nf_mark = nfsd_file_mark_find_or_create(nf); + if (nf->nf_mark) { +-- +2.43.0 + diff --git a/queue-5.10/nfsd-nfs3-remove-unused-macro-nfsd3_fhandleres.patch b/queue-5.10/nfsd-nfs3-remove-unused-macro-nfsd3_fhandleres.patch new file mode 100644 index 00000000000..2f3c6e9be31 --- /dev/null +++ b/queue-5.10/nfsd-nfs3-remove-unused-macro-nfsd3_fhandleres.patch @@ -0,0 +1,39 @@ +From 5cd7ffcd90b9d95b5ff748030bd2915a44a12c83 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Nov 2020 13:40:57 +0800 +Subject: nfsd/nfs3: remove unused macro nfsd3_fhandleres + +From: Alex Shi + +[ Upstream commit 71fd721839a74d945c242299f6be29a246fc2131 ] + +The macro is unused, remove it to tame gcc warning: +fs/nfsd/nfs3proc.c:702:0: warning: macro "nfsd3_fhandleres" is not used +[-Wunused-macros] + +Signed-off-by: Alex Shi +Cc: "J. Bruce Fields" +Cc: Chuck Lever +Cc: linux-nfs@vger.kernel.org +Cc: linux-kernel@vger.kernel.org +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3proc.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c +index 981a4e4c9a3cf..eba84417406ca 100644 +--- a/fs/nfsd/nfs3proc.c ++++ b/fs/nfsd/nfs3proc.c +@@ -694,7 +694,6 @@ nfsd3_proc_commit(struct svc_rqst *rqstp) + #define nfsd3_mkdirargs nfsd3_createargs + #define nfsd3_readdirplusargs nfsd3_readdirargs + #define nfsd3_fhandleargs nfsd_fhandle +-#define nfsd3_fhandleres nfsd3_attrstat + #define nfsd3_attrstatres nfsd3_attrstat + #define nfsd3_wccstatres nfsd3_attrstat + #define nfsd3_createres nfsd3_diropres +-- +2.43.0 + diff --git a/queue-5.10/nfsd-nfsd_file_hash_remove-can-compute-hashval.patch b/queue-5.10/nfsd-nfsd_file_hash_remove-can-compute-hashval.patch new file mode 100644 index 00000000000..c6bdabf0b1d --- /dev/null +++ b/queue-5.10/nfsd-nfsd_file_hash_remove-can-compute-hashval.patch @@ -0,0 +1,58 @@ +From 288fe0383785cfc66998ba8d32e0638530eafd06 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 Jul 2022 14:26:03 -0400 +Subject: NFSD: nfsd_file_hash_remove can compute hashval + +From: Chuck Lever + +[ Upstream commit cb7ec76e73ff6640241c8f1f2f35c81d4005a2d6 ] + +Remove an unnecessary use of nf_hashval. + +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 19 ++++++++++++++----- + 1 file changed, 14 insertions(+), 5 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index 3925df9124c39..dd59deec8b011 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -287,6 +287,18 @@ nfsd_file_do_unhash(struct nfsd_file *nf) + atomic_long_dec(&nfsd_filecache_count); + } + ++static void ++nfsd_file_hash_remove(struct nfsd_file *nf) ++{ ++ struct inode *inode = nf->nf_inode; ++ unsigned int hashval = (unsigned int)hash_long(inode->i_ino, ++ NFSD_FILE_HASH_BITS); ++ ++ spin_lock(&nfsd_file_hashtbl[hashval].nfb_lock); ++ nfsd_file_do_unhash(nf); ++ spin_unlock(&nfsd_file_hashtbl[hashval].nfb_lock); ++} ++ + static bool + nfsd_file_unhash(struct nfsd_file *nf) + { +@@ -506,11 +518,8 @@ static void nfsd_file_gc_dispose_list(struct list_head *dispose) + { + struct nfsd_file *nf; + +- list_for_each_entry(nf, dispose, nf_lru) { +- spin_lock(&nfsd_file_hashtbl[nf->nf_hashval].nfb_lock); +- nfsd_file_do_unhash(nf); +- spin_unlock(&nfsd_file_hashtbl[nf->nf_hashval].nfb_lock); +- } ++ list_for_each_entry(nf, dispose, nf_lru) ++ nfsd_file_hash_remove(nf); + nfsd_file_dispose_list_delayed(dispose); + } + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-nfsd_file_key_inode-only-needs-to-find-gc-ed-en.patch b/queue-5.10/nfsd-nfsd_file_key_inode-only-needs-to-find-gc-ed-en.patch new file mode 100644 index 00000000000..e17f805b220 --- /dev/null +++ b/queue-5.10/nfsd-nfsd_file_key_inode-only-needs-to-find-gc-ed-en.patch @@ -0,0 +1,55 @@ +From c11b5100eaa42dc4fd6fccaf50aaed30615e4141 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Jan 2023 10:39:00 -0500 +Subject: nfsd: NFSD_FILE_KEY_INODE only needs to find GC'ed entries + +From: Jeff Layton + +[ Upstream commit 6c31e4c98853a4ba47355ea151b36a77c42b7734 ] + +Since v4 files are expected to be long-lived, there's little value in +closing them out of the cache when there is conflicting access. + +Change the comparator to also match the gc value in the key. Change both +of the current users of that key to set the gc value in the key to +"true". + +Signed-off-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index 677a8d935ccc2..4ddc82b84f7c4 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -174,6 +174,8 @@ static int nfsd_file_obj_cmpfn(struct rhashtable_compare_arg *arg, + + switch (key->type) { + case NFSD_FILE_KEY_INODE: ++ if (test_bit(NFSD_FILE_GC, &nf->nf_flags) != key->gc) ++ return 1; + if (nf->nf_inode != key->inode) + return 1; + break; +@@ -694,6 +696,7 @@ nfsd_file_queue_for_close(struct inode *inode, struct list_head *dispose) + struct nfsd_file_lookup_key key = { + .type = NFSD_FILE_KEY_INODE, + .inode = inode, ++ .gc = true, + }; + struct nfsd_file *nf; + +@@ -1048,6 +1051,7 @@ nfsd_file_is_cached(struct inode *inode) + struct nfsd_file_lookup_key key = { + .type = NFSD_FILE_KEY_INODE, + .inode = inode, ++ .gc = true, + }; + bool ret = false; + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-nfsd_file_put-can-sleep.patch b/queue-5.10/nfsd-nfsd_file_put-can-sleep.patch new file mode 100644 index 00000000000..18609626b7d --- /dev/null +++ b/queue-5.10/nfsd-nfsd_file_put-can-sleep.patch @@ -0,0 +1,39 @@ +From b94cb9f2df3b65789e0ad4dc0a98b24f0777e945 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 May 2022 13:02:21 -0400 +Subject: NFSD: nfsd_file_put() can sleep + +From: Chuck Lever + +[ Upstream commit 08af54b3e5729bc1d56ad3190af811301bdc37a1 ] + +Now that there are no more callers of nfsd_file_put() that might +hold a spin lock, ensure the lockdep infrastructure can catch +newly introduced calls to nfsd_file_put() made while a spinlock +is held. + +Link: https://lore.kernel.org/linux-nfs/ece7fd1d-5fb3-5155-54ba-347cfc19bd9a@oracle.com/T/#mf1855552570cf9a9c80d1e49d91438cd9085aada +Signed-off-by: Chuck Lever +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index bdb5de8c08036..11c096b447401 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -302,6 +302,8 @@ nfsd_file_put_noref(struct nfsd_file *nf) + void + nfsd_file_put(struct nfsd_file *nf) + { ++ might_sleep(); ++ + set_bit(NFSD_FILE_REFERENCED, &nf->nf_flags); + if (test_bit(NFSD_FILE_HASHED, &nf->nf_flags) == 0) { + nfsd_file_flush(nf); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-nfsd_file_unhash-can-compute-hashval-from-nf-nf.patch b/queue-5.10/nfsd-nfsd_file_unhash-can-compute-hashval-from-nf-nf.patch new file mode 100644 index 00000000000..9017990a342 --- /dev/null +++ b/queue-5.10/nfsd-nfsd_file_unhash-can-compute-hashval-from-nf-nf.patch @@ -0,0 +1,45 @@ +From d447928c9ef5516ae6aeeb678847b0df886cffb0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 Jul 2022 14:25:50 -0400 +Subject: NFSD: nfsd_file_unhash can compute hashval from nf->nf_inode + +From: Chuck Lever + +[ Upstream commit 8755326399f471ec3b31e2ab8c5074c0d28a0fb5 ] + +Remove an unnecessary usage of nf_hashval. + +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index 6a01de8677959..d7c74b51eabf3 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -272,13 +272,17 @@ static void nfsd_file_lru_remove(struct nfsd_file *nf) + static void + nfsd_file_do_unhash(struct nfsd_file *nf) + { +- lockdep_assert_held(&nfsd_file_hashtbl[nf->nf_hashval].nfb_lock); ++ struct inode *inode = nf->nf_inode; ++ unsigned int hashval = (unsigned int)hash_long(inode->i_ino, ++ NFSD_FILE_HASH_BITS); ++ ++ lockdep_assert_held(&nfsd_file_hashtbl[hashval].nfb_lock); + + trace_nfsd_file_unhash(nf); + + if (nfsd_file_check_write_error(nf)) + nfsd_reset_write_verifier(net_generic(nf->nf_net, nfsd_net_id)); +- --nfsd_file_hashtbl[nf->nf_hashval].nfb_count; ++ --nfsd_file_hashtbl[hashval].nfb_count; + hlist_del_rcu(&nf->nf_node); + atomic_long_dec(&nfsd_filecache_count); + } +-- +2.43.0 + diff --git a/queue-5.10/nfsd-nfserrno-enomem-is-nfserr_jukebox.patch b/queue-5.10/nfsd-nfserrno-enomem-is-nfserr_jukebox.patch new file mode 100644 index 00000000000..cc75ec2732a --- /dev/null +++ b/queue-5.10/nfsd-nfserrno-enomem-is-nfserr_jukebox.patch @@ -0,0 +1,41 @@ +From f40ac61a0517e500d1ff34ce5b5d48d07c98c18c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 Jul 2022 14:40:09 -0400 +Subject: NFSD: nfserrno(-ENOMEM) is nfserr_jukebox + +From: Chuck Lever + +[ Upstream commit bb4d842722b84a2731257054b6405f2d866fc5f3 ] + +Suggested-by: Dai Ngo +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index a98513cb35b10..fcf56e396e66b 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -1810,7 +1810,7 @@ nfsd4_decode_test_stateid(struct nfsd4_compoundargs *argp, struct nfsd4_test_sta + for (i = 0; i < test_stateid->ts_num_ids; i++) { + stateid = svcxdr_tmpalloc(argp, sizeof(*stateid)); + if (!stateid) +- return nfserrno(-ENOMEM); /* XXX: not jukebox? */ ++ return nfserr_jukebox; + INIT_LIST_HEAD(&stateid->ts_id_list); + list_add_tail(&stateid->ts_id_list, &test_stateid->ts_stateid_list); + status = nfsd4_decode_stateid4(argp, &stateid->ts_id_stateid); +@@ -1933,7 +1933,7 @@ nfsd4_decode_copy(struct nfsd4_compoundargs *argp, struct nfsd4_copy *copy) + + ns_dummy = kmalloc(sizeof(struct nl4_server), GFP_KERNEL); + if (ns_dummy == NULL) +- return nfserrno(-ENOMEM); /* XXX: jukebox? */ ++ return nfserr_jukebox; + for (i = 0; i < count - 1; i++) { + status = nfsd4_decode_nl4_server(argp, ns_dummy); + if (status) { +-- +2.43.0 + diff --git a/queue-5.10/nfsd-nfsv4-close-should-release-an-nfsd_file-immedia.patch b/queue-5.10/nfsd-nfsv4-close-should-release-an-nfsd_file-immedia.patch new file mode 100644 index 00000000000..be2cdaac226 --- /dev/null +++ b/queue-5.10/nfsd-nfsv4-close-should-release-an-nfsd_file-immedia.patch @@ -0,0 +1,85 @@ +From e48109cb2b57c06b7c4a2494ffd70f20ae7445f2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 Jul 2022 14:27:02 -0400 +Subject: NFSD: NFSv4 CLOSE should release an nfsd_file immediately + +From: Chuck Lever + +[ Upstream commit 5e138c4a750dc140d881dab4a8804b094bbc08d2 ] + +The last close of a file should enable other accessors to open and +use that file immediately. Leaving the file open in the filecache +prevents other users from accessing that file until the filecache +garbage-collects the file -- sometimes that takes several seconds. + +Reported-by: Wang Yugui +Link: https://bugzilla.linux-nfs.org/show_bug.cgi?387 +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 18 ++++++++++++++++++ + fs/nfsd/filecache.h | 1 + + fs/nfsd/nfs4state.c | 4 ++-- + 3 files changed, 21 insertions(+), 2 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index 26cfae138b906..7ad27655db699 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -451,6 +451,24 @@ nfsd_file_put(struct nfsd_file *nf) + nfsd_file_put_noref(nf); + } + ++/** ++ * nfsd_file_close - Close an nfsd_file ++ * @nf: nfsd_file to close ++ * ++ * If this is the final reference for @nf, free it immediately. ++ * This reflects an on-the-wire CLOSE or DELEGRETURN into the ++ * VFS and exported filesystem. ++ */ ++void nfsd_file_close(struct nfsd_file *nf) ++{ ++ nfsd_file_put(nf); ++ if (refcount_dec_if_one(&nf->nf_ref)) { ++ nfsd_file_unhash(nf); ++ nfsd_file_lru_remove(nf); ++ nfsd_file_free(nf); ++ } ++} ++ + struct nfsd_file * + nfsd_file_get(struct nfsd_file *nf) + { +diff --git a/fs/nfsd/filecache.h b/fs/nfsd/filecache.h +index ee9ed99d8b8fa..28145f1628923 100644 +--- a/fs/nfsd/filecache.h ++++ b/fs/nfsd/filecache.h +@@ -52,6 +52,7 @@ void nfsd_file_cache_shutdown(void); + int nfsd_file_cache_start_net(struct net *net); + void nfsd_file_cache_shutdown_net(struct net *net); + void nfsd_file_put(struct nfsd_file *nf); ++void nfsd_file_close(struct nfsd_file *nf); + struct nfsd_file *nfsd_file_get(struct nfsd_file *nf); + void nfsd_file_close_inode_sync(struct inode *inode); + bool nfsd_file_is_cached(struct inode *inode); +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 587e792346579..c4c1e35d3eb7a 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -831,9 +831,9 @@ static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag) + swap(f2, fp->fi_fds[O_RDWR]); + spin_unlock(&fp->fi_lock); + if (f1) +- nfsd_file_put(f1); ++ nfsd_file_close(f1); + if (f2) +- nfsd_file_put(f2); ++ nfsd_file_close(f2); + } + } + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-no-longer-record-nf_hashval-in-the-trace-log.patch b/queue-5.10/nfsd-no-longer-record-nf_hashval-in-the-trace-log.patch new file mode 100644 index 00000000000..9bcadb54e18 --- /dev/null +++ b/queue-5.10/nfsd-no-longer-record-nf_hashval-in-the-trace-log.patch @@ -0,0 +1,212 @@ +From abbabcdd000c02c6143eedd331849405de06e281 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 Jul 2022 14:25:37 -0400 +Subject: NFSD: No longer record nf_hashval in the trace log + +From: Chuck Lever + +[ Upstream commit 54f7df7094b329ca35d9f9808692bb16c48b13e9 ] + +I'm about to replace nfsd_file_hashtbl with an rhashtable. The +individual hash values will no longer be visible or relevant, so +remove them from the tracepoints. + +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 15 ++++++++------- + fs/nfsd/trace.h | 45 +++++++++++++++++++++------------------------ + 2 files changed, 29 insertions(+), 31 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index 7a02ff11b9ec1..2d013a88e3565 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -588,7 +588,7 @@ nfsd_file_close_inode_sync(struct inode *inode) + LIST_HEAD(dispose); + + __nfsd_file_close_inode(inode, hashval, &dispose); +- trace_nfsd_file_close_inode_sync(inode, hashval, !list_empty(&dispose)); ++ trace_nfsd_file_close_inode_sync(inode, !list_empty(&dispose)); + nfsd_file_dispose_list_sync(&dispose); + } + +@@ -608,7 +608,7 @@ nfsd_file_close_inode(struct inode *inode) + LIST_HEAD(dispose); + + __nfsd_file_close_inode(inode, hashval, &dispose); +- trace_nfsd_file_close_inode(inode, hashval, !list_empty(&dispose)); ++ trace_nfsd_file_close_inode(inode, !list_empty(&dispose)); + nfsd_file_dispose_list_delayed(&dispose); + } + +@@ -962,7 +962,7 @@ nfsd_file_is_cached(struct inode *inode) + } + } + rcu_read_unlock(); +- trace_nfsd_file_is_cached(inode, hashval, (int)ret); ++ trace_nfsd_file_is_cached(inode, (int)ret); + return ret; + } + +@@ -994,9 +994,8 @@ nfsd_do_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + + new = nfsd_file_alloc(inode, may_flags, hashval, net); + if (!new) { +- trace_nfsd_file_acquire(rqstp, hashval, inode, may_flags, +- NULL, nfserr_jukebox); +- return nfserr_jukebox; ++ status = nfserr_jukebox; ++ goto out_status; + } + + spin_lock(&nfsd_file_hashtbl[hashval].nfb_lock); +@@ -1034,8 +1033,10 @@ nfsd_do_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + nf = NULL; + } + +- trace_nfsd_file_acquire(rqstp, hashval, inode, may_flags, nf, status); ++out_status: ++ trace_nfsd_file_acquire(rqstp, inode, may_flags, nf, status); + return status; ++ + open_file: + nf = new; + /* Take reference for the hashtable */ +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index 5919cdcf137b8..8b34f2a5ad296 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -713,7 +713,6 @@ DECLARE_EVENT_CLASS(nfsd_file_class, + TP_PROTO(struct nfsd_file *nf), + TP_ARGS(nf), + TP_STRUCT__entry( +- __field(unsigned int, nf_hashval) + __field(void *, nf_inode) + __field(int, nf_ref) + __field(unsigned long, nf_flags) +@@ -721,15 +720,13 @@ DECLARE_EVENT_CLASS(nfsd_file_class, + __field(struct file *, nf_file) + ), + TP_fast_assign( +- __entry->nf_hashval = nf->nf_hashval; + __entry->nf_inode = nf->nf_inode; + __entry->nf_ref = refcount_read(&nf->nf_ref); + __entry->nf_flags = nf->nf_flags; + __entry->nf_may = nf->nf_may; + __entry->nf_file = nf->nf_file; + ), +- TP_printk("hash=0x%x inode=%p ref=%d flags=%s may=%s file=%p", +- __entry->nf_hashval, ++ TP_printk("inode=%p ref=%d flags=%s may=%s nf_file=%p", + __entry->nf_inode, + __entry->nf_ref, + show_nf_flags(__entry->nf_flags), +@@ -749,15 +746,18 @@ DEFINE_NFSD_FILE_EVENT(nfsd_file_put); + DEFINE_NFSD_FILE_EVENT(nfsd_file_unhash_and_release_locked); + + TRACE_EVENT(nfsd_file_acquire, +- TP_PROTO(struct svc_rqst *rqstp, unsigned int hash, +- struct inode *inode, unsigned int may_flags, +- struct nfsd_file *nf, __be32 status), ++ TP_PROTO( ++ struct svc_rqst *rqstp, ++ struct inode *inode, ++ unsigned int may_flags, ++ struct nfsd_file *nf, ++ __be32 status ++ ), + +- TP_ARGS(rqstp, hash, inode, may_flags, nf, status), ++ TP_ARGS(rqstp, inode, may_flags, nf, status), + + TP_STRUCT__entry( + __field(u32, xid) +- __field(unsigned int, hash) + __field(void *, inode) + __field(unsigned long, may_flags) + __field(int, nf_ref) +@@ -769,7 +769,6 @@ TRACE_EVENT(nfsd_file_acquire, + + TP_fast_assign( + __entry->xid = be32_to_cpu(rqstp->rq_xid); +- __entry->hash = hash; + __entry->inode = inode; + __entry->may_flags = may_flags; + __entry->nf_ref = nf ? refcount_read(&nf->nf_ref) : 0; +@@ -779,8 +778,8 @@ TRACE_EVENT(nfsd_file_acquire, + __entry->status = be32_to_cpu(status); + ), + +- TP_printk("xid=0x%x hash=0x%x inode=%p may_flags=%s ref=%d nf_flags=%s nf_may=%s nf_file=%p status=%u", +- __entry->xid, __entry->hash, __entry->inode, ++ TP_printk("xid=0x%x inode=%p may_flags=%s ref=%d nf_flags=%s nf_may=%s nf_file=%p status=%u", ++ __entry->xid, __entry->inode, + show_nfsd_may_flags(__entry->may_flags), + __entry->nf_ref, show_nf_flags(__entry->nf_flags), + show_nfsd_may_flags(__entry->nf_may), +@@ -791,7 +790,6 @@ TRACE_EVENT(nfsd_file_open, + TP_PROTO(struct nfsd_file *nf, __be32 status), + TP_ARGS(nf, status), + TP_STRUCT__entry( +- __field(unsigned int, nf_hashval) + __field(void *, nf_inode) /* cannot be dereferenced */ + __field(int, nf_ref) + __field(unsigned long, nf_flags) +@@ -799,15 +797,13 @@ TRACE_EVENT(nfsd_file_open, + __field(void *, nf_file) /* cannot be dereferenced */ + ), + TP_fast_assign( +- __entry->nf_hashval = nf->nf_hashval; + __entry->nf_inode = nf->nf_inode; + __entry->nf_ref = refcount_read(&nf->nf_ref); + __entry->nf_flags = nf->nf_flags; + __entry->nf_may = nf->nf_may; + __entry->nf_file = nf->nf_file; + ), +- TP_printk("hash=0x%x inode=%p ref=%d flags=%s may=%s file=%p", +- __entry->nf_hashval, ++ TP_printk("inode=%p ref=%d flags=%s may=%s file=%p", + __entry->nf_inode, + __entry->nf_ref, + show_nf_flags(__entry->nf_flags), +@@ -816,26 +812,27 @@ TRACE_EVENT(nfsd_file_open, + ) + + DECLARE_EVENT_CLASS(nfsd_file_search_class, +- TP_PROTO(struct inode *inode, unsigned int hash, int found), +- TP_ARGS(inode, hash, found), ++ TP_PROTO( ++ struct inode *inode, ++ int found ++ ), ++ TP_ARGS(inode, found), + TP_STRUCT__entry( + __field(struct inode *, inode) +- __field(unsigned int, hash) + __field(int, found) + ), + TP_fast_assign( + __entry->inode = inode; +- __entry->hash = hash; + __entry->found = found; + ), +- TP_printk("hash=0x%x inode=%p found=%d", __entry->hash, +- __entry->inode, __entry->found) ++ TP_printk("inode=%p found=%d", ++ __entry->inode, __entry->found) + ); + + #define DEFINE_NFSD_FILE_SEARCH_EVENT(name) \ + DEFINE_EVENT(nfsd_file_search_class, name, \ +- TP_PROTO(struct inode *inode, unsigned int hash, int found), \ +- TP_ARGS(inode, hash, found)) ++ TP_PROTO(struct inode *inode, int found), \ ++ TP_ARGS(inode, found)) + + DEFINE_NFSD_FILE_SEARCH_EVENT(nfsd_file_close_inode_sync); + DEFINE_NFSD_FILE_SEARCH_EVENT(nfsd_file_close_inode); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-only-call-fh_unlock-once-in-nfsd_link.patch b/queue-5.10/nfsd-only-call-fh_unlock-once-in-nfsd_link.patch new file mode 100644 index 00000000000..8414eed1c48 --- /dev/null +++ b/queue-5.10/nfsd-only-call-fh_unlock-once-in-nfsd_link.patch @@ -0,0 +1,71 @@ +From bcda32db2ef664c1855040f4debb930a089ffba6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 Jul 2022 16:45:30 +1000 +Subject: NFSD: only call fh_unlock() once in nfsd_link() + +From: NeilBrown + +[ Upstream commit e18bcb33bc5b69bccc2b532075aa00bb49cc01c5 ] + +On non-error paths, nfsd_link() calls fh_unlock() twice. This is safe +because fh_unlock() records that the unlock has been done and doesn't +repeat it. +However it makes the code a little confusing and interferes with changes +that are planned for directory locking. + +So rearrange the code to ensure fh_unlock() is called exactly once if +fh_lock() was called. + +Reviewed-by: Jeff Layton +Signed-off-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/vfs.c | 19 ++++++++++--------- + 1 file changed, 10 insertions(+), 9 deletions(-) + +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index 6b8e1826956bf..dd945099ae6b5 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -1557,9 +1557,10 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, + dirp = d_inode(ddir); + + dnew = lookup_one_len(name, ddir, len); +- host_err = PTR_ERR(dnew); +- if (IS_ERR(dnew)) +- goto out_nfserr; ++ if (IS_ERR(dnew)) { ++ err = nfserrno(PTR_ERR(dnew)); ++ goto out_unlock; ++ } + + dold = tfhp->fh_dentry; + +@@ -1578,17 +1579,17 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, + else + err = nfserrno(host_err); + } +-out_dput: + dput(dnew); +-out_unlock: +- fh_unlock(ffhp); ++out_drop_write: + fh_drop_write(tfhp); + out: + return err; + +-out_nfserr: +- err = nfserrno(host_err); +- goto out_unlock; ++out_dput: ++ dput(dnew); ++out_unlock: ++ fh_unlock(ffhp); ++ goto out_drop_write; + } + + static void +-- +2.43.0 + diff --git a/queue-5.10/nfsd-only-call-inode_query_iversion-in-the-i_version.patch b/queue-5.10/nfsd-only-call-inode_query_iversion-in-the-i_version.patch new file mode 100644 index 00000000000..f2c305109da --- /dev/null +++ b/queue-5.10/nfsd-only-call-inode_query_iversion-in-the-i_version.patch @@ -0,0 +1,105 @@ +From 848a6a22f38258f12b8af129148ab490d759c55f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Nov 2020 17:46:14 -0500 +Subject: nfsd: only call inode_query_iversion in the I_VERSION case + +From: J. Bruce Fields + +[ Upstream commit 70b87f77294d16d3e567056ba4c9ee2b091a5b50 ] + +inode_query_iversion() can modify i_version. Depending on the exported +filesystem, that may not be safe. For example, if you're re-exporting +NFS, NFS stores the server's change attribute in i_version and does not +expect it to be modified locally. This has been observed causing +unnecessary cache invalidations. + +The way a filesystem indicates that it's OK to call +inode_query_iverson() is by setting SB_I_VERSION. + +So, move the I_VERSION check out of encode_change(), where it's used +only in GETATTR responses, to nfsd4_change_attribute(), which is +also called for pre- and post- operation attributes. + +(Note we could also pull the NFSEXP_V4ROOT case into +nfsd4_change_attribute() as well. That would actually be a no-op, +since pre/post attrs are only used for metadata-modifying operations, +and V4ROOT exports are read-only. But we might make the change in +the future just for simplicity.) + +Reported-by: Daire Byrne +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3xdr.c | 5 ++--- + fs/nfsd/nfs4xdr.c | 6 +----- + fs/nfsd/nfsfh.h | 14 ++++++++++---- + 3 files changed, 13 insertions(+), 12 deletions(-) + +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index 0d75d201db1b3..5956b0317c55e 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -291,14 +291,13 @@ void fill_post_wcc(struct svc_fh *fhp) + printk("nfsd: inode locked twice during operation.\n"); + + err = fh_getattr(fhp, &fhp->fh_post_attr); +- fhp->fh_post_change = nfsd4_change_attribute(&fhp->fh_post_attr, +- d_inode(fhp->fh_dentry)); + if (err) { + fhp->fh_post_saved = false; +- /* Grab the ctime anyway - set_change_info might use it */ + fhp->fh_post_attr.ctime = d_inode(fhp->fh_dentry)->i_ctime; + } else + fhp->fh_post_saved = true; ++ fhp->fh_post_change = nfsd4_change_attribute(&fhp->fh_post_attr, ++ d_inode(fhp->fh_dentry)); + } + + /* +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 315be1c1ab85c..bdcfb5f7021da 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -2426,12 +2426,8 @@ static __be32 *encode_change(__be32 *p, struct kstat *stat, struct inode *inode, + if (exp->ex_flags & NFSEXP_V4ROOT) { + *p++ = cpu_to_be32(convert_to_wallclock(exp->cd->flush_time)); + *p++ = 0; +- } else if (IS_I_VERSION(inode)) { ++ } else + p = xdr_encode_hyper(p, nfsd4_change_attribute(stat, inode)); +- } else { +- *p++ = cpu_to_be32(stat->ctime.tv_sec); +- *p++ = cpu_to_be32(stat->ctime.tv_nsec); +- } + return p; + } + +diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h +index 56cfbc3615618..39d764b129fa3 100644 +--- a/fs/nfsd/nfsfh.h ++++ b/fs/nfsd/nfsfh.h +@@ -261,10 +261,16 @@ static inline u64 nfsd4_change_attribute(struct kstat *stat, + { + u64 chattr; + +- chattr = stat->ctime.tv_sec; +- chattr <<= 30; +- chattr += stat->ctime.tv_nsec; +- chattr += inode_query_iversion(inode); ++ if (IS_I_VERSION(inode)) { ++ chattr = stat->ctime.tv_sec; ++ chattr <<= 30; ++ chattr += stat->ctime.tv_nsec; ++ chattr += inode_query_iversion(inode); ++ } else { ++ chattr = stat->ctime.tv_sec; ++ chattr <<= 32; ++ chattr += stat->ctime.tv_nsec; ++ } + return chattr; + } + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-only-fill-out-return-pointer-on-success-in-nfsd.patch b/queue-5.10/nfsd-only-fill-out-return-pointer-on-success-in-nfsd.patch new file mode 100644 index 00000000000..5808549dac8 --- /dev/null +++ b/queue-5.10/nfsd-only-fill-out-return-pointer-on-success-in-nfsd.patch @@ -0,0 +1,56 @@ +From 26f9d1a23612c576fd8d975a24fecf31d08819a6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 26 Sep 2022 12:38:44 -0400 +Subject: nfsd: only fill out return pointer on success in nfsd4_lookup_stateid + +From: Jeff Layton + +[ Upstream commit 4d01416ab41540bb13ec4a39ac4e6c4aa5934bc9 ] + +In the case of a revoked delegation, we still fill out the pointer even +when returning an error, which is bad form. Only overwrite the pointer +on success. + +Signed-off-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index f207c73ae1b58..1dc3823f3d124 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -6289,6 +6289,7 @@ nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate, + struct nfs4_stid **s, struct nfsd_net *nn) + { + __be32 status; ++ struct nfs4_stid *stid; + bool return_revoked = false; + + /* +@@ -6311,15 +6312,16 @@ nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate, + } + if (status) + return status; +- *s = find_stateid_by_type(cstate->clp, stateid, typemask); +- if (!*s) ++ stid = find_stateid_by_type(cstate->clp, stateid, typemask); ++ if (!stid) + return nfserr_bad_stateid; +- if (((*s)->sc_type == NFS4_REVOKED_DELEG_STID) && !return_revoked) { +- nfs4_put_stid(*s); ++ if ((stid->sc_type == NFS4_REVOKED_DELEG_STID) && !return_revoked) { ++ nfs4_put_stid(stid); + if (cstate->minorversion) + return nfserr_deleg_revoked; + return nfserr_bad_stateid; + } ++ *s = stid; + return nfs_ok; + } + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-optimize-drc-bucket-pruning.patch b/queue-5.10/nfsd-optimize-drc-bucket-pruning.patch new file mode 100644 index 00000000000..3ff650d5e64 --- /dev/null +++ b/queue-5.10/nfsd-optimize-drc-bucket-pruning.patch @@ -0,0 +1,116 @@ +From 8e8e27759d1b860c63b77e47d6cb2e9c45eb6e67 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 20 Sep 2021 15:25:21 -0400 +Subject: NFSD: Optimize DRC bucket pruning + +From: Chuck Lever + +[ Upstream commit 8847ecc9274a14114385d1cb4030326baa0766eb ] + +DRC bucket pruning is done by nfsd_cache_lookup(), which is part of +every NFSv2 and NFSv3 dispatch (ie, it's done while the client is +waiting). + +I added a trace_printk() in prune_bucket() to see just how long +it takes to prune. Here are two ends of the spectrum: + + prune_bucket: Scanned 1 and freed 0 in 90 ns, 62 entries remaining + prune_bucket: Scanned 2 and freed 1 in 716 ns, 63 entries remaining +... + prune_bucket: Scanned 75 and freed 74 in 34149 ns, 1 entries remaining + +Pruning latency is noticeable on fast transports with fast storage. +By noticeable, I mean that the latency measured here in the worst +case is the same order of magnitude as the round trip time for +cached server operations. + +We could do something like moving expired entries to an expired list +and then free them later instead of freeing them right in +prune_bucket(). But simply limiting the number of entries that can +be pruned by a lookup is simple and retains more entries in the +cache, making the DRC somewhat more effective. + +Comparison with a 70/30 fio 8KB 12 thread direct I/O test: + +Before: + + write: IOPS=61.6k, BW=481MiB/s (505MB/s)(14.1GiB/30001msec); 0 zone resets + +WRITE: + 1848726 ops (30%) + avg bytes sent per op: 8340 avg bytes received per op: 136 + backlog wait: 0.635158 RTT: 0.128525 total execute time: 0.827242 (milliseconds) + +After: + + write: IOPS=63.0k, BW=492MiB/s (516MB/s)(14.4GiB/30001msec); 0 zone resets + +WRITE: + 1891144 ops (30%) + avg bytes sent per op: 8340 avg bytes received per op: 136 + backlog wait: 0.616114 RTT: 0.126842 total execute time: 0.805348 (milliseconds) + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfscache.c | 17 +++++++++++------ + 1 file changed, 11 insertions(+), 6 deletions(-) + +diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c +index 96cdf77925f33..6e0b6f3148dca 100644 +--- a/fs/nfsd/nfscache.c ++++ b/fs/nfsd/nfscache.c +@@ -241,8 +241,8 @@ lru_put_end(struct nfsd_drc_bucket *b, struct svc_cacherep *rp) + list_move_tail(&rp->c_lru, &b->lru_head); + } + +-static long +-prune_bucket(struct nfsd_drc_bucket *b, struct nfsd_net *nn) ++static long prune_bucket(struct nfsd_drc_bucket *b, struct nfsd_net *nn, ++ unsigned int max) + { + struct svc_cacherep *rp, *tmp; + long freed = 0; +@@ -258,11 +258,17 @@ prune_bucket(struct nfsd_drc_bucket *b, struct nfsd_net *nn) + time_before(jiffies, rp->c_timestamp + RC_EXPIRE)) + break; + nfsd_reply_cache_free_locked(b, rp, nn); +- freed++; ++ if (max && freed++ > max) ++ break; + } + return freed; + } + ++static long nfsd_prune_bucket(struct nfsd_drc_bucket *b, struct nfsd_net *nn) ++{ ++ return prune_bucket(b, nn, 3); ++} ++ + /* + * Walk the LRU list and prune off entries that are older than RC_EXPIRE. + * Also prune the oldest ones when the total exceeds the max number of entries. +@@ -279,7 +285,7 @@ prune_cache_entries(struct nfsd_net *nn) + if (list_empty(&b->lru_head)) + continue; + spin_lock(&b->cache_lock); +- freed += prune_bucket(b, nn); ++ freed += prune_bucket(b, nn, 0); + spin_unlock(&b->cache_lock); + } + return freed; +@@ -453,8 +459,7 @@ int nfsd_cache_lookup(struct svc_rqst *rqstp) + atomic_inc(&nn->num_drc_entries); + nfsd_stats_drc_mem_usage_add(nn, sizeof(*rp)); + +- /* go ahead and prune the cache */ +- prune_bucket(b, nn); ++ nfsd_prune_bucket(b, nn); + + out_unlock: + spin_unlock(&b->cache_lock); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-optimize-nfsd4_encode_fattr.patch b/queue-5.10/nfsd-optimize-nfsd4_encode_fattr.patch new file mode 100644 index 00000000000..c8941bd18ec --- /dev/null +++ b/queue-5.10/nfsd-optimize-nfsd4_encode_fattr.patch @@ -0,0 +1,65 @@ +From 1c500812e2552191fd1c2c9c6af92adf140b82fd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 Jul 2022 16:08:45 -0400 +Subject: NFSD: Optimize nfsd4_encode_fattr() + +From: Chuck Lever + +[ Upstream commit ab04de60ae1cc64ae16b77feae795311b97720c7 ] + +write_bytes_to_xdr_buf() is a generic way to place a variable-length +data item in an already-reserved spot in the encoding buffer. + +However, it is costly. In nfsd4_encode_fattr(), it is unnecessary +because the data item is fixed in size and the buffer destination +address is always word-aligned. + +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 11 ++++------- + 1 file changed, 4 insertions(+), 7 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 14e8e37550609..1e388cdf9b005 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -2828,10 +2828,9 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, + struct kstat stat; + struct svc_fh *tempfh = NULL; + struct kstatfs statfs; +- __be32 *p; ++ __be32 *p, *attrlen_p; + int starting_len = xdr->buf->len; + int attrlen_offset; +- __be32 attrlen; + u32 dummy; + u64 dummy64; + u32 rdattr_err = 0; +@@ -2919,10 +2918,9 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, + goto out; + + attrlen_offset = xdr->buf->len; +- p = xdr_reserve_space(xdr, 4); +- if (!p) ++ attrlen_p = xdr_reserve_space(xdr, XDR_UNIT); ++ if (!attrlen_p) + goto out_resource; +- p++; /* to be backfilled later */ + + if (bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) { + u32 supp[3]; +@@ -3344,8 +3342,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, + *p++ = cpu_to_be32(err == 0); + } + +- attrlen = htonl(xdr->buf->len - attrlen_offset - 4); +- write_bytes_to_xdr_buf(xdr->buf, attrlen_offset, &attrlen, 4); ++ *attrlen_p = cpu_to_be32(xdr->buf->len - attrlen_offset - XDR_UNIT); + status = nfs_ok; + + out: +-- +2.43.0 + diff --git a/queue-5.10/nfsd-optimize-nfsd4_encode_operation.patch b/queue-5.10/nfsd-optimize-nfsd4_encode_operation.patch new file mode 100644 index 00000000000..aa964b7227e --- /dev/null +++ b/queue-5.10/nfsd-optimize-nfsd4_encode_operation.patch @@ -0,0 +1,40 @@ +From f624b967305190960e044f726bb639a2d466f63e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 Jul 2022 16:08:38 -0400 +Subject: NFSD: Optimize nfsd4_encode_operation() + +From: Chuck Lever + +[ Upstream commit 095a764b7afb06c9499b798c04eaa3cbf70ebe2d ] + +write_bytes_to_xdr_buf() is a generic way to place a variable-length +data item in an already-reserved spot in the encoding buffer. +However, it is costly, and here, it is unnecessary because the +data item is fixed in size, the buffer destination address is +always word-aligned, and the destination location is already in +@p. + +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index b98a24c2a753c..14e8e37550609 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -5381,8 +5381,7 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op) + so->so_replay.rp_buf, len); + } + status: +- /* Note that op->status is already in network byte order: */ +- write_bytes_to_xdr_buf(xdr->buf, post_err_offset - 4, &op->status, 4); ++ *p = op->status; + } + + /* +-- +2.43.0 + diff --git a/queue-5.10/nfsd-optimize-nfsd4_encode_readv.patch b/queue-5.10/nfsd-optimize-nfsd4_encode_readv.patch new file mode 100644 index 00000000000..9f940f24965 --- /dev/null +++ b/queue-5.10/nfsd-optimize-nfsd4_encode_readv.patch @@ -0,0 +1,78 @@ +From a99065a2e83ae9fa91e5f1f857084bdf0b2679fa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 Jul 2022 16:09:04 -0400 +Subject: NFSD: Optimize nfsd4_encode_readv() + +From: Chuck Lever + +[ Upstream commit 28d5bc468efe74b790e052f758ce083a5015c665 ] + +write_bytes_to_xdr_buf() is pretty expensive to use for inserting +an XDR data item that is always 1 XDR_UNIT at an address that is +always XDR word-aligned. + +Since both the readv and splice read paths encode EOF and maxcount +values, move both to a common code path. + +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 18 ++++++------------ + 1 file changed, 6 insertions(+), 12 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 8437a390480df..36f0f06714dec 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -3891,7 +3891,6 @@ static __be32 nfsd4_encode_splice_read( + struct xdr_buf *buf = xdr->buf; + int status, space_left; + __be32 nfserr; +- __be32 *p = xdr->p - 2; + + /* Make sure there will be room for padding if needed */ + if (xdr->end - xdr->p < 1) +@@ -3910,9 +3909,6 @@ static __be32 nfsd4_encode_splice_read( + goto out_err; + } + +- *(p++) = htonl(read->rd_eof); +- *(p++) = htonl(maxcount); +- + buf->page_len = maxcount; + buf->len += maxcount; + xdr->page_ptr += (buf->page_base + maxcount + PAGE_SIZE - 1) +@@ -3973,11 +3969,6 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp, + return nfserr_io; + xdr_truncate_encode(xdr, starting_len + 8 + xdr_align_size(maxcount)); + +- tmp = htonl(read->rd_eof); +- write_bytes_to_xdr_buf(xdr->buf, starting_len , &tmp, 4); +- tmp = htonl(maxcount); +- write_bytes_to_xdr_buf(xdr->buf, starting_len + 4, &tmp, 4); +- + tmp = xdr_zero; + pad = (maxcount&3) ? 4 - (maxcount&3) : 0; + write_bytes_to_xdr_buf(xdr->buf, starting_len + 8 + maxcount, +@@ -4019,11 +4010,14 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr, + nfserr = nfsd4_encode_splice_read(resp, read, file, maxcount); + else + nfserr = nfsd4_encode_readv(resp, read, file, maxcount); +- +- if (nfserr) ++ if (nfserr) { + xdr_truncate_encode(xdr, starting_len); ++ return nfserr; ++ } + +- return nfserr; ++ p = xdr_encode_bool(p, read->rd_eof); ++ *p = cpu_to_be32(read->rd_length); ++ return nfs_ok; + } + + static __be32 +-- +2.43.0 + diff --git a/queue-5.10/nfsd-pack-struct-nfsd4_compoundres.patch b/queue-5.10/nfsd-pack-struct-nfsd4_compoundres.patch new file mode 100644 index 00000000000..701b769d7da --- /dev/null +++ b/queue-5.10/nfsd-pack-struct-nfsd4_compoundres.patch @@ -0,0 +1,34 @@ +From b469281bfc446c966bec6e5392c10e2591f2dab3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Sep 2022 17:23:36 -0400 +Subject: NFSD: Pack struct nfsd4_compoundres + +From: Chuck Lever + +[ Upstream commit 9f553e61bd36c1048543ac2f6945103dd2f742be ] + +Remove a couple of 4-byte holes on platforms with 64-bit pointers. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/xdr4.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h +index 624a19ec3ad11..8f323d9071f06 100644 +--- a/fs/nfsd/xdr4.h ++++ b/fs/nfsd/xdr4.h +@@ -732,8 +732,8 @@ struct nfsd4_compoundres { + struct svc_rqst * rqstp; + + __be32 *statusp; +- u32 taglen; + char * tag; ++ u32 taglen; + u32 opcnt; + + struct nfsd4_compound_state cstate; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-pass-range-end-to-vfs_fsync_range-instead-of-co.patch b/queue-5.10/nfsd-pass-range-end-to-vfs_fsync_range-instead-of-co.patch new file mode 100644 index 00000000000..01c1aae74be --- /dev/null +++ b/queue-5.10/nfsd-pass-range-end-to-vfs_fsync_range-instead-of-co.patch @@ -0,0 +1,48 @@ +From 4a4568ed89acd305c1db22e6184a9b79842da913 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 16 Nov 2022 10:28:36 -0500 +Subject: NFSD: pass range end to vfs_fsync_range() instead of count + +From: Brian Foster + +[ Upstream commit 79a1d88a36f77374c77fd41a4386d8c2736b8704 ] + +_nfsd_copy_file_range() calls vfs_fsync_range() with an offset and +count (bytes written), but the former wants the start and end bytes +of the range to sync. Fix it up. + +Fixes: eac0b17a77fb ("NFSD add vfs_fsync after async copy is done") +Signed-off-by: Brian Foster +Tested-by: Dai Ngo +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 86ab9b8ac2daf..cf558d951ec68 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -1632,6 +1632,7 @@ static ssize_t _nfsd_copy_file_range(struct nfsd4_copy *copy, + u64 src_pos = copy->cp_src_pos; + u64 dst_pos = copy->cp_dst_pos; + int status; ++ loff_t end; + + /* See RFC 7862 p.67: */ + if (bytes_total == 0) +@@ -1651,8 +1652,8 @@ static ssize_t _nfsd_copy_file_range(struct nfsd4_copy *copy, + /* for a non-zero asynchronous copy do a commit of data */ + if (nfsd4_copy_is_async(copy) && copy->cp_res.wr_bytes_written > 0) { + since = READ_ONCE(dst->f_wb_err); +- status = vfs_fsync_range(dst, copy->cp_dst_pos, +- copy->cp_res.wr_bytes_written, 0); ++ end = copy->cp_dst_pos + copy->cp_res.wr_bytes_written - 1; ++ status = vfs_fsync_range(dst, copy->cp_dst_pos, end, 0); + if (!status) + status = filemap_check_wb_err(dst->f_mapping, since); + if (!status) +-- +2.43.0 + diff --git a/queue-5.10/nfsd-pass-the-target-nfsd_file-to-nfsd_commit.patch b/queue-5.10/nfsd-pass-the-target-nfsd_file-to-nfsd_commit.patch new file mode 100644 index 00000000000..13172bfcf06 --- /dev/null +++ b/queue-5.10/nfsd-pass-the-target-nfsd_file-to-nfsd_commit.patch @@ -0,0 +1,153 @@ +From 8b5e64ed2b39ebd84d137030df9adfd6cfaaaddd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Oct 2022 10:46:38 -0400 +Subject: NFSD: Pass the target nfsd_file to nfsd_commit() + +From: Chuck Lever + +[ Upstream commit c252849082ff525af18b4f253b3c9ece94e951ed ] + +In a moment I'm going to introduce separate nfsd_file types, one of +which is garbage-collected; the other, not. The garbage-collected +variety is to be used by NFSv2 and v3, and the non-garbage-collected +variety is to be used by NFSv4. + +nfsd_commit() is invoked by both NFSv3 and NFSv4 consumers. We want +nfsd_commit() to find and use the correct variety of cached +nfsd_file object for the NFS version that is in use. + +Signed-off-by: Chuck Lever +Tested-by: Jeff Layton +Reviewed-by: Jeff Layton +Reviewed-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3proc.c | 10 +++++++++- + fs/nfsd/nfs4proc.c | 11 ++++++++++- + fs/nfsd/vfs.c | 15 ++++----------- + fs/nfsd/vfs.h | 3 ++- + 4 files changed, 25 insertions(+), 14 deletions(-) + +diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c +index a9bf455aee821..a3a55b2be4f67 100644 +--- a/fs/nfsd/nfs3proc.c ++++ b/fs/nfsd/nfs3proc.c +@@ -13,6 +13,7 @@ + #include "cache.h" + #include "xdr3.h" + #include "vfs.h" ++#include "filecache.h" + + #define NFSDDBG_FACILITY NFSDDBG_PROC + +@@ -763,6 +764,7 @@ nfsd3_proc_commit(struct svc_rqst *rqstp) + { + struct nfsd3_commitargs *argp = rqstp->rq_argp; + struct nfsd3_commitres *resp = rqstp->rq_resp; ++ struct nfsd_file *nf; + + dprintk("nfsd: COMMIT(3) %s %u@%Lu\n", + SVCFH_fmt(&argp->fh), +@@ -770,8 +772,14 @@ nfsd3_proc_commit(struct svc_rqst *rqstp) + (unsigned long long) argp->offset); + + fh_copy(&resp->fh, &argp->fh); +- resp->status = nfsd_commit(rqstp, &resp->fh, argp->offset, ++ resp->status = nfsd_file_acquire(rqstp, &resp->fh, NFSD_MAY_WRITE | ++ NFSD_MAY_NOT_BREAK_LEASE, &nf); ++ if (resp->status) ++ goto out; ++ resp->status = nfsd_commit(rqstp, &resp->fh, nf, argp->offset, + argp->count, resp->verf); ++ nfsd_file_put(nf); ++out: + return rpc_success; + } + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 50fd4ba04a3e0..3fe1966ed7358 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -731,10 +731,19 @@ nfsd4_commit(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + union nfsd4_op_u *u) + { + struct nfsd4_commit *commit = &u->commit; ++ struct nfsd_file *nf; ++ __be32 status; + +- return nfsd_commit(rqstp, &cstate->current_fh, commit->co_offset, ++ status = nfsd_file_acquire(rqstp, &cstate->current_fh, NFSD_MAY_WRITE | ++ NFSD_MAY_NOT_BREAK_LEASE, &nf); ++ if (status != nfs_ok) ++ return status; ++ ++ status = nfsd_commit(rqstp, &cstate->current_fh, nf, commit->co_offset, + commit->co_count, + (__be32 *)commit->co_verf.data); ++ nfsd_file_put(nf); ++ return status; + } + + static __be32 +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index 9bda56fe303cf..3278dddd11ba9 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -1213,6 +1213,7 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, + * nfsd_commit - Commit pending writes to stable storage + * @rqstp: RPC request being processed + * @fhp: NFS filehandle ++ * @nf: target file + * @offset: raw offset from beginning of file + * @count: raw count of bytes to sync + * @verf: filled in with the server's current write verifier +@@ -1229,19 +1230,13 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, + * An nfsstat value in network byte order. + */ + __be32 +-nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, u64 offset, +- u32 count, __be32 *verf) ++nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf, ++ u64 offset, u32 count, __be32 *verf) + { ++ __be32 err = nfs_ok; + u64 maxbytes; + loff_t start, end; + struct nfsd_net *nn; +- struct nfsd_file *nf; +- __be32 err; +- +- err = nfsd_file_acquire(rqstp, fhp, +- NFSD_MAY_WRITE|NFSD_MAY_NOT_BREAK_LEASE, &nf); +- if (err) +- goto out; + + /* + * Convert the client-provided (offset, count) range to a +@@ -1282,8 +1277,6 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, u64 offset, + } else + nfsd_copy_write_verifier(verf, nn); + +- nfsd_file_put(nf); +-out: + return err; + } + +diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h +index 8ddd687f83599..dbdfef7ae85bb 100644 +--- a/fs/nfsd/vfs.h ++++ b/fs/nfsd/vfs.h +@@ -89,7 +89,8 @@ __be32 nfsd_access(struct svc_rqst *, struct svc_fh *, u32 *, u32 *); + __be32 nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, + struct svc_fh *resfhp, struct nfsd_attrs *iap); + __be32 nfsd_commit(struct svc_rqst *rqst, struct svc_fh *fhp, +- u64 offset, u32 count, __be32 *verf); ++ struct nfsd_file *nf, u64 offset, u32 count, ++ __be32 *verf); + #ifdef CONFIG_NFSD_V4 + __be32 nfsd_getxattr(struct svc_rqst *rqstp, struct svc_fh *fhp, + char *name, void **bufp, int *lenp); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-prevent-a-possible-oops-in-the-nfs_dirent-trace.patch b/queue-5.10/nfsd-prevent-a-possible-oops-in-the-nfs_dirent-trace.patch new file mode 100644 index 00000000000..bff983d56e2 --- /dev/null +++ b/queue-5.10/nfsd-prevent-a-possible-oops-in-the-nfs_dirent-trace.patch @@ -0,0 +1,37 @@ +From b070d3903755be6f34ec375c250d3b36fdf2e572 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 25 Jun 2021 11:12:49 -0400 +Subject: NFSD: Prevent a possible oops in the nfs_dirent() tracepoint + +From: Chuck Lever + +[ Upstream commit 7b08cf62b1239a4322427d677ea9363f0ab677c6 ] + +The double copy of the string is a mistake, plus __assign_str() +uses strlen(), which is wrong to do on a string that isn't +guaranteed to be NUL-terminated. + +Fixes: 6019ce0742ca ("NFSD: Add a tracepoint to record directory entry encoding") +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/trace.h | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index 68a0fecdd5f46..de245f433392d 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -408,7 +408,6 @@ TRACE_EVENT(nfsd_dirent, + __entry->ino = ino; + __entry->len = namlen; + memcpy(__get_str(name), name, namlen); +- __assign_str(name, name); + ), + TP_printk("fh_hash=0x%08x ino=%llu name=%.*s", + __entry->fh_hash, __entry->ino, +-- +2.43.0 + diff --git a/queue-5.10/nfsd-prevent-truncation-of-an-unlinked-inode-from-bl.patch b/queue-5.10/nfsd-prevent-truncation-of-an-unlinked-inode-from-bl.patch new file mode 100644 index 00000000000..692841d09f7 --- /dev/null +++ b/queue-5.10/nfsd-prevent-truncation-of-an-unlinked-inode-from-bl.patch @@ -0,0 +1,57 @@ +From 4b4b2f629e1ade8fd1e7c7aef5ef0b62981520a5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 14 May 2021 11:58:29 +0800 +Subject: nfsd: Prevent truncation of an unlinked inode from blocking access to + its directory + +From: Yu Hsiang Huang + +[ Upstream commit e5d74a2d0ee67ae00edad43c3d7811016e4d2e21 ] + +Truncation of an unlinked inode may take a long time for I/O waiting, and +it doesn't have to prevent access to the directory. Thus, let truncation +occur outside the directory's mutex, just like do_unlinkat() does. + +Signed-off-by: Yu Hsiang Huang +Signed-off-by: Bing Jing Chang +Signed-off-by: Robbie Ko +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/vfs.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index 520e55c35e742..2eb3bfbc8a35f 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -1870,6 +1870,7 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, + { + struct dentry *dentry, *rdentry; + struct inode *dirp; ++ struct inode *rinode; + __be32 err; + int host_err; + +@@ -1898,6 +1899,8 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, + host_err = -ENOENT; + goto out_drop_write; + } ++ rinode = d_inode(rdentry); ++ ihold(rinode); + + if (!type) + type = d_inode(rdentry)->i_mode & S_IFMT; +@@ -1913,6 +1916,8 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, + if (!host_err) + host_err = commit_metadata(fhp); + dput(rdentry); ++ fh_unlock(fhp); ++ iput(rinode); /* truncate the inode here */ + + out_drop_write: + fh_drop_write(fhp); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-propagate-some-error-code-returned-by-memdup_us.patch b/queue-5.10/nfsd-propagate-some-error-code-returned-by-memdup_us.patch new file mode 100644 index 00000000000..8710110f86c --- /dev/null +++ b/queue-5.10/nfsd-propagate-some-error-code-returned-by-memdup_us.patch @@ -0,0 +1,55 @@ +From 6600062cb0e1217badb66ff31e6089513a4e7346 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 1 Sep 2022 07:27:19 +0200 +Subject: nfsd: Propagate some error code returned by memdup_user() + +From: Christophe JAILLET + +[ Upstream commit 30a30fcc3fc1ad4c5d017c9fcb75dc8f59e7bdad ] + +Propagate the error code returned by memdup_user() instead of a hard coded +-EFAULT. + +Suggested-by: Dan Carpenter +Signed-off-by: Christophe JAILLET +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4recover.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c +index b9394a639a41a..189c622dde61c 100644 +--- a/fs/nfsd/nfs4recover.c ++++ b/fs/nfsd/nfs4recover.c +@@ -808,7 +808,7 @@ __cld_pipe_inprogress_downcall(const struct cld_msg_v2 __user *cmsg, + return -EFAULT; + name.data = memdup_user(&ci->cc_name.cn_id, namelen); + if (IS_ERR(name.data)) +- return -EFAULT; ++ return PTR_ERR(name.data); + name.len = namelen; + get_user(princhashlen, &ci->cc_princhash.cp_len); + if (princhashlen > 0) { +@@ -817,7 +817,7 @@ __cld_pipe_inprogress_downcall(const struct cld_msg_v2 __user *cmsg, + princhashlen); + if (IS_ERR(princhash.data)) { + kfree(name.data); +- return -EFAULT; ++ return PTR_ERR(princhash.data); + } + princhash.len = princhashlen; + } else +@@ -830,7 +830,7 @@ __cld_pipe_inprogress_downcall(const struct cld_msg_v2 __user *cmsg, + return -EFAULT; + name.data = memdup_user(&cnm->cn_id, namelen); + if (IS_ERR(name.data)) +- return -EFAULT; ++ return PTR_ERR(name.data); + name.len = namelen; + } + if (name.len > 5 && memcmp(name.data, "hash:", 5) == 0) { +-- +2.43.0 + diff --git a/queue-5.10/nfsd-protect-against-filesystem-freezing.patch b/queue-5.10/nfsd-protect-against-filesystem-freezing.patch new file mode 100644 index 00000000000..7ce2c40a430 --- /dev/null +++ b/queue-5.10/nfsd-protect-against-filesystem-freezing.patch @@ -0,0 +1,42 @@ +From c85126162e89e4da721b50a00cf7324a53117897 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 6 Mar 2023 10:43:47 -0500 +Subject: NFSD: Protect against filesystem freezing + +From: Chuck Lever + +[ Upstream commit fd9a2e1d513823e840960cb3bc26d8b7749d4ac2 ] + +Flole observes this WARNING on occasion: + +[1210423.486503] WARNING: CPU: 8 PID: 1524732 at fs/ext4/ext4_jbd2.c:75 ext4_journal_check_start+0x68/0xb0 + +Reported-by: +Suggested-by: Jan Kara +Link: https://bugzilla.kernel.org/show_bug.cgi?id=217123 +Fixes: 73da852e3831 ("nfsd: use vfs_iter_read/write") +Reviewed-by: Jeff Layton +Reviewed-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/vfs.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index 3d67dd7eab4b5..ddf424d76d410 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -1117,7 +1117,9 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf, + since = READ_ONCE(file->f_wb_err); + if (verf) + nfsd_copy_write_verifier(verf, nn); ++ file_start_write(file); + host_err = vfs_iter_write(file, &iter, &pos, flags); ++ file_end_write(file); + if (host_err < 0) { + nfsd_reset_write_verifier(nn); + trace_nfsd_writeverf_reset(nn, rqstp, host_err); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-protect-against-send-buffer-overflow-in-nfsv2-r.patch b/queue-5.10/nfsd-protect-against-send-buffer-overflow-in-nfsv2-r.patch new file mode 100644 index 00000000000..7f5c8b38c62 --- /dev/null +++ b/queue-5.10/nfsd-protect-against-send-buffer-overflow-in-nfsv2-r.patch @@ -0,0 +1,43 @@ +From 2fa75cb1316a35dee8db48f5b5265d6f69d66663 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 1 Sep 2022 15:10:05 -0400 +Subject: NFSD: Protect against send buffer overflow in NFSv2 READDIR + +From: Chuck Lever + +[ Upstream commit 00b4492686e0497fdb924a9d4c8f6f99377e176c ] + +Restore the previous limit on the @count argument to prevent a +buffer overflow attack. + +Fixes: 53b1119a6e50 ("NFSD: Fix READDIR buffer overflow") +Signed-off-by: Chuck Lever +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsproc.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c +index e533550a26db5..559603a0a5358 100644 +--- a/fs/nfsd/nfsproc.c ++++ b/fs/nfsd/nfsproc.c +@@ -567,12 +567,11 @@ static void nfsd_init_dirlist_pages(struct svc_rqst *rqstp, + struct xdr_buf *buf = &resp->dirlist; + struct xdr_stream *xdr = &resp->xdr; + +- count = clamp(count, (u32)(XDR_UNIT * 2), svc_max_payload(rqstp)); +- + memset(buf, 0, sizeof(*buf)); + + /* Reserve room for the NULL ptr & eof flag (-2 words) */ +- buf->buflen = count - XDR_UNIT * 2; ++ buf->buflen = clamp(count, (u32)(XDR_UNIT * 2), (u32)PAGE_SIZE); ++ buf->buflen -= XDR_UNIT * 2; + buf->pages = rqstp->rq_next_page; + rqstp->rq_next_page++; + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-protect-against-send-buffer-overflow-in-nfsv2-r.patch-22138 b/queue-5.10/nfsd-protect-against-send-buffer-overflow-in-nfsv2-r.patch-22138 new file mode 100644 index 00000000000..1dd39172143 --- /dev/null +++ b/queue-5.10/nfsd-protect-against-send-buffer-overflow-in-nfsv2-r.patch-22138 @@ -0,0 +1,50 @@ +From 2c5dc7c14fac1506fa8ae9ce8eb3626fc6df0b12 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 1 Sep 2022 15:10:18 -0400 +Subject: NFSD: Protect against send buffer overflow in NFSv2 READ + +From: Chuck Lever + +[ Upstream commit 401bc1f90874280a80b93f23be33a0e7e2d1f912 ] + +Since before the git era, NFSD has conserved the number of pages +held by each nfsd thread by combining the RPC receive and send +buffers into a single array of pages. This works because there are +no cases where an operation needs a large RPC Call message and a +large RPC Reply at the same time. + +Once an RPC Call has been received, svc_process() updates +svc_rqst::rq_res to describe the part of rq_pages that can be +used for constructing the Reply. This means that the send buffer +(rq_res) shrinks when the received RPC record containing the RPC +Call is large. + +A client can force this shrinkage on TCP by sending a correctly- +formed RPC Call header contained in an RPC record that is +excessively large. The full maximum payload size cannot be +constructed in that case. + +Cc: +Signed-off-by: Chuck Lever +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsproc.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c +index 559603a0a5358..749c3354304c2 100644 +--- a/fs/nfsd/nfsproc.c ++++ b/fs/nfsd/nfsproc.c +@@ -185,6 +185,7 @@ nfsd_proc_read(struct svc_rqst *rqstp) + argp->count, argp->offset); + + argp->count = min_t(u32, argp->count, NFSSVC_MAXBLKSIZE_V2); ++ argp->count = min_t(u32, argp->count, rqstp->rq_res.buflen); + + v = 0; + len = argp->count; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-protect-against-send-buffer-overflow-in-nfsv3-r.patch b/queue-5.10/nfsd-protect-against-send-buffer-overflow-in-nfsv3-r.patch new file mode 100644 index 00000000000..38c63585ca9 --- /dev/null +++ b/queue-5.10/nfsd-protect-against-send-buffer-overflow-in-nfsv3-r.patch @@ -0,0 +1,64 @@ +From 7c6691c3dad395ca715c972974de3ef242147e1a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 1 Sep 2022 15:10:12 -0400 +Subject: NFSD: Protect against send buffer overflow in NFSv3 READDIR + +From: Chuck Lever + +[ Upstream commit 640f87c190e0d1b2a0fcb2ecf6d2cd53b1c41991 ] + +Since before the git era, NFSD has conserved the number of pages +held by each nfsd thread by combining the RPC receive and send +buffers into a single array of pages. This works because there are +no cases where an operation needs a large RPC Call message and a +large RPC Reply message at the same time. + +Once an RPC Call has been received, svc_process() updates +svc_rqst::rq_res to describe the part of rq_pages that can be +used for constructing the Reply. This means that the send buffer +(rq_res) shrinks when the received RPC record containing the RPC +Call is large. + +A client can force this shrinkage on TCP by sending a correctly- +formed RPC Call header contained in an RPC record that is +excessively large. The full maximum payload size cannot be +constructed in that case. + +Thanks to Aleksi Illikainen and Kari Hulkko for uncovering this +issue. + +Reported-by: Ben Ronallo +Cc: +Signed-off-by: Chuck Lever +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3proc.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c +index 1a52f0b06ec32..d808779ab4538 100644 +--- a/fs/nfsd/nfs3proc.c ++++ b/fs/nfsd/nfs3proc.c +@@ -563,13 +563,14 @@ static void nfsd3_init_dirlist_pages(struct svc_rqst *rqstp, + { + struct xdr_buf *buf = &resp->dirlist; + struct xdr_stream *xdr = &resp->xdr; +- +- count = clamp(count, (u32)(XDR_UNIT * 2), svc_max_payload(rqstp)); ++ unsigned int sendbuf = min_t(unsigned int, rqstp->rq_res.buflen, ++ svc_max_payload(rqstp)); + + memset(buf, 0, sizeof(*buf)); + + /* Reserve room for the NULL ptr & eof flag (-2 words) */ +- buf->buflen = count - XDR_UNIT * 2; ++ buf->buflen = clamp(count, (u32)(XDR_UNIT * 2), sendbuf); ++ buf->buflen -= XDR_UNIT * 2; + buf->pages = rqstp->rq_next_page; + rqstp->rq_next_page += (buf->buflen + PAGE_SIZE - 1) >> PAGE_SHIFT; + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-protect-against-send-buffer-overflow-in-nfsv3-r.patch-26809 b/queue-5.10/nfsd-protect-against-send-buffer-overflow-in-nfsv3-r.patch-26809 new file mode 100644 index 00000000000..abf5bc7bad0 --- /dev/null +++ b/queue-5.10/nfsd-protect-against-send-buffer-overflow-in-nfsv3-r.patch-26809 @@ -0,0 +1,60 @@ +From 70c8857d58aed91598f46eab9e8541671ec22e86 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 1 Sep 2022 15:10:24 -0400 +Subject: NFSD: Protect against send buffer overflow in NFSv3 READ + +From: Chuck Lever + +[ Upstream commit fa6be9cc6e80ec79892ddf08a8c10cabab9baf38 ] + +Since before the git era, NFSD has conserved the number of pages +held by each nfsd thread by combining the RPC receive and send +buffers into a single array of pages. This works because there are +no cases where an operation needs a large RPC Call message and a +large RPC Reply at the same time. + +Once an RPC Call has been received, svc_process() updates +svc_rqst::rq_res to describe the part of rq_pages that can be +used for constructing the Reply. This means that the send buffer +(rq_res) shrinks when the received RPC record containing the RPC +Call is large. + +A client can force this shrinkage on TCP by sending a correctly- +formed RPC Call header contained in an RPC record that is +excessively large. The full maximum payload size cannot be +constructed in that case. + +Cc: +Signed-off-by: Chuck Lever +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3proc.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c +index d808779ab4538..8679c41746027 100644 +--- a/fs/nfsd/nfs3proc.c ++++ b/fs/nfsd/nfs3proc.c +@@ -150,7 +150,6 @@ nfsd3_proc_read(struct svc_rqst *rqstp) + { + struct nfsd3_readargs *argp = rqstp->rq_argp; + struct nfsd3_readres *resp = rqstp->rq_resp; +- u32 max_blocksize = svc_max_payload(rqstp); + unsigned int len; + int v; + +@@ -159,7 +158,8 @@ nfsd3_proc_read(struct svc_rqst *rqstp) + (unsigned long) argp->count, + (unsigned long long) argp->offset); + +- argp->count = min_t(u32, argp->count, max_blocksize); ++ argp->count = min_t(u32, argp->count, svc_max_payload(rqstp)); ++ argp->count = min_t(u32, argp->count, rqstp->rq_res.buflen); + if (argp->offset > (u64)OFFSET_MAX) + argp->offset = (u64)OFFSET_MAX; + if (argp->offset + argp->count > (u64)OFFSET_MAX) +-- +2.43.0 + diff --git a/queue-5.10/nfsd-protect-concurrent-access-to-nfsd-stats-counter.patch b/queue-5.10/nfsd-protect-concurrent-access-to-nfsd-stats-counter.patch new file mode 100644 index 00000000000..e9ed570f380 --- /dev/null +++ b/queue-5.10/nfsd-protect-concurrent-access-to-nfsd-stats-counter.patch @@ -0,0 +1,513 @@ +From 310af496196f35661767ab1460071e8cc6e2463d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 Jan 2021 09:52:35 +0200 +Subject: nfsd: protect concurrent access to nfsd stats counters + +From: Amir Goldstein + +[ Upstream commit e567b98ce9a4b35b63c364d24828a9e5cd7a8179 ] + +nfsd stats counters can be updated by concurrent nfsd threads without any +protection. + +Convert some nfsd_stats and nfsd_net struct members to use percpu counters. + +The longest_chain* members of struct nfsd_net remain unprotected. + +Signed-off-by: Amir Goldstein +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/netns.h | 23 +++++++------ + fs/nfsd/nfs4proc.c | 2 +- + fs/nfsd/nfscache.c | 52 +++++++++++++++++++++--------- + fs/nfsd/nfsctl.c | 5 ++- + fs/nfsd/nfsfh.c | 2 +- + fs/nfsd/stats.c | 77 ++++++++++++++++++++++++++++++++++++-------- + fs/nfsd/stats.h | 80 +++++++++++++++++++++++++++++++++++++++------- + fs/nfsd/vfs.c | 4 +-- + 8 files changed, 192 insertions(+), 53 deletions(-) + +diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h +index 02d3d2f0e6168..a75abeb1e6988 100644 +--- a/fs/nfsd/netns.h ++++ b/fs/nfsd/netns.h +@@ -10,6 +10,7 @@ + + #include + #include ++#include + + /* Hash tables for nfs4_clientid state */ + #define CLIENT_HASH_BITS 4 +@@ -21,6 +22,14 @@ + struct cld_net; + struct nfsd4_client_tracking_ops; + ++enum { ++ /* cache misses due only to checksum comparison failures */ ++ NFSD_NET_PAYLOAD_MISSES, ++ /* amount of memory (in bytes) currently consumed by the DRC */ ++ NFSD_NET_DRC_MEM_USAGE, ++ NFSD_NET_COUNTERS_NUM ++}; ++ + /* + * Represents a nfsd "container". With respect to nfsv4 state tracking, the + * fields of interest are the *_id_hashtbls and the *_name_tree. These track +@@ -149,20 +158,16 @@ struct nfsd_net { + + /* + * Stats and other tracking of on the duplicate reply cache. +- * These fields and the "rc" fields in nfsdstats are modified +- * with only the per-bucket cache lock, which isn't really safe +- * and should be fixed if we want the statistics to be +- * completely accurate. ++ * The longest_chain* fields are modified with only the per-bucket ++ * cache lock, which isn't really safe and should be fixed if we want ++ * these statistics to be completely accurate. + */ + + /* total number of entries */ + atomic_t num_drc_entries; + +- /* cache misses due only to checksum comparison failures */ +- unsigned int payload_misses; +- +- /* amount of memory (in bytes) currently consumed by the DRC */ +- unsigned int drc_mem_usage; ++ /* Per-netns stats counters */ ++ struct percpu_counter counter[NFSD_NET_COUNTERS_NUM]; + + /* longest hash chain seen */ + unsigned int longest_chain; +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index a5e1f5c1a4d64..4f64d94909ec1 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -2168,7 +2168,7 @@ nfsd4_proc_null(struct svc_rqst *rqstp) + static inline void nfsd4_increment_op_stats(u32 opnum) + { + if (opnum >= FIRST_NFS4_OP && opnum <= LAST_NFS4_OP) +- nfsdstats.nfs4_opcount[opnum]++; ++ percpu_counter_inc(&nfsdstats.counter[NFSD_STATS_NFS4_OP(opnum)]); + } + + static const struct nfsd4_operation nfsd4_ops[]; +diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c +index 80c90fc231a53..96cdf77925f33 100644 +--- a/fs/nfsd/nfscache.c ++++ b/fs/nfsd/nfscache.c +@@ -121,14 +121,14 @@ nfsd_reply_cache_free_locked(struct nfsd_drc_bucket *b, struct svc_cacherep *rp, + struct nfsd_net *nn) + { + if (rp->c_type == RC_REPLBUFF && rp->c_replvec.iov_base) { +- nn->drc_mem_usage -= rp->c_replvec.iov_len; ++ nfsd_stats_drc_mem_usage_sub(nn, rp->c_replvec.iov_len); + kfree(rp->c_replvec.iov_base); + } + if (rp->c_state != RC_UNUSED) { + rb_erase(&rp->c_node, &b->rb_head); + list_del(&rp->c_lru); + atomic_dec(&nn->num_drc_entries); +- nn->drc_mem_usage -= sizeof(*rp); ++ nfsd_stats_drc_mem_usage_sub(nn, sizeof(*rp)); + } + kmem_cache_free(drc_slab, rp); + } +@@ -154,6 +154,16 @@ void nfsd_drc_slab_free(void) + kmem_cache_destroy(drc_slab); + } + ++static int nfsd_reply_cache_stats_init(struct nfsd_net *nn) ++{ ++ return nfsd_percpu_counters_init(nn->counter, NFSD_NET_COUNTERS_NUM); ++} ++ ++static void nfsd_reply_cache_stats_destroy(struct nfsd_net *nn) ++{ ++ nfsd_percpu_counters_destroy(nn->counter, NFSD_NET_COUNTERS_NUM); ++} ++ + int nfsd_reply_cache_init(struct nfsd_net *nn) + { + unsigned int hashsize; +@@ -165,12 +175,16 @@ int nfsd_reply_cache_init(struct nfsd_net *nn) + hashsize = nfsd_hashsize(nn->max_drc_entries); + nn->maskbits = ilog2(hashsize); + ++ status = nfsd_reply_cache_stats_init(nn); ++ if (status) ++ goto out_nomem; ++ + nn->nfsd_reply_cache_shrinker.scan_objects = nfsd_reply_cache_scan; + nn->nfsd_reply_cache_shrinker.count_objects = nfsd_reply_cache_count; + nn->nfsd_reply_cache_shrinker.seeks = 1; + status = register_shrinker(&nn->nfsd_reply_cache_shrinker); + if (status) +- goto out_nomem; ++ goto out_stats_destroy; + + nn->drc_hashtbl = kvzalloc(array_size(hashsize, + sizeof(*nn->drc_hashtbl)), GFP_KERNEL); +@@ -186,6 +200,8 @@ int nfsd_reply_cache_init(struct nfsd_net *nn) + return 0; + out_shrinker: + unregister_shrinker(&nn->nfsd_reply_cache_shrinker); ++out_stats_destroy: ++ nfsd_reply_cache_stats_destroy(nn); + out_nomem: + printk(KERN_ERR "nfsd: failed to allocate reply cache\n"); + return -ENOMEM; +@@ -196,6 +212,7 @@ void nfsd_reply_cache_shutdown(struct nfsd_net *nn) + struct svc_cacherep *rp; + unsigned int i; + ++ nfsd_reply_cache_stats_destroy(nn); + unregister_shrinker(&nn->nfsd_reply_cache_shrinker); + + for (i = 0; i < nn->drc_hashsize; i++) { +@@ -324,7 +341,7 @@ nfsd_cache_key_cmp(const struct svc_cacherep *key, + { + if (key->c_key.k_xid == rp->c_key.k_xid && + key->c_key.k_csum != rp->c_key.k_csum) { +- ++nn->payload_misses; ++ nfsd_stats_payload_misses_inc(nn); + trace_nfsd_drc_mismatch(nn, key, rp); + } + +@@ -407,7 +424,7 @@ int nfsd_cache_lookup(struct svc_rqst *rqstp) + + rqstp->rq_cacherep = NULL; + if (type == RC_NOCACHE) { +- nfsdstats.rcnocache++; ++ nfsd_stats_rc_nocache_inc(); + goto out; + } + +@@ -429,12 +446,12 @@ int nfsd_cache_lookup(struct svc_rqst *rqstp) + goto found_entry; + } + +- nfsdstats.rcmisses++; ++ nfsd_stats_rc_misses_inc(); + rqstp->rq_cacherep = rp; + rp->c_state = RC_INPROG; + + atomic_inc(&nn->num_drc_entries); +- nn->drc_mem_usage += sizeof(*rp); ++ nfsd_stats_drc_mem_usage_add(nn, sizeof(*rp)); + + /* go ahead and prune the cache */ + prune_bucket(b, nn); +@@ -446,7 +463,7 @@ int nfsd_cache_lookup(struct svc_rqst *rqstp) + + found_entry: + /* We found a matching entry which is either in progress or done. */ +- nfsdstats.rchits++; ++ nfsd_stats_rc_hits_inc(); + rtn = RC_DROPIT; + + /* Request being processed */ +@@ -548,7 +565,7 @@ void nfsd_cache_update(struct svc_rqst *rqstp, int cachetype, __be32 *statp) + return; + } + spin_lock(&b->cache_lock); +- nn->drc_mem_usage += bufsize; ++ nfsd_stats_drc_mem_usage_add(nn, bufsize); + lru_put_end(b, rp); + rp->c_secure = test_bit(RQ_SECURE, &rqstp->rq_flags); + rp->c_type = cachetype; +@@ -588,13 +605,18 @@ static int nfsd_reply_cache_stats_show(struct seq_file *m, void *v) + + seq_printf(m, "max entries: %u\n", nn->max_drc_entries); + seq_printf(m, "num entries: %u\n", +- atomic_read(&nn->num_drc_entries)); ++ atomic_read(&nn->num_drc_entries)); + seq_printf(m, "hash buckets: %u\n", 1 << nn->maskbits); +- seq_printf(m, "mem usage: %u\n", nn->drc_mem_usage); +- seq_printf(m, "cache hits: %u\n", nfsdstats.rchits); +- seq_printf(m, "cache misses: %u\n", nfsdstats.rcmisses); +- seq_printf(m, "not cached: %u\n", nfsdstats.rcnocache); +- seq_printf(m, "payload misses: %u\n", nn->payload_misses); ++ seq_printf(m, "mem usage: %lld\n", ++ percpu_counter_sum_positive(&nn->counter[NFSD_NET_DRC_MEM_USAGE])); ++ seq_printf(m, "cache hits: %lld\n", ++ percpu_counter_sum_positive(&nfsdstats.counter[NFSD_STATS_RC_HITS])); ++ seq_printf(m, "cache misses: %lld\n", ++ percpu_counter_sum_positive(&nfsdstats.counter[NFSD_STATS_RC_MISSES])); ++ seq_printf(m, "not cached: %lld\n", ++ percpu_counter_sum_positive(&nfsdstats.counter[NFSD_STATS_RC_NOCACHE])); ++ seq_printf(m, "payload misses: %lld\n", ++ percpu_counter_sum_positive(&nn->counter[NFSD_NET_PAYLOAD_MISSES])); + seq_printf(m, "longest chain len: %u\n", nn->longest_chain); + seq_printf(m, "cachesize at longest: %u\n", nn->longest_chain_cachesize); + return 0; +diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c +index c4b11560ac1b6..7f85c171f83aa 100644 +--- a/fs/nfsd/nfsctl.c ++++ b/fs/nfsd/nfsctl.c +@@ -1522,7 +1522,9 @@ static int __init init_nfsd(void) + retval = nfsd4_init_pnfs(); + if (retval) + goto out_free_slabs; +- nfsd_stat_init(); /* Statistics */ ++ retval = nfsd_stat_init(); /* Statistics */ ++ if (retval) ++ goto out_free_pnfs; + retval = nfsd_drc_slab_create(); + if (retval) + goto out_free_stat; +@@ -1552,6 +1554,7 @@ static int __init init_nfsd(void) + nfsd_drc_slab_free(); + out_free_stat: + nfsd_stat_shutdown(); ++out_free_pnfs: + nfsd4_exit_pnfs(); + out_free_slabs: + nfsd4_free_slabs(); +diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c +index 66f2ef67792a7..9e31b2b5c6d26 100644 +--- a/fs/nfsd/nfsfh.c ++++ b/fs/nfsd/nfsfh.c +@@ -422,7 +422,7 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int access) + } + out: + if (error == nfserr_stale) +- nfsdstats.fh_stale++; ++ nfsd_stats_fh_stale_inc(); + return error; + } + +diff --git a/fs/nfsd/stats.c b/fs/nfsd/stats.c +index e928e224205ac..1d3b881e73821 100644 +--- a/fs/nfsd/stats.c ++++ b/fs/nfsd/stats.c +@@ -36,13 +36,13 @@ static int nfsd_proc_show(struct seq_file *seq, void *v) + { + int i; + +- seq_printf(seq, "rc %u %u %u\nfh %u 0 0 0 0\nio %u %u\n", +- nfsdstats.rchits, +- nfsdstats.rcmisses, +- nfsdstats.rcnocache, +- nfsdstats.fh_stale, +- nfsdstats.io_read, +- nfsdstats.io_write); ++ seq_printf(seq, "rc %lld %lld %lld\nfh %lld 0 0 0 0\nio %lld %lld\n", ++ percpu_counter_sum_positive(&nfsdstats.counter[NFSD_STATS_RC_HITS]), ++ percpu_counter_sum_positive(&nfsdstats.counter[NFSD_STATS_RC_MISSES]), ++ percpu_counter_sum_positive(&nfsdstats.counter[NFSD_STATS_RC_NOCACHE]), ++ percpu_counter_sum_positive(&nfsdstats.counter[NFSD_STATS_FH_STALE]), ++ percpu_counter_sum_positive(&nfsdstats.counter[NFSD_STATS_IO_READ]), ++ percpu_counter_sum_positive(&nfsdstats.counter[NFSD_STATS_IO_WRITE])); + + /* thread usage: */ + seq_printf(seq, "th %u 0", nfsdstats.th_cnt); +@@ -61,8 +61,10 @@ static int nfsd_proc_show(struct seq_file *seq, void *v) + /* Show count for individual nfsv4 operations */ + /* Writing operation numbers 0 1 2 also for maintaining uniformity */ + seq_printf(seq,"proc4ops %u", LAST_NFS4_OP + 1); +- for (i = 0; i <= LAST_NFS4_OP; i++) +- seq_printf(seq, " %u", nfsdstats.nfs4_opcount[i]); ++ for (i = 0; i <= LAST_NFS4_OP; i++) { ++ seq_printf(seq, " %lld", ++ percpu_counter_sum_positive(&nfsdstats.counter[NFSD_STATS_NFS4_OP(i)])); ++ } + + seq_putc(seq, '\n'); + #endif +@@ -82,14 +84,63 @@ static const struct proc_ops nfsd_proc_ops = { + .proc_release = single_release, + }; + +-void +-nfsd_stat_init(void) ++int nfsd_percpu_counters_init(struct percpu_counter counters[], int num) + { ++ int i, err = 0; ++ ++ for (i = 0; !err && i < num; i++) ++ err = percpu_counter_init(&counters[i], 0, GFP_KERNEL); ++ ++ if (!err) ++ return 0; ++ ++ for (; i > 0; i--) ++ percpu_counter_destroy(&counters[i-1]); ++ ++ return err; ++} ++ ++void nfsd_percpu_counters_reset(struct percpu_counter counters[], int num) ++{ ++ int i; ++ ++ for (i = 0; i < num; i++) ++ percpu_counter_set(&counters[i], 0); ++} ++ ++void nfsd_percpu_counters_destroy(struct percpu_counter counters[], int num) ++{ ++ int i; ++ ++ for (i = 0; i < num; i++) ++ percpu_counter_destroy(&counters[i]); ++} ++ ++static int nfsd_stat_counters_init(void) ++{ ++ return nfsd_percpu_counters_init(nfsdstats.counter, NFSD_STATS_COUNTERS_NUM); ++} ++ ++static void nfsd_stat_counters_destroy(void) ++{ ++ nfsd_percpu_counters_destroy(nfsdstats.counter, NFSD_STATS_COUNTERS_NUM); ++} ++ ++int nfsd_stat_init(void) ++{ ++ int err; ++ ++ err = nfsd_stat_counters_init(); ++ if (err) ++ return err; ++ + svc_proc_register(&init_net, &nfsd_svcstats, &nfsd_proc_ops); ++ ++ return 0; + } + +-void +-nfsd_stat_shutdown(void) ++void nfsd_stat_shutdown(void) + { ++ nfsd_stat_counters_destroy(); + svc_proc_unregister(&init_net, "nfsd"); + } +diff --git a/fs/nfsd/stats.h b/fs/nfsd/stats.h +index 5e3cdf21556a1..87c3150c200f0 100644 +--- a/fs/nfsd/stats.h ++++ b/fs/nfsd/stats.h +@@ -8,27 +8,85 @@ + #define _NFSD_STATS_H + + #include ++#include + + +-struct nfsd_stats { +- unsigned int rchits; /* repcache hits */ +- unsigned int rcmisses; /* repcache hits */ +- unsigned int rcnocache; /* uncached reqs */ +- unsigned int fh_stale; /* FH stale error */ +- unsigned int io_read; /* bytes returned to read requests */ +- unsigned int io_write; /* bytes passed in write requests */ +- unsigned int th_cnt; /* number of available threads */ ++enum { ++ NFSD_STATS_RC_HITS, /* repcache hits */ ++ NFSD_STATS_RC_MISSES, /* repcache misses */ ++ NFSD_STATS_RC_NOCACHE, /* uncached reqs */ ++ NFSD_STATS_FH_STALE, /* FH stale error */ ++ NFSD_STATS_IO_READ, /* bytes returned to read requests */ ++ NFSD_STATS_IO_WRITE, /* bytes passed in write requests */ + #ifdef CONFIG_NFSD_V4 +- unsigned int nfs4_opcount[LAST_NFS4_OP + 1]; /* count of individual nfsv4 operations */ ++ NFSD_STATS_FIRST_NFS4_OP, /* count of individual nfsv4 operations */ ++ NFSD_STATS_LAST_NFS4_OP = NFSD_STATS_FIRST_NFS4_OP + LAST_NFS4_OP, ++#define NFSD_STATS_NFS4_OP(op) (NFSD_STATS_FIRST_NFS4_OP + (op)) + #endif ++ NFSD_STATS_COUNTERS_NUM ++}; ++ ++struct nfsd_stats { ++ struct percpu_counter counter[NFSD_STATS_COUNTERS_NUM]; + ++ /* Protected by nfsd_mutex */ ++ unsigned int th_cnt; /* number of available threads */ + }; + + + extern struct nfsd_stats nfsdstats; ++ + extern struct svc_stat nfsd_svcstats; + +-void nfsd_stat_init(void); +-void nfsd_stat_shutdown(void); ++int nfsd_percpu_counters_init(struct percpu_counter counters[], int num); ++void nfsd_percpu_counters_reset(struct percpu_counter counters[], int num); ++void nfsd_percpu_counters_destroy(struct percpu_counter counters[], int num); ++int nfsd_stat_init(void); ++void nfsd_stat_shutdown(void); ++ ++static inline void nfsd_stats_rc_hits_inc(void) ++{ ++ percpu_counter_inc(&nfsdstats.counter[NFSD_STATS_RC_HITS]); ++} ++ ++static inline void nfsd_stats_rc_misses_inc(void) ++{ ++ percpu_counter_inc(&nfsdstats.counter[NFSD_STATS_RC_MISSES]); ++} ++ ++static inline void nfsd_stats_rc_nocache_inc(void) ++{ ++ percpu_counter_inc(&nfsdstats.counter[NFSD_STATS_RC_NOCACHE]); ++} ++ ++static inline void nfsd_stats_fh_stale_inc(void) ++{ ++ percpu_counter_inc(&nfsdstats.counter[NFSD_STATS_FH_STALE]); ++} ++ ++static inline void nfsd_stats_io_read_add(s64 amount) ++{ ++ percpu_counter_add(&nfsdstats.counter[NFSD_STATS_IO_READ], amount); ++} ++ ++static inline void nfsd_stats_io_write_add(s64 amount) ++{ ++ percpu_counter_add(&nfsdstats.counter[NFSD_STATS_IO_WRITE], amount); ++} ++ ++static inline void nfsd_stats_payload_misses_inc(struct nfsd_net *nn) ++{ ++ percpu_counter_inc(&nn->counter[NFSD_NET_PAYLOAD_MISSES]); ++} ++ ++static inline void nfsd_stats_drc_mem_usage_add(struct nfsd_net *nn, s64 amount) ++{ ++ percpu_counter_add(&nn->counter[NFSD_NET_DRC_MEM_USAGE], amount); ++} ++ ++static inline void nfsd_stats_drc_mem_usage_sub(struct nfsd_net *nn, s64 amount) ++{ ++ percpu_counter_sub(&nn->counter[NFSD_NET_DRC_MEM_USAGE], amount); ++} + + #endif /* _NFSD_STATS_H */ +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index a515cbd0a7d8f..1b44d8f985be9 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -897,7 +897,7 @@ static __be32 nfsd_finish_read(struct svc_rqst *rqstp, struct svc_fh *fhp, + unsigned long *count, u32 *eof, ssize_t host_err) + { + if (host_err >= 0) { +- nfsdstats.io_read += host_err; ++ nfsd_stats_io_read_add(host_err); + *eof = nfsd_eof_on_read(file, offset, host_err, *count); + *count = host_err; + fsnotify_access(file); +@@ -1050,7 +1050,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf, + goto out_nfserr; + } + *cnt = host_err; +- nfsdstats.io_write += *cnt; ++ nfsd_stats_io_write_add(*cnt); + fsnotify_modify(file); + host_err = filemap_check_wb_err(file->f_mapping, since); + if (host_err < 0) +-- +2.43.0 + diff --git a/queue-5.10/nfsd-put-the-export-reference-in-nfsd4_verify_deleg_.patch b/queue-5.10/nfsd-put-the-export-reference-in-nfsd4_verify_deleg_.patch new file mode 100644 index 00000000000..d2db8b540a8 --- /dev/null +++ b/queue-5.10/nfsd-put-the-export-reference-in-nfsd4_verify_deleg_.patch @@ -0,0 +1,37 @@ +From aa5798a0cbf26e9fbd283b6611f3985765620d51 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 8 Nov 2022 11:23:11 -0500 +Subject: nfsd: put the export reference in nfsd4_verify_deleg_dentry + +From: Jeff Layton + +[ Upstream commit 50256e4793a5e5ab77703c82a47344ad2e774a59 ] + +nfsd_lookup_dentry returns an export reference in addition to the dentry +ref. Ensure that we put it too. + +Link: https://bugzilla.redhat.com/show_bug.cgi?id=2138866 +Fixes: 876c553cb410 ("NFSD: verify the opened dentry after setting a delegation") +Reported-by: Yongcheng Yang +Signed-off-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 948ef17178158..10915c72c7815 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -5397,6 +5397,7 @@ nfsd4_verify_deleg_dentry(struct nfsd4_open *open, struct nfs4_file *fp, + if (err) + return -EAGAIN; + ++ exp_put(exp); + dput(child); + if (child != file_dentry(fp->fi_deleg_file->nf_file)) + return -EAGAIN; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-record-nfsv4-pre-post-op-attributes-as-non-atom.patch b/queue-5.10/nfsd-record-nfsv4-pre-post-op-attributes-as-non-atom.patch new file mode 100644 index 00000000000..fee940c78e1 --- /dev/null +++ b/queue-5.10/nfsd-record-nfsv4-pre-post-op-attributes-as-non-atom.patch @@ -0,0 +1,96 @@ +From a89ced1800f4a3d8f2111666a4d0d7605e264333 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Nov 2020 23:14:27 -0500 +Subject: nfsd: Record NFSv4 pre/post-op attributes as non-atomic + +From: Trond Myklebust + +[ Upstream commit 716a8bc7f706eeef80ab42c99d9f210eda845c81 ] + +For the case of NFSv4, specify to the client that the pre/post-op +attributes were not recorded atomically with the main operation. + +Signed-off-by: Trond Myklebust +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfs/export.c | 3 ++- + fs/nfsd/nfsfh.c | 4 ++++ + fs/nfsd/nfsfh.h | 5 +++++ + fs/nfsd/xdr4.h | 2 +- + include/linux/exportfs.h | 3 +++ + 5 files changed, 15 insertions(+), 2 deletions(-) + +diff --git a/fs/nfs/export.c b/fs/nfs/export.c +index 48b879cfe6e3b..7412bb164fa77 100644 +--- a/fs/nfs/export.c ++++ b/fs/nfs/export.c +@@ -172,5 +172,6 @@ const struct export_operations nfs_export_ops = { + .fh_to_dentry = nfs_fh_to_dentry, + .get_parent = nfs_get_parent, + .flags = EXPORT_OP_NOWCC|EXPORT_OP_NOSUBTREECHK| +- EXPORT_OP_CLOSE_BEFORE_UNLINK|EXPORT_OP_REMOTE_FS, ++ EXPORT_OP_CLOSE_BEFORE_UNLINK|EXPORT_OP_REMOTE_FS| ++ EXPORT_OP_NOATOMIC_ATTR, + }; +diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c +index e80a7525561d0..66f2ef67792a7 100644 +--- a/fs/nfsd/nfsfh.c ++++ b/fs/nfsd/nfsfh.c +@@ -301,6 +301,10 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp) + fhp->fh_export = exp; + + switch (rqstp->rq_vers) { ++ case 4: ++ if (dentry->d_sb->s_export_op->flags & EXPORT_OP_NOATOMIC_ATTR) ++ fhp->fh_no_atomic_attr = true; ++ break; + case 3: + if (dentry->d_sb->s_export_op->flags & EXPORT_OP_NOWCC) + fhp->fh_no_wcc = true; +diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h +index 347d10aa62655..cb20c2cd34695 100644 +--- a/fs/nfsd/nfsfh.h ++++ b/fs/nfsd/nfsfh.h +@@ -36,6 +36,11 @@ typedef struct svc_fh { + bool fh_locked; /* inode locked by us */ + bool fh_want_write; /* remount protection taken */ + bool fh_no_wcc; /* no wcc data needed */ ++ bool fh_no_atomic_attr; ++ /* ++ * wcc data is not atomic with ++ * operation ++ */ + int fh_flags; /* FH flags */ + #ifdef CONFIG_NFSD_V3 + bool fh_post_saved; /* post-op attrs saved */ +diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h +index b4556e86e97c3..a60ff5ce1a375 100644 +--- a/fs/nfsd/xdr4.h ++++ b/fs/nfsd/xdr4.h +@@ -748,7 +748,7 @@ static inline void + set_change_info(struct nfsd4_change_info *cinfo, struct svc_fh *fhp) + { + BUG_ON(!fhp->fh_pre_saved); +- cinfo->atomic = (u32)fhp->fh_post_saved; ++ cinfo->atomic = (u32)(fhp->fh_post_saved && !fhp->fh_no_atomic_attr); + + cinfo->before_change = fhp->fh_pre_change; + cinfo->after_change = fhp->fh_post_change; +diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h +index d93e8a6737bb0..9f4d4bcbf251d 100644 +--- a/include/linux/exportfs.h ++++ b/include/linux/exportfs.h +@@ -217,6 +217,9 @@ struct export_operations { + #define EXPORT_OP_NOSUBTREECHK (0x2) /* no subtree checking */ + #define EXPORT_OP_CLOSE_BEFORE_UNLINK (0x4) /* close files before unlink */ + #define EXPORT_OP_REMOTE_FS (0x8) /* Filesystem is remote */ ++#define EXPORT_OP_NOATOMIC_ATTR (0x10) /* Filesystem cannot supply ++ atomic attribute updates ++ */ + unsigned long flags; + }; + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-record-number-of-flush-calls.patch b/queue-5.10/nfsd-record-number-of-flush-calls.patch new file mode 100644 index 00000000000..36e12cce263 --- /dev/null +++ b/queue-5.10/nfsd-record-number-of-flush-calls.patch @@ -0,0 +1,71 @@ +From b0821df96696c6de915f25233c318328f8a773fc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 Jul 2022 14:24:45 -0400 +Subject: NFSD: Record number of flush calls + +From: Chuck Lever + +[ Upstream commit df2aff524faceaf743b7c5ab0f4fb86cb511f782 ] + +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 13 +++++++++++-- + 1 file changed, 11 insertions(+), 2 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index e5bd9f06492c8..b9941d4ef20d6 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -45,6 +45,7 @@ static DEFINE_PER_CPU(unsigned long, nfsd_file_cache_hits); + static DEFINE_PER_CPU(unsigned long, nfsd_file_acquisitions); + static DEFINE_PER_CPU(unsigned long, nfsd_file_releases); + static DEFINE_PER_CPU(unsigned long, nfsd_file_total_age); ++static DEFINE_PER_CPU(unsigned long, nfsd_file_pages_flushed); + static DEFINE_PER_CPU(unsigned long, nfsd_file_evictions); + + struct nfsd_fcache_disposal { +@@ -242,7 +243,12 @@ nfsd_file_check_write_error(struct nfsd_file *nf) + static void + nfsd_file_flush(struct nfsd_file *nf) + { +- if (nf->nf_file && vfs_fsync(nf->nf_file, 1) != 0) ++ struct file *file = nf->nf_file; ++ ++ if (!file || !(file->f_mode & FMODE_WRITE)) ++ return; ++ this_cpu_add(nfsd_file_pages_flushed, file->f_mapping->nrpages); ++ if (vfs_fsync(file, 1) != 0) + nfsd_reset_write_verifier(net_generic(nf->nf_net, nfsd_net_id)); + } + +@@ -1069,7 +1075,8 @@ nfsd_file_create(struct svc_rqst *rqstp, struct svc_fh *fhp, + */ + static int nfsd_file_cache_stats_show(struct seq_file *m, void *v) + { +- unsigned long hits = 0, acquisitions = 0, releases = 0, evictions = 0; ++ unsigned long releases = 0, pages_flushed = 0, evictions = 0; ++ unsigned long hits = 0, acquisitions = 0; + unsigned int i, count = 0, longest = 0; + unsigned long lru = 0, total_age = 0; + +@@ -1094,6 +1101,7 @@ static int nfsd_file_cache_stats_show(struct seq_file *m, void *v) + releases += per_cpu(nfsd_file_releases, i); + total_age += per_cpu(nfsd_file_total_age, i); + evictions += per_cpu(nfsd_file_evictions, i); ++ pages_flushed += per_cpu(nfsd_file_pages_flushed, i); + } + + seq_printf(m, "total entries: %u\n", count); +@@ -1107,6 +1115,7 @@ static int nfsd_file_cache_stats_show(struct seq_file *m, void *v) + seq_printf(m, "mean age (ms): %ld\n", total_age / releases); + else + seq_printf(m, "mean age (ms): -\n"); ++ seq_printf(m, "pages flushed: %lu\n", pages_flushed); + return 0; + } + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-reduce-amount-of-struct-nfsd4_compoundargs-that.patch b/queue-5.10/nfsd-reduce-amount-of-struct-nfsd4_compoundargs-that.patch new file mode 100644 index 00000000000..726ff48637a --- /dev/null +++ b/queue-5.10/nfsd-reduce-amount-of-struct-nfsd4_compoundargs-that.patch @@ -0,0 +1,390 @@ +From 3d64e54e492fe3f79fd4ded54d066f5c924d00d2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Sep 2022 17:22:44 -0400 +Subject: NFSD: Reduce amount of struct nfsd4_compoundargs that needs clearing + +From: Chuck Lever + +[ Upstream commit 3fdc546462348b8a497c72bc894e0cde9f10fc40 ] + +Have SunRPC clear everything except for the iops array. Then have +each NFSv4 XDR decoder clear it's own argument before decoding. + +Now individual operations may have a large argument struct while not +penalizing the vast majority of operations with a small struct. + +And, clearing the argument structure occurs as the argument fields +are initialized, enabling the CPU to do write combining on that +memory. In some cases, clearing is not even necessary because all +of the fields in the argument structure are initialized by the +decoder. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 2 +- + fs/nfsd/nfs4xdr.c | 61 +++++++++++++++++++++++++++++++++++++--------- + 2 files changed, 51 insertions(+), 12 deletions(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index f6ea7445073fe..79f1990d40c44 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -3588,7 +3588,7 @@ static const struct svc_procedure nfsd_procedures4[2] = { + .pc_decode = nfs4svc_decode_compoundargs, + .pc_encode = nfs4svc_encode_compoundres, + .pc_argsize = sizeof(struct nfsd4_compoundargs), +- .pc_argzero = sizeof(struct nfsd4_compoundargs), ++ .pc_argzero = offsetof(struct nfsd4_compoundargs, iops), + .pc_ressize = sizeof(struct nfsd4_compoundres), + .pc_release = nfsd4_release_compoundargs, + .pc_cachetype = RC_NOCACHE, +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index b5ca83045d6e9..04699198eace7 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -793,6 +793,7 @@ nfsd4_decode_commit(struct nfsd4_compoundargs *argp, struct nfsd4_commit *commit + return nfserr_bad_xdr; + if (xdr_stream_decode_u32(argp->xdr, &commit->co_count) < 0) + return nfserr_bad_xdr; ++ memset(&commit->co_verf, 0, sizeof(commit->co_verf)); + return nfs_ok; + } + +@@ -801,6 +802,7 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create + { + __be32 *p, status; + ++ memset(create, 0, sizeof(*create)); + if (xdr_stream_decode_u32(argp->xdr, &create->cr_type) < 0) + return nfserr_bad_xdr; + switch (create->cr_type) { +@@ -850,6 +852,7 @@ nfsd4_decode_delegreturn(struct nfsd4_compoundargs *argp, struct nfsd4_delegretu + static inline __be32 + nfsd4_decode_getattr(struct nfsd4_compoundargs *argp, struct nfsd4_getattr *getattr) + { ++ memset(getattr, 0, sizeof(*getattr)); + return nfsd4_decode_bitmap4(argp, getattr->ga_bmval, + ARRAY_SIZE(getattr->ga_bmval)); + } +@@ -857,6 +860,7 @@ nfsd4_decode_getattr(struct nfsd4_compoundargs *argp, struct nfsd4_getattr *geta + static __be32 + nfsd4_decode_link(struct nfsd4_compoundargs *argp, struct nfsd4_link *link) + { ++ memset(link, 0, sizeof(*link)); + return nfsd4_decode_component4(argp, &link->li_name, &link->li_namelen); + } + +@@ -905,6 +909,7 @@ nfsd4_decode_locker4(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock) + static __be32 + nfsd4_decode_lock(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock) + { ++ memset(lock, 0, sizeof(*lock)); + if (xdr_stream_decode_u32(argp->xdr, &lock->lk_type) < 0) + return nfserr_bad_xdr; + if ((lock->lk_type < NFS4_READ_LT) || (lock->lk_type > NFS4_WRITEW_LT)) +@@ -921,6 +926,7 @@ nfsd4_decode_lock(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock) + static __be32 + nfsd4_decode_lockt(struct nfsd4_compoundargs *argp, struct nfsd4_lockt *lockt) + { ++ memset(lockt, 0, sizeof(*lockt)); + if (xdr_stream_decode_u32(argp->xdr, &lockt->lt_type) < 0) + return nfserr_bad_xdr; + if ((lockt->lt_type < NFS4_READ_LT) || (lockt->lt_type > NFS4_WRITEW_LT)) +@@ -1142,11 +1148,8 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) + __be32 status; + u32 dummy; + +- memset(open->op_bmval, 0, sizeof(open->op_bmval)); +- open->op_iattr.ia_valid = 0; +- open->op_openowner = NULL; ++ memset(open, 0, sizeof(*open)); + +- open->op_xdr_error = 0; + if (xdr_stream_decode_u32(argp->xdr, &open->op_seqid) < 0) + return nfserr_bad_xdr; + /* deleg_want is ignored */ +@@ -1181,6 +1184,8 @@ nfsd4_decode_open_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_open_con + if (xdr_stream_decode_u32(argp->xdr, &open_conf->oc_seqid) < 0) + return nfserr_bad_xdr; + ++ memset(&open_conf->oc_resp_stateid, 0, ++ sizeof(open_conf->oc_resp_stateid)); + return nfs_ok; + } + +@@ -1189,6 +1194,7 @@ nfsd4_decode_open_downgrade(struct nfsd4_compoundargs *argp, struct nfsd4_open_d + { + __be32 status; + ++ memset(open_down, 0, sizeof(*open_down)); + status = nfsd4_decode_stateid4(argp, &open_down->od_stateid); + if (status) + return status; +@@ -1218,6 +1224,7 @@ nfsd4_decode_putfh(struct nfsd4_compoundargs *argp, struct nfsd4_putfh *putfh) + if (!putfh->pf_fhval) + return nfserr_jukebox; + ++ putfh->no_verify = false; + return nfs_ok; + } + +@@ -1234,6 +1241,7 @@ nfsd4_decode_read(struct nfsd4_compoundargs *argp, struct nfsd4_read *read) + { + __be32 status; + ++ memset(read, 0, sizeof(*read)); + status = nfsd4_decode_stateid4(argp, &read->rd_stateid); + if (status) + return status; +@@ -1250,6 +1258,7 @@ nfsd4_decode_readdir(struct nfsd4_compoundargs *argp, struct nfsd4_readdir *read + { + __be32 status; + ++ memset(readdir, 0, sizeof(*readdir)); + if (xdr_stream_decode_u64(argp->xdr, &readdir->rd_cookie) < 0) + return nfserr_bad_xdr; + status = nfsd4_decode_verifier4(argp, &readdir->rd_verf); +@@ -1269,6 +1278,7 @@ nfsd4_decode_readdir(struct nfsd4_compoundargs *argp, struct nfsd4_readdir *read + static __be32 + nfsd4_decode_remove(struct nfsd4_compoundargs *argp, struct nfsd4_remove *remove) + { ++ memset(&remove->rm_cinfo, 0, sizeof(remove->rm_cinfo)); + return nfsd4_decode_component4(argp, &remove->rm_name, &remove->rm_namelen); + } + +@@ -1277,6 +1287,7 @@ nfsd4_decode_rename(struct nfsd4_compoundargs *argp, struct nfsd4_rename *rename + { + __be32 status; + ++ memset(rename, 0, sizeof(*rename)); + status = nfsd4_decode_component4(argp, &rename->rn_sname, &rename->rn_snamelen); + if (status) + return status; +@@ -1293,6 +1304,7 @@ static __be32 + nfsd4_decode_secinfo(struct nfsd4_compoundargs *argp, + struct nfsd4_secinfo *secinfo) + { ++ secinfo->si_exp = NULL; + return nfsd4_decode_component4(argp, &secinfo->si_name, &secinfo->si_namelen); + } + +@@ -1301,6 +1313,7 @@ nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *seta + { + __be32 status; + ++ memset(setattr, 0, sizeof(*setattr)); + status = nfsd4_decode_stateid4(argp, &setattr->sa_stateid); + if (status) + return status; +@@ -1315,6 +1328,8 @@ nfsd4_decode_setclientid(struct nfsd4_compoundargs *argp, struct nfsd4_setclient + { + __be32 *p, status; + ++ memset(setclientid, 0, sizeof(*setclientid)); ++ + if (argp->minorversion >= 1) + return nfserr_notsupp; + +@@ -1371,6 +1386,8 @@ nfsd4_decode_verify(struct nfsd4_compoundargs *argp, struct nfsd4_verify *verify + { + __be32 *p, status; + ++ memset(verify, 0, sizeof(*verify)); ++ + status = nfsd4_decode_bitmap4(argp, verify->ve_bmval, + ARRAY_SIZE(verify->ve_bmval)); + if (status) +@@ -1410,6 +1427,9 @@ nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write) + if (!xdr_stream_subsegment(argp->xdr, &write->wr_payload, write->wr_buflen)) + return nfserr_bad_xdr; + ++ write->wr_bytes_written = 0; ++ write->wr_how_written = 0; ++ memset(&write->wr_verifier, 0, sizeof(write->wr_verifier)); + return nfs_ok; + } + +@@ -1434,6 +1454,7 @@ nfsd4_decode_release_lockowner(struct nfsd4_compoundargs *argp, struct nfsd4_rel + + static __be32 nfsd4_decode_backchannel_ctl(struct nfsd4_compoundargs *argp, struct nfsd4_backchannel_ctl *bc) + { ++ memset(bc, 0, sizeof(*bc)); + if (xdr_stream_decode_u32(argp->xdr, &bc->bc_cb_program) < 0) + return nfserr_bad_xdr; + return nfsd4_decode_cb_sec(argp, &bc->bc_cb_sec); +@@ -1444,6 +1465,7 @@ static __be32 nfsd4_decode_bind_conn_to_session(struct nfsd4_compoundargs *argp, + u32 use_conn_in_rdma_mode; + __be32 status; + ++ memset(bcts, 0, sizeof(*bcts)); + status = nfsd4_decode_sessionid4(argp, &bcts->sessionid); + if (status) + return status; +@@ -1585,6 +1607,7 @@ nfsd4_decode_exchange_id(struct nfsd4_compoundargs *argp, + { + __be32 status; + ++ memset(exid, 0, sizeof(*exid)); + status = nfsd4_decode_verifier4(argp, &exid->verifier); + if (status) + return status; +@@ -1637,6 +1660,7 @@ nfsd4_decode_create_session(struct nfsd4_compoundargs *argp, + { + __be32 status; + ++ memset(sess, 0, sizeof(*sess)); + status = nfsd4_decode_clientid4(argp, &sess->clientid); + if (status) + return status; +@@ -1652,11 +1676,7 @@ nfsd4_decode_create_session(struct nfsd4_compoundargs *argp, + return status; + if (xdr_stream_decode_u32(argp->xdr, &sess->callback_prog) < 0) + return nfserr_bad_xdr; +- status = nfsd4_decode_cb_sec(argp, &sess->cb_sec); +- if (status) +- return status; +- +- return nfs_ok; ++ return nfsd4_decode_cb_sec(argp, &sess->cb_sec); + } + + static __be32 +@@ -1680,6 +1700,7 @@ nfsd4_decode_getdeviceinfo(struct nfsd4_compoundargs *argp, + { + __be32 status; + ++ memset(gdev, 0, sizeof(*gdev)); + status = nfsd4_decode_deviceid4(argp, &gdev->gd_devid); + if (status) + return status; +@@ -1700,6 +1721,7 @@ nfsd4_decode_layoutcommit(struct nfsd4_compoundargs *argp, + { + __be32 *p, status; + ++ memset(lcp, 0, sizeof(*lcp)); + if (xdr_stream_decode_u64(argp->xdr, &lcp->lc_seg.offset) < 0) + return nfserr_bad_xdr; + if (xdr_stream_decode_u64(argp->xdr, &lcp->lc_seg.length) < 0) +@@ -1735,6 +1757,7 @@ nfsd4_decode_layoutget(struct nfsd4_compoundargs *argp, + { + __be32 status; + ++ memset(lgp, 0, sizeof(*lgp)); + if (xdr_stream_decode_u32(argp->xdr, &lgp->lg_signal) < 0) + return nfserr_bad_xdr; + if (xdr_stream_decode_u32(argp->xdr, &lgp->lg_layout_type) < 0) +@@ -1760,6 +1783,7 @@ static __be32 + nfsd4_decode_layoutreturn(struct nfsd4_compoundargs *argp, + struct nfsd4_layoutreturn *lrp) + { ++ memset(lrp, 0, sizeof(*lrp)); + if (xdr_stream_decode_bool(argp->xdr, &lrp->lr_reclaim) < 0) + return nfserr_bad_xdr; + if (xdr_stream_decode_u32(argp->xdr, &lrp->lr_layout_type) < 0) +@@ -1775,6 +1799,8 @@ static __be32 nfsd4_decode_secinfo_no_name(struct nfsd4_compoundargs *argp, + { + if (xdr_stream_decode_u32(argp->xdr, &sin->sin_style) < 0) + return nfserr_bad_xdr; ++ ++ sin->sin_exp = NULL; + return nfs_ok; + } + +@@ -1795,6 +1821,7 @@ nfsd4_decode_sequence(struct nfsd4_compoundargs *argp, + seq->maxslots = be32_to_cpup(p++); + seq->cachethis = be32_to_cpup(p); + ++ seq->status_flags = 0; + return nfs_ok; + } + +@@ -1805,6 +1832,7 @@ nfsd4_decode_test_stateid(struct nfsd4_compoundargs *argp, struct nfsd4_test_sta + __be32 status; + u32 i; + ++ memset(test_stateid, 0, sizeof(*test_stateid)); + if (xdr_stream_decode_u32(argp->xdr, &test_stateid->ts_num_ids) < 0) + return nfserr_bad_xdr; + +@@ -1902,6 +1930,7 @@ nfsd4_decode_copy(struct nfsd4_compoundargs *argp, struct nfsd4_copy *copy) + struct nl4_server *ns_dummy; + __be32 status; + ++ memset(copy, 0, sizeof(*copy)); + status = nfsd4_decode_stateid4(argp, ©->cp_src_stateid); + if (status) + return status; +@@ -1957,6 +1986,7 @@ nfsd4_decode_copy_notify(struct nfsd4_compoundargs *argp, + { + __be32 status; + ++ memset(cn, 0, sizeof(*cn)); + cn->cpn_src = svcxdr_tmpalloc(argp, sizeof(*cn->cpn_src)); + if (cn->cpn_src == NULL) + return nfserr_jukebox; +@@ -1974,6 +2004,8 @@ static __be32 + nfsd4_decode_offload_status(struct nfsd4_compoundargs *argp, + struct nfsd4_offload_status *os) + { ++ os->count = 0; ++ os->status = 0; + return nfsd4_decode_stateid4(argp, &os->stateid); + } + +@@ -1990,6 +2022,8 @@ nfsd4_decode_seek(struct nfsd4_compoundargs *argp, struct nfsd4_seek *seek) + if (xdr_stream_decode_u32(argp->xdr, &seek->seek_whence) < 0) + return nfserr_bad_xdr; + ++ seek->seek_eof = 0; ++ seek->seek_pos = 0; + return nfs_ok; + } + +@@ -2125,6 +2159,7 @@ nfsd4_decode_getxattr(struct nfsd4_compoundargs *argp, + __be32 status; + u32 maxcount; + ++ memset(getxattr, 0, sizeof(*getxattr)); + status = nfsd4_decode_xattr_name(argp, &getxattr->getxa_name); + if (status) + return status; +@@ -2133,8 +2168,7 @@ nfsd4_decode_getxattr(struct nfsd4_compoundargs *argp, + maxcount = min_t(u32, XATTR_SIZE_MAX, maxcount); + + getxattr->getxa_len = maxcount; +- +- return status; ++ return nfs_ok; + } + + static __be32 +@@ -2144,6 +2178,8 @@ nfsd4_decode_setxattr(struct nfsd4_compoundargs *argp, + u32 flags, maxcount, size; + __be32 status; + ++ memset(setxattr, 0, sizeof(*setxattr)); ++ + if (xdr_stream_decode_u32(argp->xdr, &flags) < 0) + return nfserr_bad_xdr; + +@@ -2182,6 +2218,8 @@ nfsd4_decode_listxattrs(struct nfsd4_compoundargs *argp, + { + u32 maxcount; + ++ memset(listxattrs, 0, sizeof(*listxattrs)); ++ + if (xdr_stream_decode_u64(argp->xdr, &listxattrs->lsxa_cookie) < 0) + return nfserr_bad_xdr; + +@@ -2209,6 +2247,7 @@ static __be32 + nfsd4_decode_removexattr(struct nfsd4_compoundargs *argp, + struct nfsd4_removexattr *removexattr) + { ++ memset(removexattr, 0, sizeof(*removexattr)); + return nfsd4_decode_xattr_name(argp, &removexattr->rmxa_name); + } + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-reduce-locking-in-nfsd_lookup.patch b/queue-5.10/nfsd-reduce-locking-in-nfsd_lookup.patch new file mode 100644 index 00000000000..9bdeb1e6bf6 --- /dev/null +++ b/queue-5.10/nfsd-reduce-locking-in-nfsd_lookup.patch @@ -0,0 +1,210 @@ +From a75713444bcd0561308c2fe8110e34f126640a21 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 Jul 2022 16:45:30 +1000 +Subject: NFSD: reduce locking in nfsd_lookup() + +From: NeilBrown + +[ Upstream commit 19d008b46941b8c668402170522e0f7a9258409c ] + +nfsd_lookup() takes an exclusive lock on the parent inode, but no +callers want the lock and it may not be needed at all if the +result is in the dcache. + +Change nfsd_lookup_dentry() to not take the lock, and call +lookup_one_len_locked() which takes lock only if needed. + +nfsd4_open() currently expects the lock to still be held, but that isn't +necessary as nfsd_validate_delegated_dentry() provides required +guarantees without the lock. + +NOTE: NFSv4 requires directory changeinfo for OPEN even when a create + wasn't requested and no change happened. Now that nfsd_lookup() + doesn't use fh_lock(), we need to explicitly fill the attributes + when no create happens. A new fh_fill_both_attrs() is provided + for that task. + +Signed-off-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 20 ++++++++++++-------- + fs/nfsd/nfs4state.c | 3 --- + fs/nfsd/nfsfh.c | 19 +++++++++++++++++++ + fs/nfsd/nfsfh.h | 2 +- + fs/nfsd/vfs.c | 34 ++++++++++++++-------------------- + 5 files changed, 46 insertions(+), 32 deletions(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index f588e592a0703..9cf4298817c4b 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -302,6 +302,11 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp, + if (d_really_is_positive(child)) { + status = nfs_ok; + ++ /* NFSv4 protocol requires change attributes even though ++ * no change happened. ++ */ ++ fh_fill_both_attrs(fhp); ++ + switch (open->op_createmode) { + case NFS4_CREATE_UNCHECKED: + if (!d_is_reg(child)) +@@ -417,15 +422,15 @@ do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, stru + if (nfsd4_create_is_exclusive(open->op_createmode) && status == 0) + open->op_bmval[1] |= (FATTR4_WORD1_TIME_ACCESS | + FATTR4_WORD1_TIME_MODIFY); +- } else +- /* +- * Note this may exit with the parent still locked. +- * We will hold the lock until nfsd4_open's final +- * lookup, to prevent renames or unlinks until we've had +- * a chance to an acquire a delegation if appropriate. +- */ ++ } else { + status = nfsd_lookup(rqstp, current_fh, + open->op_fname, open->op_fnamelen, *resfh); ++ if (!status) ++ /* NFSv4 protocol requires change attributes even though ++ * no change happened. ++ */ ++ fh_fill_both_attrs(current_fh); ++ } + if (status) + goto out; + status = nfsd_check_obj_isreg(*resfh); +@@ -1043,7 +1048,6 @@ nfsd4_secinfo(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + &exp, &dentry); + if (err) + return err; +- fh_unlock(&cstate->current_fh); + if (d_really_is_negative(dentry)) { + exp_put(exp); + err = nfserr_noent; +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 2b6c9f1b9de88..e44d9c8d5065a 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -5321,9 +5321,6 @@ nfsd4_verify_deleg_dentry(struct nfsd4_open *open, struct nfs4_file *fp, + struct dentry *child; + __be32 err; + +- /* parent may already be locked, and it may get unlocked by +- * this call, but that is safe. +- */ + err = nfsd_lookup_dentry(open->op_rqstp, parent, + open->op_fname, open->op_fnamelen, + &exp, &child); +diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c +index d4ae838948ba5..cc680deecafa7 100644 +--- a/fs/nfsd/nfsfh.c ++++ b/fs/nfsd/nfsfh.c +@@ -670,6 +670,25 @@ void fh_fill_post_attrs(struct svc_fh *fhp) + nfsd4_change_attribute(&fhp->fh_post_attr, inode); + } + ++/** ++ * fh_fill_both_attrs - Fill pre-op and post-op attributes ++ * @fhp: file handle to be updated ++ * ++ * This is used when the directory wasn't changed, but wcc attributes ++ * are needed anyway. ++ */ ++void fh_fill_both_attrs(struct svc_fh *fhp) ++{ ++ fh_fill_post_attrs(fhp); ++ if (!fhp->fh_post_saved) ++ return; ++ fhp->fh_pre_change = fhp->fh_post_change; ++ fhp->fh_pre_mtime = fhp->fh_post_attr.mtime; ++ fhp->fh_pre_ctime = fhp->fh_post_attr.ctime; ++ fhp->fh_pre_size = fhp->fh_post_attr.size; ++ fhp->fh_pre_saved = true; ++} ++ + /* + * Release a file handle. + */ +diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h +index fb9d358a267e5..28a4f9a94e2c8 100644 +--- a/fs/nfsd/nfsfh.h ++++ b/fs/nfsd/nfsfh.h +@@ -322,7 +322,7 @@ static inline u64 nfsd4_change_attribute(struct kstat *stat, + + extern void fh_fill_pre_attrs(struct svc_fh *fhp); + extern void fh_fill_post_attrs(struct svc_fh *fhp); +- ++extern void fh_fill_both_attrs(struct svc_fh *fhp); + + /* + * Lock a file handle/inode +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index dd945099ae6b5..03f6dd2ec653b 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -198,27 +198,13 @@ nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp, + goto out_nfserr; + } + } else { +- /* +- * In the nfsd4_open() case, this may be held across +- * subsequent open and delegation acquisition which may +- * need to take the child's i_mutex: +- */ +- fh_lock_nested(fhp, I_MUTEX_PARENT); +- dentry = lookup_one_len(name, dparent, len); ++ dentry = lookup_one_len_unlocked(name, dparent, len); + host_err = PTR_ERR(dentry); + if (IS_ERR(dentry)) + goto out_nfserr; + if (nfsd_mountpoint(dentry, exp)) { +- /* +- * We don't need the i_mutex after all. It's +- * still possible we could open this (regular +- * files can be mountpoints too), but the +- * i_mutex is just there to prevent renames of +- * something that we might be about to delegate, +- * and a mountpoint won't be renamed: +- */ +- fh_unlock(fhp); +- if ((host_err = nfsd_cross_mnt(rqstp, &dentry, &exp))) { ++ host_err = nfsd_cross_mnt(rqstp, &dentry, &exp); ++ if (host_err) { + dput(dentry); + goto out_nfserr; + } +@@ -233,7 +219,15 @@ nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp, + return nfserrno(host_err); + } + +-/* ++/** ++ * nfsd_lookup - look up a single path component for nfsd ++ * ++ * @rqstp: the request context ++ * @fhp: the file handle of the directory ++ * @name: the component name, or %NULL to look up parent ++ * @len: length of name to examine ++ * @resfh: pointer to pre-initialised filehandle to hold result. ++ * + * Look up one component of a pathname. + * N.B. After this call _both_ fhp and resfh need an fh_put + * +@@ -243,11 +237,11 @@ nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp, + * returned. Otherwise the covered directory is returned. + * NOTE: this mountpoint crossing is not supported properly by all + * clients and is explicitly disallowed for NFSv3 +- * NeilBrown ++ * + */ + __be32 + nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, +- unsigned int len, struct svc_fh *resfh) ++ unsigned int len, struct svc_fh *resfh) + { + struct svc_export *exp; + struct dentry *dentry; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-reduce-svc_rqst-rq_pages-churn-during-readdir-o.patch b/queue-5.10/nfsd-reduce-svc_rqst-rq_pages-churn-during-readdir-o.patch new file mode 100644 index 00000000000..42995fe5bd1 --- /dev/null +++ b/queue-5.10/nfsd-reduce-svc_rqst-rq_pages-churn-during-readdir-o.patch @@ -0,0 +1,61 @@ +From 96a6c44015e8d61dbfe298981eeaf4a4b15c91fe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 15 Jan 2021 09:28:44 -0500 +Subject: NFSD: Reduce svc_rqst::rq_pages churn during READDIR operations + +From: Chuck Lever + +[ Upstream commit 76ed0dd96eeb2771b21bf5dcbd88326ef89ee0ed ] + +During NFSv2 and NFSv3 READDIR/PLUS operations, NFSD advances +rq_next_page to the full size of the client-requested buffer, then +releases all those pages at the end of the request. The next request +to use that nfsd thread has to refill the pages. + +NFSD does this even when the dirlist in the reply is small. With +NFSv3 clients that send READDIR operations with large buffer sizes, +that can be 256 put_page/alloc_page pairs per READDIR request, even +though those pages often remain unused. + +We can save some work by not releasing dirlist buffer pages that +were not used to form the READDIR Reply. I've left the NFSv2 code +alone since there are never more than three pages involved in an +NFSv2 READDIR Reply. + +Eventually we should nail down why these pages need to be released +at all in order to avoid allocating and releasing pages +unnecessarily. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3proc.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c +index 781bb2b115e74..be1ed33e424e0 100644 +--- a/fs/nfsd/nfs3proc.c ++++ b/fs/nfsd/nfs3proc.c +@@ -498,6 +498,9 @@ nfsd3_proc_readdir(struct svc_rqst *rqstp) + memcpy(resp->verf, argp->verf, 8); + nfs3svc_encode_cookie3(resp, offset); + ++ /* Recycle only pages that were part of the reply */ ++ rqstp->rq_next_page = resp->xdr.page_ptr + 1; ++ + return rpc_success; + } + +@@ -538,6 +541,9 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp) + memcpy(resp->verf, argp->verf, 8); + nfs3svc_encode_cookie3(resp, offset); + ++ /* Recycle only pages that were part of the reply */ ++ rqstp->rq_next_page = resp->xdr.page_ptr + 1; ++ + out: + return rpc_success; + } +-- +2.43.0 + diff --git a/queue-5.10/nfsd-refactor-__nfsd_file_close_inode.patch b/queue-5.10/nfsd-refactor-__nfsd_file_close_inode.patch new file mode 100644 index 00000000000..eff6d4b7b3a --- /dev/null +++ b/queue-5.10/nfsd-refactor-__nfsd_file_close_inode.patch @@ -0,0 +1,179 @@ +From 2035e3bd5e886b98e5354f75ba0143ee1a758376 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 Jul 2022 14:25:57 -0400 +Subject: NFSD: Refactor __nfsd_file_close_inode() + +From: Chuck Lever + +[ Upstream commit a845511007a63467fee575353c706806c21218b1 ] + +The code that computes the hashval is the same in both callers. + +To prevent them from going stale, reframe the documenting comments +to remove descriptions of the underlying hash table structure, which +is about to be replaced. + +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 40 +++++++++++++++++++++------------------- + fs/nfsd/trace.h | 44 +++++++++++++++++++++++++++++++++----------- + 2 files changed, 54 insertions(+), 30 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index d7c74b51eabf3..3925df9124c39 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -558,39 +558,44 @@ static struct shrinker nfsd_file_shrinker = { + .seeks = 1, + }; + +-static void +-__nfsd_file_close_inode(struct inode *inode, unsigned int hashval, +- struct list_head *dispose) ++/* ++ * Find all cache items across all net namespaces that match @inode and ++ * move them to @dispose. The lookup is atomic wrt nfsd_file_acquire(). ++ */ ++static unsigned int ++__nfsd_file_close_inode(struct inode *inode, struct list_head *dispose) + { ++ unsigned int hashval = (unsigned int)hash_long(inode->i_ino, ++ NFSD_FILE_HASH_BITS); ++ unsigned int count = 0; + struct nfsd_file *nf; + struct hlist_node *tmp; + + spin_lock(&nfsd_file_hashtbl[hashval].nfb_lock); + hlist_for_each_entry_safe(nf, tmp, &nfsd_file_hashtbl[hashval].nfb_head, nf_node) { +- if (inode == nf->nf_inode) ++ if (inode == nf->nf_inode) { + nfsd_file_unhash_and_release_locked(nf, dispose); ++ count++; ++ } + } + spin_unlock(&nfsd_file_hashtbl[hashval].nfb_lock); ++ return count; + } + + /** + * nfsd_file_close_inode_sync - attempt to forcibly close a nfsd_file + * @inode: inode of the file to attempt to remove + * +- * Walk the whole hash bucket, looking for any files that correspond to "inode". +- * If any do, then unhash them and put the hashtable reference to them and +- * destroy any that had their last reference put. Also ensure that any of the +- * fputs also have their final __fput done as well. ++ * Unhash and put, then flush and fput all cache items associated with @inode. + */ + void + nfsd_file_close_inode_sync(struct inode *inode) + { +- unsigned int hashval = (unsigned int)hash_long(inode->i_ino, +- NFSD_FILE_HASH_BITS); + LIST_HEAD(dispose); ++ unsigned int count; + +- __nfsd_file_close_inode(inode, hashval, &dispose); +- trace_nfsd_file_close_inode_sync(inode, !list_empty(&dispose)); ++ count = __nfsd_file_close_inode(inode, &dispose); ++ trace_nfsd_file_close_inode_sync(inode, count); + nfsd_file_dispose_list_sync(&dispose); + } + +@@ -598,19 +603,16 @@ nfsd_file_close_inode_sync(struct inode *inode) + * nfsd_file_close_inode - attempt a delayed close of a nfsd_file + * @inode: inode of the file to attempt to remove + * +- * Walk the whole hash bucket, looking for any files that correspond to "inode". +- * If any do, then unhash them and put the hashtable reference to them and +- * destroy any that had their last reference put. ++ * Unhash and put all cache item associated with @inode. + */ + static void + nfsd_file_close_inode(struct inode *inode) + { +- unsigned int hashval = (unsigned int)hash_long(inode->i_ino, +- NFSD_FILE_HASH_BITS); + LIST_HEAD(dispose); ++ unsigned int count; + +- __nfsd_file_close_inode(inode, hashval, &dispose); +- trace_nfsd_file_close_inode(inode, !list_empty(&dispose)); ++ count = __nfsd_file_close_inode(inode, &dispose); ++ trace_nfsd_file_close_inode(inode, count); + nfsd_file_dispose_list_delayed(&dispose); + } + +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index 8b34f2a5ad296..f170f07ec0fd2 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -813,30 +813,52 @@ TRACE_EVENT(nfsd_file_open, + + DECLARE_EVENT_CLASS(nfsd_file_search_class, + TP_PROTO( +- struct inode *inode, +- int found ++ const struct inode *inode, ++ unsigned int count + ), +- TP_ARGS(inode, found), ++ TP_ARGS(inode, count), + TP_STRUCT__entry( +- __field(struct inode *, inode) +- __field(int, found) ++ __field(const struct inode *, inode) ++ __field(unsigned int, count) + ), + TP_fast_assign( + __entry->inode = inode; +- __entry->found = found; ++ __entry->count = count; + ), +- TP_printk("inode=%p found=%d", +- __entry->inode, __entry->found) ++ TP_printk("inode=%p count=%u", ++ __entry->inode, __entry->count) + ); + + #define DEFINE_NFSD_FILE_SEARCH_EVENT(name) \ + DEFINE_EVENT(nfsd_file_search_class, name, \ +- TP_PROTO(struct inode *inode, int found), \ +- TP_ARGS(inode, found)) ++ TP_PROTO( \ ++ const struct inode *inode, \ ++ unsigned int count \ ++ ), \ ++ TP_ARGS(inode, count)) + + DEFINE_NFSD_FILE_SEARCH_EVENT(nfsd_file_close_inode_sync); + DEFINE_NFSD_FILE_SEARCH_EVENT(nfsd_file_close_inode); +-DEFINE_NFSD_FILE_SEARCH_EVENT(nfsd_file_is_cached); ++ ++TRACE_EVENT(nfsd_file_is_cached, ++ TP_PROTO( ++ const struct inode *inode, ++ int found ++ ), ++ TP_ARGS(inode, found), ++ TP_STRUCT__entry( ++ __field(const struct inode *, inode) ++ __field(int, found) ++ ), ++ TP_fast_assign( ++ __entry->inode = inode; ++ __entry->found = found; ++ ), ++ TP_printk("inode=%p is %scached", ++ __entry->inode, ++ __entry->found ? "" : "not " ++ ) ++); + + TRACE_EVENT(nfsd_file_fsnotify_handle_event, + TP_PROTO(struct inode *inode, u32 mask), +-- +2.43.0 + diff --git a/queue-5.10/nfsd-refactor-common-code-out-of-dirlist-helpers.patch b/queue-5.10/nfsd-refactor-common-code-out-of-dirlist-helpers.patch new file mode 100644 index 00000000000..3b487f517a0 --- /dev/null +++ b/queue-5.10/nfsd-refactor-common-code-out-of-dirlist-helpers.patch @@ -0,0 +1,115 @@ +From de064d9ef867b3fbbe1ccfcae29cc8c1f194e2bb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Sep 2022 17:22:56 -0400 +Subject: NFSD: Refactor common code out of dirlist helpers + +From: Chuck Lever + +[ Upstream commit 98124f5bd6c76699d514fbe491dd95265369cc99 ] + +The dust has settled a bit and it's become obvious what code is +totally common between nfsd_init_dirlist_pages() and +nfsd3_init_dirlist_pages(). Move that common code to SUNRPC. + +The new helper brackets the existing xdr_init_decode_pages() API. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3proc.c | 10 +--------- + fs/nfsd/nfsproc.c | 10 +--------- + include/linux/sunrpc/xdr.h | 2 ++ + net/sunrpc/xdr.c | 22 ++++++++++++++++++++++ + 4 files changed, 26 insertions(+), 18 deletions(-) + +diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c +index 5c2e2b5e5945f..a9bf455aee821 100644 +--- a/fs/nfsd/nfs3proc.c ++++ b/fs/nfsd/nfs3proc.c +@@ -574,15 +574,7 @@ static void nfsd3_init_dirlist_pages(struct svc_rqst *rqstp, + buf->pages = rqstp->rq_next_page; + rqstp->rq_next_page += (buf->buflen + PAGE_SIZE - 1) >> PAGE_SHIFT; + +- /* This is xdr_init_encode(), but it assumes that +- * the head kvec has already been consumed. */ +- xdr_set_scratch_buffer(xdr, NULL, 0); +- xdr->buf = buf; +- xdr->page_ptr = buf->pages; +- xdr->iov = NULL; +- xdr->p = page_address(*buf->pages); +- xdr->end = (void *)xdr->p + min_t(u32, buf->buflen, PAGE_SIZE); +- xdr->rqst = NULL; ++ xdr_init_encode_pages(xdr, buf, buf->pages, NULL); + } + + /* +diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c +index 3509331a66504..78fa5a9edf277 100644 +--- a/fs/nfsd/nfsproc.c ++++ b/fs/nfsd/nfsproc.c +@@ -575,15 +575,7 @@ static void nfsd_init_dirlist_pages(struct svc_rqst *rqstp, + buf->pages = rqstp->rq_next_page; + rqstp->rq_next_page++; + +- /* This is xdr_init_encode(), but it assumes that +- * the head kvec has already been consumed. */ +- xdr_set_scratch_buffer(xdr, NULL, 0); +- xdr->buf = buf; +- xdr->page_ptr = buf->pages; +- xdr->iov = NULL; +- xdr->p = page_address(*buf->pages); +- xdr->end = (void *)xdr->p + min_t(u32, buf->buflen, PAGE_SIZE); +- xdr->rqst = NULL; ++ xdr_init_encode_pages(xdr, buf, buf->pages, NULL); + } + + /* +diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h +index 59d99ff31c1a9..c1c50eaae4726 100644 +--- a/include/linux/sunrpc/xdr.h ++++ b/include/linux/sunrpc/xdr.h +@@ -239,6 +239,8 @@ typedef int (*kxdrdproc_t)(struct rpc_rqst *rqstp, struct xdr_stream *xdr, + + extern void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, + __be32 *p, struct rpc_rqst *rqst); ++extern void xdr_init_encode_pages(struct xdr_stream *xdr, struct xdr_buf *buf, ++ struct page **pages, struct rpc_rqst *rqst); + extern __be32 *xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes); + extern int xdr_reserve_space_vec(struct xdr_stream *xdr, struct kvec *vec, + size_t nbytes); +diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c +index f66e2de7cd279..e2bd0cd391142 100644 +--- a/net/sunrpc/xdr.c ++++ b/net/sunrpc/xdr.c +@@ -690,6 +690,28 @@ void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p, + } + EXPORT_SYMBOL_GPL(xdr_init_encode); + ++/** ++ * xdr_init_encode_pages - Initialize an xdr_stream for encoding into pages ++ * @xdr: pointer to xdr_stream struct ++ * @buf: pointer to XDR buffer into which to encode data ++ * @pages: list of pages to decode into ++ * @rqst: pointer to controlling rpc_rqst, for debugging ++ * ++ */ ++void xdr_init_encode_pages(struct xdr_stream *xdr, struct xdr_buf *buf, ++ struct page **pages, struct rpc_rqst *rqst) ++{ ++ xdr_reset_scratch_buffer(xdr); ++ ++ xdr->buf = buf; ++ xdr->page_ptr = pages; ++ xdr->iov = NULL; ++ xdr->p = page_address(*pages); ++ xdr->end = (void *)xdr->p + min_t(u32, buf->buflen, PAGE_SIZE); ++ xdr->rqst = rqst; ++} ++EXPORT_SYMBOL_GPL(xdr_init_encode_pages); ++ + /** + * __xdr_commit_encode - Ensure all data is written to buffer + * @xdr: pointer to xdr_stream +-- +2.43.0 + diff --git a/queue-5.10/nfsd-refactor-find_file.patch b/queue-5.10/nfsd-refactor-find_file.patch new file mode 100644 index 00000000000..6b8b18de0fe --- /dev/null +++ b/queue-5.10/nfsd-refactor-find_file.patch @@ -0,0 +1,85 @@ +From 8d35ec776dc1362bd854fd9b0f03a0d32f79cda7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Oct 2022 10:47:47 -0400 +Subject: NFSD: Refactor find_file() + +From: Chuck Lever + +[ Upstream commit 15424748001a9b5ea62b3e6ad45f0a8b27f01df9 ] + +find_file() is now the only caller of find_file_locked(), so just +fold these two together. + +Signed-off-by: Chuck Lever +Reviewed-by: NeilBrown +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 36 +++++++++++++++--------------------- + 1 file changed, 15 insertions(+), 21 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index d2664aa4bde0d..69329dc159f64 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -4682,31 +4682,24 @@ move_to_close_lru(struct nfs4_ol_stateid *s, struct net *net) + nfs4_put_stid(&last->st_stid); + } + +-/* search file_hashtbl[] for file */ +-static struct nfs4_file * +-find_file_locked(const struct svc_fh *fh, unsigned int hashval) ++static noinline_for_stack struct nfs4_file * ++nfsd4_file_hash_lookup(const struct svc_fh *fhp) + { +- struct nfs4_file *fp; ++ unsigned int hashval = file_hashval(fhp); ++ struct nfs4_file *fi; + +- hlist_for_each_entry_rcu(fp, &file_hashtbl[hashval], fi_hash, +- lockdep_is_held(&state_lock)) { +- if (fh_match(&fp->fi_fhandle, &fh->fh_handle)) { +- if (refcount_inc_not_zero(&fp->fi_ref)) +- return fp; ++ rcu_read_lock(); ++ hlist_for_each_entry_rcu(fi, &file_hashtbl[hashval], fi_hash, ++ lockdep_is_held(&state_lock)) { ++ if (fh_match(&fi->fi_fhandle, &fhp->fh_handle)) { ++ if (refcount_inc_not_zero(&fi->fi_ref)) { ++ rcu_read_unlock(); ++ return fi; ++ } + } + } +- return NULL; +-} +- +-static struct nfs4_file * find_file(struct svc_fh *fh) +-{ +- struct nfs4_file *fp; +- unsigned int hashval = file_hashval(fh); +- +- rcu_read_lock(); +- fp = find_file_locked(fh, hashval); + rcu_read_unlock(); +- return fp; ++ return NULL; + } + + /* +@@ -4757,9 +4750,10 @@ nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type) + struct nfs4_file *fp; + __be32 ret = nfs_ok; + +- fp = find_file(current_fh); ++ fp = nfsd4_file_hash_lookup(current_fh); + if (!fp) + return ret; ++ + /* Check for conflicting share reservations */ + spin_lock(&fp->fi_lock); + if (fp->fi_share_deny & deny_type) +-- +2.43.0 + diff --git a/queue-5.10/nfsd-refactor-nfsd4_cleanup_inter_ssc-1-2.patch b/queue-5.10/nfsd-refactor-nfsd4_cleanup_inter_ssc-1-2.patch new file mode 100644 index 00000000000..a829635662b --- /dev/null +++ b/queue-5.10/nfsd-refactor-nfsd4_cleanup_inter_ssc-1-2.patch @@ -0,0 +1,66 @@ +From 90102bc4f18ef896b6d663843e943c9dd4f6a340 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 Jul 2022 14:40:47 -0400 +Subject: NFSD: Refactor nfsd4_cleanup_inter_ssc() (1/2) + +From: Chuck Lever + +[ Upstream commit 24d796ea383b8a4c8234e06d1b14bbcd371192ea ] + +The @src parameter is sometimes a pointer to a struct nfsd_file and +sometimes a pointer to struct file hiding in a phony struct +nfsd_file. Refactor nfsd4_cleanup_inter_ssc() so the @src parameter +is always an explicit struct file. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index a4bc096e509d4..d39150425da88 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -1549,7 +1549,7 @@ nfsd4_setup_inter_ssc(struct svc_rqst *rqstp, + } + + static void +-nfsd4_cleanup_inter_ssc(struct vfsmount *ss_mnt, struct nfsd_file *src, ++nfsd4_cleanup_inter_ssc(struct vfsmount *ss_mnt, struct file *filp, + struct nfsd_file *dst) + { + bool found = false; +@@ -1558,9 +1558,9 @@ nfsd4_cleanup_inter_ssc(struct vfsmount *ss_mnt, struct nfsd_file *src, + struct nfsd4_ssc_umount_item *ni = NULL; + struct nfsd_net *nn = net_generic(dst->nf_net, nfsd_net_id); + +- nfs42_ssc_close(src->nf_file); ++ nfs42_ssc_close(filp); + nfsd_file_put(dst); +- fput(src->nf_file); ++ fput(filp); + + if (!nn) { + mntput(ss_mnt); +@@ -1603,7 +1603,7 @@ nfsd4_setup_inter_ssc(struct svc_rqst *rqstp, + } + + static void +-nfsd4_cleanup_inter_ssc(struct vfsmount *ss_mnt, struct nfsd_file *src, ++nfsd4_cleanup_inter_ssc(struct vfsmount *ss_mnt, struct file *filp, + struct nfsd_file *dst) + { + } +@@ -1716,7 +1716,7 @@ static __be32 nfsd4_do_copy(struct nfsd4_copy *copy, bool sync) + } + + if (nfsd4_ssc_is_inter(copy)) +- nfsd4_cleanup_inter_ssc(copy->ss_mnt, copy->nf_src, ++ nfsd4_cleanup_inter_ssc(copy->ss_mnt, copy->nf_src->nf_file, + copy->nf_dst); + else + nfsd4_cleanup_intra_ssc(copy->nf_src, copy->nf_dst); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-refactor-nfsd4_cleanup_inter_ssc-2-2.patch b/queue-5.10/nfsd-refactor-nfsd4_cleanup_inter_ssc-2-2.patch new file mode 100644 index 00000000000..424a89fab3b --- /dev/null +++ b/queue-5.10/nfsd-refactor-nfsd4_cleanup_inter_ssc-2-2.patch @@ -0,0 +1,64 @@ +From 063603f0ca68923824c0637995705f6627bcae77 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 Jul 2022 14:40:53 -0400 +Subject: NFSD: Refactor nfsd4_cleanup_inter_ssc() (2/2) + +From: Chuck Lever + +[ Upstream commit 478ed7b10d875da2743d1a22822b9f8a82df8f12 ] + +Move the nfsd4_cleanup_*() call sites out of nfsd4_do_copy(). A +subsequent patch will modify one of the new call sites to avoid +the need to manufacture the phony struct nfsd_file. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 15 +++++++-------- + 1 file changed, 7 insertions(+), 8 deletions(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index d39150425da88..5d05bb7a0c0f6 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -1714,13 +1714,6 @@ static __be32 nfsd4_do_copy(struct nfsd4_copy *copy, bool sync) + nfsd4_init_copy_res(copy, sync); + status = nfs_ok; + } +- +- if (nfsd4_ssc_is_inter(copy)) +- nfsd4_cleanup_inter_ssc(copy->ss_mnt, copy->nf_src->nf_file, +- copy->nf_dst); +- else +- nfsd4_cleanup_intra_ssc(copy->nf_src, copy->nf_dst); +- + return status; + } + +@@ -1776,9 +1769,14 @@ static int nfsd4_do_async_copy(void *data) + /* ss_mnt will be unmounted by the laundromat */ + goto do_callback; + } ++ copy->nfserr = nfsd4_do_copy(copy, 0); ++ nfsd4_cleanup_inter_ssc(copy->ss_mnt, copy->nf_src->nf_file, ++ copy->nf_dst); ++ } else { ++ copy->nfserr = nfsd4_do_copy(copy, 0); ++ nfsd4_cleanup_intra_ssc(copy->nf_src, copy->nf_dst); + } + +- copy->nfserr = nfsd4_do_copy(copy, 0); + do_callback: + cb_copy = kzalloc(sizeof(struct nfsd4_copy), GFP_KERNEL); + if (!cb_copy) +@@ -1854,6 +1852,7 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + status = nfs_ok; + } else { + status = nfsd4_do_copy(copy, 1); ++ nfsd4_cleanup_intra_ssc(copy->nf_src, copy->nf_dst); + } + out: + return status; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-refactor-nfsd4_do_copy.patch b/queue-5.10/nfsd-refactor-nfsd4_do_copy.patch new file mode 100644 index 00000000000..62988f8f5c7 --- /dev/null +++ b/queue-5.10/nfsd-refactor-nfsd4_do_copy.patch @@ -0,0 +1,84 @@ +From ecf108709139d5eaec1725f0fccf64ce1d78d8e5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 Jul 2022 14:40:59 -0400 +Subject: NFSD: Refactor nfsd4_do_copy() + +From: Chuck Lever + +[ Upstream commit 3b7bf5933cada732783554edf0dc61283551c6cf ] + +Refactor: Now that nfsd4_do_copy() no longer calls the cleanup +helpers, plumb the use of struct file pointers all the way down to +_nfsd_copy_file_range(). + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 22 ++++++++++++++-------- + 1 file changed, 14 insertions(+), 8 deletions(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 5d05bb7a0c0f6..16f968c165c98 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -1660,10 +1660,10 @@ static void nfsd4_init_copy_res(struct nfsd4_copy *copy, bool sync) + gen_boot_verifier(©->cp_res.wr_verifier, copy->cp_clp->net); + } + +-static ssize_t _nfsd_copy_file_range(struct nfsd4_copy *copy) ++static ssize_t _nfsd_copy_file_range(struct nfsd4_copy *copy, ++ struct file *dst, ++ struct file *src) + { +- struct file *dst = copy->nf_dst->nf_file; +- struct file *src = copy->nf_src->nf_file; + errseq_t since; + ssize_t bytes_copied = 0; + u64 bytes_total = copy->cp_count; +@@ -1699,12 +1699,15 @@ static ssize_t _nfsd_copy_file_range(struct nfsd4_copy *copy) + return bytes_copied; + } + +-static __be32 nfsd4_do_copy(struct nfsd4_copy *copy, bool sync) ++static __be32 nfsd4_do_copy(struct nfsd4_copy *copy, ++ struct file *src, struct file *dst, ++ bool sync) + { + __be32 status; + ssize_t bytes; + +- bytes = _nfsd_copy_file_range(copy); ++ bytes = _nfsd_copy_file_range(copy, dst, src); ++ + /* for async copy, we ignore the error, client can always retry + * to get the error + */ +@@ -1769,11 +1772,13 @@ static int nfsd4_do_async_copy(void *data) + /* ss_mnt will be unmounted by the laundromat */ + goto do_callback; + } +- copy->nfserr = nfsd4_do_copy(copy, 0); ++ copy->nfserr = nfsd4_do_copy(copy, copy->nf_src->nf_file, ++ copy->nf_dst->nf_file, false); + nfsd4_cleanup_inter_ssc(copy->ss_mnt, copy->nf_src->nf_file, + copy->nf_dst); + } else { +- copy->nfserr = nfsd4_do_copy(copy, 0); ++ copy->nfserr = nfsd4_do_copy(copy, copy->nf_src->nf_file, ++ copy->nf_dst->nf_file, false); + nfsd4_cleanup_intra_ssc(copy->nf_src, copy->nf_dst); + } + +@@ -1851,7 +1856,8 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + wake_up_process(async_copy->copy_task); + status = nfs_ok; + } else { +- status = nfsd4_do_copy(copy, 1); ++ status = nfsd4_do_copy(copy, copy->nf_src->nf_file, ++ copy->nf_dst->nf_file, true); + nfsd4_cleanup_intra_ssc(copy->nf_src, copy->nf_dst); + } + out: +-- +2.43.0 + diff --git a/queue-5.10/nfsd-refactor-nfsd_create_setattr.patch b/queue-5.10/nfsd-refactor-nfsd_create_setattr.patch new file mode 100644 index 00000000000..96934777d46 --- /dev/null +++ b/queue-5.10/nfsd-refactor-nfsd_create_setattr.patch @@ -0,0 +1,163 @@ +From 3585158a2dd3fa455d013402ee9ec71e7ea2ad6d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 28 Mar 2022 16:10:17 -0400 +Subject: NFSD: Refactor nfsd_create_setattr() + +From: Chuck Lever + +[ Upstream commit 5f46e950c395b9c14c282b53ba78c5fd46d6c256 ] + +I'd like to move do_nfsd_create() out of vfs.c. Therefore +nfsd_create_setattr() needs to be made publicly visible. + +Note that both call sites in vfs.c commit both the new object and +its parent directory, so just combine those common metadata commits +into nfsd_create_setattr(). + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/vfs.c | 79 +++++++++++++++++++++++++++------------------------ + fs/nfsd/vfs.h | 2 ++ + 2 files changed, 44 insertions(+), 37 deletions(-) + +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index cdeba19db16df..50451789a9444 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -1207,14 +1207,26 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, u64 offset, + return err; + } + +-static __be32 +-nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *resfhp, +- struct iattr *iap) ++/** ++ * nfsd_create_setattr - Set a created file's attributes ++ * @rqstp: RPC transaction being executed ++ * @fhp: NFS filehandle of parent directory ++ * @resfhp: NFS filehandle of new object ++ * @iap: requested attributes of new object ++ * ++ * Returns nfs_ok on success, or an nfsstat in network byte order. ++ */ ++__be32 ++nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, ++ struct svc_fh *resfhp, struct iattr *iap) + { ++ __be32 status; ++ + /* +- * Mode has already been set earlier in create: ++ * Mode has already been set by file creation. + */ + iap->ia_valid &= ~ATTR_MODE; ++ + /* + * Setting uid/gid works only for root. Irix appears to + * send along the gid on create when it tries to implement +@@ -1222,10 +1234,31 @@ nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *resfhp, + */ + if (!uid_eq(current_fsuid(), GLOBAL_ROOT_UID)) + iap->ia_valid &= ~(ATTR_UID|ATTR_GID); ++ ++ /* ++ * Callers expect new file metadata to be committed even ++ * if the attributes have not changed. ++ */ + if (iap->ia_valid) +- return nfsd_setattr(rqstp, resfhp, iap, 0, (time64_t)0); +- /* Callers expect file metadata to be committed here */ +- return nfserrno(commit_metadata(resfhp)); ++ status = nfsd_setattr(rqstp, resfhp, iap, 0, (time64_t)0); ++ else ++ status = nfserrno(commit_metadata(resfhp)); ++ ++ /* ++ * Transactional filesystems had a chance to commit changes ++ * for both parent and child simultaneously making the ++ * following commit_metadata a noop in many cases. ++ */ ++ if (!status) ++ status = nfserrno(commit_metadata(fhp)); ++ ++ /* ++ * Update the new filehandle to pick up the new attributes. ++ */ ++ if (!status) ++ status = fh_update(resfhp); ++ ++ return status; + } + + /* HPUX client sometimes creates a file in mode 000, and sets size to 0. +@@ -1252,7 +1285,6 @@ nfsd_create_locked(struct svc_rqst *rqstp, struct svc_fh *fhp, + struct dentry *dentry, *dchild; + struct inode *dirp; + __be32 err; +- __be32 err2; + int host_err; + + dentry = fhp->fh_dentry; +@@ -1324,22 +1356,8 @@ nfsd_create_locked(struct svc_rqst *rqstp, struct svc_fh *fhp, + if (host_err < 0) + goto out_nfserr; + +- err = nfsd_create_setattr(rqstp, resfhp, iap); ++ err = nfsd_create_setattr(rqstp, fhp, resfhp, iap); + +- /* +- * nfsd_create_setattr already committed the child. Transactional +- * filesystems had a chance to commit changes for both parent and +- * child simultaneously making the following commit_metadata a +- * noop. +- */ +- err2 = nfserrno(commit_metadata(fhp)); +- if (err2) +- err = err2; +- /* +- * Update the file handle to get the new inode info. +- */ +- if (!err) +- err = fh_update(resfhp); + out: + dput(dchild); + return err; +@@ -1530,20 +1548,7 @@ do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, + } + + set_attr: +- err = nfsd_create_setattr(rqstp, resfhp, iap); +- +- /* +- * nfsd_create_setattr already committed the child +- * (and possibly also the parent). +- */ +- if (!err) +- err = nfserrno(commit_metadata(fhp)); +- +- /* +- * Update the filehandle to get the new inode info. +- */ +- if (!err) +- err = fh_update(resfhp); ++ err = nfsd_create_setattr(rqstp, fhp, resfhp, iap); + + out: + fh_unlock(fhp); +diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h +index ccb87b2864f64..1f32a83456b03 100644 +--- a/fs/nfsd/vfs.h ++++ b/fs/nfsd/vfs.h +@@ -69,6 +69,8 @@ __be32 nfsd_create(struct svc_rqst *, struct svc_fh *, + char *name, int len, struct iattr *attrs, + int type, dev_t rdev, struct svc_fh *res); + __be32 nfsd_access(struct svc_rqst *, struct svc_fh *, u32 *, u32 *); ++__be32 nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, ++ struct svc_fh *resfhp, struct iattr *iap); + __be32 do_nfsd_create(struct svc_rqst *, struct svc_fh *, + char *name, int len, struct iattr *attrs, + struct svc_fh *res, int createmode, +-- +2.43.0 + diff --git a/queue-5.10/nfsd-refactor-nfsd_file_gc.patch b/queue-5.10/nfsd-refactor-nfsd_file_gc.patch new file mode 100644 index 00000000000..37161ecf7f7 --- /dev/null +++ b/queue-5.10/nfsd-refactor-nfsd_file_gc.patch @@ -0,0 +1,38 @@ +From afc10fed5268caf0bd198b502c047df99e2935c9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 Jul 2022 14:24:25 -0400 +Subject: NFSD: Refactor nfsd_file_gc() + +From: Chuck Lever + +[ Upstream commit 3bc6d3470fe412f818f9bff6b71d1be3a76af8f3 ] + +Refactor nfsd_file_gc() to use the new list_lru helper. + +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index ffe46f3f33495..656c94c779417 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -491,7 +491,11 @@ nfsd_file_lru_walk_list(struct shrink_control *sc) + static void + nfsd_file_gc(void) + { +- nfsd_file_lru_walk_list(NULL); ++ LIST_HEAD(dispose); ++ ++ list_lru_walk(&nfsd_file_lru, nfsd_file_lru_cb, ++ &dispose, LONG_MAX); ++ nfsd_file_gc_dispose_list(&dispose); + } + + static void +-- +2.43.0 + diff --git a/queue-5.10/nfsd-refactor-nfsd_file_lru_scan.patch b/queue-5.10/nfsd-refactor-nfsd_file_lru_scan.patch new file mode 100644 index 00000000000..50da459cc7f --- /dev/null +++ b/queue-5.10/nfsd-refactor-nfsd_file_lru_scan.patch @@ -0,0 +1,62 @@ +From ecb53c5e5fb13706b3dd2d90cc7939bdb598bcaa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 Jul 2022 14:24:31 -0400 +Subject: NFSD: Refactor nfsd_file_lru_scan() + +From: Chuck Lever + +[ Upstream commit 39f1d1ff8148902c5692ffb0e1c4479416ab44a7 ] + +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 25 +++++++------------------ + 1 file changed, 7 insertions(+), 18 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index 656c94c779417..1d94491e5ddad 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -471,23 +471,6 @@ static void nfsd_file_gc_dispose_list(struct list_head *dispose) + nfsd_file_dispose_list_delayed(dispose); + } + +-static unsigned long +-nfsd_file_lru_walk_list(struct shrink_control *sc) +-{ +- LIST_HEAD(head); +- unsigned long ret; +- +- if (sc) +- ret = list_lru_shrink_walk(&nfsd_file_lru, sc, +- nfsd_file_lru_cb, &head); +- else +- ret = list_lru_walk(&nfsd_file_lru, +- nfsd_file_lru_cb, +- &head, LONG_MAX); +- nfsd_file_gc_dispose_list(&head); +- return ret; +-} +- + static void + nfsd_file_gc(void) + { +@@ -514,7 +497,13 @@ nfsd_file_lru_count(struct shrinker *s, struct shrink_control *sc) + static unsigned long + nfsd_file_lru_scan(struct shrinker *s, struct shrink_control *sc) + { +- return nfsd_file_lru_walk_list(sc); ++ LIST_HEAD(dispose); ++ unsigned long ret; ++ ++ ret = list_lru_shrink_walk(&nfsd_file_lru, sc, ++ nfsd_file_lru_cb, &dispose); ++ nfsd_file_gc_dispose_list(&dispose); ++ return ret; + } + + static struct shrinker nfsd_file_shrinker = { +-- +2.43.0 + diff --git a/queue-5.10/nfsd-refactor-nfsd_setattr.patch b/queue-5.10/nfsd-refactor-nfsd_setattr.patch new file mode 100644 index 00000000000..79243205c69 --- /dev/null +++ b/queue-5.10/nfsd-refactor-nfsd_setattr.patch @@ -0,0 +1,145 @@ +From 56ef4b9ae70f84e4dced1f5b74db75587bdc86a8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 8 Sep 2022 18:14:07 -0400 +Subject: NFSD: Refactor nfsd_setattr() + +From: Chuck Lever + +[ Upstream commit c0aa1913db57219e91a0a8832363cbafb3a9cf8f ] + +Move code that will be retried (in a subsequent patch) into a helper +function. + +Reviewed-by: Jeff Layton +[ cel: backported to 5.10.y, prior to idmapped mounts ] +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/vfs.c | 97 ++++++++++++++++++++++++++++++--------------------- + 1 file changed, 57 insertions(+), 40 deletions(-) + +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index 5ec1119a87859..e32b0c807ea9d 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -356,8 +356,61 @@ nfsd_get_write_access(struct svc_rqst *rqstp, struct svc_fh *fhp, + return nfserrno(host_err); + } + +-/* +- * Set various file attributes. After this call fhp needs an fh_put. ++static int __nfsd_setattr(struct dentry *dentry, struct iattr *iap) ++{ ++ int host_err; ++ ++ if (iap->ia_valid & ATTR_SIZE) { ++ /* ++ * RFC5661, Section 18.30.4: ++ * Changing the size of a file with SETATTR indirectly ++ * changes the time_modify and change attributes. ++ * ++ * (and similar for the older RFCs) ++ */ ++ struct iattr size_attr = { ++ .ia_valid = ATTR_SIZE | ATTR_CTIME | ATTR_MTIME, ++ .ia_size = iap->ia_size, ++ }; ++ ++ if (iap->ia_size < 0) ++ return -EFBIG; ++ ++ host_err = notify_change(dentry, &size_attr, NULL); ++ if (host_err) ++ return host_err; ++ iap->ia_valid &= ~ATTR_SIZE; ++ ++ /* ++ * Avoid the additional setattr call below if the only other ++ * attribute that the client sends is the mtime, as we update ++ * it as part of the size change above. ++ */ ++ if ((iap->ia_valid & ~ATTR_MTIME) == 0) ++ return 0; ++ } ++ ++ if (!iap->ia_valid) ++ return 0; ++ ++ iap->ia_valid |= ATTR_CTIME; ++ return notify_change(dentry, iap, NULL); ++} ++ ++/** ++ * nfsd_setattr - Set various file attributes. ++ * @rqstp: controlling RPC transaction ++ * @fhp: filehandle of target ++ * @attr: attributes to set ++ * @check_guard: set to 1 if guardtime is a valid timestamp ++ * @guardtime: do not act if ctime.tv_sec does not match this timestamp ++ * ++ * This call may adjust the contents of @attr (in particular, this ++ * call may change the bits in the na_iattr.ia_valid field). ++ * ++ * Returns nfs_ok on success, otherwise an NFS status code is ++ * returned. Caller must release @fhp by calling fh_put in either ++ * case. + */ + __be32 + nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, +@@ -370,7 +423,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, + int accmode = NFSD_MAY_SATTR; + umode_t ftype = 0; + __be32 err; +- int host_err = 0; ++ int host_err; + bool get_write_count; + bool size_change = (iap->ia_valid & ATTR_SIZE); + +@@ -427,43 +480,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, + } + + inode_lock(inode); +- if (size_change) { +- /* +- * RFC5661, Section 18.30.4: +- * Changing the size of a file with SETATTR indirectly +- * changes the time_modify and change attributes. +- * +- * (and similar for the older RFCs) +- */ +- struct iattr size_attr = { +- .ia_valid = ATTR_SIZE | ATTR_CTIME | ATTR_MTIME, +- .ia_size = iap->ia_size, +- }; +- +- host_err = -EFBIG; +- if (iap->ia_size < 0) +- goto out_unlock; +- +- host_err = notify_change(dentry, &size_attr, NULL); +- if (host_err) +- goto out_unlock; +- iap->ia_valid &= ~ATTR_SIZE; +- +- /* +- * Avoid the additional setattr call below if the only other +- * attribute that the client sends is the mtime, as we update +- * it as part of the size change above. +- */ +- if ((iap->ia_valid & ~ATTR_MTIME) == 0) +- goto out_unlock; +- } +- +- if (iap->ia_valid) { +- iap->ia_valid |= ATTR_CTIME; +- host_err = notify_change(dentry, iap, NULL); +- } +- +-out_unlock: ++ host_err = __nfsd_setattr(dentry, iap); + if (attr->na_seclabel && attr->na_seclabel->len) + attr->na_labelerr = security_inode_setsecctx(dentry, + attr->na_seclabel->data, attr->na_seclabel->len); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-refactor-nfsv3-create.patch b/queue-5.10/nfsd-refactor-nfsv3-create.patch new file mode 100644 index 00000000000..d7b343fb204 --- /dev/null +++ b/queue-5.10/nfsd-refactor-nfsv3-create.patch @@ -0,0 +1,183 @@ +From 6a8ea3b6972c1d5262cd5b49fcaf97a31c1fa6b3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 28 Mar 2022 13:29:23 -0400 +Subject: NFSD: Refactor NFSv3 CREATE + +From: Chuck Lever + +[ Upstream commit df9606abddfb01090d5ece7dcc2441d848f690f0 ] + +The NFSv3 CREATE and NFSv4 OPEN(CREATE) use cases are about to +diverge such that it makes sense to split do_nfsd_create() into one +version for NFSv3 and one for NFSv4. + +As a first step, copy do_nfsd_create() to nfs3proc.c and remove +NFSv4-specific logic. + +One immediate legibility benefit is that the logic for handling +NFSv3 createhow is now quite straightforward. NFSv4 createhow +has some subtleties that IMO do not belong in generic code. + +[ cel: backported to 5.10.y, prior to idmapped mounts ] +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3proc.c | 127 ++++++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 121 insertions(+), 6 deletions(-) + +diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c +index 981a2a71c5af7..e314545bbdb2e 100644 +--- a/fs/nfsd/nfs3proc.c ++++ b/fs/nfsd/nfs3proc.c +@@ -8,6 +8,7 @@ + #include + #include + #include ++#include + + #include "cache.h" + #include "xdr3.h" +@@ -220,10 +221,126 @@ nfsd3_proc_write(struct svc_rqst *rqstp) + } + + /* +- * With NFSv3, CREATE processing is a lot easier than with NFSv2. +- * At least in theory; we'll see how it fares in practice when the +- * first reports about SunOS compatibility problems start to pour in... ++ * Implement NFSv3's unchecked, guarded, and exclusive CREATE ++ * semantics for regular files. Except for the created file, ++ * this operation is stateless on the server. ++ * ++ * Upon return, caller must release @fhp and @resfhp. + */ ++static __be32 ++nfsd3_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp, ++ struct svc_fh *resfhp, struct nfsd3_createargs *argp) ++{ ++ struct iattr *iap = &argp->attrs; ++ struct dentry *parent, *child; ++ __u32 v_mtime, v_atime; ++ struct inode *inode; ++ __be32 status; ++ int host_err; ++ ++ if (isdotent(argp->name, argp->len)) ++ return nfserr_exist; ++ if (!(iap->ia_valid & ATTR_MODE)) ++ iap->ia_mode = 0; ++ ++ status = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_EXEC); ++ if (status != nfs_ok) ++ return status; ++ ++ parent = fhp->fh_dentry; ++ inode = d_inode(parent); ++ ++ host_err = fh_want_write(fhp); ++ if (host_err) ++ return nfserrno(host_err); ++ ++ fh_lock_nested(fhp, I_MUTEX_PARENT); ++ ++ child = lookup_one_len(argp->name, parent, argp->len); ++ if (IS_ERR(child)) { ++ status = nfserrno(PTR_ERR(child)); ++ goto out; ++ } ++ ++ if (d_really_is_negative(child)) { ++ status = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_CREATE); ++ if (status != nfs_ok) ++ goto out; ++ } ++ ++ status = fh_compose(resfhp, fhp->fh_export, child, fhp); ++ if (status != nfs_ok) ++ goto out; ++ ++ v_mtime = 0; ++ v_atime = 0; ++ if (argp->createmode == NFS3_CREATE_EXCLUSIVE) { ++ u32 *verifier = (u32 *)argp->verf; ++ ++ /* ++ * Solaris 7 gets confused (bugid 4218508) if these have ++ * the high bit set, as do xfs filesystems without the ++ * "bigtime" feature. So just clear the high bits. ++ */ ++ v_mtime = verifier[0] & 0x7fffffff; ++ v_atime = verifier[1] & 0x7fffffff; ++ } ++ ++ if (d_really_is_positive(child)) { ++ status = nfs_ok; ++ ++ switch (argp->createmode) { ++ case NFS3_CREATE_UNCHECKED: ++ if (!d_is_reg(child)) ++ break; ++ iap->ia_valid &= ATTR_SIZE; ++ goto set_attr; ++ case NFS3_CREATE_GUARDED: ++ status = nfserr_exist; ++ break; ++ case NFS3_CREATE_EXCLUSIVE: ++ if (d_inode(child)->i_mtime.tv_sec == v_mtime && ++ d_inode(child)->i_atime.tv_sec == v_atime && ++ d_inode(child)->i_size == 0) { ++ break; ++ } ++ status = nfserr_exist; ++ } ++ goto out; ++ } ++ ++ if (!IS_POSIXACL(inode)) ++ iap->ia_mode &= ~current_umask(); ++ ++ host_err = vfs_create(inode, child, iap->ia_mode, true); ++ if (host_err < 0) { ++ status = nfserrno(host_err); ++ goto out; ++ } ++ ++ /* A newly created file already has a file size of zero. */ ++ if ((iap->ia_valid & ATTR_SIZE) && (iap->ia_size == 0)) ++ iap->ia_valid &= ~ATTR_SIZE; ++ if (argp->createmode == NFS3_CREATE_EXCLUSIVE) { ++ iap->ia_valid = ATTR_MTIME | ATTR_ATIME | ++ ATTR_MTIME_SET | ATTR_ATIME_SET; ++ iap->ia_mtime.tv_sec = v_mtime; ++ iap->ia_atime.tv_sec = v_atime; ++ iap->ia_mtime.tv_nsec = 0; ++ iap->ia_atime.tv_nsec = 0; ++ } ++ ++set_attr: ++ status = nfsd_create_setattr(rqstp, fhp, resfhp, iap); ++ ++out: ++ fh_unlock(fhp); ++ if (child && !IS_ERR(child)) ++ dput(child); ++ fh_drop_write(fhp); ++ return status; ++} ++ + static __be32 + nfsd3_proc_create(struct svc_rqst *rqstp) + { +@@ -239,9 +356,7 @@ nfsd3_proc_create(struct svc_rqst *rqstp) + dirfhp = fh_copy(&resp->dirfh, &argp->fh); + newfhp = fh_init(&resp->fh, NFS3_FHSIZE); + +- resp->status = do_nfsd_create(rqstp, dirfhp, argp->name, argp->len, +- &argp->attrs, newfhp, argp->createmode, +- (u32 *)argp->verf, NULL, NULL); ++ resp->status = nfsd3_create_file(rqstp, dirfhp, newfhp, argp); + return rpc_success; + } + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-refactor-nfsv4-open-create.patch b/queue-5.10/nfsd-refactor-nfsv4-open-create.patch new file mode 100644 index 00000000000..b4152b8252f --- /dev/null +++ b/queue-5.10/nfsd-refactor-nfsv4-open-create.patch @@ -0,0 +1,216 @@ +From 0d67a032b8eafa7c60081ef032287346802078f9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 28 Mar 2022 14:47:34 -0400 +Subject: NFSD: Refactor NFSv4 OPEN(CREATE) + +From: Chuck Lever + +[ Upstream commit 254454a5aa4a9f696d6bae080c08d5863e650f49 ] + +Copy do_nfsd_create() to nfs4proc.c and remove NFSv3-specific logic. + +[ cel: backported to 5.10.y, prior to idmapped mounts ] +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 162 ++++++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 152 insertions(+), 10 deletions(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index f3d6bd2bfa4f7..adb64c9259bd8 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -37,6 +37,8 @@ + #include + #include + #include ++#include ++ + #include + #include + +@@ -235,6 +237,154 @@ static void nfsd4_set_open_owner_reply_cache(struct nfsd4_compound_state *cstate + &resfh->fh_handle); + } + ++static inline bool nfsd4_create_is_exclusive(int createmode) ++{ ++ return createmode == NFS4_CREATE_EXCLUSIVE || ++ createmode == NFS4_CREATE_EXCLUSIVE4_1; ++} ++ ++/* ++ * Implement NFSv4's unchecked, guarded, and exclusive create ++ * semantics for regular files. Open state for this new file is ++ * subsequently fabricated in nfsd4_process_open2(). ++ * ++ * Upon return, caller must release @fhp and @resfhp. ++ */ ++static __be32 ++nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp, ++ struct svc_fh *resfhp, struct nfsd4_open *open) ++{ ++ struct iattr *iap = &open->op_iattr; ++ struct dentry *parent, *child; ++ __u32 v_mtime, v_atime; ++ struct inode *inode; ++ __be32 status; ++ int host_err; ++ ++ if (isdotent(open->op_fname, open->op_fnamelen)) ++ return nfserr_exist; ++ if (!(iap->ia_valid & ATTR_MODE)) ++ iap->ia_mode = 0; ++ ++ status = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_EXEC); ++ if (status != nfs_ok) ++ return status; ++ parent = fhp->fh_dentry; ++ inode = d_inode(parent); ++ ++ host_err = fh_want_write(fhp); ++ if (host_err) ++ return nfserrno(host_err); ++ ++ fh_lock_nested(fhp, I_MUTEX_PARENT); ++ ++ child = lookup_one_len(open->op_fname, parent, open->op_fnamelen); ++ if (IS_ERR(child)) { ++ status = nfserrno(PTR_ERR(child)); ++ goto out; ++ } ++ ++ if (d_really_is_negative(child)) { ++ status = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_CREATE); ++ if (status != nfs_ok) ++ goto out; ++ } ++ ++ status = fh_compose(resfhp, fhp->fh_export, child, fhp); ++ if (status != nfs_ok) ++ goto out; ++ ++ v_mtime = 0; ++ v_atime = 0; ++ if (nfsd4_create_is_exclusive(open->op_createmode)) { ++ u32 *verifier = (u32 *)open->op_verf.data; ++ ++ /* ++ * Solaris 7 gets confused (bugid 4218508) if these have ++ * the high bit set, as do xfs filesystems without the ++ * "bigtime" feature. So just clear the high bits. If this ++ * is ever changed to use different attrs for storing the ++ * verifier, then do_open_lookup() will also need to be ++ * fixed accordingly. ++ */ ++ v_mtime = verifier[0] & 0x7fffffff; ++ v_atime = verifier[1] & 0x7fffffff; ++ } ++ ++ if (d_really_is_positive(child)) { ++ status = nfs_ok; ++ ++ switch (open->op_createmode) { ++ case NFS4_CREATE_UNCHECKED: ++ if (!d_is_reg(child)) ++ break; ++ ++ /* ++ * In NFSv4, we don't want to truncate the file ++ * now. This would be wrong if the OPEN fails for ++ * some other reason. Furthermore, if the size is ++ * nonzero, we should ignore it according to spec! ++ */ ++ open->op_truncate = (iap->ia_valid & ATTR_SIZE) && ++ !iap->ia_size; ++ break; ++ case NFS4_CREATE_GUARDED: ++ status = nfserr_exist; ++ break; ++ case NFS4_CREATE_EXCLUSIVE: ++ if (d_inode(child)->i_mtime.tv_sec == v_mtime && ++ d_inode(child)->i_atime.tv_sec == v_atime && ++ d_inode(child)->i_size == 0) { ++ open->op_created = true; ++ break; /* subtle */ ++ } ++ status = nfserr_exist; ++ break; ++ case NFS4_CREATE_EXCLUSIVE4_1: ++ if (d_inode(child)->i_mtime.tv_sec == v_mtime && ++ d_inode(child)->i_atime.tv_sec == v_atime && ++ d_inode(child)->i_size == 0) { ++ open->op_created = true; ++ goto set_attr; /* subtle */ ++ } ++ status = nfserr_exist; ++ } ++ goto out; ++ } ++ ++ if (!IS_POSIXACL(inode)) ++ iap->ia_mode &= ~current_umask(); ++ ++ host_err = vfs_create(inode, child, iap->ia_mode, true); ++ if (host_err < 0) { ++ status = nfserrno(host_err); ++ goto out; ++ } ++ open->op_created = true; ++ ++ /* A newly created file already has a file size of zero. */ ++ if ((iap->ia_valid & ATTR_SIZE) && (iap->ia_size == 0)) ++ iap->ia_valid &= ~ATTR_SIZE; ++ if (nfsd4_create_is_exclusive(open->op_createmode)) { ++ iap->ia_valid = ATTR_MTIME | ATTR_ATIME | ++ ATTR_MTIME_SET|ATTR_ATIME_SET; ++ iap->ia_mtime.tv_sec = v_mtime; ++ iap->ia_atime.tv_sec = v_atime; ++ iap->ia_mtime.tv_nsec = 0; ++ iap->ia_atime.tv_nsec = 0; ++ } ++ ++set_attr: ++ status = nfsd_create_setattr(rqstp, fhp, resfhp, iap); ++ ++out: ++ fh_unlock(fhp); ++ if (child && !IS_ERR(child)) ++ dput(child); ++ fh_drop_write(fhp); ++ return status; ++} ++ + static __be32 + do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_open *open, struct svc_fh **resfh) + { +@@ -264,16 +414,8 @@ do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, stru + * yes | yes | GUARDED4 | GUARDED4 + */ + +- /* +- * Note: create modes (UNCHECKED,GUARDED...) are the same +- * in NFSv4 as in v3 except EXCLUSIVE4_1. +- */ + current->fs->umask = open->op_umask; +- status = do_nfsd_create(rqstp, current_fh, open->op_fname, +- open->op_fnamelen, &open->op_iattr, +- *resfh, open->op_createmode, +- (u32 *)open->op_verf.data, +- &open->op_truncate, &open->op_created); ++ status = nfsd4_create_file(rqstp, current_fh, *resfh, open); + current->fs->umask = 0; + + if (!status && open->op_label.len) +@@ -284,7 +426,7 @@ do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, stru + * use the returned bitmask to indicate which attributes + * we used to store the verifier: + */ +- if (nfsd_create_is_exclusive(open->op_createmode) && status == 0) ++ if (nfsd4_create_is_exclusive(open->op_createmode) && status == 0) + open->op_bmval[1] |= (FATTR4_WORD1_TIME_ACCESS | + FATTR4_WORD1_TIME_MODIFY); + } else +-- +2.43.0 + diff --git a/queue-5.10/nfsd-refactor-set_client.patch b/queue-5.10/nfsd-refactor-set_client.patch new file mode 100644 index 00000000000..a4f288db6f5 --- /dev/null +++ b/queue-5.10/nfsd-refactor-set_client.patch @@ -0,0 +1,82 @@ +From 6156ea9b4a802f8037e84b26248d044f990f15aa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 Jan 2021 17:57:41 -0500 +Subject: nfsd: refactor set_client + +From: J. Bruce Fields + +[ Upstream commit 7950b5316e40d99dcb85ab81a2d1dbb913d7c1c8 ] + +This'll be useful elsewhere. + +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 32 ++++++++++++++++---------------- + 1 file changed, 16 insertions(+), 16 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 60c66becbc876..c4e9f807b4a1b 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -4675,40 +4675,40 @@ static __be32 nfsd4_check_seqid(struct nfsd4_compound_state *cstate, struct nfs4 + return nfserr_bad_seqid; + } + ++static struct nfs4_client *lookup_clientid(clientid_t *clid, bool sessions, ++ struct nfsd_net *nn) ++{ ++ struct nfs4_client *found; ++ ++ spin_lock(&nn->client_lock); ++ found = find_confirmed_client(clid, sessions, nn); ++ if (found) ++ atomic_inc(&found->cl_rpc_users); ++ spin_unlock(&nn->client_lock); ++ return found; ++} ++ + static __be32 set_client(clientid_t *clid, + struct nfsd4_compound_state *cstate, + struct nfsd_net *nn, + bool sessions) + { +- struct nfs4_client *found; +- + if (cstate->clp) { +- found = cstate->clp; +- if (!same_clid(&found->cl_clientid, clid)) ++ if (!same_clid(&cstate->clp->cl_clientid, clid)) + return nfserr_stale_clientid; + return nfs_ok; + } +- + if (STALE_CLIENTID(clid, nn)) + return nfserr_stale_clientid; +- + /* + * For v4.1+ we get the client in the SEQUENCE op. If we don't have one + * cached already then we know this is for is for v4.0 and "sessions" + * will be false. + */ + WARN_ON_ONCE(cstate->session); +- spin_lock(&nn->client_lock); +- found = find_confirmed_client(clid, sessions, nn); +- if (!found) { +- spin_unlock(&nn->client_lock); ++ cstate->clp = lookup_clientid(clid, sessions, nn); ++ if (!cstate->clp) + return nfserr_expired; +- } +- atomic_inc(&found->cl_rpc_users); +- spin_unlock(&nn->client_lock); +- +- /* Cache the nfs4_client in cstate! */ +- cstate->clp = found; + return nfs_ok; + } + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-refactoring-courtesy_client_reaper-to-a-generic.patch b/queue-5.10/nfsd-refactoring-courtesy_client_reaper-to-a-generic.patch new file mode 100644 index 00000000000..f223d47b955 --- /dev/null +++ b/queue-5.10/nfsd-refactoring-courtesy_client_reaper-to-a-generic.patch @@ -0,0 +1,94 @@ +From dfa18cb46516ec9cf6292dbfc1d2d11d1e607230 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 16 Nov 2022 19:44:45 -0800 +Subject: NFSD: refactoring courtesy_client_reaper to a generic low memory + shrinker + +From: Dai Ngo + +[ Upstream commit a1049eb47f20b9eabf9afb218578fff16b4baca6 ] + +Refactoring courtesy_client_reaper to generic low memory +shrinker so it can be used for other purposes. + +Signed-off-by: Dai Ngo +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 25 ++++++++++++++++--------- + 1 file changed, 16 insertions(+), 9 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 9a8038bfaa0d5..8fdf5ab5b9e47 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -4361,7 +4361,7 @@ nfsd4_init_slabs(void) + } + + static unsigned long +-nfsd_courtesy_client_count(struct shrinker *shrink, struct shrink_control *sc) ++nfsd4_state_shrinker_count(struct shrinker *shrink, struct shrink_control *sc) + { + int cnt; + struct nfsd_net *nn = container_of(shrink, +@@ -4374,7 +4374,7 @@ nfsd_courtesy_client_count(struct shrinker *shrink, struct shrink_control *sc) + } + + static unsigned long +-nfsd_courtesy_client_scan(struct shrinker *shrink, struct shrink_control *sc) ++nfsd4_state_shrinker_scan(struct shrinker *shrink, struct shrink_control *sc) + { + return SHRINK_STOP; + } +@@ -4401,8 +4401,8 @@ nfsd4_init_leases_net(struct nfsd_net *nn) + nn->nfs4_max_clients = max_t(int, max_clients, NFS4_CLIENTS_PER_GB); + + atomic_set(&nn->nfsd_courtesy_clients, 0); +- nn->nfsd_client_shrinker.scan_objects = nfsd_courtesy_client_scan; +- nn->nfsd_client_shrinker.count_objects = nfsd_courtesy_client_count; ++ nn->nfsd_client_shrinker.scan_objects = nfsd4_state_shrinker_scan; ++ nn->nfsd_client_shrinker.count_objects = nfsd4_state_shrinker_count; + nn->nfsd_client_shrinker.seeks = DEFAULT_SEEKS; + return register_shrinker(&nn->nfsd_client_shrinker); + } +@@ -6151,17 +6151,24 @@ laundromat_main(struct work_struct *laundry) + } + + static void +-courtesy_client_reaper(struct work_struct *reaper) ++courtesy_client_reaper(struct nfsd_net *nn) + { + struct list_head reaplist; +- struct delayed_work *dwork = to_delayed_work(reaper); +- struct nfsd_net *nn = container_of(dwork, struct nfsd_net, +- nfsd_shrinker_work); + + nfs4_get_courtesy_client_reaplist(nn, &reaplist); + nfs4_process_client_reaplist(&reaplist); + } + ++static void ++nfsd4_state_shrinker_worker(struct work_struct *work) ++{ ++ struct delayed_work *dwork = to_delayed_work(work); ++ struct nfsd_net *nn = container_of(dwork, struct nfsd_net, ++ nfsd_shrinker_work); ++ ++ courtesy_client_reaper(nn); ++} ++ + static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stid *stp) + { + if (!fh_match(&fhp->fh_handle, &stp->sc_file->fi_fhandle)) +@@ -7997,7 +8004,7 @@ static int nfs4_state_create_net(struct net *net) + INIT_LIST_HEAD(&nn->blocked_locks_lru); + + INIT_DELAYED_WORK(&nn->laundromat_work, laundromat_main); +- INIT_DELAYED_WORK(&nn->nfsd_shrinker_work, courtesy_client_reaper); ++ INIT_DELAYED_WORK(&nn->nfsd_shrinker_work, nfsd4_state_shrinker_worker); + get_net(net); + + return 0; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-refactoring-v4-specific-code-to-a-helper-in-nfs.patch b/queue-5.10/nfsd-refactoring-v4-specific-code-to-a-helper-in-nfs.patch new file mode 100644 index 00000000000..82dad614469 --- /dev/null +++ b/queue-5.10/nfsd-refactoring-v4-specific-code-to-a-helper-in-nfs.patch @@ -0,0 +1,88 @@ +From 29dec7103bd73074403d21163d631b1a88c99ed3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 15 Jul 2022 16:54:51 -0700 +Subject: NFSD: refactoring v4 specific code to a helper in nfs4state.c + +From: Dai Ngo + +[ Upstream commit 6867137ebcf4155fe25f2ecf7c29b9fb90a76d1d ] + +This patch moves the v4 specific code from nfsd_init_net() to +nfsd4_init_leases_net() helper in nfs4state.c + +Signed-off-by: Dai Ngo +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 12 ++++++++++++ + fs/nfsd/nfsctl.c | 9 +-------- + fs/nfsd/nfsd.h | 4 ++++ + 3 files changed, 17 insertions(+), 8 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 16e5bd54d92c2..76a77329cf368 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -4347,6 +4347,18 @@ nfsd4_init_slabs(void) + return -ENOMEM; + } + ++void nfsd4_init_leases_net(struct nfsd_net *nn) ++{ ++ nn->nfsd4_lease = 90; /* default lease time */ ++ nn->nfsd4_grace = 90; ++ nn->somebody_reclaimed = false; ++ nn->track_reclaim_completes = false; ++ nn->clverifier_counter = prandom_u32(); ++ nn->clientid_base = prandom_u32(); ++ nn->clientid_counter = nn->clientid_base + 1; ++ nn->s2s_cp_cl_id = nn->clientid_counter++; ++} ++ + static void init_nfs4_replay(struct nfs4_replay *rp) + { + rp->rp_status = nfserr_serverfault; +diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c +index 7002edbf26870..164c822ae3ae9 100644 +--- a/fs/nfsd/nfsctl.c ++++ b/fs/nfsd/nfsctl.c +@@ -1484,14 +1484,7 @@ static __net_init int nfsd_init_net(struct net *net) + retval = nfsd_reply_cache_init(nn); + if (retval) + goto out_drc_error; +- nn->nfsd4_lease = 90; /* default lease time */ +- nn->nfsd4_grace = 90; +- nn->somebody_reclaimed = false; +- nn->track_reclaim_completes = false; +- nn->clverifier_counter = prandom_u32(); +- nn->clientid_base = prandom_u32(); +- nn->clientid_counter = nn->clientid_base + 1; +- nn->s2s_cp_cl_id = nn->clientid_counter++; ++ nfsd4_init_leases_net(nn); + + get_random_bytes(&nn->siphash_key, sizeof(nn->siphash_key)); + seqlock_init(&nn->writeverf_lock); +diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h +index 9a8b09afc1733..ef8087691138a 100644 +--- a/fs/nfsd/nfsd.h ++++ b/fs/nfsd/nfsd.h +@@ -496,12 +496,16 @@ extern void unregister_cld_notifier(void); + extern void nfsd4_ssc_init_umount_work(struct nfsd_net *nn); + #endif + ++extern void nfsd4_init_leases_net(struct nfsd_net *nn); ++ + #else /* CONFIG_NFSD_V4 */ + static inline int nfsd4_is_junction(struct dentry *dentry) + { + return 0; + } + ++static inline void nfsd4_init_leases_net(struct nfsd_net *nn) {}; ++ + #define register_cld_notifier() 0 + #define unregister_cld_notifier() do { } while(0) + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-register-unregister-of-nfsd-client-shrinker-at-.patch b/queue-5.10/nfsd-register-unregister-of-nfsd-client-shrinker-at-.patch new file mode 100644 index 00000000000..e01dc7bc243 --- /dev/null +++ b/queue-5.10/nfsd-register-unregister-of-nfsd-client-shrinker-at-.patch @@ -0,0 +1,147 @@ +From 2cd9ea3e65c604413dee563739661e6ecbabf31a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Jan 2023 12:17:09 -0800 +Subject: NFSD: register/unregister of nfsd-client shrinker at nfsd + startup/shutdown time + +From: Dai Ngo + +[ Upstream commit f385f7d244134246f984975ed34cd75f77de479f ] + +Currently the nfsd-client shrinker is registered and unregistered at +the time the nfsd module is loaded and unloaded. The problem with this +is the shrinker is being registered before all of the relevant fields +in nfsd_net are initialized when nfsd is started. This can lead to an +oops when memory is low and the shrinker is called while nfsd is not +running. + +This patch moves the register/unregister of nfsd-client shrinker from +module load/unload time to nfsd startup/shutdown time. + +Fixes: 44df6f439a17 ("NFSD: add delegation reaper to react to low memory condition") +Reported-by: Mike Galbraith +Signed-off-by: Dai Ngo +[ cel: adjusted to apply without e33c267ab70d ] +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 22 +++++++++++----------- + fs/nfsd/nfsctl.c | 7 +------ + fs/nfsd/nfsd.h | 6 ++---- + 3 files changed, 14 insertions(+), 21 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 5eb3e055fde43..f2647cbc108e3 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -4420,7 +4420,7 @@ nfsd4_state_shrinker_scan(struct shrinker *shrink, struct shrink_control *sc) + return SHRINK_STOP; + } + +-int ++void + nfsd4_init_leases_net(struct nfsd_net *nn) + { + struct sysinfo si; +@@ -4442,16 +4442,6 @@ nfsd4_init_leases_net(struct nfsd_net *nn) + nn->nfs4_max_clients = max_t(int, max_clients, NFS4_CLIENTS_PER_GB); + + atomic_set(&nn->nfsd_courtesy_clients, 0); +- nn->nfsd_client_shrinker.scan_objects = nfsd4_state_shrinker_scan; +- nn->nfsd_client_shrinker.count_objects = nfsd4_state_shrinker_count; +- nn->nfsd_client_shrinker.seeks = DEFAULT_SEEKS; +- return register_shrinker(&nn->nfsd_client_shrinker); +-} +- +-void +-nfsd4_leases_net_shutdown(struct nfsd_net *nn) +-{ +- unregister_shrinker(&nn->nfsd_client_shrinker); + } + + static void init_nfs4_replay(struct nfs4_replay *rp) +@@ -8079,8 +8069,17 @@ static int nfs4_state_create_net(struct net *net) + INIT_DELAYED_WORK(&nn->nfsd_shrinker_work, nfsd4_state_shrinker_worker); + get_net(net); + ++ nn->nfsd_client_shrinker.scan_objects = nfsd4_state_shrinker_scan; ++ nn->nfsd_client_shrinker.count_objects = nfsd4_state_shrinker_count; ++ nn->nfsd_client_shrinker.seeks = DEFAULT_SEEKS; ++ ++ if (register_shrinker(&nn->nfsd_client_shrinker)) ++ goto err_shrinker; + return 0; + ++err_shrinker: ++ put_net(net); ++ kfree(nn->sessionid_hashtbl); + err_sessionid: + kfree(nn->unconf_id_hashtbl); + err_unconf_id: +@@ -8173,6 +8172,7 @@ nfs4_state_shutdown_net(struct net *net) + struct list_head *pos, *next, reaplist; + struct nfsd_net *nn = net_generic(net, nfsd_net_id); + ++ unregister_shrinker(&nn->nfsd_client_shrinker); + cancel_delayed_work_sync(&nn->laundromat_work); + locks_end_grace(&nn->nfsd4_manager); + +diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c +index d1e581a60480c..c2577ee7ffb22 100644 +--- a/fs/nfsd/nfsctl.c ++++ b/fs/nfsd/nfsctl.c +@@ -1457,9 +1457,7 @@ static __net_init int nfsd_init_net(struct net *net) + goto out_idmap_error; + nn->nfsd_versions = NULL; + nn->nfsd4_minorversions = NULL; +- retval = nfsd4_init_leases_net(nn); +- if (retval) +- goto out_drc_error; ++ nfsd4_init_leases_net(nn); + retval = nfsd_reply_cache_init(nn); + if (retval) + goto out_cache_error; +@@ -1469,8 +1467,6 @@ static __net_init int nfsd_init_net(struct net *net) + return 0; + + out_cache_error: +- nfsd4_leases_net_shutdown(nn); +-out_drc_error: + nfsd_idmap_shutdown(net); + out_idmap_error: + nfsd_export_shutdown(net); +@@ -1486,7 +1482,6 @@ static __net_exit void nfsd_exit_net(struct net *net) + nfsd_idmap_shutdown(net); + nfsd_export_shutdown(net); + nfsd_netns_free_versions(net_generic(net, nfsd_net_id)); +- nfsd4_leases_net_shutdown(nn); + } + + static struct pernet_operations nfsd_net_ops = { +diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h +index 93b42ef9ed91b..fa0144a742678 100644 +--- a/fs/nfsd/nfsd.h ++++ b/fs/nfsd/nfsd.h +@@ -504,8 +504,7 @@ extern void unregister_cld_notifier(void); + extern void nfsd4_ssc_init_umount_work(struct nfsd_net *nn); + #endif + +-extern int nfsd4_init_leases_net(struct nfsd_net *nn); +-extern void nfsd4_leases_net_shutdown(struct nfsd_net *nn); ++extern void nfsd4_init_leases_net(struct nfsd_net *nn); + + #else /* CONFIG_NFSD_V4 */ + static inline int nfsd4_is_junction(struct dentry *dentry) +@@ -513,8 +512,7 @@ static inline int nfsd4_is_junction(struct dentry *dentry) + return 0; + } + +-static inline int nfsd4_init_leases_net(struct nfsd_net *nn) { return 0; }; +-static inline void nfsd4_leases_net_shutdown(struct nfsd_net *nn) {}; ++static inline void nfsd4_init_leases_net(struct nfsd_net *nn) { }; + + #define register_cld_notifier() 0 + #define unregister_cld_notifier() do { } while(0) +-- +2.43.0 + diff --git a/queue-5.10/nfsd-relocate-nfsd4_decode_opaque.patch b/queue-5.10/nfsd-relocate-nfsd4_decode_opaque.patch new file mode 100644 index 00000000000..1eb5b299eca --- /dev/null +++ b/queue-5.10/nfsd-relocate-nfsd4_decode_opaque.patch @@ -0,0 +1,82 @@ +From 2ea15b62fb5c740cd20d08d12e79e3f1dd992923 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Nov 2020 11:41:55 -0500 +Subject: NFSD: Relocate nfsd4_decode_opaque() + +From: Chuck Lever + +[ Upstream commit 5dcbfabb676b2b6d97767209cf707eb463ca232a ] + +Enable nfsd4_decode_opaque() to be used in more decoders, and +replace the READ* macros in nfsd4_decode_opaque(). + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 43 +++++++++++++++++++++++++++---------------- + 1 file changed, 27 insertions(+), 16 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 4596b8cef222c..b3459059cec1b 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -207,6 +207,33 @@ static char *savemem(struct nfsd4_compoundargs *argp, __be32 *p, int nbytes) + return ret; + } + ++ ++/* ++ * NFSv4 basic data type decoders ++ */ ++ ++static __be32 ++nfsd4_decode_opaque(struct nfsd4_compoundargs *argp, struct xdr_netobj *o) ++{ ++ __be32 *p; ++ u32 len; ++ ++ if (xdr_stream_decode_u32(argp->xdr, &len) < 0) ++ return nfserr_bad_xdr; ++ if (len == 0 || len > NFS4_OPAQUE_LIMIT) ++ return nfserr_bad_xdr; ++ p = xdr_inline_decode(argp->xdr, len); ++ if (!p) ++ return nfserr_bad_xdr; ++ o->data = svcxdr_tmpalloc(argp, len); ++ if (!o->data) ++ return nfserr_jukebox; ++ o->len = len; ++ memcpy(o->data, p, len); ++ ++ return nfs_ok; ++} ++ + static __be32 + nfsd4_decode_component4(struct nfsd4_compoundargs *argp, char **namp, u32 *lenp) + { +@@ -943,22 +970,6 @@ static __be32 nfsd4_decode_share_deny(struct nfsd4_compoundargs *argp, u32 *x) + return nfserr_bad_xdr; + } + +-static __be32 nfsd4_decode_opaque(struct nfsd4_compoundargs *argp, struct xdr_netobj *o) +-{ +- DECODE_HEAD; +- +- READ_BUF(4); +- o->len = be32_to_cpup(p++); +- +- if (o->len == 0 || o->len > NFS4_OPAQUE_LIMIT) +- return nfserr_bad_xdr; +- +- READ_BUF(o->len); +- SAVEMEM(o->data, o->len); +- +- DECODE_TAIL; +-} +- + static __be32 + nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) + { +-- +2.43.0 + diff --git a/queue-5.10/nfsd-remove-argument-length-checking-in-nfsd_dispatc.patch b/queue-5.10/nfsd-remove-argument-length-checking-in-nfsd_dispatc.patch new file mode 100644 index 00000000000..35adaf875a3 --- /dev/null +++ b/queue-5.10/nfsd-remove-argument-length-checking-in-nfsd_dispatc.patch @@ -0,0 +1,74 @@ +From a4267ab612fe7424af73a78fb698dffd11821c48 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Oct 2020 10:08:19 -0400 +Subject: NFSD: Remove argument length checking in nfsd_dispatch() + +From: Chuck Lever + +[ Upstream commit 5650682e16f41722f735b7beeb2dbc3411dfbeb6 ] + +Now that the argument decoders for NFSv2 and NFSv3 use the +xdr_stream mechanism, the version-specific length checking logic in +nfsd_dispatch() is no longer necessary. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfssvc.c | 34 ---------------------------------- + 1 file changed, 34 deletions(-) + +diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c +index 423410cc02145..6c1d70935ea81 100644 +--- a/fs/nfsd/nfssvc.c ++++ b/fs/nfsd/nfssvc.c +@@ -988,37 +988,6 @@ nfsd(void *vrqstp) + return 0; + } + +-/* +- * A write procedure can have a large argument, and a read procedure can +- * have a large reply, but no NFSv2 or NFSv3 procedure has argument and +- * reply that can both be larger than a page. The xdr code has taken +- * advantage of this assumption to be a sloppy about bounds checking in +- * some cases. Pending a rewrite of the NFSv2/v3 xdr code to fix that +- * problem, we enforce these assumptions here: +- */ +-static bool nfs_request_too_big(struct svc_rqst *rqstp, +- const struct svc_procedure *proc) +-{ +- /* +- * The ACL code has more careful bounds-checking and is not +- * susceptible to this problem: +- */ +- if (rqstp->rq_prog != NFS_PROGRAM) +- return false; +- /* +- * Ditto NFSv4 (which can in theory have argument and reply both +- * more than a page): +- */ +- if (rqstp->rq_vers >= 4) +- return false; +- /* The reply will be small, we're OK: */ +- if (proc->pc_xdrressize > 0 && +- proc->pc_xdrressize < XDR_QUADLEN(PAGE_SIZE)) +- return false; +- +- return rqstp->rq_arg.len > PAGE_SIZE; +-} +- + /** + * nfsd_dispatch - Process an NFS or NFSACL Request + * @rqstp: incoming request +@@ -1037,9 +1006,6 @@ int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) + struct kvec *resv = &rqstp->rq_res.head[0]; + __be32 *p; + +- if (nfs_request_too_big(rqstp, proc)) +- goto out_decode_err; +- + /* + * Give the xdr decoder a chance to change this if it wants + * (necessary in the NFSv4.0 compound case) +-- +2.43.0 + diff --git a/queue-5.10/nfsd-remove-be32_to_cpu-from-drc-hash-function.patch b/queue-5.10/nfsd-remove-be32_to_cpu-from-drc-hash-function.patch new file mode 100644 index 00000000000..94f26a6dd26 --- /dev/null +++ b/queue-5.10/nfsd-remove-be32_to_cpu-from-drc-hash-function.patch @@ -0,0 +1,46 @@ +From 46beb937a204dd62755493cc7c9e394257a18afc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Sep 2021 19:10:03 -0400 +Subject: NFSD: Remove be32_to_cpu() from DRC hash function + +From: Chuck Lever + +[ Upstream commit 7578b2f628db27281d3165af0aa862311883a858 ] + +Commit 7142b98d9fd7 ("nfsd: Clean up drc cache in preparation for +global spinlock elimination"), billed as a clean-up, added +be32_to_cpu() to the DRC hash function without explanation. That +commit removed two comments that state that byte-swapping in the +hash function is unnecessary without explaining whether there was +a need for that change. + +On some Intel CPUs, the swab32 instruction is known to cause a CPU +pipeline stall. be32_to_cpu() does not add extra randomness, since +the hash multiplication is done /before/ shifting to the high-order +bits of the result. + +As a micro-optimization, remove the unnecessary transform from the +DRC hash function. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfscache.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c +index 6e0b6f3148dca..a4a69ab6ab280 100644 +--- a/fs/nfsd/nfscache.c ++++ b/fs/nfsd/nfscache.c +@@ -87,7 +87,7 @@ nfsd_hashsize(unsigned int limit) + static u32 + nfsd_cache_hash(__be32 xid, struct nfsd_net *nn) + { +- return hash_32(be32_to_cpu(xid), nn->maskbits); ++ return hash_32((__force u32)xid, nn->maskbits); + } + + static struct svc_cacherep * +-- +2.43.0 + diff --git a/queue-5.10/nfsd-remove-config_nfsd_v3.patch b/queue-5.10/nfsd-remove-config_nfsd_v3.patch new file mode 100644 index 00000000000..5730d842f0e --- /dev/null +++ b/queue-5.10/nfsd-remove-config_nfsd_v3.patch @@ -0,0 +1,269 @@ +From 98c9b2281466cb9cdba66bc5f25c1cbf1770039e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 6 Feb 2022 12:25:47 -0500 +Subject: NFSD: Remove CONFIG_NFSD_V3 + +From: Chuck Lever + +[ Upstream commit 5f9a62ff7d2808c7b56c0ec90f3b7eae5872afe6 ] + +Eventually support for NFSv2 in the Linux NFS server is to be +deprecated and then removed. + +However, NFSv2 is the "always supported" version that is available +as soon as CONFIG_NFSD is set. Before NFSv2 support can be removed, +we need to choose a different "always supported" version. + +This patch removes CONFIG_NFSD_V3 so that NFSv3 is always supported, +as NFSv2 is today. When NFSv2 support is removed, NFSv3 will become +the only "always supported" NFS version. + +The defconfigs still need to be updated to remove CONFIG_NFSD_V3=y. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/Kconfig | 2 +- + fs/nfsd/Kconfig | 12 +----------- + fs/nfsd/Makefile | 3 +-- + fs/nfsd/nfsfh.c | 4 ---- + fs/nfsd/nfsfh.h | 20 -------------------- + fs/nfsd/nfssvc.c | 2 -- + fs/nfsd/vfs.c | 9 --------- + fs/nfsd/vfs.h | 2 -- + 8 files changed, 3 insertions(+), 51 deletions(-) + +diff --git a/fs/Kconfig b/fs/Kconfig +index eaff422877c39..11b60d160f88f 100644 +--- a/fs/Kconfig ++++ b/fs/Kconfig +@@ -320,7 +320,7 @@ config LOCKD + + config LOCKD_V4 + bool +- depends on NFSD_V3 || NFS_V3 ++ depends on NFSD || NFS_V3 + depends on FILE_LOCKING + default y + +diff --git a/fs/nfsd/Kconfig b/fs/nfsd/Kconfig +index f229172652be0..887af7966b032 100644 +--- a/fs/nfsd/Kconfig ++++ b/fs/nfsd/Kconfig +@@ -35,18 +35,9 @@ config NFSD_V2_ACL + bool + depends on NFSD + +-config NFSD_V3 +- bool "NFS server support for NFS version 3" +- depends on NFSD +- help +- This option enables support in your system's NFS server for +- version 3 of the NFS protocol (RFC 1813). +- +- If unsure, say Y. +- + config NFSD_V3_ACL + bool "NFS server support for the NFSv3 ACL protocol extension" +- depends on NFSD_V3 ++ depends on NFSD + select NFSD_V2_ACL + help + Solaris NFS servers support an auxiliary NFSv3 ACL protocol that +@@ -70,7 +61,6 @@ config NFSD_V3_ACL + config NFSD_V4 + bool "NFS server support for NFS version 4" + depends on NFSD && PROC_FS +- select NFSD_V3 + select FS_POSIX_ACL + select SUNRPC_GSS + select CRYPTO +diff --git a/fs/nfsd/Makefile b/fs/nfsd/Makefile +index 3f0983e93a998..805c06d5f1b4b 100644 +--- a/fs/nfsd/Makefile ++++ b/fs/nfsd/Makefile +@@ -12,9 +12,8 @@ nfsd-y += trace.o + + nfsd-y += nfssvc.o nfsctl.o nfsproc.o nfsfh.o vfs.o \ + export.o auth.o lockd.o nfscache.o nfsxdr.o \ +- stats.o filecache.o ++ stats.o filecache.o nfs3proc.o nfs3xdr.o + nfsd-$(CONFIG_NFSD_V2_ACL) += nfs2acl.o +-nfsd-$(CONFIG_NFSD_V3) += nfs3proc.o nfs3xdr.o + nfsd-$(CONFIG_NFSD_V3_ACL) += nfs3acl.o + nfsd-$(CONFIG_NFSD_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4idmap.o \ + nfs4acl.o nfs4callback.o nfs4recover.o +diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c +index 3b9751555f8f2..d4ae838948ba5 100644 +--- a/fs/nfsd/nfsfh.c ++++ b/fs/nfsd/nfsfh.c +@@ -610,8 +610,6 @@ fh_update(struct svc_fh *fhp) + return nfserr_serverfault; + } + +-#ifdef CONFIG_NFSD_V3 +- + /** + * fh_fill_pre_attrs - Fill in pre-op attributes + * @fhp: file handle to be updated +@@ -672,8 +670,6 @@ void fh_fill_post_attrs(struct svc_fh *fhp) + nfsd4_change_attribute(&fhp->fh_post_attr, inode); + } + +-#endif /* CONFIG_NFSD_V3 */ +- + /* + * Release a file handle. + */ +diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h +index 434930d8a946e..fb9d358a267e5 100644 +--- a/fs/nfsd/nfsfh.h ++++ b/fs/nfsd/nfsfh.h +@@ -90,7 +90,6 @@ typedef struct svc_fh { + * operation + */ + int fh_flags; /* FH flags */ +-#ifdef CONFIG_NFSD_V3 + bool fh_post_saved; /* post-op attrs saved */ + bool fh_pre_saved; /* pre-op attrs saved */ + +@@ -107,7 +106,6 @@ typedef struct svc_fh { + /* Post-op attributes saved in fh_unlock */ + struct kstat fh_post_attr; /* full attrs after operation */ + u64 fh_post_change; /* nfsv4 change; see above */ +-#endif /* CONFIG_NFSD_V3 */ + } svc_fh; + #define NFSD4_FH_FOREIGN (1<<0) + #define SET_FH_FLAG(c, f) ((c)->fh_flags |= (f)) +@@ -283,8 +281,6 @@ static inline u32 knfsd_fh_hash(const struct knfsd_fh *fh) + } + #endif + +-#ifdef CONFIG_NFSD_V3 +- + /** + * fh_clear_pre_post_attrs - Reset pre/post attributes + * @fhp: file handle to be updated +@@ -327,22 +323,6 @@ static inline u64 nfsd4_change_attribute(struct kstat *stat, + extern void fh_fill_pre_attrs(struct svc_fh *fhp); + extern void fh_fill_post_attrs(struct svc_fh *fhp); + +-#else /* !CONFIG_NFSD_V3 */ +- +-static inline void fh_clear_pre_post_attrs(struct svc_fh *fhp) +-{ +-} +- +-static inline void fh_fill_pre_attrs(struct svc_fh *fhp) +-{ +-} +- +-static inline void fh_fill_post_attrs(struct svc_fh *fhp) +-{ +-} +- +-#endif /* !CONFIG_NFSD_V3 */ +- + + /* + * Lock a file handle/inode +diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c +index 2f74be98ff2d9..011c556caa1e7 100644 +--- a/fs/nfsd/nfssvc.c ++++ b/fs/nfsd/nfssvc.c +@@ -117,9 +117,7 @@ static struct svc_stat nfsd_acl_svcstats = { + + static const struct svc_version *nfsd_version[] = { + [2] = &nfsd_version2, +-#if defined(CONFIG_NFSD_V3) + [3] = &nfsd_version3, +-#endif + #if defined(CONFIG_NFSD_V4) + [4] = &nfsd_version4, + #endif +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index 89c50ccedf4d3..86584e727ce09 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -32,9 +32,7 @@ + #include + #include + +-#ifdef CONFIG_NFSD_V3 + #include "xdr3.h" +-#endif /* CONFIG_NFSD_V3 */ + + #ifdef CONFIG_NFSD_V4 + #include "../internal.h" +@@ -627,7 +625,6 @@ __be32 nfsd4_vfs_fallocate(struct svc_rqst *rqstp, struct svc_fh *fhp, + } + #endif /* defined(CONFIG_NFSD_V4) */ + +-#ifdef CONFIG_NFSD_V3 + /* + * Check server access rights to a file system object + */ +@@ -739,7 +736,6 @@ nfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access, u32 *suppor + out: + return error; + } +-#endif /* CONFIG_NFSD_V3 */ + + int nfsd_open_break_lease(struct inode *inode, int access) + { +@@ -1139,7 +1135,6 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, + return err; + } + +-#ifdef CONFIG_NFSD_V3 + /** + * nfsd_commit - Commit pending writes to stable storage + * @rqstp: RPC request being processed +@@ -1217,7 +1212,6 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, u64 offset, + out: + return err; + } +-#endif /* CONFIG_NFSD_V3 */ + + static __be32 + nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *resfhp, +@@ -1406,8 +1400,6 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, + rdev, resfhp); + } + +-#ifdef CONFIG_NFSD_V3 +- + /* + * NFSv3 and NFSv4 version of nfsd_create + */ +@@ -1573,7 +1565,6 @@ do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, + err = nfserrno(host_err); + goto out; + } +-#endif /* CONFIG_NFSD_V3 */ + + /* + * Read a symlink. On entry, *lenp must contain the maximum path length that +diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h +index 2c43d10e3cab4..ccb87b2864f64 100644 +--- a/fs/nfsd/vfs.h ++++ b/fs/nfsd/vfs.h +@@ -68,7 +68,6 @@ __be32 nfsd_create_locked(struct svc_rqst *, struct svc_fh *, + __be32 nfsd_create(struct svc_rqst *, struct svc_fh *, + char *name, int len, struct iattr *attrs, + int type, dev_t rdev, struct svc_fh *res); +-#ifdef CONFIG_NFSD_V3 + __be32 nfsd_access(struct svc_rqst *, struct svc_fh *, u32 *, u32 *); + __be32 do_nfsd_create(struct svc_rqst *, struct svc_fh *, + char *name, int len, struct iattr *attrs, +@@ -76,7 +75,6 @@ __be32 do_nfsd_create(struct svc_rqst *, struct svc_fh *, + u32 *verifier, bool *truncp, bool *created); + __be32 nfsd_commit(struct svc_rqst *rqst, struct svc_fh *fhp, + u64 offset, u32 count, __be32 *verf); +-#endif /* CONFIG_NFSD_V3 */ + #ifdef CONFIG_NFSD_V4 + __be32 nfsd_getxattr(struct svc_rqst *rqstp, struct svc_fh *fhp, + char *name, void **bufp, int *lenp); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-remove-do_nfsd_create.patch b/queue-5.10/nfsd-remove-do_nfsd_create.patch new file mode 100644 index 00000000000..6d76bb9208e --- /dev/null +++ b/queue-5.10/nfsd-remove-do_nfsd_create.patch @@ -0,0 +1,210 @@ +From a4195a0cf02dbb35a92d4c48bfef9c5ed823f546 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 28 Mar 2022 15:36:58 -0400 +Subject: NFSD: Remove do_nfsd_create() + +From: Chuck Lever + +[ Upstream commit 1c388f27759c5d9271d4fca081f7ee138986eb7d ] + +Now that its two callers have their own version-specific instance of +this function, do_nfsd_create() is no longer used. + +[ cel: backported to 5.10.y, prior to idmapped mounts ] +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/vfs.c | 150 -------------------------------------------------- + fs/nfsd/vfs.h | 10 ---- + 2 files changed, 160 deletions(-) + +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index 50451789a9444..26ae28b6f9b02 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -1412,156 +1412,6 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, + rdev, resfhp); + } + +-/* +- * NFSv3 and NFSv4 version of nfsd_create +- */ +-__be32 +-do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, +- char *fname, int flen, struct iattr *iap, +- struct svc_fh *resfhp, int createmode, u32 *verifier, +- bool *truncp, bool *created) +-{ +- struct dentry *dentry, *dchild = NULL; +- struct inode *dirp; +- __be32 err; +- int host_err; +- __u32 v_mtime=0, v_atime=0; +- +- err = nfserr_perm; +- if (!flen) +- goto out; +- err = nfserr_exist; +- if (isdotent(fname, flen)) +- goto out; +- if (!(iap->ia_valid & ATTR_MODE)) +- iap->ia_mode = 0; +- err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_EXEC); +- if (err) +- goto out; +- +- dentry = fhp->fh_dentry; +- dirp = d_inode(dentry); +- +- host_err = fh_want_write(fhp); +- if (host_err) +- goto out_nfserr; +- +- fh_lock_nested(fhp, I_MUTEX_PARENT); +- +- /* +- * Compose the response file handle. +- */ +- dchild = lookup_one_len(fname, dentry, flen); +- host_err = PTR_ERR(dchild); +- if (IS_ERR(dchild)) +- goto out_nfserr; +- +- /* If file doesn't exist, check for permissions to create one */ +- if (d_really_is_negative(dchild)) { +- err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_CREATE); +- if (err) +- goto out; +- } +- +- err = fh_compose(resfhp, fhp->fh_export, dchild, fhp); +- if (err) +- goto out; +- +- if (nfsd_create_is_exclusive(createmode)) { +- /* solaris7 gets confused (bugid 4218508) if these have +- * the high bit set, as do xfs filesystems without the +- * "bigtime" feature. So just clear the high bits. If this is +- * ever changed to use different attrs for storing the +- * verifier, then do_open_lookup() will also need to be fixed +- * accordingly. +- */ +- v_mtime = verifier[0]&0x7fffffff; +- v_atime = verifier[1]&0x7fffffff; +- } +- +- if (d_really_is_positive(dchild)) { +- err = 0; +- +- switch (createmode) { +- case NFS3_CREATE_UNCHECKED: +- if (! d_is_reg(dchild)) +- goto out; +- else if (truncp) { +- /* in nfsv4, we need to treat this case a little +- * differently. we don't want to truncate the +- * file now; this would be wrong if the OPEN +- * fails for some other reason. furthermore, +- * if the size is nonzero, we should ignore it +- * according to spec! +- */ +- *truncp = (iap->ia_valid & ATTR_SIZE) && !iap->ia_size; +- } +- else { +- iap->ia_valid &= ATTR_SIZE; +- goto set_attr; +- } +- break; +- case NFS3_CREATE_EXCLUSIVE: +- if ( d_inode(dchild)->i_mtime.tv_sec == v_mtime +- && d_inode(dchild)->i_atime.tv_sec == v_atime +- && d_inode(dchild)->i_size == 0 ) { +- if (created) +- *created = true; +- break; +- } +- fallthrough; +- case NFS4_CREATE_EXCLUSIVE4_1: +- if ( d_inode(dchild)->i_mtime.tv_sec == v_mtime +- && d_inode(dchild)->i_atime.tv_sec == v_atime +- && d_inode(dchild)->i_size == 0 ) { +- if (created) +- *created = true; +- goto set_attr; +- } +- fallthrough; +- case NFS3_CREATE_GUARDED: +- err = nfserr_exist; +- } +- goto out; +- } +- +- if (!IS_POSIXACL(dirp)) +- iap->ia_mode &= ~current_umask(); +- +- host_err = vfs_create(dirp, dchild, iap->ia_mode, true); +- if (host_err < 0) +- goto out_nfserr; +- if (created) +- *created = true; +- +- nfsd_check_ignore_resizing(iap); +- +- if (nfsd_create_is_exclusive(createmode)) { +- /* Cram the verifier into atime/mtime */ +- iap->ia_valid = ATTR_MTIME|ATTR_ATIME +- | ATTR_MTIME_SET|ATTR_ATIME_SET; +- /* XXX someone who knows this better please fix it for nsec */ +- iap->ia_mtime.tv_sec = v_mtime; +- iap->ia_atime.tv_sec = v_atime; +- iap->ia_mtime.tv_nsec = 0; +- iap->ia_atime.tv_nsec = 0; +- } +- +- set_attr: +- err = nfsd_create_setattr(rqstp, fhp, resfhp, iap); +- +- out: +- fh_unlock(fhp); +- if (dchild && !IS_ERR(dchild)) +- dput(dchild); +- fh_drop_write(fhp); +- return err; +- +- out_nfserr: +- err = nfserrno(host_err); +- goto out; +-} +- + /* + * Read a symlink. On entry, *lenp must contain the maximum path length that + * fits into the buffer. On return, it contains the true length. +diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h +index 1f32a83456b03..f99794b033a55 100644 +--- a/fs/nfsd/vfs.h ++++ b/fs/nfsd/vfs.h +@@ -71,10 +71,6 @@ __be32 nfsd_create(struct svc_rqst *, struct svc_fh *, + __be32 nfsd_access(struct svc_rqst *, struct svc_fh *, u32 *, u32 *); + __be32 nfsd_create_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, + struct svc_fh *resfhp, struct iattr *iap); +-__be32 do_nfsd_create(struct svc_rqst *, struct svc_fh *, +- char *name, int len, struct iattr *attrs, +- struct svc_fh *res, int createmode, +- u32 *verifier, bool *truncp, bool *created); + __be32 nfsd_commit(struct svc_rqst *rqst, struct svc_fh *fhp, + u64 offset, u32 count, __be32 *verf); + #ifdef CONFIG_NFSD_V4 +@@ -161,10 +157,4 @@ static inline __be32 fh_getattr(const struct svc_fh *fh, struct kstat *stat) + AT_STATX_SYNC_AS_STAT)); + } + +-static inline int nfsd_create_is_exclusive(int createmode) +-{ +- return createmode == NFS3_CREATE_EXCLUSIVE +- || createmode == NFS4_CREATE_EXCLUSIVE4_1; +-} +- + #endif /* LINUX_NFSD_VFS_H */ +-- +2.43.0 + diff --git a/queue-5.10/nfsd-remove-dprintk-call-sites-from-tail-of-nfsd4_op.patch b/queue-5.10/nfsd-remove-dprintk-call-sites-from-tail-of-nfsd4_op.patch new file mode 100644 index 00000000000..8279ee23a6c --- /dev/null +++ b/queue-5.10/nfsd-remove-dprintk-call-sites-from-tail-of-nfsd4_op.patch @@ -0,0 +1,39 @@ +From 651c3a4c614137ce9ce0baa6f62594f7d0fe1f42 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 30 Mar 2022 14:28:51 -0400 +Subject: NFSD: Remove dprintk call sites from tail of nfsd4_open() + +From: Chuck Lever + +[ Upstream commit f67a16b147045815b6aaafeef8663e5faeb6d569 ] + +Clean up: These relics are not likely to benefit server +administrators. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 166ebb126d37b..c21cfaabf873a 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -622,13 +622,9 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + break; + case NFS4_OPEN_CLAIM_DELEG_PREV_FH: + case NFS4_OPEN_CLAIM_DELEGATE_PREV: +- dprintk("NFSD: unsupported OPEN claim type %d\n", +- open->op_claim_type); + status = nfserr_notsupp; + goto out; + default: +- dprintk("NFSD: Invalid OPEN claim type %d\n", +- open->op_claim_type); + status = nfserr_inval; + goto out; + } +-- +2.43.0 + diff --git a/queue-5.10/nfsd-remove-extra-0x-in-tracepoint-format-specifier.patch b/queue-5.10/nfsd-remove-extra-0x-in-tracepoint-format-specifier.patch new file mode 100644 index 00000000000..acbbc4f06be --- /dev/null +++ b/queue-5.10/nfsd-remove-extra-0x-in-tracepoint-format-specifier.patch @@ -0,0 +1,60 @@ +From 82f029582b7f46586d2a93307fbc9b0c9ac64d5d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 4 Sep 2020 15:06:26 -0400 +Subject: NFSD: Remove extra "0x" in tracepoint format specifier + +From: Chuck Lever + +[ Upstream commit 3a90e1dff16afdae6e1c918bfaff24f4d0f84869 ] + +Clean up: %p adds its own 0x already. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/trace.h | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index 7bb1c398daa51..9239d97b682c7 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -444,7 +444,7 @@ DECLARE_EVENT_CLASS(nfsd_file_class, + __entry->nf_may = nf->nf_may; + __entry->nf_file = nf->nf_file; + ), +- TP_printk("hash=0x%x inode=0x%p ref=%d flags=%s may=%s file=%p", ++ TP_printk("hash=0x%x inode=%p ref=%d flags=%s may=%s file=%p", + __entry->nf_hashval, + __entry->nf_inode, + __entry->nf_ref, +@@ -495,7 +495,7 @@ TRACE_EVENT(nfsd_file_acquire, + __entry->status = be32_to_cpu(status); + ), + +- TP_printk("xid=0x%x hash=0x%x inode=0x%p may_flags=%s ref=%d nf_flags=%s nf_may=%s nf_file=0x%p status=%u", ++ TP_printk("xid=0x%x hash=0x%x inode=%p may_flags=%s ref=%d nf_flags=%s nf_may=%s nf_file=%p status=%u", + __entry->xid, __entry->hash, __entry->inode, + show_nfsd_may_flags(__entry->may_flags), + __entry->nf_ref, show_nf_flags(__entry->nf_flags), +@@ -516,7 +516,7 @@ DECLARE_EVENT_CLASS(nfsd_file_search_class, + __entry->hash = hash; + __entry->found = found; + ), +- TP_printk("hash=0x%x inode=0x%p found=%d", __entry->hash, ++ TP_printk("hash=0x%x inode=%p found=%d", __entry->hash, + __entry->inode, __entry->found) + ); + +@@ -544,7 +544,7 @@ TRACE_EVENT(nfsd_file_fsnotify_handle_event, + __entry->mode = inode->i_mode; + __entry->mask = mask; + ), +- TP_printk("inode=0x%p nlink=%u mode=0%ho mask=0x%x", __entry->inode, ++ TP_printk("inode=%p nlink=%u mode=0%ho mask=0x%x", __entry->inode, + __entry->nlink, __entry->mode, __entry->mask) + ); + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-remove-inline-directives-on-op_rsize_bop-helper.patch b/queue-5.10/nfsd-remove-inline-directives-on-op_rsize_bop-helper.patch new file mode 100644 index 00000000000..ac643b8bd88 --- /dev/null +++ b/queue-5.10/nfsd-remove-inline-directives-on-op_rsize_bop-helper.patch @@ -0,0 +1,374 @@ +From d156798c4650dffffc5cad29c4273e3367834129 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Sep 2022 17:23:25 -0400 +Subject: NFSD: Remove "inline" directives on op_rsize_bop helpers + +From: Chuck Lever + +[ Upstream commit 6604148cf961b57fc735e4204f8996536da9253c ] + +These helpers are always invoked indirectly, so the compiler can't +inline these anyway. While we're updating the synopses of these +helpers, defensively convert their parameters to const pointers. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 121 ++++++++++++++++++++++++++++----------------- + fs/nfsd/xdr4.h | 3 +- + 2 files changed, 77 insertions(+), 47 deletions(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 79f1990d40c44..1bb0fb917cf0d 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -2763,28 +2763,33 @@ nfsd4_proc_compound(struct svc_rqst *rqstp) + + #define op_encode_channel_attrs_maxsz (6 + 1 + 1) + +-static inline u32 nfsd4_only_status_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) ++static u32 nfsd4_only_status_rsize(const struct svc_rqst *rqstp, ++ const struct nfsd4_op *op) + { + return (op_encode_hdr_size) * sizeof(__be32); + } + +-static inline u32 nfsd4_status_stateid_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) ++static u32 nfsd4_status_stateid_rsize(const struct svc_rqst *rqstp, ++ const struct nfsd4_op *op) + { + return (op_encode_hdr_size + op_encode_stateid_maxsz)* sizeof(__be32); + } + +-static inline u32 nfsd4_access_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) ++static u32 nfsd4_access_rsize(const struct svc_rqst *rqstp, ++ const struct nfsd4_op *op) + { + /* ac_supported, ac_resp_access */ + return (op_encode_hdr_size + 2)* sizeof(__be32); + } + +-static inline u32 nfsd4_commit_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) ++static u32 nfsd4_commit_rsize(const struct svc_rqst *rqstp, ++ const struct nfsd4_op *op) + { + return (op_encode_hdr_size + op_encode_verifier_maxsz) * sizeof(__be32); + } + +-static inline u32 nfsd4_create_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) ++static u32 nfsd4_create_rsize(const struct svc_rqst *rqstp, ++ const struct nfsd4_op *op) + { + return (op_encode_hdr_size + op_encode_change_info_maxsz + + nfs4_fattr_bitmap_maxsz) * sizeof(__be32); +@@ -2795,10 +2800,10 @@ static inline u32 nfsd4_create_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op + * the op prematurely if the estimate is too large. We may turn off splice + * reads unnecessarily. + */ +-static inline u32 nfsd4_getattr_rsize(struct svc_rqst *rqstp, +- struct nfsd4_op *op) ++static u32 nfsd4_getattr_rsize(const struct svc_rqst *rqstp, ++ const struct nfsd4_op *op) + { +- u32 *bmap = op->u.getattr.ga_bmval; ++ const u32 *bmap = op->u.getattr.ga_bmval; + u32 bmap0 = bmap[0], bmap1 = bmap[1], bmap2 = bmap[2]; + u32 ret = 0; + +@@ -2833,24 +2838,28 @@ static inline u32 nfsd4_getattr_rsize(struct svc_rqst *rqstp, + return ret; + } + +-static inline u32 nfsd4_getfh_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) ++static u32 nfsd4_getfh_rsize(const struct svc_rqst *rqstp, ++ const struct nfsd4_op *op) + { + return (op_encode_hdr_size + 1) * sizeof(__be32) + NFS4_FHSIZE; + } + +-static inline u32 nfsd4_link_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) ++static u32 nfsd4_link_rsize(const struct svc_rqst *rqstp, ++ const struct nfsd4_op *op) + { + return (op_encode_hdr_size + op_encode_change_info_maxsz) + * sizeof(__be32); + } + +-static inline u32 nfsd4_lock_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) ++static u32 nfsd4_lock_rsize(const struct svc_rqst *rqstp, ++ const struct nfsd4_op *op) + { + return (op_encode_hdr_size + op_encode_lock_denied_maxsz) + * sizeof(__be32); + } + +-static inline u32 nfsd4_open_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) ++static u32 nfsd4_open_rsize(const struct svc_rqst *rqstp, ++ const struct nfsd4_op *op) + { + return (op_encode_hdr_size + op_encode_stateid_maxsz + + op_encode_change_info_maxsz + 1 +@@ -2858,7 +2867,8 @@ static inline u32 nfsd4_open_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) + + op_encode_delegation_maxsz) * sizeof(__be32); + } + +-static inline u32 nfsd4_read_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) ++static u32 nfsd4_read_rsize(const struct svc_rqst *rqstp, ++ const struct nfsd4_op *op) + { + u32 maxcount = 0, rlen = 0; + +@@ -2868,7 +2878,8 @@ static inline u32 nfsd4_read_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) + return (op_encode_hdr_size + 2 + XDR_QUADLEN(rlen)) * sizeof(__be32); + } + +-static inline u32 nfsd4_read_plus_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) ++static u32 nfsd4_read_plus_rsize(const struct svc_rqst *rqstp, ++ const struct nfsd4_op *op) + { + u32 maxcount = svc_max_payload(rqstp); + u32 rlen = min(op->u.read.rd_length, maxcount); +@@ -2882,7 +2893,8 @@ static inline u32 nfsd4_read_plus_rsize(struct svc_rqst *rqstp, struct nfsd4_op + return (op_encode_hdr_size + 2 + seg_len + XDR_QUADLEN(rlen)) * sizeof(__be32); + } + +-static inline u32 nfsd4_readdir_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) ++static u32 nfsd4_readdir_rsize(const struct svc_rqst *rqstp, ++ const struct nfsd4_op *op) + { + u32 maxcount = 0, rlen = 0; + +@@ -2893,59 +2905,68 @@ static inline u32 nfsd4_readdir_rsize(struct svc_rqst *rqstp, struct nfsd4_op *o + XDR_QUADLEN(rlen)) * sizeof(__be32); + } + +-static inline u32 nfsd4_readlink_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) ++static u32 nfsd4_readlink_rsize(const struct svc_rqst *rqstp, ++ const struct nfsd4_op *op) + { + return (op_encode_hdr_size + 1) * sizeof(__be32) + PAGE_SIZE; + } + +-static inline u32 nfsd4_remove_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) ++static u32 nfsd4_remove_rsize(const struct svc_rqst *rqstp, ++ const struct nfsd4_op *op) + { + return (op_encode_hdr_size + op_encode_change_info_maxsz) + * sizeof(__be32); + } + +-static inline u32 nfsd4_rename_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) ++static u32 nfsd4_rename_rsize(const struct svc_rqst *rqstp, ++ const struct nfsd4_op *op) + { + return (op_encode_hdr_size + op_encode_change_info_maxsz + + op_encode_change_info_maxsz) * sizeof(__be32); + } + +-static inline u32 nfsd4_sequence_rsize(struct svc_rqst *rqstp, +- struct nfsd4_op *op) ++static u32 nfsd4_sequence_rsize(const struct svc_rqst *rqstp, ++ const struct nfsd4_op *op) + { + return (op_encode_hdr_size + + XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + 5) * sizeof(__be32); + } + +-static inline u32 nfsd4_test_stateid_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) ++static u32 nfsd4_test_stateid_rsize(const struct svc_rqst *rqstp, ++ const struct nfsd4_op *op) + { + return (op_encode_hdr_size + 1 + op->u.test_stateid.ts_num_ids) + * sizeof(__be32); + } + +-static inline u32 nfsd4_setattr_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) ++static u32 nfsd4_setattr_rsize(const struct svc_rqst *rqstp, ++ const struct nfsd4_op *op) + { + return (op_encode_hdr_size + nfs4_fattr_bitmap_maxsz) * sizeof(__be32); + } + +-static inline u32 nfsd4_secinfo_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) ++static u32 nfsd4_secinfo_rsize(const struct svc_rqst *rqstp, ++ const struct nfsd4_op *op) + { + return (op_encode_hdr_size + RPC_AUTH_MAXFLAVOR * + (4 + XDR_QUADLEN(GSS_OID_MAX_LEN))) * sizeof(__be32); + } + +-static inline u32 nfsd4_setclientid_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) ++static u32 nfsd4_setclientid_rsize(const struct svc_rqst *rqstp, ++ const struct nfsd4_op *op) + { + return (op_encode_hdr_size + 2 + XDR_QUADLEN(NFS4_VERIFIER_SIZE)) * + sizeof(__be32); + } + +-static inline u32 nfsd4_write_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) ++static u32 nfsd4_write_rsize(const struct svc_rqst *rqstp, ++ const struct nfsd4_op *op) + { + return (op_encode_hdr_size + 2 + op_encode_verifier_maxsz) * sizeof(__be32); + } + +-static inline u32 nfsd4_exchange_id_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) ++static u32 nfsd4_exchange_id_rsize(const struct svc_rqst *rqstp, ++ const struct nfsd4_op *op) + { + return (op_encode_hdr_size + 2 + 1 + /* eir_clientid, eir_sequenceid */\ + 1 + 1 + /* eir_flags, spr_how */\ +@@ -2959,14 +2980,16 @@ static inline u32 nfsd4_exchange_id_rsize(struct svc_rqst *rqstp, struct nfsd4_o + 0 /* ignored eir_server_impl_id contents */) * sizeof(__be32); + } + +-static inline u32 nfsd4_bind_conn_to_session_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) ++static u32 nfsd4_bind_conn_to_session_rsize(const struct svc_rqst *rqstp, ++ const struct nfsd4_op *op) + { + return (op_encode_hdr_size + \ + XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + /* bctsr_sessid */\ + 2 /* bctsr_dir, use_conn_in_rdma_mode */) * sizeof(__be32); + } + +-static inline u32 nfsd4_create_session_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) ++static u32 nfsd4_create_session_rsize(const struct svc_rqst *rqstp, ++ const struct nfsd4_op *op) + { + return (op_encode_hdr_size + \ + XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + /* sessionid */\ +@@ -2975,7 +2998,8 @@ static inline u32 nfsd4_create_session_rsize(struct svc_rqst *rqstp, struct nfsd + op_encode_channel_attrs_maxsz) * sizeof(__be32); + } + +-static inline u32 nfsd4_copy_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) ++static u32 nfsd4_copy_rsize(const struct svc_rqst *rqstp, ++ const struct nfsd4_op *op) + { + return (op_encode_hdr_size + + 1 /* wr_callback */ + +@@ -2987,16 +3011,16 @@ static inline u32 nfsd4_copy_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) + 1 /* cr_synchronous */) * sizeof(__be32); + } + +-static inline u32 nfsd4_offload_status_rsize(struct svc_rqst *rqstp, +- struct nfsd4_op *op) ++static u32 nfsd4_offload_status_rsize(const struct svc_rqst *rqstp, ++ const struct nfsd4_op *op) + { + return (op_encode_hdr_size + + 2 /* osr_count */ + + 1 /* osr_complete<1> optional 0 for now */) * sizeof(__be32); + } + +-static inline u32 nfsd4_copy_notify_rsize(struct svc_rqst *rqstp, +- struct nfsd4_op *op) ++static u32 nfsd4_copy_notify_rsize(const struct svc_rqst *rqstp, ++ const struct nfsd4_op *op) + { + return (op_encode_hdr_size + + 3 /* cnr_lease_time */ + +@@ -3011,7 +3035,8 @@ static inline u32 nfsd4_copy_notify_rsize(struct svc_rqst *rqstp, + } + + #ifdef CONFIG_NFSD_PNFS +-static inline u32 nfsd4_getdeviceinfo_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) ++static u32 nfsd4_getdeviceinfo_rsize(const struct svc_rqst *rqstp, ++ const struct nfsd4_op *op) + { + u32 maxcount = 0, rlen = 0; + +@@ -3029,7 +3054,8 @@ static inline u32 nfsd4_getdeviceinfo_rsize(struct svc_rqst *rqstp, struct nfsd4 + * so we need to define an arbitrary upper bound here. + */ + #define MAX_LAYOUT_SIZE 128 +-static inline u32 nfsd4_layoutget_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) ++static u32 nfsd4_layoutget_rsize(const struct svc_rqst *rqstp, ++ const struct nfsd4_op *op) + { + return (op_encode_hdr_size + + 1 /* logr_return_on_close */ + +@@ -3038,14 +3064,16 @@ static inline u32 nfsd4_layoutget_rsize(struct svc_rqst *rqstp, struct nfsd4_op + MAX_LAYOUT_SIZE) * sizeof(__be32); + } + +-static inline u32 nfsd4_layoutcommit_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) ++static u32 nfsd4_layoutcommit_rsize(const struct svc_rqst *rqstp, ++ const struct nfsd4_op *op) + { + return (op_encode_hdr_size + + 1 /* locr_newsize */ + + 2 /* ns_size */) * sizeof(__be32); + } + +-static inline u32 nfsd4_layoutreturn_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) ++static u32 nfsd4_layoutreturn_rsize(const struct svc_rqst *rqstp, ++ const struct nfsd4_op *op) + { + return (op_encode_hdr_size + + 1 /* lrs_stateid */ + +@@ -3054,13 +3082,14 @@ static inline u32 nfsd4_layoutreturn_rsize(struct svc_rqst *rqstp, struct nfsd4_ + #endif /* CONFIG_NFSD_PNFS */ + + +-static inline u32 nfsd4_seek_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) ++static u32 nfsd4_seek_rsize(const struct svc_rqst *rqstp, ++ const struct nfsd4_op *op) + { + return (op_encode_hdr_size + 3) * sizeof(__be32); + } + +-static inline u32 nfsd4_getxattr_rsize(struct svc_rqst *rqstp, +- struct nfsd4_op *op) ++static u32 nfsd4_getxattr_rsize(const struct svc_rqst *rqstp, ++ const struct nfsd4_op *op) + { + u32 maxcount, rlen; + +@@ -3070,14 +3099,14 @@ static inline u32 nfsd4_getxattr_rsize(struct svc_rqst *rqstp, + return (op_encode_hdr_size + 1 + XDR_QUADLEN(rlen)) * sizeof(__be32); + } + +-static inline u32 nfsd4_setxattr_rsize(struct svc_rqst *rqstp, +- struct nfsd4_op *op) ++static u32 nfsd4_setxattr_rsize(const struct svc_rqst *rqstp, ++ const struct nfsd4_op *op) + { + return (op_encode_hdr_size + op_encode_change_info_maxsz) + * sizeof(__be32); + } +-static inline u32 nfsd4_listxattrs_rsize(struct svc_rqst *rqstp, +- struct nfsd4_op *op) ++static u32 nfsd4_listxattrs_rsize(const struct svc_rqst *rqstp, ++ const struct nfsd4_op *op) + { + u32 maxcount, rlen; + +@@ -3087,8 +3116,8 @@ static inline u32 nfsd4_listxattrs_rsize(struct svc_rqst *rqstp, + return (op_encode_hdr_size + 4 + XDR_QUADLEN(rlen)) * sizeof(__be32); + } + +-static inline u32 nfsd4_removexattr_rsize(struct svc_rqst *rqstp, +- struct nfsd4_op *op) ++static u32 nfsd4_removexattr_rsize(const struct svc_rqst *rqstp, ++ const struct nfsd4_op *op) + { + return (op_encode_hdr_size + op_encode_change_info_maxsz) + * sizeof(__be32); +diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h +index 2a699e8ca1baf..1e83fda7601ab 100644 +--- a/fs/nfsd/xdr4.h ++++ b/fs/nfsd/xdr4.h +@@ -889,7 +889,8 @@ struct nfsd4_operation { + u32 op_flags; + char *op_name; + /* Try to get response size before operation */ +- u32 (*op_rsize_bop)(struct svc_rqst *, struct nfsd4_op *); ++ u32 (*op_rsize_bop)(const struct svc_rqst *rqstp, ++ const struct nfsd4_op *op); + void (*op_get_currentstateid)(struct nfsd4_compound_state *, + union nfsd4_op_u *); + void (*op_set_currentstateid)(struct nfsd4_compound_state *, +-- +2.43.0 + diff --git a/queue-5.10/nfsd-remove-kmalloc-from-nfsd4_do_async_copy.patch b/queue-5.10/nfsd-remove-kmalloc-from-nfsd4_do_async_copy.patch new file mode 100644 index 00000000000..4ee4c872035 --- /dev/null +++ b/queue-5.10/nfsd-remove-kmalloc-from-nfsd4_do_async_copy.patch @@ -0,0 +1,80 @@ +From 040131a0024336e8df915405aeadefdd5dca1fa4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 Jul 2022 14:41:06 -0400 +Subject: NFSD: Remove kmalloc from nfsd4_do_async_copy() + +From: Chuck Lever + +[ Upstream commit ad1e46c9b07b13659635ee5405f83ad0df143116 ] + +Instead of manufacturing a phony struct nfsd_file, pass the +struct file returned by nfs42_ssc_open() directly to +nfsd4_do_copy(). + +[ cel: adjusted to apply to v5.10.y ] +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 28 ++++++++++++++-------------- + 1 file changed, 14 insertions(+), 14 deletions(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 16f968c165c98..dbc507c9aa11b 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -1753,29 +1753,31 @@ static void cleanup_async_copy(struct nfsd4_copy *copy) + nfs4_put_copy(copy); + } + ++/** ++ * nfsd4_do_async_copy - kthread function for background server-side COPY ++ * @data: arguments for COPY operation ++ * ++ * Return values: ++ * %0: Copy operation is done. ++ */ + static int nfsd4_do_async_copy(void *data) + { + struct nfsd4_copy *copy = (struct nfsd4_copy *)data; + struct nfsd4_copy *cb_copy; + + if (nfsd4_ssc_is_inter(copy)) { +- copy->nf_src = kzalloc(sizeof(struct nfsd_file), GFP_KERNEL); +- if (!copy->nf_src) { +- copy->nfserr = nfserr_serverfault; +- /* ss_mnt will be unmounted by the laundromat */ +- goto do_callback; +- } +- copy->nf_src->nf_file = nfs42_ssc_open(copy->ss_mnt, ©->c_fh, +- ©->stateid); +- if (IS_ERR(copy->nf_src->nf_file)) { ++ struct file *filp; ++ ++ filp = nfs42_ssc_open(copy->ss_mnt, ©->c_fh, ++ ©->stateid); ++ if (IS_ERR(filp)) { + copy->nfserr = nfserr_offload_denied; + /* ss_mnt will be unmounted by the laundromat */ + goto do_callback; + } +- copy->nfserr = nfsd4_do_copy(copy, copy->nf_src->nf_file, ++ copy->nfserr = nfsd4_do_copy(copy, filp, + copy->nf_dst->nf_file, false); +- nfsd4_cleanup_inter_ssc(copy->ss_mnt, copy->nf_src->nf_file, +- copy->nf_dst); ++ nfsd4_cleanup_inter_ssc(copy->ss_mnt, filp, copy->nf_dst); + } else { + copy->nfserr = nfsd4_do_copy(copy, copy->nf_src->nf_file, + copy->nf_dst->nf_file, false); +@@ -1797,8 +1799,6 @@ static int nfsd4_do_async_copy(void *data) + ©->fh, copy->cp_count, copy->nfserr); + nfsd4_run_cb(&cb_copy->cp_cb); + out: +- if (nfsd4_ssc_is_inter(copy)) +- kfree(copy->nf_src); + cleanup_async_copy(copy); + return 0; + } +-- +2.43.0 + diff --git a/queue-5.10/nfsd-remove-lockdep-assertion-from-unhash_and_releas.patch b/queue-5.10/nfsd-remove-lockdep-assertion-from-unhash_and_releas.patch new file mode 100644 index 00000000000..ed02853080b --- /dev/null +++ b/queue-5.10/nfsd-remove-lockdep-assertion-from-unhash_and_releas.patch @@ -0,0 +1,35 @@ +From b87367d489d67b995a23f2674e3f260bbd8e8206 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 Jul 2022 14:25:44 -0400 +Subject: NFSD: Remove lockdep assertion from unhash_and_release_locked() + +From: Chuck Lever + +[ Upstream commit f53cef15dddec7203df702cdc62e554190385450 ] + +IIUC, holding the hash bucket lock is needed only in +nfsd_file_unhash, and there is already a lockdep assertion there. + +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index 2d013a88e3565..6a01de8677959 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -299,8 +299,6 @@ nfsd_file_unhash(struct nfsd_file *nf) + static bool + nfsd_file_unhash_and_release_locked(struct nfsd_file *nf, struct list_head *dispose) + { +- lockdep_assert_held(&nfsd_file_hashtbl[nf->nf_hashval].nfb_lock); +- + trace_nfsd_file_unhash_and_release_locked(nf); + if (!nfsd_file_unhash(nf)) + return false; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-remove-macros-that-are-no-longer-used.patch b/queue-5.10/nfsd-remove-macros-that-are-no-longer-used.patch new file mode 100644 index 00000000000..2e458167589 --- /dev/null +++ b/queue-5.10/nfsd-remove-macros-that-are-no-longer-used.patch @@ -0,0 +1,107 @@ +From c6a5ad6a86e8e5179b47e5b16a2c8d90484bb990 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Nov 2020 11:12:18 -0500 +Subject: NFSD: Remove macros that are no longer used + +From: Chuck Lever + +[ Upstream commit 5cfc822f3e77b0477e6602d399116130317f537a ] + +Now that all the NFSv4 decoder functions have been converted to +make direct calls to the xdr helpers, remove the unused C macros. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 40 ---------------------------------------- + fs/nfsd/xdr4.h | 9 --------- + 2 files changed, 49 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 30604a3e70c0f..315be1c1ab85c 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -102,45 +102,6 @@ check_filename(char *str, int len) + return 0; + } + +-#define DECODE_HEAD \ +- __be32 *p; \ +- __be32 status +-#define DECODE_TAIL \ +- status = 0; \ +-out: \ +- return status; \ +-xdr_error: \ +- dprintk("NFSD: xdr error (%s:%d)\n", \ +- __FILE__, __LINE__); \ +- status = nfserr_bad_xdr; \ +- goto out +- +-#define READMEM(x,nbytes) do { \ +- x = (char *)p; \ +- p += XDR_QUADLEN(nbytes); \ +-} while (0) +-#define SAVEMEM(x,nbytes) do { \ +- if (!(x = (p==argp->tmp || p == argp->tmpp) ? \ +- savemem(argp, p, nbytes) : \ +- (char *)p)) { \ +- dprintk("NFSD: xdr error (%s:%d)\n", \ +- __FILE__, __LINE__); \ +- goto xdr_error; \ +- } \ +- p += XDR_QUADLEN(nbytes); \ +-} while (0) +-#define COPYMEM(x,nbytes) do { \ +- memcpy((x), p, nbytes); \ +- p += XDR_QUADLEN(nbytes); \ +-} while (0) +-#define READ_BUF(nbytes) \ +- do { \ +- p = xdr_inline_decode(argp->xdr,\ +- nbytes); \ +- if (!p) \ +- goto xdr_error; \ +- } while (0) +- + static int zero_clientid(clientid_t *clid) + { + return (clid->cl_boot == 0) && (clid->cl_id == 0); +@@ -5478,7 +5439,6 @@ nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, __be32 *p) + struct nfsd4_compoundargs *args = rqstp->rq_argp; + + /* svcxdr_tmp_alloc */ +- args->tmpp = NULL; + args->to_free = NULL; + + args->xdr = &rqstp->rq_arg_stream; +diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h +index 2c31f3a7d7c74..e12fbe382e3f3 100644 +--- a/fs/nfsd/xdr4.h ++++ b/fs/nfsd/xdr4.h +@@ -386,13 +386,6 @@ struct nfsd4_setclientid_confirm { + nfs4_verifier sc_confirm; + }; + +-struct nfsd4_saved_compoundargs { +- __be32 *p; +- __be32 *end; +- int pagelen; +- struct page **pagelist; +-}; +- + struct nfsd4_test_stateid_id { + __be32 ts_id_status; + stateid_t ts_id_stateid; +@@ -696,8 +689,6 @@ struct svcxdr_tmpbuf { + + struct nfsd4_compoundargs { + /* scratch variables for XDR decode */ +- __be32 tmp[8]; +- __be32 * tmpp; + struct xdr_stream *xdr; + struct svcxdr_tmpbuf *to_free; + struct svc_rqst *rqstp; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-remove-nfsd4_prepare_cb_recall-declaration.patch b/queue-5.10/nfsd-remove-nfsd4_prepare_cb_recall-declaration.patch new file mode 100644 index 00000000000..4cca995eac7 --- /dev/null +++ b/queue-5.10/nfsd-remove-nfsd4_prepare_cb_recall-declaration.patch @@ -0,0 +1,35 @@ +From 58460c9a83ce7d4f9164ed3a22753046d7304f77 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 9 Sep 2022 14:59:10 +0800 +Subject: nfsd: remove nfsd4_prepare_cb_recall() declaration + +From: Gaosheng Cui + +[ Upstream commit 18224dc58d960c65446971930d0487fc72d00598 ] + +nfsd4_prepare_cb_recall() has been removed since +commit 0162ac2b978e ("nfsd: introduce nfsd4_callback_ops"), +so remove it. + +Signed-off-by: Gaosheng Cui +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/state.h | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h +index 5d28beb290fef..4155be65d8069 100644 +--- a/fs/nfsd/state.h ++++ b/fs/nfsd/state.h +@@ -697,7 +697,6 @@ extern int nfsd4_create_callback_queue(void); + extern void nfsd4_destroy_callback_queue(void); + extern void nfsd4_shutdown_callback(struct nfs4_client *); + extern void nfsd4_shutdown_copy(struct nfs4_client *clp); +-extern void nfsd4_prepare_cb_recall(struct nfs4_delegation *dp); + extern struct nfs4_client_reclaim *nfs4_client_to_reclaim(struct xdr_netobj name, + struct xdr_netobj princhash, struct nfsd_net *nn); + extern bool nfs4_has_reclaimed_state(struct xdr_netobj name, struct nfsd_net *nn); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-remove-nfsd_file-nf_hashval.patch b/queue-5.10/nfsd-remove-nfsd_file-nf_hashval.patch new file mode 100644 index 00000000000..baff8328f4e --- /dev/null +++ b/queue-5.10/nfsd-remove-nfsd_file-nf_hashval.patch @@ -0,0 +1,66 @@ +From 2664654d0b9956f3b9b164ba811d30c46a1884bb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 Jul 2022 14:26:10 -0400 +Subject: NFSD: Remove nfsd_file::nf_hashval + +From: Chuck Lever + +[ Upstream commit f0743c2b25c65debd4f599a7c861428cd9de5906 ] + +The value in this field can always be computed from nf_inode, thus +it is no longer used. + +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 6 ++---- + fs/nfsd/filecache.h | 1 - + 2 files changed, 2 insertions(+), 5 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index dd59deec8b011..29b1f57692a60 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -167,8 +167,7 @@ nfsd_file_mark_find_or_create(struct nfsd_file *nf) + } + + static struct nfsd_file * +-nfsd_file_alloc(struct inode *inode, unsigned int may, unsigned int hashval, +- struct net *net) ++nfsd_file_alloc(struct inode *inode, unsigned int may, struct net *net) + { + struct nfsd_file *nf; + +@@ -182,7 +181,6 @@ nfsd_file_alloc(struct inode *inode, unsigned int may, unsigned int hashval, + nf->nf_net = net; + nf->nf_flags = 0; + nf->nf_inode = inode; +- nf->nf_hashval = hashval; + refcount_set(&nf->nf_ref, 1); + nf->nf_may = may & NFSD_FILE_MAY_MASK; + nf->nf_mark = NULL; +@@ -1005,7 +1003,7 @@ nfsd_do_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + if (nf) + goto wait_for_construction; + +- new = nfsd_file_alloc(inode, may_flags, hashval, net); ++ new = nfsd_file_alloc(inode, may_flags, net); + if (!new) { + status = nfserr_jukebox; + goto out_status; +diff --git a/fs/nfsd/filecache.h b/fs/nfsd/filecache.h +index c6ad5fe47f12f..82051e1b8420d 100644 +--- a/fs/nfsd/filecache.h ++++ b/fs/nfsd/filecache.h +@@ -40,7 +40,6 @@ struct nfsd_file { + #define NFSD_FILE_REFERENCED (2) + unsigned long nf_flags; + struct inode *nf_inode; +- unsigned int nf_hashval; + refcount_t nf_ref; + unsigned char nf_may; + struct nfsd_file_mark *nf_mark; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-remove-redundant-assignment-to-pointer-this.patch b/queue-5.10/nfsd-remove-redundant-assignment-to-pointer-this.patch new file mode 100644 index 00000000000..3298e6c60eb --- /dev/null +++ b/queue-5.10/nfsd-remove-redundant-assignment-to-pointer-this.patch @@ -0,0 +1,38 @@ +From ca8f4c26c9488aced8dc17afd5b1a333e121d855 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 13 May 2021 16:16:39 +0100 +Subject: nfsd: remove redundant assignment to pointer 'this' + +From: Colin Ian King + +[ Upstream commit e34c0ce9136a0fe96f0f547898d14c44f3c9f147 ] + +The pointer 'this' is being initialized with a value that is never read +and it is being updated later with a new value. The initialization is +redundant and can be removed. + +Addresses-Coverity: ("Unused value") +Signed-off-by: Colin Ian King +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index f7ddfa204abc4..1f840c72e9780 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -3369,7 +3369,7 @@ bool nfsd4_spo_must_allow(struct svc_rqst *rqstp) + { + struct nfsd4_compoundres *resp = rqstp->rq_resp; + struct nfsd4_compoundargs *argp = rqstp->rq_argp; +- struct nfsd4_op *this = &argp->ops[resp->opcnt - 1]; ++ struct nfsd4_op *this; + struct nfsd4_compound_state *cstate = &resp->cstate; + struct nfs4_op_map *allow = &cstate->clp->cl_spo_must_allow; + u32 opiter; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-remove-redundant-assignment-to-variable-host_er.patch b/queue-5.10/nfsd-remove-redundant-assignment-to-variable-host_er.patch new file mode 100644 index 00000000000..5b908cf5da1 --- /dev/null +++ b/queue-5.10/nfsd-remove-redundant-assignment-to-variable-host_er.patch @@ -0,0 +1,39 @@ +From b68518ad06e4c7781a9890e63fcc330885cb93db Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 10 Oct 2022 21:24:23 +0100 +Subject: NFSD: Remove redundant assignment to variable host_err + +From: Colin Ian King + +[ Upstream commit 69eed23baf877bbb1f14d7f4df54f89807c9ee2a ] + +Variable host_err is assigned a value that is never read, it is being +re-assigned a value in every different execution path in the following +switch statement. The assignment is redundant and can be removed. + +Cleans up clang-scan warning: +warning: Value stored to 'host_err' is never read [deadcode.DeadStores] + +Signed-off-by: Colin Ian King +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/vfs.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index 4ff626c912cc3..aae81c5cecb94 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -1322,7 +1322,6 @@ nfsd_create_locked(struct svc_rqst *rqstp, struct svc_fh *fhp, + iap->ia_mode &= ~current_umask(); + + err = 0; +- host_err = 0; + switch (type) { + case S_IFREG: + host_err = vfs_create(dirp, dchild, iap->ia_mode, true); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-remove-redundant-assignment-to-variable-len.patch b/queue-5.10/nfsd-remove-redundant-assignment-to-variable-len.patch new file mode 100644 index 00000000000..54004dc1b36 --- /dev/null +++ b/queue-5.10/nfsd-remove-redundant-assignment-to-variable-len.patch @@ -0,0 +1,38 @@ +From 728dede9ea983f6bd0d2eb3b29966e0ee6967c34 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Jun 2022 22:25:25 +0100 +Subject: nfsd: remove redundant assignment to variable len + +From: Colin Ian King + +[ Upstream commit 842e00ac3aa3b4a4f7f750c8ab54f8578fc875d3 ] + +Variable len is being assigned a value zero and this is never +read, it is being re-assigned later. The assignment is redundant +and can be removed. + +Cleans up clang scan-build warning: +fs/nfsd/nfsctl.c:636:2: warning: Value stored to 'len' is never read + +Signed-off-by: Colin Ian King +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsctl.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c +index 0621c2faf2424..66c352bf61b1d 100644 +--- a/fs/nfsd/nfsctl.c ++++ b/fs/nfsd/nfsctl.c +@@ -633,7 +633,6 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size) + } + + /* Now write current state into reply buffer */ +- len = 0; + sep = ""; + remaining = SIMPLE_TRANSACTION_LIMIT; + for (num=2 ; num <= 4 ; num++) { +-- +2.43.0 + diff --git a/queue-5.10/nfsd-remove-redundant-variable-status.patch b/queue-5.10/nfsd-remove-redundant-variable-status.patch new file mode 100644 index 00000000000..ff10273efd2 --- /dev/null +++ b/queue-5.10/nfsd-remove-redundant-variable-status.patch @@ -0,0 +1,80 @@ +From c609cdd76f3e5b115c0bc35e0c45fecde0c1aef9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 31 Aug 2022 14:20:02 +0000 +Subject: NFSD: remove redundant variable status + +From: Jinpeng Cui + +[ Upstream commit 4ab3442ca384a02abf8b1f2b3449a6c547851873 ] + +Return value directly from fh_verify() do_open_permission() +exp_pseudoroot() instead of getting value from +redundant variable status. + +Reported-by: Zeal Robot +Signed-off-by: Jinpeng Cui +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 16 ++++------------ + 1 file changed, 4 insertions(+), 12 deletions(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index ebfe39d313119..62ffcecf78f7e 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -141,7 +141,6 @@ fh_dup2(struct svc_fh *dst, struct svc_fh *src) + static __be32 + do_open_permission(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open, int accmode) + { +- __be32 status; + + if (open->op_truncate && + !(open->op_share_access & NFS4_SHARE_ACCESS_WRITE)) +@@ -156,9 +155,7 @@ do_open_permission(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfs + if (open->op_share_deny & NFS4_SHARE_DENY_READ) + accmode |= NFSD_MAY_WRITE; + +- status = fh_verify(rqstp, current_fh, S_IFREG, accmode); +- +- return status; ++ return fh_verify(rqstp, current_fh, S_IFREG, accmode); + } + + static __be32 nfsd_check_obj_isreg(struct svc_fh *fh) +@@ -454,7 +451,6 @@ static __be32 + do_open_fhandle(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_open *open) + { + struct svc_fh *current_fh = &cstate->current_fh; +- __be32 status; + int accmode = 0; + + /* We don't know the target directory, and therefore can not +@@ -479,9 +475,7 @@ do_open_fhandle(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, str + if (open->op_claim_type == NFS4_OPEN_CLAIM_DELEG_CUR_FH) + accmode = NFSD_MAY_OWNER_OVERRIDE; + +- status = do_open_permission(rqstp, current_fh, open, accmode); +- +- return status; ++ return do_open_permission(rqstp, current_fh, open, accmode); + } + + static void +@@ -668,11 +662,9 @@ static __be32 + nfsd4_putrootfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + union nfsd4_op_u *u) + { +- __be32 status; +- + fh_put(&cstate->current_fh); +- status = exp_pseudoroot(rqstp, &cstate->current_fh); +- return status; ++ ++ return exp_pseudoroot(rqstp, &cstate->current_fh); + } + + static __be32 +-- +2.43.0 + diff --git a/queue-5.10/nfsd-remove-svc_serv_ops-svo_module.patch b/queue-5.10/nfsd-remove-svc_serv_ops-svo_module.patch new file mode 100644 index 00000000000..9a1f3e47f50 --- /dev/null +++ b/queue-5.10/nfsd-remove-svc_serv_ops-svo_module.patch @@ -0,0 +1,179 @@ +From df9ae47d6fcfed86073616098b43d3ba8b708a88 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 16 Feb 2022 12:31:09 -0500 +Subject: NFSD: Remove svc_serv_ops::svo_module + +From: Chuck Lever + +[ Upstream commit f49169c97fceb21ad6a0aaf671c50b0f520f15a5 ] + +struct svc_serv_ops is about to be removed. + +Neil Brown says: +> I suspect svo_module can go as well - I don't think the thread is +> ever the thing that primarily keeps a module active. + +A random sample of kthread_create() callers shows sunrpc is the only +one that manages module reference count in this way. + +Suggested-by: Neil Brown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/svc.c | 4 +--- + fs/nfs/callback.c | 7 ++----- + fs/nfs/nfs4state.c | 1 - + fs/nfsd/nfssvc.c | 3 --- + include/linux/sunrpc/svc.h | 5 ----- + kernel/module.c | 2 +- + net/sunrpc/svc.c | 2 -- + 7 files changed, 4 insertions(+), 20 deletions(-) + +diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c +index c83ec4a375bc1..bfde31124f3af 100644 +--- a/fs/lockd/svc.c ++++ b/fs/lockd/svc.c +@@ -184,8 +184,7 @@ lockd(void *vrqstp) + dprintk("lockd_down: service stopped\n"); + + svc_exit_thread(rqstp); +- +- module_put_and_kthread_exit(0); ++ return 0; + } + + static int create_lockd_listener(struct svc_serv *serv, const char *name, +@@ -352,7 +351,6 @@ static struct notifier_block lockd_inet6addr_notifier = { + + static const struct svc_serv_ops lockd_sv_ops = { + .svo_function = lockd, +- .svo_module = THIS_MODULE, + }; + + static int lockd_get(void) +diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c +index c98c68513590f..a494f9e7bd0a0 100644 +--- a/fs/nfs/callback.c ++++ b/fs/nfs/callback.c +@@ -17,7 +17,6 @@ + #include + #include + #include +-#include + #include + #include + +@@ -92,8 +91,8 @@ nfs4_callback_svc(void *vrqstp) + continue; + svc_process(rqstp); + } ++ + svc_exit_thread(rqstp); +- module_put_and_kthread_exit(0); + return 0; + } + +@@ -136,8 +135,8 @@ nfs41_callback_svc(void *vrqstp) + finish_wait(&serv->sv_cb_waitq, &wq); + } + } ++ + svc_exit_thread(rqstp); +- module_put_and_kthread_exit(0); + return 0; + } + +@@ -234,12 +233,10 @@ static int nfs_callback_up_net(int minorversion, struct svc_serv *serv, + + static const struct svc_serv_ops nfs40_cb_sv_ops = { + .svo_function = nfs4_callback_svc, +- .svo_module = THIS_MODULE, + }; + #if defined(CONFIG_NFS_V4_1) + static const struct svc_serv_ops nfs41_cb_sv_ops = { + .svo_function = nfs41_callback_svc, +- .svo_module = THIS_MODULE, + }; + + static const struct svc_serv_ops *nfs4_cb_sv_ops[] = { +diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c +index d8fc5d72a161c..ae2da65ffbafb 100644 +--- a/fs/nfs/nfs4state.c ++++ b/fs/nfs/nfs4state.c +@@ -2757,7 +2757,6 @@ static int nfs4_run_state_manager(void *ptr) + goto again; + + nfs_put_client(clp); +- module_put_and_kthread_exit(0); + return 0; + } + +diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c +index 38895372ec393..d25d4c12a499a 100644 +--- a/fs/nfsd/nfssvc.c ++++ b/fs/nfsd/nfssvc.c +@@ -614,7 +614,6 @@ static int nfsd_get_default_max_blksize(void) + + static const struct svc_serv_ops nfsd_thread_sv_ops = { + .svo_function = nfsd, +- .svo_module = THIS_MODULE, + }; + + void nfsd_shutdown_threads(struct net *net) +@@ -1018,8 +1017,6 @@ nfsd(void *vrqstp) + msleep(20); + } + +- /* Release module */ +- module_put_and_kthread_exit(0); + return 0; + } + +diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h +index 482a024156b11..c64db9b14a643 100644 +--- a/include/linux/sunrpc/svc.h ++++ b/include/linux/sunrpc/svc.h +@@ -57,11 +57,6 @@ struct svc_serv; + struct svc_serv_ops { + /* function for service threads to run */ + int (*svo_function)(void *); +- +- /* optional module to count when adding threads. +- * Thread function must call module_put_and_kthread_exit() to exit. +- */ +- struct module *svo_module; + }; + + /* +diff --git a/kernel/module.c b/kernel/module.c +index 9030ff8c08555..edc7b99cb16fa 100644 +--- a/kernel/module.c ++++ b/kernel/module.c +@@ -334,7 +334,7 @@ static inline void add_taint_module(struct module *mod, unsigned flag, + + /* + * A thread that wants to hold a reference to a module only while it +- * is running can call this to safely exit. nfsd and lockd use this. ++ * is running can call this to safely exit. + */ + void __noreturn __module_put_and_kthread_exit(struct module *mod, long code) + { +diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c +index c9195e40959c6..bdecc902cf998 100644 +--- a/net/sunrpc/svc.c ++++ b/net/sunrpc/svc.c +@@ -734,11 +734,9 @@ svc_start_kthreads(struct svc_serv *serv, struct svc_pool *pool, int nrservs) + if (IS_ERR(rqstp)) + return PTR_ERR(rqstp); + +- __module_get(serv->sv_ops->svo_module); + task = kthread_create_on_node(serv->sv_ops->svo_function, rqstp, + node, "%s", serv->sv_name); + if (IS_ERR(task)) { +- module_put(serv->sv_ops->svo_module); + svc_exit_thread(rqstp); + return PTR_ERR(task); + } +-- +2.43.0 + diff --git a/queue-5.10/nfsd-remove-the-nfsd_cb_work-and-nfsd_cb_done-tracep.patch b/queue-5.10/nfsd-remove-the-nfsd_cb_work-and-nfsd_cb_done-tracep.patch new file mode 100644 index 00000000000..950c6e4f6ec --- /dev/null +++ b/queue-5.10/nfsd-remove-the-nfsd_cb_work-and-nfsd_cb_done-tracep.patch @@ -0,0 +1,114 @@ +From 001e72fdae26c8dfae1d79a01f71d1245e062e31 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 14 May 2021 15:57:32 -0400 +Subject: NFSD: Remove the nfsd_cb_work and nfsd_cb_done tracepoints + +From: Chuck Lever + +[ Upstream commit 1d2bf65983a137121c165a7e69b2885572954915 ] + +Clean up: These are noise in properly working systems. If you really +need to observe the operation of the callback mechanism, use the +sunrpc:rpc\* tracepoints along with the workqueue tracepoints. + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4callback.c | 5 ----- + fs/nfsd/trace.h | 48 ------------------------------------------ + 2 files changed, 53 deletions(-) + +diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c +index 453f60b127ebb..59dc80ecd3764 100644 +--- a/fs/nfsd/nfs4callback.c ++++ b/fs/nfsd/nfs4callback.c +@@ -972,7 +972,6 @@ static void nfsd4_cb_probe_done(struct rpc_task *task, void *calldata) + { + struct nfs4_client *clp = container_of(calldata, struct nfs4_client, cl_cb_null); + +- trace_nfsd_cb_done(clp, task->tk_status); + if (task->tk_status) + nfsd4_mark_cb_down(clp, task->tk_status); + else +@@ -1174,8 +1173,6 @@ static void nfsd4_cb_done(struct rpc_task *task, void *calldata) + struct nfsd4_callback *cb = calldata; + struct nfs4_client *clp = cb->cb_clp; + +- trace_nfsd_cb_done(clp, task->tk_status); +- + if (!nfsd4_cb_sequence_done(task, cb)) + return; + +@@ -1328,8 +1325,6 @@ nfsd4_run_cb_work(struct work_struct *work) + struct rpc_clnt *clnt; + int flags; + +- trace_nfsd_cb_work(clp, cb->cb_msg.rpc_proc->p_name); +- + if (cb->cb_need_restart) { + cb->cb_need_restart = false; + } else { +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index 4361a0807f070..87ac1f19bfd0b 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -979,54 +979,6 @@ TRACE_EVENT(nfsd_cb_setup_err, + __entry->addr, __entry->cl_boot, __entry->cl_id, __entry->error) + ); + +-TRACE_EVENT(nfsd_cb_work, +- TP_PROTO( +- const struct nfs4_client *clp, +- const char *procedure +- ), +- TP_ARGS(clp, procedure), +- TP_STRUCT__entry( +- __field(u32, cl_boot) +- __field(u32, cl_id) +- __string(procedure, procedure) +- __array(unsigned char, addr, sizeof(struct sockaddr_in6)) +- ), +- TP_fast_assign( +- __entry->cl_boot = clp->cl_clientid.cl_boot; +- __entry->cl_id = clp->cl_clientid.cl_id; +- __assign_str(procedure, procedure) +- memcpy(__entry->addr, &clp->cl_cb_conn.cb_addr, +- sizeof(struct sockaddr_in6)); +- ), +- TP_printk("addr=%pISpc client %08x:%08x procedure=%s", +- __entry->addr, __entry->cl_boot, __entry->cl_id, +- __get_str(procedure)) +-); +- +-TRACE_EVENT(nfsd_cb_done, +- TP_PROTO( +- const struct nfs4_client *clp, +- int status +- ), +- TP_ARGS(clp, status), +- TP_STRUCT__entry( +- __field(u32, cl_boot) +- __field(u32, cl_id) +- __field(int, status) +- __array(unsigned char, addr, sizeof(struct sockaddr_in6)) +- ), +- TP_fast_assign( +- __entry->cl_boot = clp->cl_clientid.cl_boot; +- __entry->cl_id = clp->cl_clientid.cl_id; +- __entry->status = status; +- memcpy(__entry->addr, &clp->cl_cb_conn.cb_addr, +- sizeof(struct sockaddr_in6)); +- ), +- TP_printk("addr=%pISpc client %08x:%08x status=%d", +- __entry->addr, __entry->cl_boot, __entry->cl_id, +- __entry->status) +-); +- + TRACE_EVENT(nfsd_cb_recall, + TP_PROTO( + const struct nfs4_stid *stid +-- +2.43.0 + diff --git a/queue-5.10/nfsd-remove-the-pages_flushed-statistic-from-filecac.patch b/queue-5.10/nfsd-remove-the-pages_flushed-statistic-from-filecac.patch new file mode 100644 index 00000000000..e2950b7caa2 --- /dev/null +++ b/queue-5.10/nfsd-remove-the-pages_flushed-statistic-from-filecac.patch @@ -0,0 +1,75 @@ +From 87e12f47d7aebb56d4546b5ae1ad463cf3208b21 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 2 Nov 2022 14:44:47 -0400 +Subject: nfsd: remove the pages_flushed statistic from filecache + +From: Jeff Layton + +[ Upstream commit 1f696e230ea5198e393368b319eb55651828d687 ] + +We're counting mapping->nrpages, but not all of those are necessarily +dirty. We don't really have a simple way to count just the dirty pages, +so just remove this stat since it's not accurate. + +Signed-off-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 7 +------ + 1 file changed, 1 insertion(+), 6 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index b43d2d7ac5957..b95b1be5b2e43 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -57,7 +57,6 @@ static DEFINE_PER_CPU(unsigned long, nfsd_file_cache_hits); + static DEFINE_PER_CPU(unsigned long, nfsd_file_acquisitions); + static DEFINE_PER_CPU(unsigned long, nfsd_file_releases); + static DEFINE_PER_CPU(unsigned long, nfsd_file_total_age); +-static DEFINE_PER_CPU(unsigned long, nfsd_file_pages_flushed); + static DEFINE_PER_CPU(unsigned long, nfsd_file_evictions); + + struct nfsd_fcache_disposal { +@@ -395,7 +394,6 @@ nfsd_file_flush(struct nfsd_file *nf) + + if (!file || !(file->f_mode & FMODE_WRITE)) + return; +- this_cpu_add(nfsd_file_pages_flushed, file->f_mapping->nrpages); + if (vfs_fsync(file, 1) != 0) + nfsd_reset_write_verifier(net_generic(nf->nf_net, nfsd_net_id)); + } +@@ -1022,7 +1020,6 @@ nfsd_file_cache_shutdown(void) + per_cpu(nfsd_file_acquisitions, i) = 0; + per_cpu(nfsd_file_releases, i) = 0; + per_cpu(nfsd_file_total_age, i) = 0; +- per_cpu(nfsd_file_pages_flushed, i) = 0; + per_cpu(nfsd_file_evictions, i) = 0; + } + } +@@ -1237,7 +1234,7 @@ nfsd_file_create(struct svc_rqst *rqstp, struct svc_fh *fhp, + */ + int nfsd_file_cache_stats_show(struct seq_file *m, void *v) + { +- unsigned long releases = 0, pages_flushed = 0, evictions = 0; ++ unsigned long releases = 0, evictions = 0; + unsigned long hits = 0, acquisitions = 0; + unsigned int i, count = 0, buckets = 0; + unsigned long lru = 0, total_age = 0; +@@ -1265,7 +1262,6 @@ int nfsd_file_cache_stats_show(struct seq_file *m, void *v) + releases += per_cpu(nfsd_file_releases, i); + total_age += per_cpu(nfsd_file_total_age, i); + evictions += per_cpu(nfsd_file_evictions, i); +- pages_flushed += per_cpu(nfsd_file_pages_flushed, i); + } + + seq_printf(m, "total entries: %u\n", count); +@@ -1279,6 +1275,5 @@ int nfsd_file_cache_stats_show(struct seq_file *m, void *v) + seq_printf(m, "mean age (ms): %ld\n", total_age / releases); + else + seq_printf(m, "mean age (ms): -\n"); +- seq_printf(m, "pages flushed: %lu\n", pages_flushed); + return 0; + } +-- +2.43.0 + diff --git a/queue-5.10/nfsd-remove-trace_nfsd_clid_inuse_err.patch b/queue-5.10/nfsd-remove-trace_nfsd_clid_inuse_err.patch new file mode 100644 index 00000000000..efc87993cce --- /dev/null +++ b/queue-5.10/nfsd-remove-trace_nfsd_clid_inuse_err.patch @@ -0,0 +1,58 @@ +From 297653df040256cafa90c5a75af75a59068a8ecc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 14 May 2021 15:55:42 -0400 +Subject: NFSD: Remove trace_nfsd_clid_inuse_err + +From: Chuck Lever + +[ Upstream commit 0bfaacac57e64aa342f865b8ddcab06ca59a6f83 ] + +This tracepoint has been replaced by nfsd_clid_cred_mismatch and +nfsd_clid_verf_mismatch, and can simply be removed. + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/trace.h | 24 ------------------------ + 1 file changed, 24 deletions(-) + +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index 0ab46a0c911d2..2fac89e29f515 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -596,30 +596,6 @@ TRACE_EVENT(nfsd_clid_verf_mismatch, + ) + ); + +-TRACE_EVENT(nfsd_clid_inuse_err, +- TP_PROTO(const struct nfs4_client *clp), +- TP_ARGS(clp), +- TP_STRUCT__entry( +- __field(u32, cl_boot) +- __field(u32, cl_id) +- __array(unsigned char, addr, sizeof(struct sockaddr_in6)) +- __field(unsigned int, namelen) +- __dynamic_array(unsigned char, name, clp->cl_name.len) +- ), +- TP_fast_assign( +- __entry->cl_boot = clp->cl_clientid.cl_boot; +- __entry->cl_id = clp->cl_clientid.cl_id; +- memcpy(__entry->addr, &clp->cl_addr, +- sizeof(struct sockaddr_in6)); +- __entry->namelen = clp->cl_name.len; +- memcpy(__get_dynamic_array(name), clp->cl_name.data, +- clp->cl_name.len); +- ), +- TP_printk("nfs4_clientid %.*s already in use by %pISpc, client %08x:%08x", +- __entry->namelen, __get_str(name), __entry->addr, +- __entry->cl_boot, __entry->cl_id) +-) +- + /* + * from fs/nfsd/filecache.h + */ +-- +2.43.0 + diff --git a/queue-5.10/nfsd-remove-unused-function.patch b/queue-5.10/nfsd-remove-unused-function.patch new file mode 100644 index 00000000000..30337342b81 --- /dev/null +++ b/queue-5.10/nfsd-remove-unused-function.patch @@ -0,0 +1,45 @@ +From 24e4d871692b7e9bf686d73edc943cdb6e4adc9a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Apr 2021 16:38:24 +0800 +Subject: nfsd: remove unused function + +From: Jiapeng Chong + +[ Upstream commit 363f8dd5eecd6c67fe9840ef6065440f0ee7df3a ] + +Fix the following clang warning: + +fs/nfsd/nfs4state.c:6276:1: warning: unused function 'end_offset' +[-Wunused-function]. + +Reported-by: Abaci Robot +Signed-off-by: Jiapeng Chong +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 9 --------- + 1 file changed, 9 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 104d563636540..a42a505b3e417 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -6336,15 +6336,6 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + return status; + } + +-static inline u64 +-end_offset(u64 start, u64 len) +-{ +- u64 end; +- +- end = start + len; +- return end >= start ? end: NFS4_MAX_UINT64; +-} +- + /* last octet in a range */ + static inline u64 + last_byte_offset(u64 start, u64 len) +-- +2.43.0 + diff --git a/queue-5.10/nfsd-remove-unused-nfsd4_compoundargs-cachetype-fiel.patch b/queue-5.10/nfsd-remove-unused-nfsd4_compoundargs-cachetype-fiel.patch new file mode 100644 index 00000000000..fe07cd325ae --- /dev/null +++ b/queue-5.10/nfsd-remove-unused-nfsd4_compoundargs-cachetype-fiel.patch @@ -0,0 +1,33 @@ +From 3618e4eabc8071d64140bd15f3e94a03fc856494 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Sep 2022 17:23:30 -0400 +Subject: NFSD: Remove unused nfsd4_compoundargs::cachetype field + +From: Chuck Lever + +[ Upstream commit 77e378cf2a595d8e39cddf28a31efe6afd9394a0 ] + +This field was added by commit 1091006c5eb1 ("nfsd: turn on reply +cache for NFSv4") but was never put to use. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/xdr4.h | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h +index 1e83fda7601ab..624a19ec3ad11 100644 +--- a/fs/nfsd/xdr4.h ++++ b/fs/nfsd/xdr4.h +@@ -724,7 +724,6 @@ struct nfsd4_compoundargs { + u32 opcnt; + struct nfsd4_op *ops; + struct nfsd4_op iops[8]; +- int cachetype; + }; + + struct nfsd4_compoundres { +-- +2.43.0 + diff --git a/queue-5.10/nfsd-remove-unused-nfsv2-directory-entry-encoders.patch b/queue-5.10/nfsd-remove-unused-nfsv2-directory-entry-encoders.patch new file mode 100644 index 00000000000..ebb93880e66 --- /dev/null +++ b/queue-5.10/nfsd-remove-unused-nfsv2-directory-entry-encoders.patch @@ -0,0 +1,139 @@ +From e27195e6695c3f336549245790d08f70a172e1bd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 15 Nov 2020 14:30:13 -0500 +Subject: NFSD: Remove unused NFSv2 directory entry encoders + +From: Chuck Lever + +[ Upstream commit 8a2cf9f5709cc20a1114a7d22655928314fc86f8 ] + +Clean up. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsproc.c | 2 +- + fs/nfsd/nfsxdr.c | 51 +++-------------------------------------------- + fs/nfsd/xdr.h | 10 ++-------- + 3 files changed, 6 insertions(+), 57 deletions(-) + +diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c +index 135c0bc468bce..72f8bc4a7ea48 100644 +--- a/fs/nfsd/nfsproc.c ++++ b/fs/nfsd/nfsproc.c +@@ -602,7 +602,7 @@ nfsd_proc_readdir(struct svc_rqst *rqstp) + resp->cookie_offset = 0; + offset = argp->cookie; + resp->status = nfsd_readdir(rqstp, &argp->fh, &offset, +- &resp->common, nfs2svc_encode_entry); ++ &resp->common, nfssvc_encode_entry); + nfssvc_encode_nfscookie(resp, offset); + + fh_put(&argp->fh); +diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c +index 1102d40ded03f..5df6f00d76fd5 100644 +--- a/fs/nfsd/nfsxdr.c ++++ b/fs/nfsd/nfsxdr.c +@@ -663,7 +663,7 @@ svcxdr_encode_entry_common(struct nfsd_readdirres *resp, const char *name, + } + + /** +- * nfs2svc_encode_entry - encode one NFSv2 READDIR entry ++ * nfssvc_encode_entry - encode one NFSv2 READDIR entry + * @data: directory context + * @name: name of the object to be encoded + * @namlen: length of that name, in bytes +@@ -680,8 +680,8 @@ svcxdr_encode_entry_common(struct nfsd_readdirres *resp, const char *name, + * - resp->common.err + * - resp->cookie_offset + */ +-int nfs2svc_encode_entry(void *data, const char *name, int namlen, +- loff_t offset, u64 ino, unsigned int d_type) ++int nfssvc_encode_entry(void *data, const char *name, int namlen, ++ loff_t offset, u64 ino, unsigned int d_type) + { + struct readdir_cd *ccd = data; + struct nfsd_readdirres *resp = container_of(ccd, +@@ -706,51 +706,6 @@ int nfs2svc_encode_entry(void *data, const char *name, int namlen, + return -EINVAL; + } + +-int +-nfssvc_encode_entry(void *ccdv, const char *name, +- int namlen, loff_t offset, u64 ino, unsigned int d_type) +-{ +- struct readdir_cd *ccd = ccdv; +- struct nfsd_readdirres *cd = container_of(ccd, struct nfsd_readdirres, common); +- __be32 *p = cd->buffer; +- int buflen, slen; +- +- /* +- dprintk("nfsd: entry(%.*s off %ld ino %ld)\n", +- namlen, name, offset, ino); +- */ +- +- if (offset > ~((u32) 0)) { +- cd->common.err = nfserr_fbig; +- return -EINVAL; +- } +- nfssvc_encode_nfscookie(cd, offset); +- +- /* truncate filename */ +- namlen = min(namlen, NFS2_MAXNAMLEN); +- slen = XDR_QUADLEN(namlen); +- +- if ((buflen = cd->buflen - slen - 4) < 0) { +- cd->common.err = nfserr_toosmall; +- return -EINVAL; +- } +- if (ino > ~((u32) 0)) { +- cd->common.err = nfserr_fbig; +- return -EINVAL; +- } +- *p++ = xdr_one; /* mark entry present */ +- *p++ = htonl((u32) ino); /* file id */ +- p = xdr_encode_array(p, name, namlen);/* name length & name */ +- cd->offset = p; /* remember pointer */ +- *p++ = htonl(~0U); /* offset of next entry */ +- +- cd->count += p - cd->buffer; +- cd->buflen = buflen; +- cd->buffer = p; +- cd->common.err = nfs_ok; +- return 0; +-} +- + /* + * XDR release functions + */ +diff --git a/fs/nfsd/xdr.h b/fs/nfsd/xdr.h +index a065852c9ea86..10f3bd25e8ccc 100644 +--- a/fs/nfsd/xdr.h ++++ b/fs/nfsd/xdr.h +@@ -115,10 +115,6 @@ struct nfsd_readdirres { + struct xdr_stream xdr; + struct xdr_buf dirlist; + struct readdir_cd common; +- __be32 * buffer; +- int buflen; +- __be32 * offset; +- struct page *page; + unsigned int cookie_offset; + }; + +@@ -164,10 +160,8 @@ int nfssvc_encode_statfsres(struct svc_rqst *, __be32 *); + int nfssvc_encode_readdirres(struct svc_rqst *, __be32 *); + + void nfssvc_encode_nfscookie(struct nfsd_readdirres *resp, u32 offset); +-int nfs2svc_encode_entry(void *data, const char *name, int namlen, +- loff_t offset, u64 ino, unsigned int d_type); +-int nfssvc_encode_entry(void *, const char *name, +- int namlen, loff_t offset, u64 ino, unsigned int); ++int nfssvc_encode_entry(void *data, const char *name, int namlen, ++ loff_t offset, u64 ino, unsigned int d_type); + + void nfssvc_release_attrstat(struct svc_rqst *rqstp); + void nfssvc_release_diropres(struct svc_rqst *rqstp); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-remove-unused-nfsv3-directory-entry-encoders.patch b/queue-5.10/nfsd-remove-unused-nfsv3-directory-entry-encoders.patch new file mode 100644 index 00000000000..72e3962f410 --- /dev/null +++ b/queue-5.10/nfsd-remove-unused-nfsv3-directory-entry-encoders.patch @@ -0,0 +1,279 @@ +From 4379855a9afcac22b39844ddd9af9ae881e3db71 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 13 Nov 2020 11:27:13 -0500 +Subject: NFSD: Remove unused NFSv3 directory entry encoders + +From: Chuck Lever + +[ Upstream commit 1411934627f9fe31a36ac8c43179ce9b63edce5c ] + +Clean up. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3xdr.c | 190 ---------------------------------------------- + fs/nfsd/xdr3.h | 11 --- + 2 files changed, 201 deletions(-) + +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index f38d845ac8a0f..646bbfc5b7794 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -148,16 +148,6 @@ svcxdr_encode_post_op_fh3(struct xdr_stream *xdr, const struct svc_fh *fhp) + return true; + } + +-static __be32 * +-encode_fh(__be32 *p, struct svc_fh *fhp) +-{ +- unsigned int size = fhp->fh_handle.fh_size; +- *p++ = htonl(size); +- if (size) p[XDR_QUADLEN(size)-1]=0; +- memcpy(p, &fhp->fh_handle.fh_base, size); +- return p + XDR_QUADLEN(size); +-} +- + static bool + svcxdr_encode_cookieverf3(struct xdr_stream *xdr, const __be32 *verf) + { +@@ -1164,20 +1154,6 @@ nfs3svc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p) + return 1; + } + +-static __be32 * +-encode_entry_baggage(struct nfsd3_readdirres *cd, __be32 *p, const char *name, +- int namlen, u64 ino) +-{ +- *p++ = xdr_one; /* mark entry present */ +- p = xdr_encode_hyper(p, ino); /* file id */ +- p = xdr_encode_array(p, name, namlen);/* name length & name */ +- +- cd->offset = p; /* remember pointer */ +- p = xdr_encode_hyper(p, NFS_OFFSET_MAX);/* offset of next entry */ +- +- return p; +-} +- + static __be32 + compose_entry_fh(struct nfsd3_readdirres *cd, struct svc_fh *fhp, + const char *name, int namlen, u64 ino) +@@ -1216,26 +1192,6 @@ compose_entry_fh(struct nfsd3_readdirres *cd, struct svc_fh *fhp, + return rv; + } + +-static __be32 *encode_entryplus_baggage(struct nfsd3_readdirres *cd, __be32 *p, const char *name, int namlen, u64 ino) +-{ +- struct svc_fh *fh = &cd->scratch; +- __be32 err; +- +- fh_init(fh, NFS3_FHSIZE); +- err = compose_entry_fh(cd, fh, name, namlen, ino); +- if (err) { +- *p++ = 0; +- *p++ = 0; +- goto out; +- } +- p = encode_post_op_attr(cd->rqstp, p, fh); +- *p++ = xdr_one; /* yes, a file handle follows */ +- p = encode_fh(p, fh); +-out: +- fh_put(fh); +- return p; +-} +- + /** + * nfs3svc_encode_cookie3 - Encode a directory offset cookie + * @resp: readdir result context +@@ -1255,152 +1211,6 @@ void nfs3svc_encode_cookie3(struct nfsd3_readdirres *resp, u64 offset) + resp->cookie_offset = 0; + } + +-/* +- * Encode a directory entry. This one works for both normal readdir +- * and readdirplus. +- * The normal readdir reply requires 2 (fileid) + 1 (stringlen) +- * + string + 2 (cookie) + 1 (next) words, i.e. 6 + strlen. +- * +- * The readdirplus baggage is 1+21 words for post_op_attr, plus the +- * file handle. +- */ +- +-#define NFS3_ENTRY_BAGGAGE (2 + 1 + 2 + 1) +-#define NFS3_ENTRYPLUS_BAGGAGE (1 + 21 + 1 + (NFS3_FHSIZE >> 2)) +-static int +-encode_entry(struct readdir_cd *ccd, const char *name, int namlen, +- loff_t offset, u64 ino, unsigned int d_type, int plus) +-{ +- struct nfsd3_readdirres *cd = container_of(ccd, struct nfsd3_readdirres, +- common); +- __be32 *p = cd->buffer; +- caddr_t curr_page_addr = NULL; +- struct page ** page; +- int slen; /* string (name) length */ +- int elen; /* estimated entry length in words */ +- int num_entry_words = 0; /* actual number of words */ +- +- nfs3svc_encode_cookie3(cd, offset); +- +- /* +- dprintk("encode_entry(%.*s @%ld%s)\n", +- namlen, name, (long) offset, plus? " plus" : ""); +- */ +- +- /* truncate filename if too long */ +- namlen = min(namlen, NFS3_MAXNAMLEN); +- +- slen = XDR_QUADLEN(namlen); +- elen = slen + NFS3_ENTRY_BAGGAGE +- + (plus? NFS3_ENTRYPLUS_BAGGAGE : 0); +- +- if (cd->buflen < elen) { +- cd->common.err = nfserr_toosmall; +- return -EINVAL; +- } +- +- /* determine which page in rq_respages[] we are currently filling */ +- for (page = cd->rqstp->rq_respages + 1; +- page < cd->rqstp->rq_next_page; page++) { +- curr_page_addr = page_address(*page); +- +- if (((caddr_t)cd->buffer >= curr_page_addr) && +- ((caddr_t)cd->buffer < curr_page_addr + PAGE_SIZE)) +- break; +- } +- +- if ((caddr_t)(cd->buffer + elen) < (curr_page_addr + PAGE_SIZE)) { +- /* encode entry in current page */ +- +- p = encode_entry_baggage(cd, p, name, namlen, ino); +- +- if (plus) +- p = encode_entryplus_baggage(cd, p, name, namlen, ino); +- num_entry_words = p - cd->buffer; +- } else if (*(page+1) != NULL) { +- /* temporarily encode entry into next page, then move back to +- * current and next page in rq_respages[] */ +- __be32 *p1, *tmp; +- int len1, len2; +- +- /* grab next page for temporary storage of entry */ +- p1 = tmp = page_address(*(page+1)); +- +- p1 = encode_entry_baggage(cd, p1, name, namlen, ino); +- +- if (plus) +- p1 = encode_entryplus_baggage(cd, p1, name, namlen, ino); +- +- /* determine entry word length and lengths to go in pages */ +- num_entry_words = p1 - tmp; +- len1 = curr_page_addr + PAGE_SIZE - (caddr_t)cd->buffer; +- if ((num_entry_words << 2) < len1) { +- /* the actual number of words in the entry is less +- * than elen and can still fit in the current page +- */ +- memmove(p, tmp, num_entry_words << 2); +- p += num_entry_words; +- +- /* update offset */ +- cd->offset = cd->buffer + (cd->offset - tmp); +- } else { +- unsigned int offset_r = (cd->offset - tmp) << 2; +- +- /* update pointer to offset location. +- * This is a 64bit quantity, so we need to +- * deal with 3 cases: +- * - entirely in first page +- * - entirely in second page +- * - 4 bytes in each page +- */ +- if (offset_r + 8 <= len1) { +- cd->offset = p + (cd->offset - tmp); +- } else if (offset_r >= len1) { +- cd->offset -= len1 >> 2; +- } else { +- /* sitting on the fence */ +- BUG_ON(offset_r != len1 - 4); +- cd->offset = p + (cd->offset - tmp); +- cd->offset1 = tmp; +- } +- +- len2 = (num_entry_words << 2) - len1; +- +- /* move from temp page to current and next pages */ +- memmove(p, tmp, len1); +- memmove(tmp, (caddr_t)tmp+len1, len2); +- +- p = tmp + (len2 >> 2); +- } +- } +- else { +- cd->common.err = nfserr_toosmall; +- return -EINVAL; +- } +- +- cd->count += num_entry_words; +- cd->buflen -= num_entry_words; +- cd->buffer = p; +- cd->common.err = nfs_ok; +- return 0; +- +-} +- +-int +-nfs3svc_encode_entry(void *cd, const char *name, +- int namlen, loff_t offset, u64 ino, unsigned int d_type) +-{ +- return encode_entry(cd, name, namlen, offset, ino, d_type, 0); +-} +- +-int +-nfs3svc_encode_entry_plus(void *cd, const char *name, +- int namlen, loff_t offset, u64 ino, +- unsigned int d_type) +-{ +- return encode_entry(cd, name, namlen, offset, ino, d_type, 1); +-} +- + static bool + svcxdr_encode_entry3_common(struct nfsd3_readdirres *resp, const char *name, + int namlen, loff_t offset, u64 ino) +diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h +index 81dea78b0f17e..b851458373db6 100644 +--- a/fs/nfsd/xdr3.h ++++ b/fs/nfsd/xdr3.h +@@ -172,7 +172,6 @@ struct nfsd3_readdirres { + /* Components of the reply */ + __be32 status; + struct svc_fh fh; +- int count; + __be32 verf[2]; + + /* Used to encode the reply's entry list */ +@@ -180,10 +179,6 @@ struct nfsd3_readdirres { + struct xdr_buf dirlist; + struct svc_fh scratch; + struct readdir_cd common; +- __be32 * buffer; +- int buflen; +- __be32 * offset; +- __be32 * offset1; + unsigned int cookie_offset; + struct svc_rqst * rqstp; + +@@ -305,12 +300,6 @@ void nfs3svc_release_fhandle(struct svc_rqst *); + void nfs3svc_release_fhandle2(struct svc_rqst *); + + void nfs3svc_encode_cookie3(struct nfsd3_readdirres *resp, u64 offset); +-int nfs3svc_encode_entry(void *, const char *name, +- int namlen, loff_t offset, u64 ino, +- unsigned int); +-int nfs3svc_encode_entry_plus(void *, const char *name, +- int namlen, loff_t offset, u64 ino, +- unsigned int); + int nfs3svc_encode_entry3(void *data, const char *name, int namlen, + loff_t offset, u64 ino, unsigned int d_type); + int nfs3svc_encode_entryplus3(void *data, const char *name, int namlen, +-- +2.43.0 + diff --git a/queue-5.10/nfsd-remove-unused-set_client-argument.patch b/queue-5.10/nfsd-remove-unused-set_client-argument.patch new file mode 100644 index 00000000000..eade09225da --- /dev/null +++ b/queue-5.10/nfsd-remove-unused-set_client-argument.patch @@ -0,0 +1,107 @@ +From f44512ef26af5c44e764021e23f21dc7ac7c6f0b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 Jan 2021 17:57:43 -0500 +Subject: nfsd: remove unused set_client argument + +From: J. Bruce Fields + +[ Upstream commit f71475ba8c2a77fff8051903cf4b7d826c3d1693 ] + +Every caller is setting this argument to false, so we don't need it. + +Also cut this comment a bit and remove an unnecessary warning. + +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 23 ++++++++++------------- + 1 file changed, 10 insertions(+), 13 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index b05598e5bc168..cbec87ee6bc0e 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -4690,8 +4690,7 @@ static struct nfs4_client *lookup_clientid(clientid_t *clid, bool sessions, + + static __be32 set_client(clientid_t *clid, + struct nfsd4_compound_state *cstate, +- struct nfsd_net *nn, +- bool sessions) ++ struct nfsd_net *nn) + { + if (cstate->clp) { + if (!same_clid(&cstate->clp->cl_clientid, clid)) +@@ -4701,12 +4700,10 @@ static __be32 set_client(clientid_t *clid, + if (STALE_CLIENTID(clid, nn)) + return nfserr_stale_clientid; + /* +- * For v4.1+ we get the client in the SEQUENCE op. If we don't have one +- * cached already then we know this is for is for v4.0 and "sessions" +- * will be false. ++ * We're in the 4.0 case (otherwise the SEQUENCE op would have ++ * set cstate->clp), so session = false: + */ +- WARN_ON_ONCE(cstate->session); +- cstate->clp = lookup_clientid(clid, sessions, nn); ++ cstate->clp = lookup_clientid(clid, false, nn); + if (!cstate->clp) + return nfserr_expired; + return nfs_ok; +@@ -4730,7 +4727,7 @@ nfsd4_process_open1(struct nfsd4_compound_state *cstate, + if (open->op_file == NULL) + return nfserr_jukebox; + +- status = set_client(clientid, cstate, nn, false); ++ status = set_client(clientid, cstate, nn); + if (status) + return status; + clp = cstate->clp; +@@ -5320,7 +5317,7 @@ nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); + + trace_nfsd_clid_renew(clid); +- status = set_client(clid, cstate, nn, false); ++ status = set_client(clid, cstate, nn); + if (status) + return status; + clp = cstate->clp; +@@ -5701,7 +5698,7 @@ nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate, + if (ZERO_STATEID(stateid) || ONE_STATEID(stateid) || + CLOSE_STATEID(stateid)) + return nfserr_bad_stateid; +- status = set_client(&stateid->si_opaque.so_clid, cstate, nn, false); ++ status = set_client(&stateid->si_opaque.so_clid, cstate, nn); + if (status == nfserr_stale_clientid) { + if (cstate->session) + return nfserr_bad_stateid; +@@ -6938,7 +6935,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + return nfserr_inval; + + if (!nfsd4_has_session(cstate)) { +- status = set_client(&lockt->lt_clientid, cstate, nn, false); ++ status = set_client(&lockt->lt_clientid, cstate, nn); + if (status) + goto out; + } +@@ -7122,7 +7119,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, + dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n", + clid->cl_boot, clid->cl_id); + +- status = set_client(clid, cstate, nn, false); ++ status = set_client(clid, cstate, nn); + if (status) + return status; + +@@ -7262,7 +7259,7 @@ nfs4_check_open_reclaim(clientid_t *clid, + __be32 status; + + /* find clientid in conf_id_hashtbl */ +- status = set_client(clid, cstate, nn, false); ++ status = set_client(clid, cstate, nn); + if (status) + return nfserr_reclaim_bad; + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-remove-unused-stats-counters.patch b/queue-5.10/nfsd-remove-unused-stats-counters.patch new file mode 100644 index 00000000000..5078b627bdc --- /dev/null +++ b/queue-5.10/nfsd-remove-unused-stats-counters.patch @@ -0,0 +1,122 @@ +From aa603222bcdde49d6472563b464efb842b64c1c4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 Jan 2021 09:52:34 +0200 +Subject: nfsd: remove unused stats counters + +From: Amir Goldstein + +[ Upstream commit 1b76d1df1a3683b6b23cd1c813d13c5e6a9d35e5 ] + +Commit 501cb1849f86 ("nfsd: rip out the raparms cache") removed the +code that updates read-ahead cache stats counters, +commit 8bbfa9f3889b ("knfsd: remove the nfsd thread busy histogram") +removed code that updates the thread busy stats counters back in 2009 +and code that updated filehandle cache stats was removed back in 2002. + +Remove the unused stats counters from nfsd_stats struct and print +hardcoded zeros in /proc/net/rpc/nfsd. + +Signed-off-by: Amir Goldstein +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/stats.c | 41 ++++++++++++++++------------------------- + fs/nfsd/stats.h | 10 ---------- + 2 files changed, 16 insertions(+), 35 deletions(-) + +diff --git a/fs/nfsd/stats.c b/fs/nfsd/stats.c +index b1bc582b0493e..e928e224205ac 100644 +--- a/fs/nfsd/stats.c ++++ b/fs/nfsd/stats.c +@@ -7,16 +7,14 @@ + * Format: + * rc + * Statistsics for the reply cache +- * fh ++ * fh + * statistics for filehandle lookup + * io + * statistics for IO throughput +- * th <10%-20%> <20%-30%> ... <90%-100%> <100%> +- * time (seconds) when nfsd thread usage above thresholds +- * and number of times that all threads were in use +- * ra cache-size <10% <20% <30% ... <100% not-found +- * number of times that read-ahead entry was found that deep in +- * the cache. ++ * th ++ * number of threads ++ * ra ++ * + * plus generic RPC stats (see net/sunrpc/stats.c) + * + * Copyright (C) 1995, 1996, 1997 Olaf Kirch +@@ -38,31 +36,24 @@ static int nfsd_proc_show(struct seq_file *seq, void *v) + { + int i; + +- seq_printf(seq, "rc %u %u %u\nfh %u %u %u %u %u\nio %u %u\n", ++ seq_printf(seq, "rc %u %u %u\nfh %u 0 0 0 0\nio %u %u\n", + nfsdstats.rchits, + nfsdstats.rcmisses, + nfsdstats.rcnocache, + nfsdstats.fh_stale, +- nfsdstats.fh_lookup, +- nfsdstats.fh_anon, +- nfsdstats.fh_nocache_dir, +- nfsdstats.fh_nocache_nondir, + nfsdstats.io_read, + nfsdstats.io_write); ++ + /* thread usage: */ +- seq_printf(seq, "th %u %u", nfsdstats.th_cnt, nfsdstats.th_fullcnt); +- for (i=0; i<10; i++) { +- unsigned int jifs = nfsdstats.th_usage[i]; +- unsigned int sec = jifs / HZ, msec = (jifs % HZ)*1000/HZ; +- seq_printf(seq, " %u.%03u", sec, msec); +- } +- +- /* newline and ra-cache */ +- seq_printf(seq, "\nra %u", nfsdstats.ra_size); +- for (i=0; i<11; i++) +- seq_printf(seq, " %u", nfsdstats.ra_depth[i]); +- seq_putc(seq, '\n'); +- ++ seq_printf(seq, "th %u 0", nfsdstats.th_cnt); ++ ++ /* deprecated thread usage histogram stats */ ++ for (i = 0; i < 10; i++) ++ seq_puts(seq, " 0.000"); ++ ++ /* deprecated ra-cache stats */ ++ seq_puts(seq, "\nra 0 0 0 0 0 0 0 0 0 0 0 0\n"); ++ + /* show my rpc info */ + svc_seq_show(seq, &nfsd_svcstats); + +diff --git a/fs/nfsd/stats.h b/fs/nfsd/stats.h +index b23fdac698201..5e3cdf21556a1 100644 +--- a/fs/nfsd/stats.h ++++ b/fs/nfsd/stats.h +@@ -15,19 +15,9 @@ struct nfsd_stats { + unsigned int rcmisses; /* repcache hits */ + unsigned int rcnocache; /* uncached reqs */ + unsigned int fh_stale; /* FH stale error */ +- unsigned int fh_lookup; /* dentry cached */ +- unsigned int fh_anon; /* anon file dentry returned */ +- unsigned int fh_nocache_dir; /* filehandle not found in dcache */ +- unsigned int fh_nocache_nondir; /* filehandle not found in dcache */ + unsigned int io_read; /* bytes returned to read requests */ + unsigned int io_write; /* bytes passed in write requests */ + unsigned int th_cnt; /* number of available threads */ +- unsigned int th_usage[10]; /* number of ticks during which n perdeciles +- * of available threads were in use */ +- unsigned int th_fullcnt; /* number of times last free thread was used */ +- unsigned int ra_size; /* size of ra cache */ +- unsigned int ra_depth[11]; /* number of times ra entry was found that deep +- * in the cache (10percentiles). [10] = not found */ + #ifdef CONFIG_NFSD_V4 + unsigned int nfs4_opcount[LAST_NFS4_OP + 1]; /* count of individual nfsv4 operations */ + #endif +-- +2.43.0 + diff --git a/queue-5.10/nfsd-remove-vanity-comments.patch b/queue-5.10/nfsd-remove-vanity-comments.patch new file mode 100644 index 00000000000..4c11d125d55 --- /dev/null +++ b/queue-5.10/nfsd-remove-vanity-comments.patch @@ -0,0 +1,48 @@ +From 9d0f13f76f9bc152e8bbf492836232e4e84bdec0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 28 Jul 2021 08:56:09 +1000 +Subject: NFSD: remove vanity comments + +From: NeilBrown + +[ Upstream commit ea49dc79002c416a9003f3204bc14f846a0dbcae ] + +Including one's name in copyright claims is appropriate. Including it +in random comments is just vanity. After 2 decades, it is time for +these to be gone. + +Signed-off-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/vfs.c | 1 - + include/uapi/linux/nfsd/nfsfh.h | 1 - + 2 files changed, 2 deletions(-) + +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index 05b5f7e241e70..2c493937dd5ec 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -244,7 +244,6 @@ nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp, + * returned. Otherwise the covered directory is returned. + * NOTE: this mountpoint crossing is not supported properly by all + * clients and is explicitly disallowed for NFSv3 +- * NeilBrown + */ + __be32 + nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, +diff --git a/include/uapi/linux/nfsd/nfsfh.h b/include/uapi/linux/nfsd/nfsfh.h +index 427294dd56a1b..e29e8accc4f4d 100644 +--- a/include/uapi/linux/nfsd/nfsfh.h ++++ b/include/uapi/linux/nfsd/nfsfh.h +@@ -33,7 +33,6 @@ struct nfs_fhbase_old { + + /* + * This is the new flexible, extensible style NFSv2/v3/v4 file handle. +- * by Neil Brown - March 2000 + * + * The file handle starts with a sequence of four-byte words. + * The first word contains a version number (1) and three descriptor bytes +-- +2.43.0 + diff --git a/queue-5.10/nfsd-removed-unused-argument-in-nfsd_startup_generic.patch b/queue-5.10/nfsd-removed-unused-argument-in-nfsd_startup_generic.patch new file mode 100644 index 00000000000..9878c6b91e4 --- /dev/null +++ b/queue-5.10/nfsd-removed-unused-argument-in-nfsd_startup_generic.patch @@ -0,0 +1,62 @@ +From e0b53cb535d1ba17bea3ca8c5ab837881a84c13f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Apr 2021 15:00:58 +0300 +Subject: nfsd: removed unused argument in nfsd_startup_generic() + +From: Vasily Averin + +[ Upstream commit 70c5307564035c160078401f541c397d77b95415 ] + +Since commit 501cb1849f86 ("nfsd: rip out the raparms cache") +nrservs is not used in nfsd_startup_generic() + +Signed-off-by: Vasily Averin +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfssvc.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c +index 79bc75d415226..731d89898903a 100644 +--- a/fs/nfsd/nfssvc.c ++++ b/fs/nfsd/nfssvc.c +@@ -308,7 +308,7 @@ static int nfsd_init_socks(struct net *net, const struct cred *cred) + + static int nfsd_users = 0; + +-static int nfsd_startup_generic(int nrservs) ++static int nfsd_startup_generic(void) + { + int ret; + +@@ -374,7 +374,7 @@ void nfsd_reset_boot_verifier(struct nfsd_net *nn) + write_sequnlock(&nn->boot_lock); + } + +-static int nfsd_startup_net(int nrservs, struct net *net, const struct cred *cred) ++static int nfsd_startup_net(struct net *net, const struct cred *cred) + { + struct nfsd_net *nn = net_generic(net, nfsd_net_id); + int ret; +@@ -382,7 +382,7 @@ static int nfsd_startup_net(int nrservs, struct net *net, const struct cred *cre + if (nn->nfsd_net_up) + return 0; + +- ret = nfsd_startup_generic(nrservs); ++ ret = nfsd_startup_generic(); + if (ret) + return ret; + ret = nfsd_init_socks(net, cred); +@@ -790,7 +790,7 @@ nfsd_svc(int nrservs, struct net *net, const struct cred *cred) + + nfsd_up_before = nn->nfsd_net_up; + +- error = nfsd_startup_net(nrservs, net, cred); ++ error = nfsd_startup_net(net, cred); + if (error) + goto out_destroy; + error = nn->nfsd_serv->sv_ops->svo_setup(nn->nfsd_serv, +-- +2.43.0 + diff --git a/queue-5.10/nfsd-rename-boot-verifier-functions.patch b/queue-5.10/nfsd-rename-boot-verifier-functions.patch new file mode 100644 index 00000000000..070d1c70e51 --- /dev/null +++ b/queue-5.10/nfsd-rename-boot-verifier-functions.patch @@ -0,0 +1,188 @@ +From a8ce4a1d12f7696f8380c4351a31e2eb873f0fc3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Dec 2021 10:22:05 -0500 +Subject: NFSD: Rename boot verifier functions + +From: Chuck Lever + +[ Upstream commit 3988a57885eeac05ef89f0ab4d7e47b52fbcf630 ] + +Clean up: These functions handle what the specs call a write +verifier, which in the Linux NFS server implementation is now +divorced from the server's boot instance + +[ cel: adjusted to apply to v5.10.y ] +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 2 +- + fs/nfsd/netns.h | 4 ++-- + fs/nfsd/nfs4proc.c | 2 +- + fs/nfsd/nfssvc.c | 16 ++++++++-------- + fs/nfsd/vfs.c | 16 ++++++++-------- + 5 files changed, 20 insertions(+), 20 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index b6ef8256c9c64..cc2831cec6695 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -243,7 +243,7 @@ nfsd_file_do_unhash(struct nfsd_file *nf) + trace_nfsd_file_unhash(nf); + + if (nfsd_file_check_write_error(nf)) +- nfsd_reset_boot_verifier(net_generic(nf->nf_net, nfsd_net_id)); ++ nfsd_reset_write_verifier(net_generic(nf->nf_net, nfsd_net_id)); + --nfsd_file_hashtbl[nf->nf_hashval].nfb_count; + hlist_del_rcu(&nf->nf_node); + atomic_long_dec(&nfsd_filecache_count); +diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h +index a6ed300259849..1b1a962a18041 100644 +--- a/fs/nfsd/netns.h ++++ b/fs/nfsd/netns.h +@@ -198,6 +198,6 @@ extern void nfsd_netns_free_versions(struct nfsd_net *nn); + + extern unsigned int nfsd_net_id; + +-void nfsd_copy_boot_verifier(__be32 verf[2], struct nfsd_net *nn); +-void nfsd_reset_boot_verifier(struct nfsd_net *nn); ++void nfsd_copy_write_verifier(__be32 verf[2], struct nfsd_net *nn); ++void nfsd_reset_write_verifier(struct nfsd_net *nn); + #endif /* __NFSD_NETNS_H__ */ +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 0f2025b7a6415..e8ffaa7faced9 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -598,7 +598,7 @@ static void gen_boot_verifier(nfs4_verifier *verifier, struct net *net) + + BUILD_BUG_ON(2*sizeof(*verf) != sizeof(verifier->data)); + +- nfsd_copy_boot_verifier(verf, net_generic(net, nfsd_net_id)); ++ nfsd_copy_write_verifier(verf, net_generic(net, nfsd_net_id)); + } + + static __be32 +diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c +index 5a60664695352..2efe9d33a2827 100644 +--- a/fs/nfsd/nfssvc.c ++++ b/fs/nfsd/nfssvc.c +@@ -346,14 +346,14 @@ static bool nfsd_needs_lockd(struct nfsd_net *nn) + } + + /** +- * nfsd_copy_boot_verifier - Atomically copy a write verifier ++ * nfsd_copy_write_verifier - Atomically copy a write verifier + * @verf: buffer in which to receive the verifier cookie + * @nn: NFS net namespace + * + * This function provides a wait-free mechanism for copying the +- * namespace's boot verifier without tearing it. ++ * namespace's write verifier without tearing it. + */ +-void nfsd_copy_boot_verifier(__be32 verf[2], struct nfsd_net *nn) ++void nfsd_copy_write_verifier(__be32 verf[2], struct nfsd_net *nn) + { + int seq = 0; + +@@ -364,7 +364,7 @@ void nfsd_copy_boot_verifier(__be32 verf[2], struct nfsd_net *nn) + done_seqretry(&nn->writeverf_lock, seq); + } + +-static void nfsd_reset_boot_verifier_locked(struct nfsd_net *nn) ++static void nfsd_reset_write_verifier_locked(struct nfsd_net *nn) + { + struct timespec64 now; + u64 verf; +@@ -379,7 +379,7 @@ static void nfsd_reset_boot_verifier_locked(struct nfsd_net *nn) + } + + /** +- * nfsd_reset_boot_verifier - Generate a new boot verifier ++ * nfsd_reset_write_verifier - Generate a new write verifier + * @nn: NFS net namespace + * + * This function updates the ->writeverf field of @nn. This field +@@ -391,10 +391,10 @@ static void nfsd_reset_boot_verifier_locked(struct nfsd_net *nn) + * server and MUST be unique between instances of the NFSv4.1 + * server." + */ +-void nfsd_reset_boot_verifier(struct nfsd_net *nn) ++void nfsd_reset_write_verifier(struct nfsd_net *nn) + { + write_seqlock(&nn->writeverf_lock); +- nfsd_reset_boot_verifier_locked(nn); ++ nfsd_reset_write_verifier_locked(nn); + write_sequnlock(&nn->writeverf_lock); + } + +@@ -683,7 +683,7 @@ int nfsd_create_serv(struct net *net) + register_inet6addr_notifier(&nfsd_inet6addr_notifier); + #endif + } +- nfsd_reset_boot_verifier(nn); ++ nfsd_reset_write_verifier(nn); + return 0; + } + +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index b1ce38c642cde..8cf053b698314 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -572,8 +572,8 @@ __be32 nfsd4_clone_file_range(struct svc_rqst *rqstp, + &nfsd4_get_cstate(rqstp)->current_fh, + dst_pos, + count, status); +- nfsd_reset_boot_verifier(net_generic(nf_dst->nf_net, +- nfsd_net_id)); ++ nfsd_reset_write_verifier(net_generic(nf_dst->nf_net, ++ nfsd_net_id)); + ret = nfserrno(status); + } + } +@@ -1039,10 +1039,10 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf, + iov_iter_kvec(&iter, WRITE, vec, vlen, *cnt); + since = READ_ONCE(file->f_wb_err); + if (verf) +- nfsd_copy_boot_verifier(verf, nn); ++ nfsd_copy_write_verifier(verf, nn); + host_err = vfs_iter_write(file, &iter, &pos, flags); + if (host_err < 0) { +- nfsd_reset_boot_verifier(nn); ++ nfsd_reset_write_verifier(nn); + goto out_nfserr; + } + *cnt = host_err; +@@ -1055,7 +1055,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf, + if (stable && use_wgather) { + host_err = wait_for_concurrent_writes(file); + if (host_err < 0) +- nfsd_reset_boot_verifier(nn); ++ nfsd_reset_write_verifier(nn); + } + + out_nfserr: +@@ -1168,7 +1168,7 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, + err2 = vfs_fsync_range(nf->nf_file, offset, end, 0); + switch (err2) { + case 0: +- nfsd_copy_boot_verifier(verf, nn); ++ nfsd_copy_write_verifier(verf, nn); + err2 = filemap_check_wb_err(nf->nf_file->f_mapping, + since); + err = nfserrno(err2); +@@ -1177,11 +1177,11 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, + err = nfserr_notsupp; + break; + default: +- nfsd_reset_boot_verifier(nn); ++ nfsd_reset_write_verifier(nn); + err = nfserrno(err2); + } + } else +- nfsd_copy_boot_verifier(verf, nn); ++ nfsd_copy_write_verifier(verf, nn); + + nfsd_file_put(nf); + out: +-- +2.43.0 + diff --git a/queue-5.10/nfsd-rename-lookup_clientid-set_client.patch b/queue-5.10/nfsd-rename-lookup_clientid-set_client.patch new file mode 100644 index 00000000000..32a61c93a4f --- /dev/null +++ b/queue-5.10/nfsd-rename-lookup_clientid-set_client.patch @@ -0,0 +1,100 @@ +From e7ed1d40b834d8153782864d21243e2d82177c63 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 Jan 2021 17:57:40 -0500 +Subject: nfsd: rename lookup_clientid->set_client + +From: J. Bruce Fields + +[ Upstream commit 460d27091ae2c23e7ac959a61cd481c58832db58 ] + +I think this is a better name, and I'm going to reuse elsewhere the code +that does the lookup itself. + +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 18 ++++++++---------- + 1 file changed, 8 insertions(+), 10 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 574c88a9da268..60c66becbc876 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -4675,7 +4675,7 @@ static __be32 nfsd4_check_seqid(struct nfsd4_compound_state *cstate, struct nfs4 + return nfserr_bad_seqid; + } + +-static __be32 lookup_clientid(clientid_t *clid, ++static __be32 set_client(clientid_t *clid, + struct nfsd4_compound_state *cstate, + struct nfsd_net *nn, + bool sessions) +@@ -4730,7 +4730,7 @@ nfsd4_process_open1(struct nfsd4_compound_state *cstate, + if (open->op_file == NULL) + return nfserr_jukebox; + +- status = lookup_clientid(clientid, cstate, nn, false); ++ status = set_client(clientid, cstate, nn, false); + if (status) + return status; + clp = cstate->clp; +@@ -5320,7 +5320,7 @@ nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); + + trace_nfsd_clid_renew(clid); +- status = lookup_clientid(clid, cstate, nn, false); ++ status = set_client(clid, cstate, nn, false); + if (status) + return status; + clp = cstate->clp; +@@ -5701,8 +5701,7 @@ nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate, + if (ZERO_STATEID(stateid) || ONE_STATEID(stateid) || + CLOSE_STATEID(stateid)) + return nfserr_bad_stateid; +- status = lookup_clientid(&stateid->si_opaque.so_clid, cstate, nn, +- false); ++ status = set_client(&stateid->si_opaque.so_clid, cstate, nn, false); + if (status == nfserr_stale_clientid) { + if (cstate->session) + return nfserr_bad_stateid; +@@ -5841,7 +5840,7 @@ static __be32 find_cpntf_state(struct nfsd_net *nn, stateid_t *st, + + cps->cpntf_time = ktime_get_boottime_seconds(); + memset(&cstate, 0, sizeof(cstate)); +- status = lookup_clientid(&cps->cp_p_clid, &cstate, nn, true); ++ status = set_client(&cps->cp_p_clid, &cstate, nn, true); + if (status) + goto out; + status = nfsd4_lookup_stateid(&cstate, &cps->cp_p_stateid, +@@ -6933,8 +6932,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + return nfserr_inval; + + if (!nfsd4_has_session(cstate)) { +- status = lookup_clientid(&lockt->lt_clientid, cstate, nn, +- false); ++ status = set_client(&lockt->lt_clientid, cstate, nn, false); + if (status) + goto out; + } +@@ -7118,7 +7116,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, + dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n", + clid->cl_boot, clid->cl_id); + +- status = lookup_clientid(clid, cstate, nn, false); ++ status = set_client(clid, cstate, nn, false); + if (status) + return status; + +@@ -7258,7 +7256,7 @@ nfs4_check_open_reclaim(clientid_t *clid, + __be32 status; + + /* find clientid in conf_id_hashtbl */ +- status = lookup_clientid(clid, cstate, nn, false); ++ status = set_client(clid, cstate, nn, false); + if (status) + return nfserr_reclaim_bad; + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-rename-the-fields-in-copy_stateid_t.patch b/queue-5.10/nfsd-rename-the-fields-in-copy_stateid_t.patch new file mode 100644 index 00000000000..1fe11559090 --- /dev/null +++ b/queue-5.10/nfsd-rename-the-fields-in-copy_stateid_t.patch @@ -0,0 +1,170 @@ +From 05f3c2c2d4fcf080fafd9433e7b91dbc128d08ec Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Sep 2022 13:10:35 -0400 +Subject: NFSD: Rename the fields in copy_stateid_t + +From: Chuck Lever + +[ Upstream commit 781fde1a2ba2391f31142f46f964cf1148ca1791 ] + +Code maintenance: The name of the copy_stateid_t::sc_count field +collides with the sc_count field in struct nfs4_stid, making the +latter difficult to grep for when auditing stateid reference +counting. + +No behavior change expected. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 6 +++--- + fs/nfsd/nfs4state.c | 30 +++++++++++++++--------------- + fs/nfsd/state.h | 6 +++--- + 3 files changed, 21 insertions(+), 21 deletions(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 1bb0fb917cf0d..e1aa48d496b98 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -1818,7 +1818,7 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + if (!nfs4_init_copy_state(nn, copy)) + goto out_err; + refcount_set(&async_copy->refcount, 1); +- memcpy(©->cp_res.cb_stateid, ©->cp_stateid.stid, ++ memcpy(©->cp_res.cb_stateid, ©->cp_stateid.cs_stid, + sizeof(copy->cp_res.cb_stateid)); + dup_copy_fields(copy, async_copy); + async_copy->copy_task = kthread_create(nfsd4_do_async_copy, +@@ -1856,7 +1856,7 @@ find_async_copy(struct nfs4_client *clp, stateid_t *stateid) + + spin_lock(&clp->async_lock); + list_for_each_entry(copy, &clp->async_copies, copies) { +- if (memcmp(©->cp_stateid.stid, stateid, NFS4_STATEID_SIZE)) ++ if (memcmp(©->cp_stateid.cs_stid, stateid, NFS4_STATEID_SIZE)) + continue; + refcount_inc(©->refcount); + spin_unlock(&clp->async_lock); +@@ -1910,7 +1910,7 @@ nfsd4_copy_notify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + cps = nfs4_alloc_init_cpntf_state(nn, stid); + if (!cps) + goto out; +- memcpy(&cn->cpn_cnr_stateid, &cps->cp_stateid.stid, sizeof(stateid_t)); ++ memcpy(&cn->cpn_cnr_stateid, &cps->cp_stateid.cs_stid, sizeof(stateid_t)); + memcpy(&cps->cp_p_stateid, &stid->sc_stateid, sizeof(stateid_t)); + memcpy(&cps->cp_p_clid, &clp->cl_clientid, sizeof(clientid_t)); + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index fce62a4388a26..f207c73ae1b58 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -985,19 +985,19 @@ struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *sla + * Create a unique stateid_t to represent each COPY. + */ + static int nfs4_init_cp_state(struct nfsd_net *nn, copy_stateid_t *stid, +- unsigned char sc_type) ++ unsigned char cs_type) + { + int new_id; + +- stid->stid.si_opaque.so_clid.cl_boot = (u32)nn->boot_time; +- stid->stid.si_opaque.so_clid.cl_id = nn->s2s_cp_cl_id; +- stid->sc_type = sc_type; ++ stid->cs_stid.si_opaque.so_clid.cl_boot = (u32)nn->boot_time; ++ stid->cs_stid.si_opaque.so_clid.cl_id = nn->s2s_cp_cl_id; ++ stid->cs_type = cs_type; + + idr_preload(GFP_KERNEL); + spin_lock(&nn->s2s_cp_lock); + new_id = idr_alloc_cyclic(&nn->s2s_cp_stateids, stid, 0, 0, GFP_NOWAIT); +- stid->stid.si_opaque.so_id = new_id; +- stid->stid.si_generation = 1; ++ stid->cs_stid.si_opaque.so_id = new_id; ++ stid->cs_stid.si_generation = 1; + spin_unlock(&nn->s2s_cp_lock); + idr_preload_end(); + if (new_id < 0) +@@ -1019,7 +1019,7 @@ struct nfs4_cpntf_state *nfs4_alloc_init_cpntf_state(struct nfsd_net *nn, + if (!cps) + return NULL; + cps->cpntf_time = ktime_get_boottime_seconds(); +- refcount_set(&cps->cp_stateid.sc_count, 1); ++ refcount_set(&cps->cp_stateid.cs_count, 1); + if (!nfs4_init_cp_state(nn, &cps->cp_stateid, NFS4_COPYNOTIFY_STID)) + goto out_free; + spin_lock(&nn->s2s_cp_lock); +@@ -1035,11 +1035,11 @@ void nfs4_free_copy_state(struct nfsd4_copy *copy) + { + struct nfsd_net *nn; + +- WARN_ON_ONCE(copy->cp_stateid.sc_type != NFS4_COPY_STID); ++ WARN_ON_ONCE(copy->cp_stateid.cs_type != NFS4_COPY_STID); + nn = net_generic(copy->cp_clp->net, nfsd_net_id); + spin_lock(&nn->s2s_cp_lock); + idr_remove(&nn->s2s_cp_stateids, +- copy->cp_stateid.stid.si_opaque.so_id); ++ copy->cp_stateid.cs_stid.si_opaque.so_id); + spin_unlock(&nn->s2s_cp_lock); + } + +@@ -6044,7 +6044,7 @@ nfs4_laundromat(struct nfsd_net *nn) + spin_lock(&nn->s2s_cp_lock); + idr_for_each_entry(&nn->s2s_cp_stateids, cps_t, i) { + cps = container_of(cps_t, struct nfs4_cpntf_state, cp_stateid); +- if (cps->cp_stateid.sc_type == NFS4_COPYNOTIFY_STID && ++ if (cps->cp_stateid.cs_type == NFS4_COPYNOTIFY_STID && + state_expired(<, cps->cpntf_time)) + _free_cpntf_state_locked(nn, cps); + } +@@ -6384,12 +6384,12 @@ nfs4_check_file(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfs4_stid *s, + static void + _free_cpntf_state_locked(struct nfsd_net *nn, struct nfs4_cpntf_state *cps) + { +- WARN_ON_ONCE(cps->cp_stateid.sc_type != NFS4_COPYNOTIFY_STID); +- if (!refcount_dec_and_test(&cps->cp_stateid.sc_count)) ++ WARN_ON_ONCE(cps->cp_stateid.cs_type != NFS4_COPYNOTIFY_STID); ++ if (!refcount_dec_and_test(&cps->cp_stateid.cs_count)) + return; + list_del(&cps->cp_list); + idr_remove(&nn->s2s_cp_stateids, +- cps->cp_stateid.stid.si_opaque.so_id); ++ cps->cp_stateid.cs_stid.si_opaque.so_id); + kfree(cps); + } + /* +@@ -6411,12 +6411,12 @@ __be32 manage_cpntf_state(struct nfsd_net *nn, stateid_t *st, + if (cps_t) { + state = container_of(cps_t, struct nfs4_cpntf_state, + cp_stateid); +- if (state->cp_stateid.sc_type != NFS4_COPYNOTIFY_STID) { ++ if (state->cp_stateid.cs_type != NFS4_COPYNOTIFY_STID) { + state = NULL; + goto unlock; + } + if (!clp) +- refcount_inc(&state->cp_stateid.sc_count); ++ refcount_inc(&state->cp_stateid.cs_count); + else + _free_cpntf_state_locked(nn, state); + } +diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h +index 4155be65d8069..b3477087a9fc3 100644 +--- a/fs/nfsd/state.h ++++ b/fs/nfsd/state.h +@@ -57,11 +57,11 @@ typedef struct { + } stateid_t; + + typedef struct { +- stateid_t stid; ++ stateid_t cs_stid; + #define NFS4_COPY_STID 1 + #define NFS4_COPYNOTIFY_STID 2 +- unsigned char sc_type; +- refcount_t sc_count; ++ unsigned char cs_type; ++ refcount_t cs_count; + } copy_stateid_t; + + struct nfsd4_callback { +-- +2.43.0 + diff --git a/queue-5.10/nfsd-reorder-the-fields-in-struct-nfsd4_op.patch b/queue-5.10/nfsd-reorder-the-fields-in-struct-nfsd4_op.patch new file mode 100644 index 00000000000..4b26c73c1ac --- /dev/null +++ b/queue-5.10/nfsd-reorder-the-fields-in-struct-nfsd4_op.patch @@ -0,0 +1,48 @@ +From db303ffd86c0659dd58e3e497ff0151e56de699e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 Jul 2022 14:40:28 -0400 +Subject: NFSD: Reorder the fields in struct nfsd4_op + +From: Chuck Lever + +[ Upstream commit d314309425ad5dc1b6facdb2d456580fb5fa5e3a ] + +Pack the fields to reduce the size of struct nfsd4_op, which is used +an array in struct nfsd4_compoundargs. + +sizeof(struct nfsd4_op): +Before: /* size: 672, cachelines: 11, members: 5 */ +After: /* size: 640, cachelines: 10, members: 5 */ + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/xdr4.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h +index c44c76cef40cd..621937fae9acb 100644 +--- a/fs/nfsd/xdr4.h ++++ b/fs/nfsd/xdr4.h +@@ -606,8 +606,9 @@ struct nfsd4_copy_notify { + + struct nfsd4_op { + u32 opnum; +- const struct nfsd4_operation * opdesc; + __be32 status; ++ const struct nfsd4_operation *opdesc; ++ struct nfs4_replay *replay; + union nfsd4_op_u { + struct nfsd4_access access; + struct nfsd4_close close; +@@ -671,7 +672,6 @@ struct nfsd4_op { + struct nfsd4_listxattrs listxattrs; + struct nfsd4_removexattr removexattr; + } u; +- struct nfs4_replay * replay; + }; + + bool nfsd4_cache_this_op(struct nfsd4_op *); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-reorganize-filecache.c.patch b/queue-5.10/nfsd-reorganize-filecache.c.patch new file mode 100644 index 00000000000..32846645060 --- /dev/null +++ b/queue-5.10/nfsd-reorganize-filecache.c.patch @@ -0,0 +1,239 @@ +From 6cf95df73228b734cb1f45f6c252d438a6a73c57 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 2 Nov 2022 14:44:48 -0400 +Subject: nfsd: reorganize filecache.c + +From: Jeff Layton + +[ Upstream commit 8214118589881b2d390284410c5ff275e7a5e03c ] + +In a coming patch, we're going to rework how the filecache refcounting +works. Move some code around in the function to reduce the churn in the +later patches, and rename some of the functions with (hopefully) clearer +names: nfsd_file_flush becomes nfsd_file_fsync, and +nfsd_file_unhash_and_dispose is renamed to nfsd_file_unhash_and_queue. + +Also, the nfsd_file_put_final tracepoint is renamed to nfsd_file_free, +to better match the name of the function from which it's called. + +Signed-off-by: Jeff Layton +Reviewed-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 111 ++++++++++++++++++++++---------------------- + fs/nfsd/trace.h | 4 +- + 2 files changed, 58 insertions(+), 57 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index b95b1be5b2e43..fb7ada3f7410e 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -334,16 +334,59 @@ nfsd_file_alloc(struct nfsd_file_lookup_key *key, unsigned int may) + return nf; + } + ++static void ++nfsd_file_fsync(struct nfsd_file *nf) ++{ ++ struct file *file = nf->nf_file; ++ ++ if (!file || !(file->f_mode & FMODE_WRITE)) ++ return; ++ if (vfs_fsync(file, 1) != 0) ++ nfsd_reset_write_verifier(net_generic(nf->nf_net, nfsd_net_id)); ++} ++ ++static int ++nfsd_file_check_write_error(struct nfsd_file *nf) ++{ ++ struct file *file = nf->nf_file; ++ ++ if (!file || !(file->f_mode & FMODE_WRITE)) ++ return 0; ++ return filemap_check_wb_err(file->f_mapping, READ_ONCE(file->f_wb_err)); ++} ++ ++static void ++nfsd_file_hash_remove(struct nfsd_file *nf) ++{ ++ trace_nfsd_file_unhash(nf); ++ ++ if (nfsd_file_check_write_error(nf)) ++ nfsd_reset_write_verifier(net_generic(nf->nf_net, nfsd_net_id)); ++ rhashtable_remove_fast(&nfsd_file_rhash_tbl, &nf->nf_rhash, ++ nfsd_file_rhash_params); ++} ++ ++static bool ++nfsd_file_unhash(struct nfsd_file *nf) ++{ ++ if (test_and_clear_bit(NFSD_FILE_HASHED, &nf->nf_flags)) { ++ nfsd_file_hash_remove(nf); ++ return true; ++ } ++ return false; ++} ++ + static bool + nfsd_file_free(struct nfsd_file *nf) + { + s64 age = ktime_to_ms(ktime_sub(ktime_get(), nf->nf_birthtime)); + bool flush = false; + ++ trace_nfsd_file_free(nf); ++ + this_cpu_inc(nfsd_file_releases); + this_cpu_add(nfsd_file_total_age, age); + +- trace_nfsd_file_put_final(nf); + if (nf->nf_mark) + nfsd_file_mark_put(nf->nf_mark); + if (nf->nf_file) { +@@ -377,27 +420,6 @@ nfsd_file_check_writeback(struct nfsd_file *nf) + mapping_tagged(mapping, PAGECACHE_TAG_WRITEBACK); + } + +-static int +-nfsd_file_check_write_error(struct nfsd_file *nf) +-{ +- struct file *file = nf->nf_file; +- +- if (!file || !(file->f_mode & FMODE_WRITE)) +- return 0; +- return filemap_check_wb_err(file->f_mapping, READ_ONCE(file->f_wb_err)); +-} +- +-static void +-nfsd_file_flush(struct nfsd_file *nf) +-{ +- struct file *file = nf->nf_file; +- +- if (!file || !(file->f_mode & FMODE_WRITE)) +- return; +- if (vfs_fsync(file, 1) != 0) +- nfsd_reset_write_verifier(net_generic(nf->nf_net, nfsd_net_id)); +-} +- + static void nfsd_file_lru_add(struct nfsd_file *nf) + { + set_bit(NFSD_FILE_REFERENCED, &nf->nf_flags); +@@ -411,31 +433,18 @@ static void nfsd_file_lru_remove(struct nfsd_file *nf) + trace_nfsd_file_lru_del(nf); + } + +-static void +-nfsd_file_hash_remove(struct nfsd_file *nf) +-{ +- trace_nfsd_file_unhash(nf); +- +- if (nfsd_file_check_write_error(nf)) +- nfsd_reset_write_verifier(net_generic(nf->nf_net, nfsd_net_id)); +- rhashtable_remove_fast(&nfsd_file_rhash_tbl, &nf->nf_rhash, +- nfsd_file_rhash_params); +-} +- +-static bool +-nfsd_file_unhash(struct nfsd_file *nf) ++struct nfsd_file * ++nfsd_file_get(struct nfsd_file *nf) + { +- if (test_and_clear_bit(NFSD_FILE_HASHED, &nf->nf_flags)) { +- nfsd_file_hash_remove(nf); +- return true; +- } +- return false; ++ if (likely(refcount_inc_not_zero(&nf->nf_ref))) ++ return nf; ++ return NULL; + } + + static void +-nfsd_file_unhash_and_dispose(struct nfsd_file *nf, struct list_head *dispose) ++nfsd_file_unhash_and_queue(struct nfsd_file *nf, struct list_head *dispose) + { +- trace_nfsd_file_unhash_and_dispose(nf); ++ trace_nfsd_file_unhash_and_queue(nf); + if (nfsd_file_unhash(nf)) { + /* caller must call nfsd_file_dispose_list() later */ + nfsd_file_lru_remove(nf); +@@ -473,7 +482,7 @@ nfsd_file_put(struct nfsd_file *nf) + nfsd_file_unhash_and_put(nf); + + if (!test_bit(NFSD_FILE_HASHED, &nf->nf_flags)) { +- nfsd_file_flush(nf); ++ nfsd_file_fsync(nf); + nfsd_file_put_noref(nf); + } else if (nf->nf_file && test_bit(NFSD_FILE_GC, &nf->nf_flags)) { + nfsd_file_put_noref(nf); +@@ -482,14 +491,6 @@ nfsd_file_put(struct nfsd_file *nf) + nfsd_file_put_noref(nf); + } + +-struct nfsd_file * +-nfsd_file_get(struct nfsd_file *nf) +-{ +- if (likely(refcount_inc_not_zero(&nf->nf_ref))) +- return nf; +- return NULL; +-} +- + static void + nfsd_file_dispose_list(struct list_head *dispose) + { +@@ -498,7 +499,7 @@ nfsd_file_dispose_list(struct list_head *dispose) + while(!list_empty(dispose)) { + nf = list_first_entry(dispose, struct nfsd_file, nf_lru); + list_del_init(&nf->nf_lru); +- nfsd_file_flush(nf); ++ nfsd_file_fsync(nf); + nfsd_file_put_noref(nf); + } + } +@@ -512,7 +513,7 @@ nfsd_file_dispose_list_sync(struct list_head *dispose) + while(!list_empty(dispose)) { + nf = list_first_entry(dispose, struct nfsd_file, nf_lru); + list_del_init(&nf->nf_lru); +- nfsd_file_flush(nf); ++ nfsd_file_fsync(nf); + if (!refcount_dec_and_test(&nf->nf_ref)) + continue; + if (nfsd_file_free(nf)) +@@ -712,7 +713,7 @@ __nfsd_file_close_inode(struct inode *inode, struct list_head *dispose) + nfsd_file_rhash_params); + if (!nf) + break; +- nfsd_file_unhash_and_dispose(nf, dispose); ++ nfsd_file_unhash_and_queue(nf, dispose); + count++; + } while (1); + rcu_read_unlock(); +@@ -914,7 +915,7 @@ __nfsd_file_cache_purge(struct net *net) + nf = rhashtable_walk_next(&iter); + while (!IS_ERR_OR_NULL(nf)) { + if (!net || nf->nf_net == net) +- nfsd_file_unhash_and_dispose(nf, &dispose); ++ nfsd_file_unhash_and_queue(nf, &dispose); + nf = rhashtable_walk_next(&iter); + } + +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index 191b206379b76..5faec08ac7cf7 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -819,10 +819,10 @@ DEFINE_EVENT(nfsd_file_class, name, \ + TP_PROTO(struct nfsd_file *nf), \ + TP_ARGS(nf)) + +-DEFINE_NFSD_FILE_EVENT(nfsd_file_put_final); ++DEFINE_NFSD_FILE_EVENT(nfsd_file_free); + DEFINE_NFSD_FILE_EVENT(nfsd_file_unhash); + DEFINE_NFSD_FILE_EVENT(nfsd_file_put); +-DEFINE_NFSD_FILE_EVENT(nfsd_file_unhash_and_dispose); ++DEFINE_NFSD_FILE_EVENT(nfsd_file_unhash_and_queue); + + TRACE_EVENT(nfsd_file_alloc, + TP_PROTO( +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-boolean-fields-in-struct-nfsd4_copy.patch b/queue-5.10/nfsd-replace-boolean-fields-in-struct-nfsd4_copy.patch new file mode 100644 index 00000000000..22b8f92484f --- /dev/null +++ b/queue-5.10/nfsd-replace-boolean-fields-in-struct-nfsd4_copy.patch @@ -0,0 +1,276 @@ +From c33f340db36b221e19ba0f38e80f8e3e94913439 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 Jul 2022 14:40:41 -0400 +Subject: NFSD: Replace boolean fields in struct nfsd4_copy + +From: Chuck Lever + +[ Upstream commit 1913cdf56cb5bfbc8170873728d13598cbecda23 ] + +Clean up: saves 8 bytes, and we can replace check_and_set_stop_copy() +with an atomic bitop. + +[ cel: adjusted to apply to v5.10.y ] +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 49 +++++++++++++++++----------------------------- + fs/nfsd/nfs4xdr.c | 12 ++++++------ + fs/nfsd/xdr4.h | 33 ++++++++++++++++++++++++++----- + 3 files changed, 52 insertions(+), 42 deletions(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 64879350ccbda..a4bc096e509d4 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -1295,23 +1295,9 @@ static void nfs4_put_copy(struct nfsd4_copy *copy) + kfree(copy); + } + +-static bool +-check_and_set_stop_copy(struct nfsd4_copy *copy) +-{ +- bool value; +- +- spin_lock(©->cp_clp->async_lock); +- value = copy->stopped; +- if (!copy->stopped) +- copy->stopped = true; +- spin_unlock(©->cp_clp->async_lock); +- return value; +-} +- + static void nfsd4_stop_copy(struct nfsd4_copy *copy) + { +- /* only 1 thread should stop the copy */ +- if (!check_and_set_stop_copy(copy)) ++ if (!test_and_set_bit(NFSD4_COPY_F_STOPPED, ©->cp_flags)) + kthread_stop(copy->copy_task); + nfs4_put_copy(copy); + } +@@ -1668,8 +1654,9 @@ static const struct nfsd4_callback_ops nfsd4_cb_offload_ops = { + static void nfsd4_init_copy_res(struct nfsd4_copy *copy, bool sync) + { + copy->cp_res.wr_stable_how = +- copy->committed ? NFS_FILE_SYNC : NFS_UNSTABLE; +- copy->cp_synchronous = sync; ++ test_bit(NFSD4_COPY_F_COMMITTED, ©->cp_flags) ? ++ NFS_FILE_SYNC : NFS_UNSTABLE; ++ nfsd4_copy_set_sync(copy, sync); + gen_boot_verifier(©->cp_res.wr_verifier, copy->cp_clp->net); + } + +@@ -1698,16 +1685,16 @@ static ssize_t _nfsd_copy_file_range(struct nfsd4_copy *copy) + copy->cp_res.wr_bytes_written += bytes_copied; + src_pos += bytes_copied; + dst_pos += bytes_copied; +- } while (bytes_total > 0 && !copy->cp_synchronous); ++ } while (bytes_total > 0 && nfsd4_copy_is_async(copy)); + /* for a non-zero asynchronous copy do a commit of data */ +- if (!copy->cp_synchronous && copy->cp_res.wr_bytes_written > 0) { ++ if (nfsd4_copy_is_async(copy) && copy->cp_res.wr_bytes_written > 0) { + since = READ_ONCE(dst->f_wb_err); + status = vfs_fsync_range(dst, copy->cp_dst_pos, + copy->cp_res.wr_bytes_written, 0); + if (!status) + status = filemap_check_wb_err(dst->f_mapping, since); + if (!status) +- copy->committed = true; ++ set_bit(NFSD4_COPY_F_COMMITTED, ©->cp_flags); + } + return bytes_copied; + } +@@ -1728,7 +1715,7 @@ static __be32 nfsd4_do_copy(struct nfsd4_copy *copy, bool sync) + status = nfs_ok; + } + +- if (!copy->cp_intra) /* Inter server SSC */ ++ if (nfsd4_ssc_is_inter(copy)) + nfsd4_cleanup_inter_ssc(copy->ss_mnt, copy->nf_src, + copy->nf_dst); + else +@@ -1742,13 +1729,13 @@ static void dup_copy_fields(struct nfsd4_copy *src, struct nfsd4_copy *dst) + dst->cp_src_pos = src->cp_src_pos; + dst->cp_dst_pos = src->cp_dst_pos; + dst->cp_count = src->cp_count; +- dst->cp_synchronous = src->cp_synchronous; ++ dst->cp_flags = src->cp_flags; + memcpy(&dst->cp_res, &src->cp_res, sizeof(src->cp_res)); + memcpy(&dst->fh, &src->fh, sizeof(src->fh)); + dst->cp_clp = src->cp_clp; + dst->nf_dst = nfsd_file_get(src->nf_dst); +- dst->cp_intra = src->cp_intra; +- if (src->cp_intra) /* for inter, file_src doesn't exist yet */ ++ /* for inter, nf_src doesn't exist yet */ ++ if (!nfsd4_ssc_is_inter(src)) + dst->nf_src = nfsd_file_get(src->nf_src); + + memcpy(&dst->cp_stateid, &src->cp_stateid, sizeof(src->cp_stateid)); +@@ -1762,7 +1749,7 @@ static void cleanup_async_copy(struct nfsd4_copy *copy) + { + nfs4_free_copy_state(copy); + nfsd_file_put(copy->nf_dst); +- if (copy->cp_intra) ++ if (!nfsd4_ssc_is_inter(copy)) + nfsd_file_put(copy->nf_src); + spin_lock(©->cp_clp->async_lock); + list_del(©->copies); +@@ -1775,7 +1762,7 @@ static int nfsd4_do_async_copy(void *data) + struct nfsd4_copy *copy = (struct nfsd4_copy *)data; + struct nfsd4_copy *cb_copy; + +- if (!copy->cp_intra) { /* Inter server SSC */ ++ if (nfsd4_ssc_is_inter(copy)) { + copy->nf_src = kzalloc(sizeof(struct nfsd_file), GFP_KERNEL); + if (!copy->nf_src) { + copy->nfserr = nfserr_serverfault; +@@ -1807,7 +1794,7 @@ static int nfsd4_do_async_copy(void *data) + ©->fh, copy->cp_count, copy->nfserr); + nfsd4_run_cb(&cb_copy->cp_cb); + out: +- if (!copy->cp_intra) ++ if (nfsd4_ssc_is_inter(copy)) + kfree(copy->nf_src); + cleanup_async_copy(copy); + return 0; +@@ -1821,8 +1808,8 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + __be32 status; + struct nfsd4_copy *async_copy = NULL; + +- if (!copy->cp_intra) { /* Inter server SSC */ +- if (!inter_copy_offload_enable || copy->cp_synchronous) { ++ if (nfsd4_ssc_is_inter(copy)) { ++ if (!inter_copy_offload_enable || nfsd4_copy_is_sync(copy)) { + status = nfserr_notsupp; + goto out; + } +@@ -1839,7 +1826,7 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + copy->cp_clp = cstate->clp; + memcpy(©->fh, &cstate->current_fh.fh_handle, + sizeof(struct knfsd_fh)); +- if (!copy->cp_synchronous) { ++ if (nfsd4_copy_is_async(copy)) { + struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); + + status = nfserrno(-ENOMEM); +@@ -2605,7 +2592,7 @@ check_if_stalefh_allowed(struct nfsd4_compoundargs *args) + return; + } + putfh = (struct nfsd4_putfh *)&saved_op->u; +- if (!copy->cp_intra) ++ if (nfsd4_ssc_is_inter(copy)) + putfh->no_verify = true; + } + } +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 890f1009bd4ca..5476541530ead 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -1896,8 +1896,8 @@ static __be32 nfsd4_decode_nl4_server(struct nfsd4_compoundargs *argp, + static __be32 + nfsd4_decode_copy(struct nfsd4_compoundargs *argp, struct nfsd4_copy *copy) + { ++ u32 consecutive, i, count, sync; + struct nl4_server *ns_dummy; +- u32 consecutive, i, count; + __be32 status; + + status = nfsd4_decode_stateid4(argp, ©->cp_src_stateid); +@@ -1915,17 +1915,17 @@ nfsd4_decode_copy(struct nfsd4_compoundargs *argp, struct nfsd4_copy *copy) + /* ca_consecutive: we always do consecutive copies */ + if (xdr_stream_decode_u32(argp->xdr, &consecutive) < 0) + return nfserr_bad_xdr; +- if (xdr_stream_decode_u32(argp->xdr, ©->cp_synchronous) < 0) ++ if (xdr_stream_decode_bool(argp->xdr, &sync) < 0) + return nfserr_bad_xdr; ++ nfsd4_copy_set_sync(copy, sync); + + if (xdr_stream_decode_u32(argp->xdr, &count) < 0) + return nfserr_bad_xdr; + copy->cp_src = svcxdr_tmpalloc(argp, sizeof(*copy->cp_src)); + if (copy->cp_src == NULL) + return nfserr_jukebox; +- copy->cp_intra = false; + if (count == 0) { /* intra-server copy */ +- copy->cp_intra = true; ++ __set_bit(NFSD4_COPY_F_INTRA, ©->cp_flags); + return nfs_ok; + } + +@@ -4712,13 +4712,13 @@ nfsd4_encode_copy(struct nfsd4_compoundres *resp, __be32 nfserr, + __be32 *p; + + nfserr = nfsd42_encode_write_res(resp, ©->cp_res, +- !!copy->cp_synchronous); ++ nfsd4_copy_is_sync(copy)); + if (nfserr) + return nfserr; + + p = xdr_reserve_space(resp->xdr, 4 + 4); + *p++ = xdr_one; /* cr_consecutive */ +- *p++ = cpu_to_be32(copy->cp_synchronous); ++ *p = nfsd4_copy_is_sync(copy) ? xdr_one : xdr_zero; + return 0; + } + +diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h +index 621937fae9acb..1f6ac92bcf856 100644 +--- a/fs/nfsd/xdr4.h ++++ b/fs/nfsd/xdr4.h +@@ -541,10 +541,12 @@ struct nfsd4_copy { + u64 cp_dst_pos; + u64 cp_count; + struct nl4_server *cp_src; +- bool cp_intra; + +- /* both */ +- u32 cp_synchronous; ++ unsigned long cp_flags; ++#define NFSD4_COPY_F_STOPPED (0) ++#define NFSD4_COPY_F_INTRA (1) ++#define NFSD4_COPY_F_SYNCHRONOUS (2) ++#define NFSD4_COPY_F_COMMITTED (3) + + /* response */ + struct nfsd42_write_res cp_res; +@@ -564,14 +566,35 @@ struct nfsd4_copy { + struct list_head copies; + struct task_struct *copy_task; + refcount_t refcount; +- bool stopped; + + struct vfsmount *ss_mnt; + struct nfs_fh c_fh; + nfs4_stateid stateid; +- bool committed; + }; + ++static inline void nfsd4_copy_set_sync(struct nfsd4_copy *copy, bool sync) ++{ ++ if (sync) ++ set_bit(NFSD4_COPY_F_SYNCHRONOUS, ©->cp_flags); ++ else ++ clear_bit(NFSD4_COPY_F_SYNCHRONOUS, ©->cp_flags); ++} ++ ++static inline bool nfsd4_copy_is_sync(const struct nfsd4_copy *copy) ++{ ++ return test_bit(NFSD4_COPY_F_SYNCHRONOUS, ©->cp_flags); ++} ++ ++static inline bool nfsd4_copy_is_async(const struct nfsd4_copy *copy) ++{ ++ return !test_bit(NFSD4_COPY_F_SYNCHRONOUS, ©->cp_flags); ++} ++ ++static inline bool nfsd4_ssc_is_inter(const struct nfsd4_copy *copy) ++{ ++ return !test_bit(NFSD4_COPY_F_INTRA, ©->cp_flags); ++} ++ + struct nfsd4_seek { + /* request */ + stateid_t seek_stateid; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-delayed_work-with-work_struct-for-nfsd_.patch b/queue-5.10/nfsd-replace-delayed_work-with-work_struct-for-nfsd_.patch new file mode 100644 index 00000000000..c76b6e0cbac --- /dev/null +++ b/queue-5.10/nfsd-replace-delayed_work-with-work_struct-for-nfsd_.patch @@ -0,0 +1,81 @@ +From 7df7626b13b9a34478ae503880ba885421cd1413 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Jan 2023 16:06:51 -0800 +Subject: NFSD: replace delayed_work with work_struct for nfsd_client_shrinker + +From: Dai Ngo + +[ Upstream commit 7c24fa225081f31bc6da6a355c1ba801889ab29a ] + +Since nfsd4_state_shrinker_count always calls mod_delayed_work with +0 delay, we can replace delayed_work with work_struct to save some +space and overhead. + +Also add the call to cancel_work after unregister the shrinker +in nfs4_state_shutdown_net. + +Signed-off-by: Dai Ngo +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/netns.h | 2 +- + fs/nfsd/nfs4state.c | 8 ++++---- + 2 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h +index 8c854ba3285bb..51a4b7885cae2 100644 +--- a/fs/nfsd/netns.h ++++ b/fs/nfsd/netns.h +@@ -195,7 +195,7 @@ struct nfsd_net { + + atomic_t nfsd_courtesy_clients; + struct shrinker nfsd_client_shrinker; +- struct delayed_work nfsd_shrinker_work; ++ struct work_struct nfsd_shrinker_work; + }; + + /* Simple check to find out if a given net was properly initialized */ +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index f2647cbc108e3..3dd64caf06158 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -4410,7 +4410,7 @@ nfsd4_state_shrinker_count(struct shrinker *shrink, struct shrink_control *sc) + if (!count) + count = atomic_long_read(&num_delegations); + if (count) +- mod_delayed_work(laundry_wq, &nn->nfsd_shrinker_work, 0); ++ queue_work(laundry_wq, &nn->nfsd_shrinker_work); + return (unsigned long)count; + } + +@@ -6223,8 +6223,7 @@ deleg_reaper(struct nfsd_net *nn) + static void + nfsd4_state_shrinker_worker(struct work_struct *work) + { +- struct delayed_work *dwork = to_delayed_work(work); +- struct nfsd_net *nn = container_of(dwork, struct nfsd_net, ++ struct nfsd_net *nn = container_of(work, struct nfsd_net, + nfsd_shrinker_work); + + courtesy_client_reaper(nn); +@@ -8066,7 +8065,7 @@ static int nfs4_state_create_net(struct net *net) + INIT_LIST_HEAD(&nn->blocked_locks_lru); + + INIT_DELAYED_WORK(&nn->laundromat_work, laundromat_main); +- INIT_DELAYED_WORK(&nn->nfsd_shrinker_work, nfsd4_state_shrinker_worker); ++ INIT_WORK(&nn->nfsd_shrinker_work, nfsd4_state_shrinker_worker); + get_net(net); + + nn->nfsd_client_shrinker.scan_objects = nfsd4_state_shrinker_scan; +@@ -8173,6 +8172,7 @@ nfs4_state_shutdown_net(struct net *net) + struct nfsd_net *nn = net_generic(net, nfsd_net_id); + + unregister_shrinker(&nn->nfsd_client_shrinker); ++ cancel_work(&nn->nfsd_shrinker_work); + cancel_delayed_work_sync(&nn->laundromat_work); + locks_end_grace(&nn->nfsd4_manager); + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_access.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_access.patch new file mode 100644 index 00000000000..2e2ffc3c329 --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_access.patch @@ -0,0 +1,60 @@ +From fe5691408fcf8c5d460744722c44cc5d983a5786 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Nov 2020 13:12:27 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_access() + +From: Chuck Lever + +[ Upstream commit d169a6a9e5fd7f9e4b74e5e5d2e5a4fd0f84ef05 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 24 +++++++++++++----------- + 1 file changed, 13 insertions(+), 11 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 8c694844f0efb..f3d54af9de92a 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -439,17 +439,6 @@ nfsd4_decode_stateid(struct nfsd4_compoundargs *argp, stateid_t *sid) + DECODE_TAIL; + } + +-static __be32 +-nfsd4_decode_access(struct nfsd4_compoundargs *argp, struct nfsd4_access *access) +-{ +- DECODE_HEAD; +- +- READ_BUF(4); +- access->ac_req_access = be32_to_cpup(p++); +- +- DECODE_TAIL; +-} +- + static __be32 nfsd4_decode_cb_sec(struct nfsd4_compoundargs *argp, struct nfsd4_cb_sec *cbs) + { + DECODE_HEAD; +@@ -531,6 +520,19 @@ static __be32 nfsd4_decode_cb_sec(struct nfsd4_compoundargs *argp, struct nfsd4_ + DECODE_TAIL; + } + ++/* ++ * NFSv4 operation argument decoders ++ */ ++ ++static __be32 ++nfsd4_decode_access(struct nfsd4_compoundargs *argp, ++ struct nfsd4_access *access) ++{ ++ if (xdr_stream_decode_u32(argp->xdr, &access->ac_req_access) < 0) ++ return nfserr_bad_xdr; ++ return nfs_ok; ++} ++ + static __be32 nfsd4_decode_backchannel_ctl(struct nfsd4_compoundargs *argp, struct nfsd4_backchannel_ctl *bc) + { + DECODE_HEAD; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_backchannel.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_backchannel.patch new file mode 100644 index 00000000000..5f75ad95c5f --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_backchannel.patch @@ -0,0 +1,54 @@ +From 6693787fe1d0dcdddac14fb9ba5bc8ff11a13c40 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Nov 2020 13:14:35 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_backchannel_ctl() + +From: Chuck Lever + +[ Upstream commit 0f81d96098f8eb707afe2f8d5c3fe0f9316ef5ce ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 18 +++++++----------- + 1 file changed, 7 insertions(+), 11 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 6f3c86bee6211..efd1504cd02b6 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -788,17 +788,6 @@ nfsd4_decode_access(struct nfsd4_compoundargs *argp, + return nfs_ok; + } + +-static __be32 nfsd4_decode_backchannel_ctl(struct nfsd4_compoundargs *argp, struct nfsd4_backchannel_ctl *bc) +-{ +- DECODE_HEAD; +- +- READ_BUF(4); +- bc->bc_cb_program = be32_to_cpup(p++); +- nfsd4_decode_cb_sec(argp, &bc->bc_cb_sec); +- +- DECODE_TAIL; +-} +- + static __be32 nfsd4_decode_bind_conn_to_session(struct nfsd4_compoundargs *argp, struct nfsd4_bind_conn_to_session *bcts) + { + DECODE_HEAD; +@@ -1483,6 +1472,13 @@ nfsd4_decode_release_lockowner(struct nfsd4_compoundargs *argp, struct nfsd4_rel + return nfs_ok; + } + ++static __be32 nfsd4_decode_backchannel_ctl(struct nfsd4_compoundargs *argp, struct nfsd4_backchannel_ctl *bc) ++{ ++ if (xdr_stream_decode_u32(argp->xdr, &bc->bc_cb_program) < 0) ++ return nfserr_bad_xdr; ++ return nfsd4_decode_cb_sec(argp, &bc->bc_cb_sec); ++} ++ + static __be32 + nfsd4_decode_exchange_id(struct nfsd4_compoundargs *argp, + struct nfsd4_exchange_id *exid) +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_bind_conn_t.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_bind_conn_t.patch new file mode 100644 index 00000000000..4e7c360a2b6 --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_bind_conn_t.patch @@ -0,0 +1,87 @@ +From 6d6ea9981ef49e6384d0ace5837a254b582d4f0c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Nov 2020 13:16:23 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_bind_conn_to_session() + +From: Chuck Lever + +[ Upstream commit 571e0451c4de0a545960ffaea16d969931afc563 ] + +A dedicated sessionid4 decoder is introduced that will be used by +other operation decoders in subsequent patches. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 41 +++++++++++++++++++++++++++++------------ + 1 file changed, 29 insertions(+), 12 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index efd1504cd02b6..5dad32ab02ec4 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -664,6 +664,19 @@ nfsd4_decode_state_owner4(struct nfsd4_compoundargs *argp, + return nfsd4_decode_opaque(argp, owner); + } + ++static __be32 ++nfsd4_decode_sessionid4(struct nfsd4_compoundargs *argp, ++ struct nfs4_sessionid *sessionid) ++{ ++ __be32 *p; ++ ++ p = xdr_inline_decode(argp->xdr, NFS4_MAX_SESSIONID_LEN); ++ if (!p) ++ return nfserr_bad_xdr; ++ memcpy(sessionid->data, p, sizeof(sessionid->data)); ++ return nfs_ok; ++} ++ + /* Defined in Appendix A of RFC 5531 */ + static __be32 + nfsd4_decode_authsys_parms(struct nfsd4_compoundargs *argp, +@@ -788,18 +801,6 @@ nfsd4_decode_access(struct nfsd4_compoundargs *argp, + return nfs_ok; + } + +-static __be32 nfsd4_decode_bind_conn_to_session(struct nfsd4_compoundargs *argp, struct nfsd4_bind_conn_to_session *bcts) +-{ +- DECODE_HEAD; +- +- READ_BUF(NFS4_MAX_SESSIONID_LEN + 8); +- COPYMEM(bcts->sessionid.data, NFS4_MAX_SESSIONID_LEN); +- bcts->dir = be32_to_cpup(p++); +- /* XXX: skipping ctsa_use_conn_in_rdma_mode. Perhaps Tom Tucker +- * could help us figure out we should be using it. */ +- DECODE_TAIL; +-} +- + static __be32 + nfsd4_decode_close(struct nfsd4_compoundargs *argp, struct nfsd4_close *close) + { +@@ -1479,6 +1480,22 @@ static __be32 nfsd4_decode_backchannel_ctl(struct nfsd4_compoundargs *argp, stru + return nfsd4_decode_cb_sec(argp, &bc->bc_cb_sec); + } + ++static __be32 nfsd4_decode_bind_conn_to_session(struct nfsd4_compoundargs *argp, struct nfsd4_bind_conn_to_session *bcts) ++{ ++ u32 use_conn_in_rdma_mode; ++ __be32 status; ++ ++ status = nfsd4_decode_sessionid4(argp, &bcts->sessionid); ++ if (status) ++ return status; ++ if (xdr_stream_decode_u32(argp->xdr, &bcts->dir) < 0) ++ return nfserr_bad_xdr; ++ if (xdr_stream_decode_u32(argp->xdr, &use_conn_in_rdma_mode) < 0) ++ return nfserr_bad_xdr; ++ ++ return nfs_ok; ++} ++ + static __be32 + nfsd4_decode_exchange_id(struct nfsd4_compoundargs *argp, + struct nfsd4_exchange_id *exid) +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_cb_sec.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_cb_sec.patch new file mode 100644 index 00000000000..568242ce0e3 --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_cb_sec.patch @@ -0,0 +1,224 @@ +From f6351d2ae822e166340444777a65ed63d7bbe516 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Nov 2020 13:09:34 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_cb_sec() + +From: Chuck Lever + +[ Upstream commit 1a99440807bfc66597aaa2e0f0213c319b023e34 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 165 ++++++++++++++++++++++++++++++---------------- + 1 file changed, 107 insertions(+), 58 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index cc406b7a530b6..6f3c86bee6211 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -212,6 +212,25 @@ static char *savemem(struct nfsd4_compoundargs *argp, __be32 *p, int nbytes) + * NFSv4 basic data type decoders + */ + ++/* ++ * This helper handles variable-length opaques which belong to protocol ++ * elements that this implementation does not support. ++ */ ++static __be32 ++nfsd4_decode_ignored_string(struct nfsd4_compoundargs *argp, u32 maxlen) ++{ ++ u32 len; ++ ++ if (xdr_stream_decode_u32(argp->xdr, &len) < 0) ++ return nfserr_bad_xdr; ++ if (maxlen && len > maxlen) ++ return nfserr_bad_xdr; ++ if (!xdr_inline_decode(argp->xdr, len)) ++ return nfserr_bad_xdr; ++ ++ return nfs_ok; ++} ++ + static __be32 + nfsd4_decode_opaque(struct nfsd4_compoundargs *argp, struct xdr_netobj *o) + { +@@ -645,87 +664,117 @@ nfsd4_decode_state_owner4(struct nfsd4_compoundargs *argp, + return nfsd4_decode_opaque(argp, owner); + } + +-static __be32 nfsd4_decode_cb_sec(struct nfsd4_compoundargs *argp, struct nfsd4_cb_sec *cbs) ++/* Defined in Appendix A of RFC 5531 */ ++static __be32 ++nfsd4_decode_authsys_parms(struct nfsd4_compoundargs *argp, ++ struct nfsd4_cb_sec *cbs) + { +- DECODE_HEAD; +- struct user_namespace *userns = nfsd_user_namespace(argp->rqstp); +- u32 dummy, uid, gid; +- char *machine_name; +- int i; +- int nr_secflavs; ++ u32 stamp, gidcount, uid, gid; ++ __be32 *p, status; ++ ++ if (xdr_stream_decode_u32(argp->xdr, &stamp) < 0) ++ return nfserr_bad_xdr; ++ /* machine name */ ++ status = nfsd4_decode_ignored_string(argp, 255); ++ if (status) ++ return status; ++ if (xdr_stream_decode_u32(argp->xdr, &uid) < 0) ++ return nfserr_bad_xdr; ++ if (xdr_stream_decode_u32(argp->xdr, &gid) < 0) ++ return nfserr_bad_xdr; ++ if (xdr_stream_decode_u32(argp->xdr, &gidcount) < 0) ++ return nfserr_bad_xdr; ++ if (gidcount > 16) ++ return nfserr_bad_xdr; ++ p = xdr_inline_decode(argp->xdr, gidcount << 2); ++ if (!p) ++ return nfserr_bad_xdr; ++ if (cbs->flavor == (u32)(-1)) { ++ struct user_namespace *userns = nfsd_user_namespace(argp->rqstp); ++ ++ kuid_t kuid = make_kuid(userns, uid); ++ kgid_t kgid = make_kgid(userns, gid); ++ if (uid_valid(kuid) && gid_valid(kgid)) { ++ cbs->uid = kuid; ++ cbs->gid = kgid; ++ cbs->flavor = RPC_AUTH_UNIX; ++ } else { ++ dprintk("RPC_AUTH_UNIX with invalid uid or gid, ignoring!\n"); ++ } ++ } ++ ++ return nfs_ok; ++} ++ ++static __be32 ++nfsd4_decode_gss_cb_handles4(struct nfsd4_compoundargs *argp, ++ struct nfsd4_cb_sec *cbs) ++{ ++ __be32 status; ++ u32 service; ++ ++ dprintk("RPC_AUTH_GSS callback secflavor not supported!\n"); ++ ++ if (xdr_stream_decode_u32(argp->xdr, &service) < 0) ++ return nfserr_bad_xdr; ++ if (service < RPC_GSS_SVC_NONE || service > RPC_GSS_SVC_PRIVACY) ++ return nfserr_bad_xdr; ++ /* gcbp_handle_from_server */ ++ status = nfsd4_decode_ignored_string(argp, 0); ++ if (status) ++ return status; ++ /* gcbp_handle_from_client */ ++ status = nfsd4_decode_ignored_string(argp, 0); ++ if (status) ++ return status; ++ ++ return nfs_ok; ++} ++ ++/* a counted array of callback_sec_parms4 items */ ++static __be32 ++nfsd4_decode_cb_sec(struct nfsd4_compoundargs *argp, struct nfsd4_cb_sec *cbs) ++{ ++ u32 i, secflavor, nr_secflavs; ++ __be32 status; + + /* callback_sec_params4 */ +- READ_BUF(4); +- nr_secflavs = be32_to_cpup(p++); ++ if (xdr_stream_decode_u32(argp->xdr, &nr_secflavs) < 0) ++ return nfserr_bad_xdr; + if (nr_secflavs) + cbs->flavor = (u32)(-1); + else + /* Is this legal? Be generous, take it to mean AUTH_NONE: */ + cbs->flavor = 0; ++ + for (i = 0; i < nr_secflavs; ++i) { +- READ_BUF(4); +- dummy = be32_to_cpup(p++); +- switch (dummy) { ++ if (xdr_stream_decode_u32(argp->xdr, &secflavor) < 0) ++ return nfserr_bad_xdr; ++ switch (secflavor) { + case RPC_AUTH_NULL: +- /* Nothing to read */ ++ /* void */ + if (cbs->flavor == (u32)(-1)) + cbs->flavor = RPC_AUTH_NULL; + break; + case RPC_AUTH_UNIX: +- READ_BUF(8); +- /* stamp */ +- dummy = be32_to_cpup(p++); +- +- /* machine name */ +- dummy = be32_to_cpup(p++); +- READ_BUF(dummy); +- SAVEMEM(machine_name, dummy); +- +- /* uid, gid */ +- READ_BUF(8); +- uid = be32_to_cpup(p++); +- gid = be32_to_cpup(p++); +- +- /* more gids */ +- READ_BUF(4); +- dummy = be32_to_cpup(p++); +- READ_BUF(dummy * 4); +- if (cbs->flavor == (u32)(-1)) { +- kuid_t kuid = make_kuid(userns, uid); +- kgid_t kgid = make_kgid(userns, gid); +- if (uid_valid(kuid) && gid_valid(kgid)) { +- cbs->uid = kuid; +- cbs->gid = kgid; +- cbs->flavor = RPC_AUTH_UNIX; +- } else { +- dprintk("RPC_AUTH_UNIX with invalid" +- "uid or gid ignoring!\n"); +- } +- } ++ status = nfsd4_decode_authsys_parms(argp, cbs); ++ if (status) ++ return status; + break; + case RPC_AUTH_GSS: +- dprintk("RPC_AUTH_GSS callback secflavor " +- "not supported!\n"); +- READ_BUF(8); +- /* gcbp_service */ +- dummy = be32_to_cpup(p++); +- /* gcbp_handle_from_server */ +- dummy = be32_to_cpup(p++); +- READ_BUF(dummy); +- p += XDR_QUADLEN(dummy); +- /* gcbp_handle_from_client */ +- READ_BUF(4); +- dummy = be32_to_cpup(p++); +- READ_BUF(dummy); ++ status = nfsd4_decode_gss_cb_handles4(argp, cbs); ++ if (status) ++ return status; + break; + default: +- dprintk("Illegal callback secflavor\n"); + return nfserr_inval; + } + } +- DECODE_TAIL; ++ ++ return nfs_ok; + } + ++ + /* + * NFSv4 operation argument decoders + */ +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_clone.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_clone.patch new file mode 100644 index 00000000000..8d484b6aeb8 --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_clone.patch @@ -0,0 +1,95 @@ +From 52d3ed364eb5d4d29e5caabc9d53392c5decac7e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Nov 2020 10:46:46 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_clone() + +From: Chuck Lever + +[ Upstream commit 3dfd0b0e15671e2b4047ccb9222432f0b2d930be ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 52 +++++++++++++++++++---------------------------- + 1 file changed, 21 insertions(+), 31 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 2e2fae7e38db2..bf2a2ef6a8b97 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -575,18 +575,6 @@ nfsd4_decode_fattr4(struct nfsd4_compoundargs *argp, u32 *bmval, u32 bmlen, + return nfs_ok; + } + +-static __be32 +-nfsd4_decode_stateid(struct nfsd4_compoundargs *argp, stateid_t *sid) +-{ +- DECODE_HEAD; +- +- READ_BUF(sizeof(stateid_t)); +- sid->si_generation = be32_to_cpup(p++); +- COPYMEM(&sid->si_opaque, sizeof(stateid_opaque_t)); +- +- DECODE_TAIL; +-} +- + static __be32 + nfsd4_decode_stateid4(struct nfsd4_compoundargs *argp, stateid_t *sid) + { +@@ -1919,25 +1907,6 @@ nfsd4_decode_fallocate(struct nfsd4_compoundargs *argp, + return nfs_ok; + } + +-static __be32 +-nfsd4_decode_clone(struct nfsd4_compoundargs *argp, struct nfsd4_clone *clone) +-{ +- DECODE_HEAD; +- +- status = nfsd4_decode_stateid(argp, &clone->cl_src_stateid); +- if (status) +- return status; +- status = nfsd4_decode_stateid(argp, &clone->cl_dst_stateid); +- if (status) +- return status; +- +- READ_BUF(8 + 8 + 8); +- p = xdr_decode_hyper(p, &clone->cl_src_pos); +- p = xdr_decode_hyper(p, &clone->cl_dst_pos); +- p = xdr_decode_hyper(p, &clone->cl_count); +- DECODE_TAIL; +-} +- + static __be32 nfsd4_decode_nl4_server(struct nfsd4_compoundargs *argp, + struct nl4_server *ns) + { +@@ -2067,6 +2036,27 @@ nfsd4_decode_seek(struct nfsd4_compoundargs *argp, struct nfsd4_seek *seek) + return nfs_ok; + } + ++static __be32 ++nfsd4_decode_clone(struct nfsd4_compoundargs *argp, struct nfsd4_clone *clone) ++{ ++ __be32 status; ++ ++ status = nfsd4_decode_stateid4(argp, &clone->cl_src_stateid); ++ if (status) ++ return status; ++ status = nfsd4_decode_stateid4(argp, &clone->cl_dst_stateid); ++ if (status) ++ return status; ++ if (xdr_stream_decode_u64(argp->xdr, &clone->cl_src_pos) < 0) ++ return nfserr_bad_xdr; ++ if (xdr_stream_decode_u64(argp->xdr, &clone->cl_dst_pos) < 0) ++ return nfserr_bad_xdr; ++ if (xdr_stream_decode_u64(argp->xdr, &clone->cl_count) < 0) ++ return nfserr_bad_xdr; ++ ++ return nfs_ok; ++} ++ + /* + * XDR data that is more than PAGE_SIZE in size is normally part of a + * read or write. However, the size of extended attributes is limited +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_close.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_close.patch new file mode 100644 index 00000000000..46698ae549b --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_close.patch @@ -0,0 +1,59 @@ +From d471295a43d1107367ffcaa4377a836b98697f19 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Nov 2020 13:18:23 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_close() + +From: Chuck Lever + +[ Upstream commit d3d2f38154571e70d5806b5c5264bf61c101ea15 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 23 ++++++++++++++++------- + 1 file changed, 16 insertions(+), 7 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index f3d54af9de92a..ca02478534931 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -439,6 +439,19 @@ nfsd4_decode_stateid(struct nfsd4_compoundargs *argp, stateid_t *sid) + DECODE_TAIL; + } + ++static __be32 ++nfsd4_decode_stateid4(struct nfsd4_compoundargs *argp, stateid_t *sid) ++{ ++ __be32 *p; ++ ++ p = xdr_inline_decode(argp->xdr, NFS4_STATEID_SIZE); ++ if (!p) ++ return nfserr_bad_xdr; ++ sid->si_generation = be32_to_cpup(p++); ++ memcpy(&sid->si_opaque, p, sizeof(sid->si_opaque)); ++ return nfs_ok; ++} ++ + static __be32 nfsd4_decode_cb_sec(struct nfsd4_compoundargs *argp, struct nfsd4_cb_sec *cbs) + { + DECODE_HEAD; +@@ -559,13 +572,9 @@ static __be32 nfsd4_decode_bind_conn_to_session(struct nfsd4_compoundargs *argp, + static __be32 + nfsd4_decode_close(struct nfsd4_compoundargs *argp, struct nfsd4_close *close) + { +- DECODE_HEAD; +- +- READ_BUF(4); +- close->cl_seqid = be32_to_cpup(p++); +- return nfsd4_decode_stateid(argp, &close->cl_stateid); +- +- DECODE_TAIL; ++ if (xdr_stream_decode_u32(argp->xdr, &close->cl_seqid) < 0) ++ return nfserr_bad_xdr; ++ return nfsd4_decode_stateid4(argp, &close->cl_stateid); + } + + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_commit.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_commit.patch new file mode 100644 index 00000000000..8fdbd54e2b8 --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_commit.patch @@ -0,0 +1,74 @@ +From 516f14de291d78cdc039350910c7d7004d271aba Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Nov 2020 13:19:51 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_commit() + +From: Chuck Lever + +[ Upstream commit cbd9abb3706e96563b36af67595707a7054ab693 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 12 +++++------- + include/linux/sunrpc/xdr.h | 21 +++++++++++++++++++++ + 2 files changed, 26 insertions(+), 7 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index ca02478534931..8251b905d5479 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -581,13 +581,11 @@ nfsd4_decode_close(struct nfsd4_compoundargs *argp, struct nfsd4_close *close) + static __be32 + nfsd4_decode_commit(struct nfsd4_compoundargs *argp, struct nfsd4_commit *commit) + { +- DECODE_HEAD; +- +- READ_BUF(12); +- p = xdr_decode_hyper(p, &commit->co_offset); +- commit->co_count = be32_to_cpup(p++); +- +- DECODE_TAIL; ++ if (xdr_stream_decode_u64(argp->xdr, &commit->co_offset) < 0) ++ return nfserr_bad_xdr; ++ if (xdr_stream_decode_u32(argp->xdr, &commit->co_count) < 0) ++ return nfserr_bad_xdr; ++ return nfs_ok; + } + + static __be32 +diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h +index c03f7bf585c96..6b17575437474 100644 +--- a/include/linux/sunrpc/xdr.h ++++ b/include/linux/sunrpc/xdr.h +@@ -569,6 +569,27 @@ xdr_stream_decode_u32(struct xdr_stream *xdr, __u32 *ptr) + return 0; + } + ++/** ++ * xdr_stream_decode_u64 - Decode a 64-bit integer ++ * @xdr: pointer to xdr_stream ++ * @ptr: location to store 64-bit integer ++ * ++ * Return values: ++ * %0 on success ++ * %-EBADMSG on XDR buffer overflow ++ */ ++static inline ssize_t ++xdr_stream_decode_u64(struct xdr_stream *xdr, __u64 *ptr) ++{ ++ const size_t count = sizeof(*ptr); ++ __be32 *p = xdr_inline_decode(xdr, count); ++ ++ if (unlikely(!p)) ++ return -EBADMSG; ++ xdr_decode_hyper(p, ptr); ++ return 0; ++} ++ + /** + * xdr_stream_decode_opaque_fixed - Decode fixed length opaque xdr data + * @xdr: pointer to xdr_stream +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_compound.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_compound.patch new file mode 100644 index 00000000000..36a5717fc07 --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_compound.patch @@ -0,0 +1,154 @@ +From ccb7f62d0a0a668736a27bf38a93482b4c48e8ca Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Nov 2020 11:07:06 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_compound() + +From: Chuck Lever + +[ Upstream commit d9b74bdac6f24afc3101b6a5b6f59842610c9c94 ] + +And clean-up: Now that we have removed the DECODE_TAIL macro from +nfsd4_decode_compound(), we observe that there's no benefit for +nfsd4_decode_compound() to return nfs_ok or nfserr_bad_xdr only to +have its sole caller convert those values to one or zero, +respectively. Have nfsd4_decode_compound() return 1/0 instead. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 69 ++++++++++++++++++++--------------------------- + 1 file changed, 29 insertions(+), 40 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 085191b4b3aa5..30604a3e70c0f 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -186,28 +186,6 @@ svcxdr_dupstr(struct nfsd4_compoundargs *argp, void *buf, u32 len) + return p; + } + +-/** +- * savemem - duplicate a chunk of memory for later processing +- * @argp: NFSv4 compound argument structure to be freed with +- * @p: pointer to be duplicated +- * @nbytes: length to be duplicated +- * +- * Returns a pointer to a copy of @nbytes bytes of memory at @p +- * that are preserved until processing of the NFSv4 compound +- * operation described by @argp finishes. +- */ +-static char *savemem(struct nfsd4_compoundargs *argp, __be32 *p, int nbytes) +-{ +- void *ret; +- +- ret = svcxdr_tmpalloc(argp, nbytes); +- if (!ret) +- return NULL; +- memcpy(ret, p, nbytes); +- return ret; +-} +- +- + /* + * NFSv4 basic data type decoders + */ +@@ -2372,43 +2350,54 @@ nfsd4_opnum_in_range(struct nfsd4_compoundargs *argp, struct nfsd4_op *op) + return true; + } + +-static __be32 ++static int + nfsd4_decode_compound(struct nfsd4_compoundargs *argp) + { +- DECODE_HEAD; + struct nfsd4_op *op; + bool cachethis = false; + int auth_slack= argp->rqstp->rq_auth_slack; + int max_reply = auth_slack + 8; /* opcnt, status */ + int readcount = 0; + int readbytes = 0; ++ __be32 *p; + int i; + +- READ_BUF(4); +- argp->taglen = be32_to_cpup(p++); +- READ_BUF(argp->taglen); +- SAVEMEM(argp->tag, argp->taglen); +- READ_BUF(8); +- argp->minorversion = be32_to_cpup(p++); +- argp->opcnt = be32_to_cpup(p++); +- max_reply += 4 + (XDR_QUADLEN(argp->taglen) << 2); +- +- if (argp->taglen > NFSD4_MAX_TAGLEN) +- goto xdr_error; ++ if (xdr_stream_decode_u32(argp->xdr, &argp->taglen) < 0) ++ return 0; ++ max_reply += XDR_UNIT; ++ argp->tag = NULL; ++ if (unlikely(argp->taglen)) { ++ if (argp->taglen > NFSD4_MAX_TAGLEN) ++ return 0; ++ p = xdr_inline_decode(argp->xdr, argp->taglen); ++ if (!p) ++ return 0; ++ argp->tag = svcxdr_tmpalloc(argp, argp->taglen); ++ if (!argp->tag) ++ return 0; ++ memcpy(argp->tag, p, argp->taglen); ++ max_reply += xdr_align_size(argp->taglen); ++ } ++ ++ if (xdr_stream_decode_u32(argp->xdr, &argp->minorversion) < 0) ++ return 0; ++ if (xdr_stream_decode_u32(argp->xdr, &argp->opcnt) < 0) ++ return 0; ++ + /* + * NFS4ERR_RESOURCE is a more helpful error than GARBAGE_ARGS + * here, so we return success at the xdr level so that + * nfsd4_proc can handle this is an NFS-level error. + */ + if (argp->opcnt > NFSD_MAX_OPS_PER_COMPOUND) +- return 0; ++ return 1; + + if (argp->opcnt > ARRAY_SIZE(argp->iops)) { + argp->ops = kzalloc(argp->opcnt * sizeof(*argp->ops), GFP_KERNEL); + if (!argp->ops) { + argp->ops = argp->iops; + dprintk("nfsd: couldn't allocate room for COMPOUND\n"); +- goto xdr_error; ++ return 0; + } + } + +@@ -2420,7 +2409,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) + op->replay = NULL; + + if (xdr_stream_decode_u32(argp->xdr, &op->opnum) < 0) +- return nfserr_bad_xdr; ++ return 0; + if (nfsd4_opnum_in_range(argp, op)) { + op->status = nfsd4_dec_ops[op->opnum](argp, &op->u); + if (op->status != nfs_ok) +@@ -2467,7 +2456,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) + if (readcount > 1 || max_reply > PAGE_SIZE - auth_slack) + clear_bit(RQ_SPLICE_OK, &argp->rqstp->rq_flags); + +- DECODE_TAIL; ++ return 1; + } + + static __be32 *encode_change(__be32 *p, struct kstat *stat, struct inode *inode, +@@ -5496,7 +5485,7 @@ nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, __be32 *p) + args->ops = args->iops; + args->rqstp = rqstp; + +- return !nfsd4_decode_compound(args); ++ return nfsd4_decode_compound(args); + } + + int +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_copy.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_copy.patch new file mode 100644 index 00000000000..9b327d7e19e --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_copy.patch @@ -0,0 +1,117 @@ +From add7307edeb09793b00cce9b7b1979b129828e0d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Nov 2020 10:49:37 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_copy() + +From: Chuck Lever + +[ Upstream commit e8febea7190bcbd1e608093acb67f2a5009556aa ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 41 ++++++++++++++++++++++------------------- + fs/nfsd/xdr4.h | 2 +- + 2 files changed, 23 insertions(+), 20 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 05aa36f92a929..2529368cbbc0b 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -1982,40 +1982,44 @@ static __be32 nfsd4_decode_nl4_server(struct nfsd4_compoundargs *argp, + static __be32 + nfsd4_decode_copy(struct nfsd4_compoundargs *argp, struct nfsd4_copy *copy) + { +- DECODE_HEAD; + struct nl4_server *ns_dummy; +- int i, count; ++ u32 consecutive, i, count; ++ __be32 status; + +- status = nfsd4_decode_stateid(argp, ©->cp_src_stateid); ++ status = nfsd4_decode_stateid4(argp, ©->cp_src_stateid); + if (status) + return status; +- status = nfsd4_decode_stateid(argp, ©->cp_dst_stateid); ++ status = nfsd4_decode_stateid4(argp, ©->cp_dst_stateid); + if (status) + return status; ++ if (xdr_stream_decode_u64(argp->xdr, ©->cp_src_pos) < 0) ++ return nfserr_bad_xdr; ++ if (xdr_stream_decode_u64(argp->xdr, ©->cp_dst_pos) < 0) ++ return nfserr_bad_xdr; ++ if (xdr_stream_decode_u64(argp->xdr, ©->cp_count) < 0) ++ return nfserr_bad_xdr; ++ /* ca_consecutive: we always do consecutive copies */ ++ if (xdr_stream_decode_u32(argp->xdr, &consecutive) < 0) ++ return nfserr_bad_xdr; ++ if (xdr_stream_decode_u32(argp->xdr, ©->cp_synchronous) < 0) ++ return nfserr_bad_xdr; + +- READ_BUF(8 + 8 + 8 + 4 + 4 + 4); +- p = xdr_decode_hyper(p, ©->cp_src_pos); +- p = xdr_decode_hyper(p, ©->cp_dst_pos); +- p = xdr_decode_hyper(p, ©->cp_count); +- p++; /* ca_consecutive: we always do consecutive copies */ +- copy->cp_synchronous = be32_to_cpup(p++); +- +- count = be32_to_cpup(p++); +- ++ if (xdr_stream_decode_u32(argp->xdr, &count) < 0) ++ return nfserr_bad_xdr; + copy->cp_intra = false; + if (count == 0) { /* intra-server copy */ + copy->cp_intra = true; +- goto intra; ++ return nfs_ok; + } + +- /* decode all the supplied server addresses but use first */ ++ /* decode all the supplied server addresses but use only the first */ + status = nfsd4_decode_nl4_server(argp, ©->cp_src); + if (status) + return status; + + ns_dummy = kmalloc(sizeof(struct nl4_server), GFP_KERNEL); + if (ns_dummy == NULL) +- return nfserrno(-ENOMEM); ++ return nfserrno(-ENOMEM); /* XXX: jukebox? */ + for (i = 0; i < count - 1; i++) { + status = nfsd4_decode_nl4_server(argp, ns_dummy); + if (status) { +@@ -2024,9 +2028,8 @@ nfsd4_decode_copy(struct nfsd4_compoundargs *argp, struct nfsd4_copy *copy) + } + } + kfree(ns_dummy); +-intra: + +- DECODE_TAIL; ++ return nfs_ok; + } + + static __be32 +@@ -4792,7 +4795,7 @@ nfsd4_encode_copy(struct nfsd4_compoundres *resp, __be32 nfserr, + __be32 *p; + + nfserr = nfsd42_encode_write_res(resp, ©->cp_res, +- copy->cp_synchronous); ++ !!copy->cp_synchronous); + if (nfserr) + return nfserr; + +diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h +index 232529bc1b798..facc5762bf831 100644 +--- a/fs/nfsd/xdr4.h ++++ b/fs/nfsd/xdr4.h +@@ -554,7 +554,7 @@ struct nfsd4_copy { + bool cp_intra; + + /* both */ +- bool cp_synchronous; ++ u32 cp_synchronous; + + /* response */ + struct nfsd42_write_res cp_res; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_copy_notify.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_copy_notify.patch new file mode 100644 index 00000000000..f65a91eae94 --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_copy_notify.patch @@ -0,0 +1,56 @@ +From a50fbdc5cbe2ff546dd79b05da75517d56380813 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 21 Nov 2020 14:19:24 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_copy_notify() + +From: Chuck Lever + +[ Upstream commit f9a953fb369bbd2135ccead3393ec1ef66544471 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 2529368cbbc0b..09aea361c1755 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -2032,25 +2032,25 @@ nfsd4_decode_copy(struct nfsd4_compoundargs *argp, struct nfsd4_copy *copy) + return nfs_ok; + } + +-static __be32 +-nfsd4_decode_offload_status(struct nfsd4_compoundargs *argp, +- struct nfsd4_offload_status *os) +-{ +- return nfsd4_decode_stateid(argp, &os->stateid); +-} +- + static __be32 + nfsd4_decode_copy_notify(struct nfsd4_compoundargs *argp, + struct nfsd4_copy_notify *cn) + { + __be32 status; + +- status = nfsd4_decode_stateid(argp, &cn->cpn_src_stateid); ++ status = nfsd4_decode_stateid4(argp, &cn->cpn_src_stateid); + if (status) + return status; + return nfsd4_decode_nl4_server(argp, &cn->cpn_dst); + } + ++static __be32 ++nfsd4_decode_offload_status(struct nfsd4_compoundargs *argp, ++ struct nfsd4_offload_status *os) ++{ ++ return nfsd4_decode_stateid(argp, &os->stateid); ++} ++ + static __be32 + nfsd4_decode_seek(struct nfsd4_compoundargs *argp, struct nfsd4_seek *seek) + { +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_create.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_create.patch new file mode 100644 index 00000000000..fb7d895eb96 --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_create.patch @@ -0,0 +1,127 @@ +From 5ce518cf7c4aff01f48a05ef4ab9955d5ca367f0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Nov 2020 13:24:10 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_create() + +From: Chuck Lever + +[ Upstream commit 000dfa18b3df9c62df5f768f9187cf1a94ded71d ] + +A dedicated decoder for component4 is introduced here, which will be +used by other operation decoders in subsequent patches. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 58 ++++++++++++++++++++++++++++++++--------------- + 1 file changed, 40 insertions(+), 18 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index c916e5d9d3074..8f296f5568b11 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -92,6 +92,8 @@ check_filename(char *str, int len) + + if (len == 0) + return nfserr_inval; ++ if (len > NFS4_MAXNAMLEN) ++ return nfserr_nametoolong; + if (isdotent(str, len)) + return nfserr_badname; + for (i = 0; i < len; i++) +@@ -205,6 +207,27 @@ static char *savemem(struct nfsd4_compoundargs *argp, __be32 *p, int nbytes) + return ret; + } + ++static __be32 ++nfsd4_decode_component4(struct nfsd4_compoundargs *argp, char **namp, u32 *lenp) ++{ ++ __be32 *p, status; ++ ++ if (xdr_stream_decode_u32(argp->xdr, lenp) < 0) ++ return nfserr_bad_xdr; ++ p = xdr_inline_decode(argp->xdr, *lenp); ++ if (!p) ++ return nfserr_bad_xdr; ++ status = check_filename((char *)p, *lenp); ++ if (status) ++ return status; ++ *namp = svcxdr_tmpalloc(argp, *lenp); ++ if (!*namp) ++ return nfserr_jukebox; ++ memcpy(*namp, p, *lenp); ++ ++ return nfs_ok; ++} ++ + static __be32 + nfsd4_decode_time(struct nfsd4_compoundargs *argp, struct timespec64 *tv) + { +@@ -698,24 +721,27 @@ nfsd4_decode_commit(struct nfsd4_compoundargs *argp, struct nfsd4_commit *commit + static __be32 + nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create) + { +- DECODE_HEAD; ++ __be32 *p, status; + +- READ_BUF(4); +- create->cr_type = be32_to_cpup(p++); ++ if (xdr_stream_decode_u32(argp->xdr, &create->cr_type) < 0) ++ return nfserr_bad_xdr; + switch (create->cr_type) { + case NF4LNK: +- READ_BUF(4); +- create->cr_datalen = be32_to_cpup(p++); +- READ_BUF(create->cr_datalen); ++ if (xdr_stream_decode_u32(argp->xdr, &create->cr_datalen) < 0) ++ return nfserr_bad_xdr; ++ p = xdr_inline_decode(argp->xdr, create->cr_datalen); ++ if (!p) ++ return nfserr_bad_xdr; + create->cr_data = svcxdr_dupstr(argp, p, create->cr_datalen); + if (!create->cr_data) + return nfserr_jukebox; + break; + case NF4BLK: + case NF4CHR: +- READ_BUF(8); +- create->cr_specdata1 = be32_to_cpup(p++); +- create->cr_specdata2 = be32_to_cpup(p++); ++ if (xdr_stream_decode_u32(argp->xdr, &create->cr_specdata1) < 0) ++ return nfserr_bad_xdr; ++ if (xdr_stream_decode_u32(argp->xdr, &create->cr_specdata2) < 0) ++ return nfserr_bad_xdr; + break; + case NF4SOCK: + case NF4FIFO: +@@ -723,22 +749,18 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create + default: + break; + } +- +- READ_BUF(4); +- create->cr_namelen = be32_to_cpup(p++); +- READ_BUF(create->cr_namelen); +- SAVEMEM(create->cr_name, create->cr_namelen); +- if ((status = check_filename(create->cr_name, create->cr_namelen))) ++ status = nfsd4_decode_component4(argp, &create->cr_name, ++ &create->cr_namelen); ++ if (status) + return status; +- + status = nfsd4_decode_fattr4(argp, create->cr_bmval, + ARRAY_SIZE(create->cr_bmval), + &create->cr_iattr, &create->cr_acl, + &create->cr_label, &create->cr_umask); + if (status) +- goto out; ++ return status; + +- DECODE_TAIL; ++ return nfs_ok; + } + + static inline __be32 +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_create_sess.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_create_sess.patch new file mode 100644 index 00000000000..c8aa4fa8ae9 --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_create_sess.patch @@ -0,0 +1,61 @@ +From 34c9f79df53174f998cac4684ac86af733910369 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Nov 2020 14:52:44 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_create_session() + +From: Chuck Lever + +[ Upstream commit 81243e3fe37ed547fc4ed8aab1cec2865540bb18 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 24 ++++++++++++++---------- + 1 file changed, 14 insertions(+), 10 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 716a16961ff48..3e2e0de00c3a7 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -1650,24 +1650,28 @@ static __be32 + nfsd4_decode_create_session(struct nfsd4_compoundargs *argp, + struct nfsd4_create_session *sess) + { +- DECODE_HEAD; +- +- READ_BUF(16); +- COPYMEM(&sess->clientid, 8); +- sess->seqid = be32_to_cpup(p++); +- sess->flags = be32_to_cpup(p++); ++ __be32 status; + ++ status = nfsd4_decode_clientid4(argp, &sess->clientid); ++ if (status) ++ return status; ++ if (xdr_stream_decode_u32(argp->xdr, &sess->seqid) < 0) ++ return nfserr_bad_xdr; ++ if (xdr_stream_decode_u32(argp->xdr, &sess->flags) < 0) ++ return nfserr_bad_xdr; + status = nfsd4_decode_channel_attrs4(argp, &sess->fore_channel); + if (status) + return status; + status = nfsd4_decode_channel_attrs4(argp, &sess->back_channel); ++ if (status) ++ return status; ++ if (xdr_stream_decode_u32(argp->xdr, &sess->callback_prog) < 0) ++ return nfserr_bad_xdr; ++ status = nfsd4_decode_cb_sec(argp, &sess->cb_sec); + if (status) + return status; + +- READ_BUF(4); +- sess->callback_prog = be32_to_cpup(p++); +- nfsd4_decode_cb_sec(argp, &sess->cb_sec); +- DECODE_TAIL; ++ return nfs_ok; + } + + static __be32 +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_delegreturn.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_delegreturn.patch new file mode 100644 index 00000000000..87164e84883 --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_delegreturn.patch @@ -0,0 +1,31 @@ +From c14ff05b66eb9dd4079ffd2fa6d29c1a2cd9b887 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 21 Nov 2020 14:11:58 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_delegreturn() + +From: Chuck Lever + +[ Upstream commit 95e6482cedfc0785b85db49b72a05323bbf41750 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 8f296f5568b11..234d500961230 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -766,7 +766,7 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create + static inline __be32 + nfsd4_decode_delegreturn(struct nfsd4_compoundargs *argp, struct nfsd4_delegreturn *dr) + { +- return nfsd4_decode_stateid(argp, &dr->dr_stateid); ++ return nfsd4_decode_stateid4(argp, &dr->dr_stateid); + } + + static inline __be32 +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_destroy_cli.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_destroy_cli.patch new file mode 100644 index 00000000000..b8c2c4d0ea5 --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_destroy_cli.patch @@ -0,0 +1,52 @@ +From 41339d05f1d50b10644fdcefe448c44f5c15e88d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Nov 2020 15:15:09 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_destroy_clientid() + +From: Chuck Lever + +[ Upstream commit c95f2ec3490586cbb33badc8f4c82d6aa4955078 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 16 ++++++---------- + 1 file changed, 6 insertions(+), 10 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 9642de1550431..d0f0b7cd4e74e 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -1738,16 +1738,6 @@ nfsd4_decode_free_stateid(struct nfsd4_compoundargs *argp, + return nfsd4_decode_stateid4(argp, &free_stateid->fr_stateid); + } + +-static __be32 nfsd4_decode_destroy_clientid(struct nfsd4_compoundargs *argp, struct nfsd4_destroy_clientid *dc) +-{ +- DECODE_HEAD; +- +- READ_BUF(8); +- COPYMEM(&dc->clientid, 8); +- +- DECODE_TAIL; +-} +- + static __be32 nfsd4_decode_reclaim_complete(struct nfsd4_compoundargs *argp, struct nfsd4_reclaim_complete *rc) + { + DECODE_HEAD; +@@ -1908,6 +1898,12 @@ nfsd4_decode_test_stateid(struct nfsd4_compoundargs *argp, struct nfsd4_test_sta + return nfs_ok; + } + ++static __be32 nfsd4_decode_destroy_clientid(struct nfsd4_compoundargs *argp, ++ struct nfsd4_destroy_clientid *dc) ++{ ++ return nfsd4_decode_clientid4(argp, &dc->clientid); ++} ++ + static __be32 + nfsd4_decode_fallocate(struct nfsd4_compoundargs *argp, + struct nfsd4_fallocate *fallocate) +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_destroy_ses.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_destroy_ses.patch new file mode 100644 index 00000000000..5381d1423e2 --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_destroy_ses.patch @@ -0,0 +1,35 @@ +From 992dd6ede424c942e972b725fd10f0d62fe777fc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Nov 2020 13:50:55 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_destroy_session() + +From: Chuck Lever + +[ Upstream commit 94e254af1f873b4b551db4c4549294f2c4d385ef ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 6 +----- + 1 file changed, 1 insertion(+), 5 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 3e2e0de00c3a7..7a0730688b2f0 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -1678,11 +1678,7 @@ static __be32 + nfsd4_decode_destroy_session(struct nfsd4_compoundargs *argp, + struct nfsd4_destroy_session *destroy_session) + { +- DECODE_HEAD; +- READ_BUF(NFS4_MAX_SESSIONID_LEN); +- COPYMEM(destroy_session->sessionid.data, NFS4_MAX_SESSIONID_LEN); +- +- DECODE_TAIL; ++ return nfsd4_decode_sessionid4(argp, &destroy_session->sessionid); + } + + static __be32 +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_fallocate.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_fallocate.patch new file mode 100644 index 00000000000..579c3204935 --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_fallocate.patch @@ -0,0 +1,47 @@ +From 400ec5464d0904fb6cc01acdf990453b0ec7739d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Nov 2020 10:44:05 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_fallocate() + +From: Chuck Lever + +[ Upstream commit 6aef27aaeae7611f98af08205acc79f5a8f3aa59 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 2c684f7e74650..c8506bb6d8725 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -1906,17 +1906,17 @@ static __be32 + nfsd4_decode_fallocate(struct nfsd4_compoundargs *argp, + struct nfsd4_fallocate *fallocate) + { +- DECODE_HEAD; ++ __be32 status; + +- status = nfsd4_decode_stateid(argp, &fallocate->falloc_stateid); ++ status = nfsd4_decode_stateid4(argp, &fallocate->falloc_stateid); + if (status) + return status; ++ if (xdr_stream_decode_u64(argp->xdr, &fallocate->falloc_offset) < 0) ++ return nfserr_bad_xdr; ++ if (xdr_stream_decode_u64(argp->xdr, &fallocate->falloc_length) < 0) ++ return nfserr_bad_xdr; + +- READ_BUF(16); +- p = xdr_decode_hyper(p, &fallocate->falloc_offset); +- xdr_decode_hyper(p, &fallocate->falloc_length); +- +- DECODE_TAIL; ++ return nfs_ok; + } + + static __be32 +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_fattr.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_fattr.patch new file mode 100644 index 00000000000..7c6af9587d8 --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_fattr.patch @@ -0,0 +1,169 @@ +From 8d6a9be53024e13c6fe462f3a99fa0db3ce5b93a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Nov 2020 12:56:05 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_fattr() + +From: Chuck Lever + +[ Upstream commit d1c263a031e876ac3ca5223c728e4d98ed50b3c0 ] + +Let's be more careful to avoid overrunning the memory that backs +the bitmap array. This requires updating the synopsis of +nfsd4_decode_fattr(). + +Bruce points out that a server needs to be careful to return nfs_ok +when a client presents bitmap bits the server doesn't support. This +includes bits in bitmap words the server might not yet support. + +The current READ* based implementation is good about that, but that +requirement hasn't been documented. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 82 ++++++++++++++++++++++++++++++++++++----------- + 1 file changed, 64 insertions(+), 18 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 2d97bbff13b68..c916e5d9d3074 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -260,6 +260,46 @@ nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval) + DECODE_TAIL; + } + ++/** ++ * nfsd4_decode_bitmap4 - Decode an NFSv4 bitmap4 ++ * @argp: NFSv4 compound argument structure ++ * @bmval: pointer to an array of u32's to decode into ++ * @bmlen: size of the @bmval array ++ * ++ * The server needs to return nfs_ok rather than nfserr_bad_xdr when ++ * encountering bitmaps containing bits it does not recognize. This ++ * includes bits in bitmap words past WORDn, where WORDn is the last ++ * bitmap WORD the implementation currently supports. Thus we are ++ * careful here to simply ignore bits in bitmap words that this ++ * implementation has yet to support explicitly. ++ * ++ * Return values: ++ * %nfs_ok: @bmval populated successfully ++ * %nfserr_bad_xdr: the encoded bitmap was invalid ++ */ ++static __be32 ++nfsd4_decode_bitmap4(struct nfsd4_compoundargs *argp, u32 *bmval, u32 bmlen) ++{ ++ u32 i, count; ++ __be32 *p; ++ ++ if (xdr_stream_decode_u32(argp->xdr, &count) < 0) ++ return nfserr_bad_xdr; ++ /* request sanity */ ++ if (count > 1000) ++ return nfserr_bad_xdr; ++ p = xdr_inline_decode(argp->xdr, count << 2); ++ if (!p) ++ return nfserr_bad_xdr; ++ i = 0; ++ while (i < count) ++ bmval[i++] = be32_to_cpup(p++); ++ while (i < bmlen) ++ bmval[i++] = 0; ++ ++ return nfs_ok; ++} ++ + static __be32 + nfsd4_decode_nfsace4(struct nfsd4_compoundargs *argp, struct nfs4_ace *ace) + { +@@ -352,17 +392,18 @@ nfsd4_decode_security_label(struct nfsd4_compoundargs *argp, + } + + static __be32 +-nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, +- struct iattr *iattr, struct nfs4_acl **acl, +- struct xdr_netobj *label, int *umask) ++nfsd4_decode_fattr4(struct nfsd4_compoundargs *argp, u32 *bmval, u32 bmlen, ++ struct iattr *iattr, struct nfs4_acl **acl, ++ struct xdr_netobj *label, int *umask) + { + unsigned int starting_pos; + u32 attrlist4_count; ++ __be32 *p, status; + +- DECODE_HEAD; + iattr->ia_valid = 0; +- if ((status = nfsd4_decode_bitmap(argp, bmval))) +- return status; ++ status = nfsd4_decode_bitmap4(argp, bmval, bmlen); ++ if (status) ++ return nfserr_bad_xdr; + + if (bmval[0] & ~NFSD_WRITEABLE_ATTRS_WORD0 + || bmval[1] & ~NFSD_WRITEABLE_ATTRS_WORD1 +@@ -490,7 +531,7 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, + if (attrlist4_count != xdr_stream_pos(argp->xdr) - starting_pos) + return nfserr_bad_xdr; + +- DECODE_TAIL; ++ return nfs_ok; + } + + static __be32 +@@ -690,9 +731,10 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create + if ((status = check_filename(create->cr_name, create->cr_namelen))) + return status; + +- status = nfsd4_decode_fattr(argp, create->cr_bmval, &create->cr_iattr, +- &create->cr_acl, &create->cr_label, +- &create->cr_umask); ++ status = nfsd4_decode_fattr4(argp, create->cr_bmval, ++ ARRAY_SIZE(create->cr_bmval), ++ &create->cr_iattr, &create->cr_acl, ++ &create->cr_label, &create->cr_umask); + if (status) + goto out; + +@@ -941,9 +983,10 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) + switch (open->op_createmode) { + case NFS4_CREATE_UNCHECKED: + case NFS4_CREATE_GUARDED: +- status = nfsd4_decode_fattr(argp, open->op_bmval, +- &open->op_iattr, &open->op_acl, &open->op_label, +- &open->op_umask); ++ status = nfsd4_decode_fattr4(argp, open->op_bmval, ++ ARRAY_SIZE(open->op_bmval), ++ &open->op_iattr, &open->op_acl, ++ &open->op_label, &open->op_umask); + if (status) + goto out; + break; +@@ -956,9 +999,10 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) + goto xdr_error; + READ_BUF(NFS4_VERIFIER_SIZE); + COPYMEM(open->op_verf.data, NFS4_VERIFIER_SIZE); +- status = nfsd4_decode_fattr(argp, open->op_bmval, +- &open->op_iattr, &open->op_acl, &open->op_label, +- &open->op_umask); ++ status = nfsd4_decode_fattr4(argp, open->op_bmval, ++ ARRAY_SIZE(open->op_bmval), ++ &open->op_iattr, &open->op_acl, ++ &open->op_label, &open->op_umask); + if (status) + goto out; + break; +@@ -1194,8 +1238,10 @@ nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *seta + status = nfsd4_decode_stateid(argp, &setattr->sa_stateid); + if (status) + return status; +- return nfsd4_decode_fattr(argp, setattr->sa_bmval, &setattr->sa_iattr, +- &setattr->sa_acl, &setattr->sa_label, NULL); ++ return nfsd4_decode_fattr4(argp, setattr->sa_bmval, ++ ARRAY_SIZE(setattr->sa_bmval), ++ &setattr->sa_iattr, &setattr->sa_acl, ++ &setattr->sa_label, NULL); + } + + static __be32 +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_free_statei.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_free_statei.patch new file mode 100644 index 00000000000..ea49bb68f9c --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_free_statei.patch @@ -0,0 +1,37 @@ +From ce161c3ea2e20629658e04ca846ce17c581e9238 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 1 Nov 2020 13:38:27 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_free_stateid() + +From: Chuck Lever + +[ Upstream commit aec387d5909304810d899f7d90ae57df33f3a75c ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 8 +------- + 1 file changed, 1 insertion(+), 7 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 7a0730688b2f0..92988926d9540 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -1685,13 +1685,7 @@ static __be32 + nfsd4_decode_free_stateid(struct nfsd4_compoundargs *argp, + struct nfsd4_free_stateid *free_stateid) + { +- DECODE_HEAD; +- +- READ_BUF(sizeof(stateid_t)); +- free_stateid->fr_stateid.si_generation = be32_to_cpup(p++); +- COPYMEM(&free_stateid->fr_stateid.si_opaque, sizeof(stateid_opaque_t)); +- +- DECODE_TAIL; ++ return nfsd4_decode_stateid4(argp, &free_stateid->fr_stateid); + } + + static __be32 +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_getattr.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_getattr.patch new file mode 100644 index 00000000000..caf7e5903c4 --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_getattr.patch @@ -0,0 +1,32 @@ +From befb64a8ef0037570fd927c37e60630ca0a335e5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Nov 2020 14:40:20 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_getattr() + +From: Chuck Lever + +[ Upstream commit f759eff260f1f0b0f56531517762f27ee3233506 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 234d500961230..70ce48340c1b7 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -772,7 +772,8 @@ nfsd4_decode_delegreturn(struct nfsd4_compoundargs *argp, struct nfsd4_delegretu + static inline __be32 + nfsd4_decode_getattr(struct nfsd4_compoundargs *argp, struct nfsd4_getattr *getattr) + { +- return nfsd4_decode_bitmap(argp, getattr->ga_bmval); ++ return nfsd4_decode_bitmap4(argp, getattr->ga_bmval, ++ ARRAY_SIZE(getattr->ga_bmval)); + } + + static __be32 +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_getdevicein.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_getdevicein.patch new file mode 100644 index 00000000000..3c4db7a8cbf --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_getdevicein.patch @@ -0,0 +1,86 @@ +From 8cd17ab3661e0b132138ef80aef1aa321cfe1432 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Nov 2020 15:03:50 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_getdeviceinfo() + +From: Chuck Lever + +[ Upstream commit 044959715f370b24870c95df3940add8710c5a29 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 50 +++++++++++++++++++++++++++-------------------- + 1 file changed, 29 insertions(+), 21 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 92988926d9540..11e32c244b23c 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -638,6 +638,21 @@ nfsd4_decode_state_owner4(struct nfsd4_compoundargs *argp, + return nfsd4_decode_opaque(argp, owner); + } + ++#ifdef CONFIG_NFSD_PNFS ++static __be32 ++nfsd4_decode_deviceid4(struct nfsd4_compoundargs *argp, ++ struct nfsd4_deviceid *devid) ++{ ++ __be32 *p; ++ ++ p = xdr_inline_decode(argp->xdr, NFS4_DEVICEID4_SIZE); ++ if (!p) ++ return nfserr_bad_xdr; ++ memcpy(devid, p, sizeof(*devid)); ++ return nfs_ok; ++} ++#endif /* CONFIG_NFSD_PNFS */ ++ + static __be32 + nfsd4_decode_sessionid4(struct nfsd4_compoundargs *argp, + struct nfs4_sessionid *sessionid) +@@ -1765,27 +1780,20 @@ static __be32 + nfsd4_decode_getdeviceinfo(struct nfsd4_compoundargs *argp, + struct nfsd4_getdeviceinfo *gdev) + { +- DECODE_HEAD; +- u32 num, i; +- +- READ_BUF(sizeof(struct nfsd4_deviceid) + 3 * 4); +- COPYMEM(&gdev->gd_devid, sizeof(struct nfsd4_deviceid)); +- gdev->gd_layout_type = be32_to_cpup(p++); +- gdev->gd_maxcount = be32_to_cpup(p++); +- num = be32_to_cpup(p++); +- if (num) { +- if (num > 1000) +- goto xdr_error; +- READ_BUF(4 * num); +- gdev->gd_notify_types = be32_to_cpup(p++); +- for (i = 1; i < num; i++) { +- if (be32_to_cpup(p++)) { +- status = nfserr_inval; +- goto out; +- } +- } +- } +- DECODE_TAIL; ++ __be32 status; ++ ++ status = nfsd4_decode_deviceid4(argp, &gdev->gd_devid); ++ if (status) ++ return status; ++ if (xdr_stream_decode_u32(argp->xdr, &gdev->gd_layout_type) < 0) ++ return nfserr_bad_xdr; ++ if (xdr_stream_decode_u32(argp->xdr, &gdev->gd_maxcount) < 0) ++ return nfserr_bad_xdr; ++ if (xdr_stream_decode_uint32_array(argp->xdr, ++ &gdev->gd_notify_types, 1) < 0) ++ return nfserr_bad_xdr; ++ ++ return nfs_ok; + } + + static __be32 +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_layoutcommi.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_layoutcommi.patch new file mode 100644 index 00000000000..eb76b22438d --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_layoutcommi.patch @@ -0,0 +1,170 @@ +From d1b868aff962d8591cb54c45503e8e71329bd379 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Nov 2020 10:40:07 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_layoutcommit() + +From: Chuck Lever + +[ Upstream commit 5185980d8a23001c2317c290129ab7ab20067e20 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 120 ++++++++++++++++++++++------------------------ + 1 file changed, 58 insertions(+), 62 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 11e32c244b23c..9cd7270e67adc 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -274,20 +274,6 @@ nfsd4_decode_component4(struct nfsd4_compoundargs *argp, char **namp, u32 *lenp) + return nfs_ok; + } + +-static __be32 +-nfsd4_decode_time(struct nfsd4_compoundargs *argp, struct timespec64 *tv) +-{ +- DECODE_HEAD; +- +- READ_BUF(12); +- p = xdr_decode_hyper(p, &tv->tv_sec); +- tv->tv_nsec = be32_to_cpup(p++); +- if (tv->tv_nsec >= (u32)1000000000) +- return nfserr_inval; +- +- DECODE_TAIL; +-} +- + static __be32 + nfsd4_decode_nfstime4(struct nfsd4_compoundargs *argp, struct timespec64 *tv) + { +@@ -651,6 +637,29 @@ nfsd4_decode_deviceid4(struct nfsd4_compoundargs *argp, + memcpy(devid, p, sizeof(*devid)); + return nfs_ok; + } ++ ++static __be32 ++nfsd4_decode_layoutupdate4(struct nfsd4_compoundargs *argp, ++ struct nfsd4_layoutcommit *lcp) ++{ ++ if (xdr_stream_decode_u32(argp->xdr, &lcp->lc_layout_type) < 0) ++ return nfserr_bad_xdr; ++ if (lcp->lc_layout_type < LAYOUT_NFSV4_1_FILES) ++ return nfserr_bad_xdr; ++ if (lcp->lc_layout_type >= LAYOUT_TYPE_MAX) ++ return nfserr_bad_xdr; ++ ++ if (xdr_stream_decode_u32(argp->xdr, &lcp->lc_up_len) < 0) ++ return nfserr_bad_xdr; ++ if (lcp->lc_up_len > 0) { ++ lcp->lc_up_layout = xdr_inline_decode(argp->xdr, lcp->lc_up_len); ++ if (!lcp->lc_up_layout) ++ return nfserr_bad_xdr; ++ } ++ ++ return nfs_ok; ++} ++ + #endif /* CONFIG_NFSD_PNFS */ + + static __be32 +@@ -1796,6 +1805,41 @@ nfsd4_decode_getdeviceinfo(struct nfsd4_compoundargs *argp, + return nfs_ok; + } + ++static __be32 ++nfsd4_decode_layoutcommit(struct nfsd4_compoundargs *argp, ++ struct nfsd4_layoutcommit *lcp) ++{ ++ __be32 *p, status; ++ ++ if (xdr_stream_decode_u64(argp->xdr, &lcp->lc_seg.offset) < 0) ++ return nfserr_bad_xdr; ++ if (xdr_stream_decode_u64(argp->xdr, &lcp->lc_seg.length) < 0) ++ return nfserr_bad_xdr; ++ if (xdr_stream_decode_bool(argp->xdr, &lcp->lc_reclaim) < 0) ++ return nfserr_bad_xdr; ++ status = nfsd4_decode_stateid4(argp, &lcp->lc_sid); ++ if (status) ++ return status; ++ if (xdr_stream_decode_u32(argp->xdr, &lcp->lc_newoffset) < 0) ++ return nfserr_bad_xdr; ++ if (lcp->lc_newoffset) { ++ if (xdr_stream_decode_u64(argp->xdr, &lcp->lc_last_wr) < 0) ++ return nfserr_bad_xdr; ++ } else ++ lcp->lc_last_wr = 0; ++ p = xdr_inline_decode(argp->xdr, XDR_UNIT); ++ if (!p) ++ return nfserr_bad_xdr; ++ if (xdr_item_is_present(p)) { ++ status = nfsd4_decode_nfstime4(argp, &lcp->lc_mtime); ++ if (status) ++ return status; ++ } else { ++ lcp->lc_mtime.tv_nsec = UTIME_NOW; ++ } ++ return nfsd4_decode_layoutupdate4(argp, lcp); ++} ++ + static __be32 + nfsd4_decode_layoutget(struct nfsd4_compoundargs *argp, + struct nfsd4_layoutget *lgp) +@@ -1820,54 +1864,6 @@ nfsd4_decode_layoutget(struct nfsd4_compoundargs *argp, + DECODE_TAIL; + } + +-static __be32 +-nfsd4_decode_layoutcommit(struct nfsd4_compoundargs *argp, +- struct nfsd4_layoutcommit *lcp) +-{ +- DECODE_HEAD; +- u32 timechange; +- +- READ_BUF(20); +- p = xdr_decode_hyper(p, &lcp->lc_seg.offset); +- p = xdr_decode_hyper(p, &lcp->lc_seg.length); +- lcp->lc_reclaim = be32_to_cpup(p++); +- +- status = nfsd4_decode_stateid(argp, &lcp->lc_sid); +- if (status) +- return status; +- +- READ_BUF(4); +- lcp->lc_newoffset = be32_to_cpup(p++); +- if (lcp->lc_newoffset) { +- READ_BUF(8); +- p = xdr_decode_hyper(p, &lcp->lc_last_wr); +- } else +- lcp->lc_last_wr = 0; +- READ_BUF(4); +- timechange = be32_to_cpup(p++); +- if (timechange) { +- status = nfsd4_decode_time(argp, &lcp->lc_mtime); +- if (status) +- return status; +- } else { +- lcp->lc_mtime.tv_nsec = UTIME_NOW; +- } +- READ_BUF(8); +- lcp->lc_layout_type = be32_to_cpup(p++); +- +- /* +- * Save the layout update in XDR format and let the layout driver deal +- * with it later. +- */ +- lcp->lc_up_len = be32_to_cpup(p++); +- if (lcp->lc_up_len > 0) { +- READ_BUF(lcp->lc_up_len); +- READMEM(lcp->lc_up_layout, lcp->lc_up_len); +- } +- +- DECODE_TAIL; +-} +- + static __be32 + nfsd4_decode_layoutreturn(struct nfsd4_compoundargs *argp, + struct nfsd4_layoutreturn *lrp) +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_layoutget.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_layoutget.patch new file mode 100644 index 00000000000..c05d0576fa4 --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_layoutget.patch @@ -0,0 +1,64 @@ +From 4bcf8bcd8b3dfd70852503f3505a3c272fbc4115 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Nov 2020 15:06:04 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_layoutget() + +From: Chuck Lever + +[ Upstream commit c8e88e3aa73889421461f878cd569ef84f231ceb ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 31 +++++++++++++++++-------------- + 1 file changed, 17 insertions(+), 14 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 9cd7270e67adc..837d2d8fb3ff8 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -1844,24 +1844,27 @@ static __be32 + nfsd4_decode_layoutget(struct nfsd4_compoundargs *argp, + struct nfsd4_layoutget *lgp) + { +- DECODE_HEAD; +- +- READ_BUF(36); +- lgp->lg_signal = be32_to_cpup(p++); +- lgp->lg_layout_type = be32_to_cpup(p++); +- lgp->lg_seg.iomode = be32_to_cpup(p++); +- p = xdr_decode_hyper(p, &lgp->lg_seg.offset); +- p = xdr_decode_hyper(p, &lgp->lg_seg.length); +- p = xdr_decode_hyper(p, &lgp->lg_minlength); ++ __be32 status; + +- status = nfsd4_decode_stateid(argp, &lgp->lg_sid); ++ if (xdr_stream_decode_u32(argp->xdr, &lgp->lg_signal) < 0) ++ return nfserr_bad_xdr; ++ if (xdr_stream_decode_u32(argp->xdr, &lgp->lg_layout_type) < 0) ++ return nfserr_bad_xdr; ++ if (xdr_stream_decode_u32(argp->xdr, &lgp->lg_seg.iomode) < 0) ++ return nfserr_bad_xdr; ++ if (xdr_stream_decode_u64(argp->xdr, &lgp->lg_seg.offset) < 0) ++ return nfserr_bad_xdr; ++ if (xdr_stream_decode_u64(argp->xdr, &lgp->lg_seg.length) < 0) ++ return nfserr_bad_xdr; ++ if (xdr_stream_decode_u64(argp->xdr, &lgp->lg_minlength) < 0) ++ return nfserr_bad_xdr; ++ status = nfsd4_decode_stateid4(argp, &lgp->lg_sid); + if (status) + return status; ++ if (xdr_stream_decode_u32(argp->xdr, &lgp->lg_maxcount) < 0) ++ return nfserr_bad_xdr; + +- READ_BUF(4); +- lgp->lg_maxcount = be32_to_cpup(p++); +- +- DECODE_TAIL; ++ return nfs_ok; + } + + static __be32 +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_layoutretur.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_layoutretur.patch new file mode 100644 index 00000000000..aee6865fca9 --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_layoutretur.patch @@ -0,0 +1,108 @@ +From 882115dea34e1006f2328b77d899f6fd820f3f1b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Nov 2020 10:42:25 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_layoutreturn() + +From: Chuck Lever + +[ Upstream commit 645fcad371420913c30e9aca80fc0a38f3acf432 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 72 +++++++++++++++++++++++++++++------------------ + 1 file changed, 44 insertions(+), 28 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 837d2d8fb3ff8..ae70070a58213 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -660,6 +660,43 @@ nfsd4_decode_layoutupdate4(struct nfsd4_compoundargs *argp, + return nfs_ok; + } + ++static __be32 ++nfsd4_decode_layoutreturn4(struct nfsd4_compoundargs *argp, ++ struct nfsd4_layoutreturn *lrp) ++{ ++ __be32 status; ++ ++ if (xdr_stream_decode_u32(argp->xdr, &lrp->lr_return_type) < 0) ++ return nfserr_bad_xdr; ++ switch (lrp->lr_return_type) { ++ case RETURN_FILE: ++ if (xdr_stream_decode_u64(argp->xdr, &lrp->lr_seg.offset) < 0) ++ return nfserr_bad_xdr; ++ if (xdr_stream_decode_u64(argp->xdr, &lrp->lr_seg.length) < 0) ++ return nfserr_bad_xdr; ++ status = nfsd4_decode_stateid4(argp, &lrp->lr_sid); ++ if (status) ++ return status; ++ if (xdr_stream_decode_u32(argp->xdr, &lrp->lrf_body_len) < 0) ++ return nfserr_bad_xdr; ++ if (lrp->lrf_body_len > 0) { ++ lrp->lrf_body = xdr_inline_decode(argp->xdr, lrp->lrf_body_len); ++ if (!lrp->lrf_body) ++ return nfserr_bad_xdr; ++ } ++ break; ++ case RETURN_FSID: ++ case RETURN_ALL: ++ lrp->lr_seg.offset = 0; ++ lrp->lr_seg.length = NFS4_MAX_UINT64; ++ break; ++ default: ++ return nfserr_bad_xdr; ++ } ++ ++ return nfs_ok; ++} ++ + #endif /* CONFIG_NFSD_PNFS */ + + static __be32 +@@ -1871,34 +1908,13 @@ static __be32 + nfsd4_decode_layoutreturn(struct nfsd4_compoundargs *argp, + struct nfsd4_layoutreturn *lrp) + { +- DECODE_HEAD; +- +- READ_BUF(16); +- lrp->lr_reclaim = be32_to_cpup(p++); +- lrp->lr_layout_type = be32_to_cpup(p++); +- lrp->lr_seg.iomode = be32_to_cpup(p++); +- lrp->lr_return_type = be32_to_cpup(p++); +- if (lrp->lr_return_type == RETURN_FILE) { +- READ_BUF(16); +- p = xdr_decode_hyper(p, &lrp->lr_seg.offset); +- p = xdr_decode_hyper(p, &lrp->lr_seg.length); +- +- status = nfsd4_decode_stateid(argp, &lrp->lr_sid); +- if (status) +- return status; +- +- READ_BUF(4); +- lrp->lrf_body_len = be32_to_cpup(p++); +- if (lrp->lrf_body_len > 0) { +- READ_BUF(lrp->lrf_body_len); +- READMEM(lrp->lrf_body, lrp->lrf_body_len); +- } +- } else { +- lrp->lr_seg.offset = 0; +- lrp->lr_seg.length = NFS4_MAX_UINT64; +- } +- +- DECODE_TAIL; ++ if (xdr_stream_decode_bool(argp->xdr, &lrp->lr_reclaim) < 0) ++ return nfserr_bad_xdr; ++ if (xdr_stream_decode_u32(argp->xdr, &lrp->lr_layout_type) < 0) ++ return nfserr_bad_xdr; ++ if (xdr_stream_decode_u32(argp->xdr, &lrp->lr_seg.iomode) < 0) ++ return nfserr_bad_xdr; ++ return nfsd4_decode_layoutreturn4(argp, lrp); + } + #endif /* CONFIG_NFSD_PNFS */ + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_link.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_link.patch new file mode 100644 index 00000000000..2f4691feffd --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_link.patch @@ -0,0 +1,40 @@ +From 2682bc6286059ff63a4af377a4097168d3fcd3a9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Nov 2020 15:01:24 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_link() + +From: Chuck Lever + +[ Upstream commit 5c505d128691c70991b766dd6a3faf49fa59ecfb ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 11 +---------- + 1 file changed, 1 insertion(+), 10 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 70ce48340c1b7..4596b8cef222c 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -779,16 +779,7 @@ nfsd4_decode_getattr(struct nfsd4_compoundargs *argp, struct nfsd4_getattr *geta + static __be32 + nfsd4_decode_link(struct nfsd4_compoundargs *argp, struct nfsd4_link *link) + { +- DECODE_HEAD; +- +- READ_BUF(4); +- link->li_namelen = be32_to_cpup(p++); +- READ_BUF(link->li_namelen); +- SAVEMEM(link->li_name, link->li_namelen); +- if ((status = check_filename(link->li_name, link->li_namelen))) +- return status; +- +- DECODE_TAIL; ++ return nfsd4_decode_component4(argp, &link->li_name, &link->li_namelen); + } + + static __be32 +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_listxattrs.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_listxattrs.patch new file mode 100644 index 00000000000..71991cad919 --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_listxattrs.patch @@ -0,0 +1,55 @@ +From 8aa39f70cd4bce5f03c8b092c30ede9187f4ac50 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Nov 2020 11:04:02 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_listxattrs() + +From: Chuck Lever + +[ Upstream commit 2212036cadf4da3c4b0e4bd2a9a8c3d78617ab4f ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 38610764d7161..bf8eacab64952 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -2223,11 +2223,10 @@ static __be32 + nfsd4_decode_listxattrs(struct nfsd4_compoundargs *argp, + struct nfsd4_listxattrs *listxattrs) + { +- DECODE_HEAD; + u32 maxcount; + +- READ_BUF(12); +- p = xdr_decode_hyper(p, &listxattrs->lsxa_cookie); ++ if (xdr_stream_decode_u64(argp->xdr, &listxattrs->lsxa_cookie) < 0) ++ return nfserr_bad_xdr; + + /* + * If the cookie is too large to have even one user.x attribute +@@ -2237,7 +2236,8 @@ nfsd4_decode_listxattrs(struct nfsd4_compoundargs *argp, + (XATTR_LIST_MAX / (XATTR_USER_PREFIX_LEN + 2))) + return nfserr_badcookie; + +- maxcount = be32_to_cpup(p++); ++ if (xdr_stream_decode_u32(argp->xdr, &maxcount) < 0) ++ return nfserr_bad_xdr; + if (maxcount < 8) + /* Always need at least 2 words (length and one character) */ + return nfserr_inval; +@@ -2245,7 +2245,7 @@ nfsd4_decode_listxattrs(struct nfsd4_compoundargs *argp, + maxcount = min(maxcount, svc_max_payload(argp->rqstp)); + listxattrs->lsxa_maxcount = maxcount; + +- DECODE_TAIL; ++ return nfs_ok; + } + + static __be32 +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_lock.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_lock.patch new file mode 100644 index 00000000000..677738787a3 --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_lock.patch @@ -0,0 +1,54 @@ +From e552a00782c7ee5221d0b5d4600784466b77ed9e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Nov 2020 13:29:27 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_lock() + +From: Chuck Lever + +[ Upstream commit 7c59deed5cd2e1cfc6cbecf06f4584ac53755f53 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 24 ++++++++++-------------- + 1 file changed, 10 insertions(+), 14 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 15ed5249e2c74..b50d2987bb6e8 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -878,21 +878,17 @@ nfsd4_decode_locker4(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock) + static __be32 + nfsd4_decode_lock(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock) + { +- DECODE_HEAD; +- +- /* +- * type, reclaim(boolean), offset, length, new_lock_owner(boolean) +- */ +- READ_BUF(28); +- lock->lk_type = be32_to_cpup(p++); ++ if (xdr_stream_decode_u32(argp->xdr, &lock->lk_type) < 0) ++ return nfserr_bad_xdr; + if ((lock->lk_type < NFS4_READ_LT) || (lock->lk_type > NFS4_WRITEW_LT)) +- goto xdr_error; +- lock->lk_reclaim = be32_to_cpup(p++); +- p = xdr_decode_hyper(p, &lock->lk_offset); +- p = xdr_decode_hyper(p, &lock->lk_length); +- status = nfsd4_decode_locker4(argp, lock); +- +- DECODE_TAIL; ++ return nfserr_bad_xdr; ++ if (xdr_stream_decode_bool(argp->xdr, &lock->lk_reclaim) < 0) ++ return nfserr_bad_xdr; ++ if (xdr_stream_decode_u64(argp->xdr, &lock->lk_offset) < 0) ++ return nfserr_bad_xdr; ++ if (xdr_stream_decode_u64(argp->xdr, &lock->lk_length) < 0) ++ return nfserr_bad_xdr; ++ return nfsd4_decode_locker4(argp, lock); + } + + static __be32 +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_lockt.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_lockt.patch new file mode 100644 index 00000000000..7fd971256fb --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_lockt.patch @@ -0,0 +1,53 @@ +From 809ccbe50d19aa703a91c708b4b95ae3f887204a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Nov 2020 13:31:44 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_lockt() + +From: Chuck Lever + +[ Upstream commit 0a146f04aa0fa7a57aaed3913d1c2732b3853f31 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 24 ++++++++++-------------- + 1 file changed, 10 insertions(+), 14 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index b50d2987bb6e8..4f2680650a567 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -894,20 +894,16 @@ nfsd4_decode_lock(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock) + static __be32 + nfsd4_decode_lockt(struct nfsd4_compoundargs *argp, struct nfsd4_lockt *lockt) + { +- DECODE_HEAD; +- +- READ_BUF(32); +- lockt->lt_type = be32_to_cpup(p++); +- if((lockt->lt_type < NFS4_READ_LT) || (lockt->lt_type > NFS4_WRITEW_LT)) +- goto xdr_error; +- p = xdr_decode_hyper(p, &lockt->lt_offset); +- p = xdr_decode_hyper(p, &lockt->lt_length); +- COPYMEM(&lockt->lt_clientid, 8); +- lockt->lt_owner.len = be32_to_cpup(p++); +- READ_BUF(lockt->lt_owner.len); +- READMEM(lockt->lt_owner.data, lockt->lt_owner.len); +- +- DECODE_TAIL; ++ if (xdr_stream_decode_u32(argp->xdr, &lockt->lt_type) < 0) ++ return nfserr_bad_xdr; ++ if ((lockt->lt_type < NFS4_READ_LT) || (lockt->lt_type > NFS4_WRITEW_LT)) ++ return nfserr_bad_xdr; ++ if (xdr_stream_decode_u64(argp->xdr, &lockt->lt_offset) < 0) ++ return nfserr_bad_xdr; ++ if (xdr_stream_decode_u64(argp->xdr, &lockt->lt_length) < 0) ++ return nfserr_bad_xdr; ++ return nfsd4_decode_state_owner4(argp, &lockt->lt_clientid, ++ &lockt->lt_owner); + } + + static __be32 +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_locku.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_locku.patch new file mode 100644 index 00000000000..1035cf94182 --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_locku.patch @@ -0,0 +1,56 @@ +From c35f7d20ee457d40946a0b55919f20783438463c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Nov 2020 13:33:28 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_locku() + +From: Chuck Lever + +[ Upstream commit ca9cf9fc27f8f722e9eb2763173ba01f6ac3dad1 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 22 ++++++++++++---------- + 1 file changed, 12 insertions(+), 10 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 4f2680650a567..3c20a1f8eaa91 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -909,21 +909,23 @@ nfsd4_decode_lockt(struct nfsd4_compoundargs *argp, struct nfsd4_lockt *lockt) + static __be32 + nfsd4_decode_locku(struct nfsd4_compoundargs *argp, struct nfsd4_locku *locku) + { +- DECODE_HEAD; ++ __be32 status; + +- READ_BUF(8); +- locku->lu_type = be32_to_cpup(p++); ++ if (xdr_stream_decode_u32(argp->xdr, &locku->lu_type) < 0) ++ return nfserr_bad_xdr; + if ((locku->lu_type < NFS4_READ_LT) || (locku->lu_type > NFS4_WRITEW_LT)) +- goto xdr_error; +- locku->lu_seqid = be32_to_cpup(p++); +- status = nfsd4_decode_stateid(argp, &locku->lu_stateid); ++ return nfserr_bad_xdr; ++ if (xdr_stream_decode_u32(argp->xdr, &locku->lu_seqid) < 0) ++ return nfserr_bad_xdr; ++ status = nfsd4_decode_stateid4(argp, &locku->lu_stateid); + if (status) + return status; +- READ_BUF(16); +- p = xdr_decode_hyper(p, &locku->lu_offset); +- p = xdr_decode_hyper(p, &locku->lu_length); ++ if (xdr_stream_decode_u64(argp->xdr, &locku->lu_offset) < 0) ++ return nfserr_bad_xdr; ++ if (xdr_stream_decode_u64(argp->xdr, &locku->lu_length) < 0) ++ return nfserr_bad_xdr; + +- DECODE_TAIL; ++ return nfs_ok; + } + + static __be32 +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_lookup.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_lookup.patch new file mode 100644 index 00000000000..1afc1512d2c --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_lookup.patch @@ -0,0 +1,40 @@ +From 3a9b4e88c853c860dbe9b5f98dcf9fa69ef0a2fe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Nov 2020 15:02:40 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_lookup() + +From: Chuck Lever + +[ Upstream commit 3d5877e8e03f60d7cc804d7b230ff9c00c9c07bd ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 11 +---------- + 1 file changed, 1 insertion(+), 10 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 3c20a1f8eaa91..431ab9d604be7 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -931,16 +931,7 @@ nfsd4_decode_locku(struct nfsd4_compoundargs *argp, struct nfsd4_locku *locku) + static __be32 + nfsd4_decode_lookup(struct nfsd4_compoundargs *argp, struct nfsd4_lookup *lookup) + { +- DECODE_HEAD; +- +- READ_BUF(4); +- lookup->lo_len = be32_to_cpup(p++); +- READ_BUF(lookup->lo_len); +- SAVEMEM(lookup->lo_name, lookup->lo_len); +- if ((status = check_filename(lookup->lo_name, lookup->lo_len))) +- return status; +- +- DECODE_TAIL; ++ return nfsd4_decode_component4(argp, &lookup->lo_name, &lookup->lo_len); + } + + static __be32 nfsd4_decode_share_access(struct nfsd4_compoundargs *argp, u32 *share_access, u32 *deleg_want, u32 *deleg_when) +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_nl4_server.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_nl4_server.patch new file mode 100644 index 00000000000..02270a6abcf --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_nl4_server.patch @@ -0,0 +1,79 @@ +From 17720e74daba52e961c3992574852a6f542d156b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Nov 2020 18:05:06 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_nl4_server() + +From: Chuck Lever + +[ Upstream commit f49e4b4d58cc835d8bd0cc9663f7b9c5497e0e7e ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 34 ++++++++++++++++++++-------------- + 1 file changed, 20 insertions(+), 14 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index c8506bb6d8725..05aa36f92a929 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -1941,36 +1941,42 @@ nfsd4_decode_clone(struct nfsd4_compoundargs *argp, struct nfsd4_clone *clone) + static __be32 nfsd4_decode_nl4_server(struct nfsd4_compoundargs *argp, + struct nl4_server *ns) + { +- DECODE_HEAD; + struct nfs42_netaddr *naddr; ++ __be32 *p; + +- READ_BUF(4); +- ns->nl4_type = be32_to_cpup(p++); ++ if (xdr_stream_decode_u32(argp->xdr, &ns->nl4_type) < 0) ++ return nfserr_bad_xdr; + + /* currently support for 1 inter-server source server */ + switch (ns->nl4_type) { + case NL4_NETADDR: + naddr = &ns->u.nl4_addr; + +- READ_BUF(4); +- naddr->netid_len = be32_to_cpup(p++); ++ if (xdr_stream_decode_u32(argp->xdr, &naddr->netid_len) < 0) ++ return nfserr_bad_xdr; + if (naddr->netid_len > RPCBIND_MAXNETIDLEN) +- goto xdr_error; ++ return nfserr_bad_xdr; + +- READ_BUF(naddr->netid_len + 4); /* 4 for uaddr len */ +- COPYMEM(naddr->netid, naddr->netid_len); ++ p = xdr_inline_decode(argp->xdr, naddr->netid_len); ++ if (!p) ++ return nfserr_bad_xdr; ++ memcpy(naddr->netid, p, naddr->netid_len); + +- naddr->addr_len = be32_to_cpup(p++); ++ if (xdr_stream_decode_u32(argp->xdr, &naddr->addr_len) < 0) ++ return nfserr_bad_xdr; + if (naddr->addr_len > RPCBIND_MAXUADDRLEN) +- goto xdr_error; ++ return nfserr_bad_xdr; + +- READ_BUF(naddr->addr_len); +- COPYMEM(naddr->addr, naddr->addr_len); ++ p = xdr_inline_decode(argp->xdr, naddr->addr_len); ++ if (!p) ++ return nfserr_bad_xdr; ++ memcpy(naddr->addr, p, naddr->addr_len); + break; + default: +- goto xdr_error; ++ return nfserr_bad_xdr; + } +- DECODE_TAIL; ++ ++ return nfs_ok; + } + + static __be32 +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_offload_sta.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_offload_sta.patch new file mode 100644 index 00000000000..3d3ccf1b046 --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_offload_sta.patch @@ -0,0 +1,31 @@ +From 992efcb61784819fa3d4b81262fc835106f1e1fe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 21 Nov 2020 14:21:25 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_offload_status() + +From: Chuck Lever + +[ Upstream commit 2846bb0525a73e00b3566fda535ea6a5879e2971 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 09aea361c1755..101beb315d963 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -2048,7 +2048,7 @@ static __be32 + nfsd4_decode_offload_status(struct nfsd4_compoundargs *argp, + struct nfsd4_offload_status *os) + { +- return nfsd4_decode_stateid(argp, &os->stateid); ++ return nfsd4_decode_stateid4(argp, &os->stateid); + } + + static __be32 +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_open.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_open.patch new file mode 100644 index 00000000000..61618dbe647 --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_open.patch @@ -0,0 +1,69 @@ +From 403576b26dc537994a772602fa4d2aabc301f123 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 1 Nov 2020 12:04:06 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_open() + +From: Chuck Lever + +[ Upstream commit 61e5e0b3ec713d1365008c8af3fe5fdd262e2a60 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 24 ++++++++++-------------- + 1 file changed, 10 insertions(+), 14 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 3e0fca521c39b..2de54e84a3ab0 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -1124,7 +1124,7 @@ nfsd4_decode_open_claim4(struct nfsd4_compoundargs *argp, + static __be32 + nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) + { +- DECODE_HEAD; ++ __be32 status; + u32 dummy; + + memset(open->op_bmval, 0, sizeof(open->op_bmval)); +@@ -1132,28 +1132,24 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) + open->op_openowner = NULL; + + open->op_xdr_error = 0; +- /* seqid, share_access, share_deny, clientid, ownerlen */ +- READ_BUF(4); +- open->op_seqid = be32_to_cpup(p++); +- /* decode, yet ignore deleg_when until supported */ ++ if (xdr_stream_decode_u32(argp->xdr, &open->op_seqid) < 0) ++ return nfserr_bad_xdr; ++ /* deleg_want is ignored */ + status = nfsd4_decode_share_access(argp, &open->op_share_access, + &open->op_deleg_want, &dummy); + if (status) +- goto xdr_error; ++ return status; + status = nfsd4_decode_share_deny(argp, &open->op_share_deny); + if (status) +- goto xdr_error; +- READ_BUF(sizeof(clientid_t)); +- COPYMEM(&open->op_clientid, sizeof(clientid_t)); +- status = nfsd4_decode_opaque(argp, &open->op_owner); ++ return status; ++ status = nfsd4_decode_state_owner4(argp, &open->op_clientid, ++ &open->op_owner); + if (status) +- goto xdr_error; ++ return status; + status = nfsd4_decode_openflag4(argp, open); + if (status) + return status; +- status = nfsd4_decode_open_claim4(argp, open); +- +- DECODE_TAIL; ++ return nfsd4_decode_open_claim4(argp, open); + } + + static __be32 +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_open_confir.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_open_confir.patch new file mode 100644 index 00000000000..84dc3b963d5 --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_open_confir.patch @@ -0,0 +1,46 @@ +From 59d1a83be66c5002472c6ba3cd5a54ed7be5d851 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Nov 2020 14:18:57 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_open_confirm() + +From: Chuck Lever + +[ Upstream commit 06bee693a1f1cb774b91000f05a6e183c257d8e9 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 2de54e84a3ab0..7b6fb11cdc809 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -1155,18 +1155,18 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) + static __be32 + nfsd4_decode_open_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_open_confirm *open_conf) + { +- DECODE_HEAD; ++ __be32 status; + + if (argp->minorversion >= 1) + return nfserr_notsupp; + +- status = nfsd4_decode_stateid(argp, &open_conf->oc_req_stateid); ++ status = nfsd4_decode_stateid4(argp, &open_conf->oc_req_stateid); + if (status) + return status; +- READ_BUF(4); +- open_conf->oc_seqid = be32_to_cpup(p++); ++ if (xdr_stream_decode_u32(argp->xdr, &open_conf->oc_seqid) < 0) ++ return nfserr_bad_xdr; + +- DECODE_TAIL; ++ return nfs_ok; + } + + static __be32 +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_open_downgr.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_open_downgr.patch new file mode 100644 index 00000000000..d7bd09ca050 --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_open_downgr.patch @@ -0,0 +1,51 @@ +From c45eb1fbbed91b008d22d90fcbbb59e1b4bb8645 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Nov 2020 14:21:01 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_open_downgrade() + +From: Chuck Lever + +[ Upstream commit dca71651f097ea608945d7a66bf62761a630de9a ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 16 +++++++--------- + 1 file changed, 7 insertions(+), 9 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 7b6fb11cdc809..95c755473899f 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -1172,21 +1172,19 @@ nfsd4_decode_open_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_open_con + static __be32 + nfsd4_decode_open_downgrade(struct nfsd4_compoundargs *argp, struct nfsd4_open_downgrade *open_down) + { +- DECODE_HEAD; +- +- status = nfsd4_decode_stateid(argp, &open_down->od_stateid); ++ __be32 status; ++ ++ status = nfsd4_decode_stateid4(argp, &open_down->od_stateid); + if (status) + return status; +- READ_BUF(4); +- open_down->od_seqid = be32_to_cpup(p++); ++ if (xdr_stream_decode_u32(argp->xdr, &open_down->od_seqid) < 0) ++ return nfserr_bad_xdr; ++ /* deleg_want is ignored */ + status = nfsd4_decode_share_access(argp, &open_down->od_share_access, + &open_down->od_deleg_want, NULL); + if (status) + return status; +- status = nfsd4_decode_share_deny(argp, &open_down->od_share_deny); +- if (status) +- return status; +- DECODE_TAIL; ++ return nfsd4_decode_share_deny(argp, &open_down->od_share_deny); + } + + static __be32 +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_putfh.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_putfh.patch new file mode 100644 index 00000000000..4be885bfb6d --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_putfh.patch @@ -0,0 +1,51 @@ +From eb4d3e83224296e7edfe9a74c9a7f9e8913fd5a9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Nov 2020 14:23:02 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_putfh() + +From: Chuck Lever + +[ Upstream commit a73bed98413b1d9eb4466f776a56d2fde8b3b2c9 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 19 ++++++++++++------- + 1 file changed, 12 insertions(+), 7 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 95c755473899f..149948393ccb1 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -1190,16 +1190,21 @@ nfsd4_decode_open_downgrade(struct nfsd4_compoundargs *argp, struct nfsd4_open_d + static __be32 + nfsd4_decode_putfh(struct nfsd4_compoundargs *argp, struct nfsd4_putfh *putfh) + { +- DECODE_HEAD; ++ __be32 *p; + +- READ_BUF(4); +- putfh->pf_fhlen = be32_to_cpup(p++); ++ if (xdr_stream_decode_u32(argp->xdr, &putfh->pf_fhlen) < 0) ++ return nfserr_bad_xdr; + if (putfh->pf_fhlen > NFS4_FHSIZE) +- goto xdr_error; +- READ_BUF(putfh->pf_fhlen); +- SAVEMEM(putfh->pf_fhval, putfh->pf_fhlen); ++ return nfserr_bad_xdr; ++ p = xdr_inline_decode(argp->xdr, putfh->pf_fhlen); ++ if (!p) ++ return nfserr_bad_xdr; ++ putfh->pf_fhval = svcxdr_tmpalloc(argp, putfh->pf_fhlen); ++ if (!putfh->pf_fhval) ++ return nfserr_jukebox; ++ memcpy(putfh->pf_fhval, p, putfh->pf_fhlen); + +- DECODE_TAIL; ++ return nfs_ok; + } + + static __be32 +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_read.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_read.patch new file mode 100644 index 00000000000..07330fd5a01 --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_read.patch @@ -0,0 +1,46 @@ +From dd52e86025f2a1bfc9fd650b0f8ae7e97baa3be5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Nov 2020 14:28:24 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_read() + +From: Chuck Lever + +[ Upstream commit 3909c3bc604688503e31ddceb429dc156c4720c1 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 13 +++++++------ + 1 file changed, 7 insertions(+), 6 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 149948393ccb1..c9652040d748b 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -1218,16 +1218,17 @@ nfsd4_decode_putpubfh(struct nfsd4_compoundargs *argp, void *p) + static __be32 + nfsd4_decode_read(struct nfsd4_compoundargs *argp, struct nfsd4_read *read) + { +- DECODE_HEAD; ++ __be32 status; + +- status = nfsd4_decode_stateid(argp, &read->rd_stateid); ++ status = nfsd4_decode_stateid4(argp, &read->rd_stateid); + if (status) + return status; +- READ_BUF(12); +- p = xdr_decode_hyper(p, &read->rd_offset); +- read->rd_length = be32_to_cpup(p++); ++ if (xdr_stream_decode_u64(argp->xdr, &read->rd_offset) < 0) ++ return nfserr_bad_xdr; ++ if (xdr_stream_decode_u32(argp->xdr, &read->rd_length) < 0) ++ return nfserr_bad_xdr; + +- DECODE_TAIL; ++ return nfs_ok; + } + + static __be32 +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_readdir.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_readdir.patch new file mode 100644 index 00000000000..c2983722f45 --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_readdir.patch @@ -0,0 +1,54 @@ +From f7ad94c3383bb0741ed957f096aaeb3b88caa2ab Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Nov 2020 14:30:59 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_readdir() + +From: Chuck Lever + +[ Upstream commit 0dfaf2a371436860ace6af889e6cd8410ee63164 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 23 ++++++++++++++--------- + 1 file changed, 14 insertions(+), 9 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index c9652040d748b..6036f8d595efa 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -1234,17 +1234,22 @@ nfsd4_decode_read(struct nfsd4_compoundargs *argp, struct nfsd4_read *read) + static __be32 + nfsd4_decode_readdir(struct nfsd4_compoundargs *argp, struct nfsd4_readdir *readdir) + { +- DECODE_HEAD; ++ __be32 status; + +- READ_BUF(24); +- p = xdr_decode_hyper(p, &readdir->rd_cookie); +- COPYMEM(readdir->rd_verf.data, sizeof(readdir->rd_verf.data)); +- readdir->rd_dircount = be32_to_cpup(p++); +- readdir->rd_maxcount = be32_to_cpup(p++); +- if ((status = nfsd4_decode_bitmap(argp, readdir->rd_bmval))) +- goto out; ++ if (xdr_stream_decode_u64(argp->xdr, &readdir->rd_cookie) < 0) ++ return nfserr_bad_xdr; ++ status = nfsd4_decode_verifier4(argp, &readdir->rd_verf); ++ if (status) ++ return status; ++ if (xdr_stream_decode_u32(argp->xdr, &readdir->rd_dircount) < 0) ++ return nfserr_bad_xdr; ++ if (xdr_stream_decode_u32(argp->xdr, &readdir->rd_maxcount) < 0) ++ return nfserr_bad_xdr; ++ if (xdr_stream_decode_uint32_array(argp->xdr, readdir->rd_bmval, ++ ARRAY_SIZE(readdir->rd_bmval)) < 0) ++ return nfserr_bad_xdr; + +- DECODE_TAIL; ++ return nfs_ok; + } + + static __be32 +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_reclaim_com.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_reclaim_com.patch new file mode 100644 index 00000000000..e4fb6f93bb6 --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_reclaim_com.patch @@ -0,0 +1,54 @@ +From abff63656d7a0a11be8c96a2e22fb144385a225a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Nov 2020 15:02:11 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_reclaim_complete() + +From: Chuck Lever + +[ Upstream commit 0d6467844d437e07db1e76d96176b1a55401018c ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 18 ++++++++---------- + 1 file changed, 8 insertions(+), 10 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index d0f0b7cd4e74e..2c684f7e74650 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -1738,16 +1738,6 @@ nfsd4_decode_free_stateid(struct nfsd4_compoundargs *argp, + return nfsd4_decode_stateid4(argp, &free_stateid->fr_stateid); + } + +-static __be32 nfsd4_decode_reclaim_complete(struct nfsd4_compoundargs *argp, struct nfsd4_reclaim_complete *rc) +-{ +- DECODE_HEAD; +- +- READ_BUF(4); +- rc->rca_one_fs = be32_to_cpup(p++); +- +- DECODE_TAIL; +-} +- + #ifdef CONFIG_NFSD_PNFS + static __be32 + nfsd4_decode_getdeviceinfo(struct nfsd4_compoundargs *argp, +@@ -1904,6 +1894,14 @@ static __be32 nfsd4_decode_destroy_clientid(struct nfsd4_compoundargs *argp, + return nfsd4_decode_clientid4(argp, &dc->clientid); + } + ++static __be32 nfsd4_decode_reclaim_complete(struct nfsd4_compoundargs *argp, ++ struct nfsd4_reclaim_complete *rc) ++{ ++ if (xdr_stream_decode_bool(argp->xdr, &rc->rca_one_fs) < 0) ++ return nfserr_bad_xdr; ++ return nfs_ok; ++} ++ + static __be32 + nfsd4_decode_fallocate(struct nfsd4_compoundargs *argp, + struct nfsd4_fallocate *fallocate) +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_release_loc.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_release_loc.patch new file mode 100644 index 00000000000..37f0e619665 --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_release_loc.patch @@ -0,0 +1,50 @@ +From 186df6c58429fa65e031b8ef7da1d0ef8e76865c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Nov 2020 13:42:25 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_release_lockowner() + +From: Chuck Lever + +[ Upstream commit a4a80c15ca4dd998ab5cbe87bd856c626a318a80 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 26744b7f0e35c..cc406b7a530b6 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -1418,20 +1418,20 @@ nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write) + static __be32 + nfsd4_decode_release_lockowner(struct nfsd4_compoundargs *argp, struct nfsd4_release_lockowner *rlockowner) + { +- DECODE_HEAD; ++ __be32 status; + + if (argp->minorversion >= 1) + return nfserr_notsupp; + +- READ_BUF(12); +- COPYMEM(&rlockowner->rl_clientid, sizeof(clientid_t)); +- rlockowner->rl_owner.len = be32_to_cpup(p++); +- READ_BUF(rlockowner->rl_owner.len); +- READMEM(rlockowner->rl_owner.data, rlockowner->rl_owner.len); ++ status = nfsd4_decode_state_owner4(argp, &rlockowner->rl_clientid, ++ &rlockowner->rl_owner); ++ if (status) ++ return status; + + if (argp->minorversion && !zero_clientid(&rlockowner->rl_clientid)) + return nfserr_inval; +- DECODE_TAIL; ++ ++ return nfs_ok; + } + + static __be32 +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_remove.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_remove.patch new file mode 100644 index 00000000000..711dc310991 --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_remove.patch @@ -0,0 +1,40 @@ +From e5dbaf8f00e755364556bb79aeeb775e86354d45 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Nov 2020 15:04:36 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_remove() + +From: Chuck Lever + +[ Upstream commit b7f5fbf219aecda98e32de305551e445f9438899 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 11 +---------- + 1 file changed, 1 insertion(+), 10 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 6036f8d595efa..d4e1e3138739c 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -1255,16 +1255,7 @@ nfsd4_decode_readdir(struct nfsd4_compoundargs *argp, struct nfsd4_readdir *read + static __be32 + nfsd4_decode_remove(struct nfsd4_compoundargs *argp, struct nfsd4_remove *remove) + { +- DECODE_HEAD; +- +- READ_BUF(4); +- remove->rm_namelen = be32_to_cpup(p++); +- READ_BUF(remove->rm_namelen); +- SAVEMEM(remove->rm_name, remove->rm_namelen); +- if ((status = check_filename(remove->rm_name, remove->rm_namelen))) +- return status; +- +- DECODE_TAIL; ++ return nfsd4_decode_component4(argp, &remove->rm_name, &remove->rm_namelen); + } + + static __be32 +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_rename.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_rename.patch new file mode 100644 index 00000000000..5d371c5fbc1 --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_rename.patch @@ -0,0 +1,49 @@ +From 756c64153c0fe553efc24f0265732ffd64f83611 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Nov 2020 15:05:58 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_rename() + +From: Chuck Lever + +[ Upstream commit ba881a0a5342b3aaf83958901ebe3fe752eaab46 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 18 ++++-------------- + 1 file changed, 4 insertions(+), 14 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index d4e1e3138739c..adf4a6fb94d4c 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -1261,22 +1261,12 @@ nfsd4_decode_remove(struct nfsd4_compoundargs *argp, struct nfsd4_remove *remove + static __be32 + nfsd4_decode_rename(struct nfsd4_compoundargs *argp, struct nfsd4_rename *rename) + { +- DECODE_HEAD; ++ __be32 status; + +- READ_BUF(4); +- rename->rn_snamelen = be32_to_cpup(p++); +- READ_BUF(rename->rn_snamelen); +- SAVEMEM(rename->rn_sname, rename->rn_snamelen); +- READ_BUF(4); +- rename->rn_tnamelen = be32_to_cpup(p++); +- READ_BUF(rename->rn_tnamelen); +- SAVEMEM(rename->rn_tname, rename->rn_tnamelen); +- if ((status = check_filename(rename->rn_sname, rename->rn_snamelen))) +- return status; +- if ((status = check_filename(rename->rn_tname, rename->rn_tnamelen))) ++ status = nfsd4_decode_component4(argp, &rename->rn_sname, &rename->rn_snamelen); ++ if (status) + return status; +- +- DECODE_TAIL; ++ return nfsd4_decode_component4(argp, &rename->rn_tname, &rename->rn_tnamelen); + } + + static __be32 +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_renew.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_renew.patch new file mode 100644 index 00000000000..72854eeddca --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_renew.patch @@ -0,0 +1,39 @@ +From fa54d105e8ac7689ad2e2eb0ba3cce63d8a39b61 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Nov 2020 15:08:50 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_renew() + +From: Chuck Lever + +[ Upstream commit d12f90458dc8c11734ba44ec88f109bf8de86ff0 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 10 +--------- + 1 file changed, 1 insertion(+), 9 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index adf4a6fb94d4c..51b59b369d726 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -1272,15 +1272,7 @@ nfsd4_decode_rename(struct nfsd4_compoundargs *argp, struct nfsd4_rename *rename + static __be32 + nfsd4_decode_renew(struct nfsd4_compoundargs *argp, clientid_t *clientid) + { +- DECODE_HEAD; +- +- if (argp->minorversion >= 1) +- return nfserr_notsupp; +- +- READ_BUF(sizeof(clientid_t)); +- COPYMEM(clientid, sizeof(clientid_t)); +- +- DECODE_TAIL; ++ return nfsd4_decode_clientid4(argp, clientid); + } + + static __be32 +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_secinfo.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_secinfo.patch new file mode 100644 index 00000000000..3b815d7e18f --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_secinfo.patch @@ -0,0 +1,40 @@ +From 33cf8efdfdab54c5fd981c9bfc34e68136986d17 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Nov 2020 15:09:42 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_secinfo() + +From: Chuck Lever + +[ Upstream commit d0abdae5191a916d767164f6fc6c0e2e814a20a7 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 11 +---------- + 1 file changed, 1 insertion(+), 10 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 51b59b369d726..42d69c0207ce8 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -1279,16 +1279,7 @@ static __be32 + nfsd4_decode_secinfo(struct nfsd4_compoundargs *argp, + struct nfsd4_secinfo *secinfo) + { +- DECODE_HEAD; +- +- READ_BUF(4); +- secinfo->si_namelen = be32_to_cpup(p++); +- READ_BUF(secinfo->si_namelen); +- SAVEMEM(secinfo->si_name, secinfo->si_namelen); +- status = check_filename(secinfo->si_name, secinfo->si_namelen); +- if (status) +- return status; +- DECODE_TAIL; ++ return nfsd4_decode_component4(argp, &secinfo->si_name, &secinfo->si_namelen); + } + + static __be32 +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_secinfo_no_.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_secinfo_no_.patch new file mode 100644 index 00000000000..c48a48a205b --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_secinfo_no_.patch @@ -0,0 +1,55 @@ +From 768f0bfc80a59bcad3c02415629c0908a7759145 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Nov 2020 14:33:12 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_secinfo_no_name() + +From: Chuck Lever + +[ Upstream commit 53d70873e37c09a582167ed73d1858e3a2af0157 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 19 ++++++++----------- + 1 file changed, 8 insertions(+), 11 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index ae70070a58213..0561b43855839 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -1356,17 +1356,6 @@ nfsd4_decode_secinfo(struct nfsd4_compoundargs *argp, + return nfsd4_decode_component4(argp, &secinfo->si_name, &secinfo->si_namelen); + } + +-static __be32 +-nfsd4_decode_secinfo_no_name(struct nfsd4_compoundargs *argp, +- struct nfsd4_secinfo_no_name *sin) +-{ +- DECODE_HEAD; +- +- READ_BUF(4); +- sin->sin_style = be32_to_cpup(p++); +- DECODE_TAIL; +-} +- + static __be32 + nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *setattr) + { +@@ -1918,6 +1907,14 @@ nfsd4_decode_layoutreturn(struct nfsd4_compoundargs *argp, + } + #endif /* CONFIG_NFSD_PNFS */ + ++static __be32 nfsd4_decode_secinfo_no_name(struct nfsd4_compoundargs *argp, ++ struct nfsd4_secinfo_no_name *sin) ++{ ++ if (xdr_stream_decode_u32(argp->xdr, &sin->sin_style) < 0) ++ return nfserr_bad_xdr; ++ return nfs_ok; ++} ++ + static __be32 + nfsd4_decode_fallocate(struct nfsd4_compoundargs *argp, + struct nfsd4_fallocate *fallocate) +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_seek.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_seek.patch new file mode 100644 index 00000000000..6ead228d45e --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_seek.patch @@ -0,0 +1,47 @@ +From e1f4944e220df4711e4f3f610075eb2ec13da9d1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Nov 2020 10:54:47 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_seek() + +From: Chuck Lever + +[ Upstream commit 9d32b412fe0a6186cc57789d218e8f8299454ae2 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 101beb315d963..2e2fae7e38db2 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -2054,17 +2054,17 @@ nfsd4_decode_offload_status(struct nfsd4_compoundargs *argp, + static __be32 + nfsd4_decode_seek(struct nfsd4_compoundargs *argp, struct nfsd4_seek *seek) + { +- DECODE_HEAD; ++ __be32 status; + +- status = nfsd4_decode_stateid(argp, &seek->seek_stateid); ++ status = nfsd4_decode_stateid4(argp, &seek->seek_stateid); + if (status) + return status; ++ if (xdr_stream_decode_u64(argp->xdr, &seek->seek_offset) < 0) ++ return nfserr_bad_xdr; ++ if (xdr_stream_decode_u32(argp->xdr, &seek->seek_whence) < 0) ++ return nfserr_bad_xdr; + +- READ_BUF(8 + 4); +- p = xdr_decode_hyper(p, &seek->seek_offset); +- seek->seek_whence = be32_to_cpup(p); +- +- DECODE_TAIL; ++ return nfs_ok; + } + + /* +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_sequence.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_sequence.patch new file mode 100644 index 00000000000..2de19f8553a --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_sequence.patch @@ -0,0 +1,72 @@ +From d8ac18862d016a199876e330c52f9795a4f5e03a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Nov 2020 14:55:19 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_sequence() + +From: Chuck Lever + +[ Upstream commit cf907b11326d9360877d6c6ea8f75e1b29f39f2f ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 36 ++++++++++++++++++++---------------- + 1 file changed, 20 insertions(+), 16 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 0561b43855839..3fe0d0228c4ac 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -1738,22 +1738,6 @@ nfsd4_decode_free_stateid(struct nfsd4_compoundargs *argp, + return nfsd4_decode_stateid4(argp, &free_stateid->fr_stateid); + } + +-static __be32 +-nfsd4_decode_sequence(struct nfsd4_compoundargs *argp, +- struct nfsd4_sequence *seq) +-{ +- DECODE_HEAD; +- +- READ_BUF(NFS4_MAX_SESSIONID_LEN + 16); +- COPYMEM(seq->sessionid.data, NFS4_MAX_SESSIONID_LEN); +- seq->seqid = be32_to_cpup(p++); +- seq->slotid = be32_to_cpup(p++); +- seq->maxslots = be32_to_cpup(p++); +- seq->cachethis = be32_to_cpup(p++); +- +- DECODE_TAIL; +-} +- + static __be32 + nfsd4_decode_test_stateid(struct nfsd4_compoundargs *argp, struct nfsd4_test_stateid *test_stateid) + { +@@ -1915,6 +1899,26 @@ static __be32 nfsd4_decode_secinfo_no_name(struct nfsd4_compoundargs *argp, + return nfs_ok; + } + ++static __be32 ++nfsd4_decode_sequence(struct nfsd4_compoundargs *argp, ++ struct nfsd4_sequence *seq) ++{ ++ __be32 *p, status; ++ ++ status = nfsd4_decode_sessionid4(argp, &seq->sessionid); ++ if (status) ++ return status; ++ p = xdr_inline_decode(argp->xdr, XDR_UNIT * 4); ++ if (!p) ++ return nfserr_bad_xdr; ++ seq->seqid = be32_to_cpup(p++); ++ seq->slotid = be32_to_cpup(p++); ++ seq->maxslots = be32_to_cpup(p++); ++ seq->cachethis = be32_to_cpup(p); ++ ++ return nfs_ok; ++} ++ + static __be32 + nfsd4_decode_fallocate(struct nfsd4_compoundargs *argp, + struct nfsd4_fallocate *fallocate) +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_setattr.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_setattr.patch new file mode 100644 index 00000000000..cce4aa8c652 --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_setattr.patch @@ -0,0 +1,31 @@ +From b7ab8f211b80a4d014c42eea9992de67fa415733 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 21 Nov 2020 14:14:59 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_setattr() + +From: Chuck Lever + +[ Upstream commit 44592fe9479d8d4b88594365ab825f7b07afdf7c ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 42d69c0207ce8..cda56ca9ca3fc 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -1298,7 +1298,7 @@ nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *seta + { + __be32 status; + +- status = nfsd4_decode_stateid(argp, &setattr->sa_stateid); ++ status = nfsd4_decode_stateid4(argp, &setattr->sa_stateid); + if (status) + return status; + return nfsd4_decode_fattr4(argp, setattr->sa_bmval, +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_setclientid.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_setclientid.patch new file mode 100644 index 00000000000..43ab2d8d3f2 --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_setclientid.patch @@ -0,0 +1,85 @@ +From dea7ba3f5ba18b27bf50032ad46687c86efe6b0d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Nov 2020 14:35:02 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_setclientid() + +From: Chuck Lever + +[ Upstream commit 92fa6c08c251d52d0d7b46066ecf87b96a0c4b8f ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 47 +++++++++++++++++++++++++++++++---------------- + 1 file changed, 31 insertions(+), 16 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index cda56ca9ca3fc..0af51cc1adba3 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -1310,31 +1310,46 @@ nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *seta + static __be32 + nfsd4_decode_setclientid(struct nfsd4_compoundargs *argp, struct nfsd4_setclientid *setclientid) + { +- DECODE_HEAD; ++ __be32 *p, status; + + if (argp->minorversion >= 1) + return nfserr_notsupp; + +- READ_BUF(NFS4_VERIFIER_SIZE); +- COPYMEM(setclientid->se_verf.data, NFS4_VERIFIER_SIZE); +- ++ status = nfsd4_decode_verifier4(argp, &setclientid->se_verf); ++ if (status) ++ return status; + status = nfsd4_decode_opaque(argp, &setclientid->se_name); + if (status) ++ return status; ++ if (xdr_stream_decode_u32(argp->xdr, &setclientid->se_callback_prog) < 0) + return nfserr_bad_xdr; +- READ_BUF(8); +- setclientid->se_callback_prog = be32_to_cpup(p++); +- setclientid->se_callback_netid_len = be32_to_cpup(p++); +- READ_BUF(setclientid->se_callback_netid_len); +- SAVEMEM(setclientid->se_callback_netid_val, setclientid->se_callback_netid_len); +- READ_BUF(4); +- setclientid->se_callback_addr_len = be32_to_cpup(p++); ++ if (xdr_stream_decode_u32(argp->xdr, &setclientid->se_callback_netid_len) < 0) ++ return nfserr_bad_xdr; ++ p = xdr_inline_decode(argp->xdr, setclientid->se_callback_netid_len); ++ if (!p) ++ return nfserr_bad_xdr; ++ setclientid->se_callback_netid_val = svcxdr_tmpalloc(argp, ++ setclientid->se_callback_netid_len); ++ if (!setclientid->se_callback_netid_val) ++ return nfserr_jukebox; ++ memcpy(setclientid->se_callback_netid_val, p, ++ setclientid->se_callback_netid_len); + +- READ_BUF(setclientid->se_callback_addr_len); +- SAVEMEM(setclientid->se_callback_addr_val, setclientid->se_callback_addr_len); +- READ_BUF(4); +- setclientid->se_callback_ident = be32_to_cpup(p++); ++ if (xdr_stream_decode_u32(argp->xdr, &setclientid->se_callback_addr_len) < 0) ++ return nfserr_bad_xdr; ++ p = xdr_inline_decode(argp->xdr, setclientid->se_callback_addr_len); ++ if (!p) ++ return nfserr_bad_xdr; ++ setclientid->se_callback_addr_val = svcxdr_tmpalloc(argp, ++ setclientid->se_callback_addr_len); ++ if (!setclientid->se_callback_addr_val) ++ return nfserr_jukebox; ++ memcpy(setclientid->se_callback_addr_val, p, ++ setclientid->se_callback_addr_len); ++ if (xdr_stream_decode_u32(argp->xdr, &setclientid->se_callback_ident) < 0) ++ return nfserr_bad_xdr; + +- DECODE_TAIL; ++ return nfs_ok; + } + + static __be32 +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_setclientid.patch-10977 b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_setclientid.patch-10977 new file mode 100644 index 00000000000..d0790ae9e59 --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_setclientid.patch-10977 @@ -0,0 +1,44 @@ +From b6cacff884227be8dc65bb7423976dcc89b207f9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Nov 2020 15:12:33 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_setclientid_confirm() + +From: Chuck Lever + +[ Upstream commit d1ca55149d67e5896f89a30053f5d83c002ac10e ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 11 +++++------ + 1 file changed, 5 insertions(+), 6 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 0af51cc1adba3..057cc1579f9b8 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -1355,16 +1355,15 @@ nfsd4_decode_setclientid(struct nfsd4_compoundargs *argp, struct nfsd4_setclient + static __be32 + nfsd4_decode_setclientid_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_setclientid_confirm *scd_c) + { +- DECODE_HEAD; ++ __be32 status; + + if (argp->minorversion >= 1) + return nfserr_notsupp; + +- READ_BUF(8 + NFS4_VERIFIER_SIZE); +- COPYMEM(&scd_c->sc_clientid, 8); +- COPYMEM(&scd_c->sc_confirm, NFS4_VERIFIER_SIZE); +- +- DECODE_TAIL; ++ status = nfsd4_decode_clientid4(argp, &scd_c->sc_clientid); ++ if (status) ++ return status; ++ return nfsd4_decode_verifier4(argp, &scd_c->sc_confirm); + } + + /* Also used for NVERIFY */ +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_setxattr.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_setxattr.patch new file mode 100644 index 00000000000..5b52a6c11fb --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_setxattr.patch @@ -0,0 +1,63 @@ +From 68491b35b44a357ab301e0f9d1a3a3c8abfa4ab7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Nov 2020 10:59:57 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_setxattr() + +From: Chuck Lever + +[ Upstream commit 403366a7e8e2930002157525cd44add7fa01bca9 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 1fcb668e4110d..38610764d7161 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -2184,11 +2184,11 @@ static __be32 + nfsd4_decode_setxattr(struct nfsd4_compoundargs *argp, + struct nfsd4_setxattr *setxattr) + { +- DECODE_HEAD; + u32 flags, maxcount, size; ++ __be32 status; + +- READ_BUF(4); +- flags = be32_to_cpup(p++); ++ if (xdr_stream_decode_u32(argp->xdr, &flags) < 0) ++ return nfserr_bad_xdr; + + if (flags > SETXATTR4_REPLACE) + return nfserr_inval; +@@ -2201,8 +2201,8 @@ nfsd4_decode_setxattr(struct nfsd4_compoundargs *argp, + maxcount = svc_max_payload(argp->rqstp); + maxcount = min_t(u32, XATTR_SIZE_MAX, maxcount); + +- READ_BUF(4); +- size = be32_to_cpup(p++); ++ if (xdr_stream_decode_u32(argp->xdr, &size) < 0) ++ return nfserr_bad_xdr; + if (size > maxcount) + return nfserr_xattr2big; + +@@ -2211,12 +2211,12 @@ nfsd4_decode_setxattr(struct nfsd4_compoundargs *argp, + struct xdr_buf payload; + + if (!xdr_stream_subsegment(argp->xdr, &payload, size)) +- goto xdr_error; ++ return nfserr_bad_xdr; + status = nfsd4_vbuf_from_vector(argp, &payload, + &setxattr->setxa_buf, size); + } + +- DECODE_TAIL; ++ return nfs_ok; + } + + static __be32 +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_share_acces.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_share_acces.patch new file mode 100644 index 00000000000..12ecd294e0a --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_share_acces.patch @@ -0,0 +1,44 @@ +From 1984ec0e20179b5e820bd5b24d2aee416a3395e8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Nov 2020 17:54:48 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_share_access() + +From: Chuck Lever + +[ Upstream commit 9aa62f5199749b274454b6d7d914c9b2a5e77031 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 76715d1935ade..a43b39940ab25 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -1012,11 +1012,10 @@ nfsd4_decode_openflag4(struct nfsd4_compoundargs *argp, struct nfsd4_open *open) + + static __be32 nfsd4_decode_share_access(struct nfsd4_compoundargs *argp, u32 *share_access, u32 *deleg_want, u32 *deleg_when) + { +- __be32 *p; + u32 w; + +- READ_BUF(4); +- w = be32_to_cpup(p++); ++ if (xdr_stream_decode_u32(argp->xdr, &w) < 0) ++ return nfserr_bad_xdr; + *share_access = w & NFS4_SHARE_ACCESS_MASK; + *deleg_want = w & NFS4_SHARE_WANT_MASK; + if (deleg_when) +@@ -1059,7 +1058,6 @@ static __be32 nfsd4_decode_share_access(struct nfsd4_compoundargs *argp, u32 *sh + NFS4_SHARE_PUSH_DELEG_WHEN_UNCONTENDED): + return nfs_ok; + } +-xdr_error: + return nfserr_bad_xdr; + } + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_share_deny.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_share_deny.patch new file mode 100644 index 00000000000..6646660f2f0 --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_share_deny.patch @@ -0,0 +1,43 @@ +From a6735cd362005816473a5ded3aa7af991f66ccc0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 16 Nov 2020 17:56:17 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_share_deny() + +From: Chuck Lever + +[ Upstream commit b07bebd9eb9842e2d0dea87efeb92884556e55b0 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 11 ++++------- + 1 file changed, 4 insertions(+), 7 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index a43b39940ab25..a9257ec9d151d 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -1063,16 +1063,13 @@ static __be32 nfsd4_decode_share_access(struct nfsd4_compoundargs *argp, u32 *sh + + static __be32 nfsd4_decode_share_deny(struct nfsd4_compoundargs *argp, u32 *x) + { +- __be32 *p; +- +- READ_BUF(4); +- *x = be32_to_cpup(p++); +- /* Note: unlinke access bits, deny bits may be zero. */ ++ if (xdr_stream_decode_u32(argp->xdr, x) < 0) ++ return nfserr_bad_xdr; ++ /* Note: unlike access bits, deny bits may be zero. */ + if (*x & ~NFS4_SHARE_DENY_BOTH) + return nfserr_bad_xdr; ++ + return nfs_ok; +-xdr_error: +- return nfserr_bad_xdr; + } + + static __be32 +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_test_statei.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_test_statei.patch new file mode 100644 index 00000000000..096aa3f384a --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_test_statei.patch @@ -0,0 +1,97 @@ +From 50dc45c9616c75aca3111ab061209e1f3b22c4dc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Nov 2020 14:57:44 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_test_stateid() + +From: Chuck Lever + +[ Upstream commit b7a0c8f6e741bf9dee0d24e69d3ce51fa4ccce78 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 61 +++++++++++++++++++---------------------------- + 1 file changed, 25 insertions(+), 36 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 3fe0d0228c4ac..9642de1550431 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -1738,42 +1738,6 @@ nfsd4_decode_free_stateid(struct nfsd4_compoundargs *argp, + return nfsd4_decode_stateid4(argp, &free_stateid->fr_stateid); + } + +-static __be32 +-nfsd4_decode_test_stateid(struct nfsd4_compoundargs *argp, struct nfsd4_test_stateid *test_stateid) +-{ +- int i; +- __be32 *p, status; +- struct nfsd4_test_stateid_id *stateid; +- +- READ_BUF(4); +- test_stateid->ts_num_ids = ntohl(*p++); +- +- INIT_LIST_HEAD(&test_stateid->ts_stateid_list); +- +- for (i = 0; i < test_stateid->ts_num_ids; i++) { +- stateid = svcxdr_tmpalloc(argp, sizeof(*stateid)); +- if (!stateid) { +- status = nfserrno(-ENOMEM); +- goto out; +- } +- +- INIT_LIST_HEAD(&stateid->ts_id_list); +- list_add_tail(&stateid->ts_id_list, &test_stateid->ts_stateid_list); +- +- status = nfsd4_decode_stateid(argp, &stateid->ts_id_stateid); +- if (status) +- goto out; +- } +- +- status = 0; +-out: +- return status; +-xdr_error: +- dprintk("NFSD: xdr error (%s:%d)\n", __FILE__, __LINE__); +- status = nfserr_bad_xdr; +- goto out; +-} +- + static __be32 nfsd4_decode_destroy_clientid(struct nfsd4_compoundargs *argp, struct nfsd4_destroy_clientid *dc) + { + DECODE_HEAD; +@@ -1919,6 +1883,31 @@ nfsd4_decode_sequence(struct nfsd4_compoundargs *argp, + return nfs_ok; + } + ++static __be32 ++nfsd4_decode_test_stateid(struct nfsd4_compoundargs *argp, struct nfsd4_test_stateid *test_stateid) ++{ ++ struct nfsd4_test_stateid_id *stateid; ++ __be32 status; ++ u32 i; ++ ++ if (xdr_stream_decode_u32(argp->xdr, &test_stateid->ts_num_ids) < 0) ++ return nfserr_bad_xdr; ++ ++ INIT_LIST_HEAD(&test_stateid->ts_stateid_list); ++ for (i = 0; i < test_stateid->ts_num_ids; i++) { ++ stateid = svcxdr_tmpalloc(argp, sizeof(*stateid)); ++ if (!stateid) ++ return nfserrno(-ENOMEM); /* XXX: not jukebox? */ ++ INIT_LIST_HEAD(&stateid->ts_id_list); ++ list_add_tail(&stateid->ts_id_list, &test_stateid->ts_stateid_list); ++ status = nfsd4_decode_stateid4(argp, &stateid->ts_id_stateid); ++ if (status) ++ return status; ++ } ++ ++ return nfs_ok; ++} ++ + static __be32 + nfsd4_decode_fallocate(struct nfsd4_compoundargs *argp, + struct nfsd4_fallocate *fallocate) +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_verify.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_verify.patch new file mode 100644 index 00000000000..83a66b2e3a0 --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_verify.patch @@ -0,0 +1,58 @@ +From 7692c739868a12c60188268865572bd997cadd79 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Nov 2020 14:40:32 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_verify() + +From: Chuck Lever + +[ Upstream commit 67cd453eeda86be90f83a0f4798f33832cf2d98c ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 23 +++++++++++++++-------- + 1 file changed, 15 insertions(+), 8 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 057cc1579f9b8..231a2628e3e6f 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -1370,20 +1370,27 @@ nfsd4_decode_setclientid_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_s + static __be32 + nfsd4_decode_verify(struct nfsd4_compoundargs *argp, struct nfsd4_verify *verify) + { +- DECODE_HEAD; ++ __be32 *p, status; + +- if ((status = nfsd4_decode_bitmap(argp, verify->ve_bmval))) +- goto out; ++ status = nfsd4_decode_bitmap4(argp, verify->ve_bmval, ++ ARRAY_SIZE(verify->ve_bmval)); ++ if (status) ++ return status; + + /* For convenience's sake, we compare raw xdr'd attributes in + * nfsd4_proc_verify */ + +- READ_BUF(4); +- verify->ve_attrlen = be32_to_cpup(p++); +- READ_BUF(verify->ve_attrlen); +- SAVEMEM(verify->ve_attrval, verify->ve_attrlen); ++ if (xdr_stream_decode_u32(argp->xdr, &verify->ve_attrlen) < 0) ++ return nfserr_bad_xdr; ++ p = xdr_inline_decode(argp->xdr, verify->ve_attrlen); ++ if (!p) ++ return nfserr_bad_xdr; ++ verify->ve_attrval = svcxdr_tmpalloc(argp, verify->ve_attrlen); ++ if (!verify->ve_attrval) ++ return nfserr_jukebox; ++ memcpy(verify->ve_attrval, p, verify->ve_attrlen); + +- DECODE_TAIL; ++ return nfs_ok; + } + + static __be32 +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_write.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_write.patch new file mode 100644 index 00000000000..54171259716 --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_write.patch @@ -0,0 +1,56 @@ +From 9fc31de8ae23b51f974e510eb86c01de25e64395 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Nov 2020 14:44:28 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_write() + +From: Chuck Lever + +[ Upstream commit 244e2befcba80f42c65293b6c56282bb78f9f417 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 21 +++++++++++---------- + 1 file changed, 11 insertions(+), 10 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 231a2628e3e6f..26744b7f0e35c 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -1396,22 +1396,23 @@ nfsd4_decode_verify(struct nfsd4_compoundargs *argp, struct nfsd4_verify *verify + static __be32 + nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write) + { +- DECODE_HEAD; ++ __be32 status; + +- status = nfsd4_decode_stateid(argp, &write->wr_stateid); ++ status = nfsd4_decode_stateid4(argp, &write->wr_stateid); + if (status) + return status; +- READ_BUF(16); +- p = xdr_decode_hyper(p, &write->wr_offset); +- write->wr_stable_how = be32_to_cpup(p++); ++ if (xdr_stream_decode_u64(argp->xdr, &write->wr_offset) < 0) ++ return nfserr_bad_xdr; ++ if (xdr_stream_decode_u32(argp->xdr, &write->wr_stable_how) < 0) ++ return nfserr_bad_xdr; + if (write->wr_stable_how > NFS_FILE_SYNC) +- goto xdr_error; +- write->wr_buflen = be32_to_cpup(p++); +- ++ return nfserr_bad_xdr; ++ if (xdr_stream_decode_u32(argp->xdr, &write->wr_buflen) < 0) ++ return nfserr_bad_xdr; + if (!xdr_stream_subsegment(argp->xdr, &write->wr_payload, write->wr_buflen)) +- goto xdr_error; ++ return nfserr_bad_xdr; + +- DECODE_TAIL; ++ return nfs_ok; + } + + static __be32 +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_xattr_name.patch b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_xattr_name.patch new file mode 100644 index 00000000000..969c5d0db7a --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-in-nfsd4_decode_xattr_name.patch @@ -0,0 +1,72 @@ +From 827d9e47406f050b38d5e5ab79167239c2603c27 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 4 Nov 2020 10:56:52 -0500 +Subject: NFSD: Replace READ* macros in nfsd4_decode_xattr_name() + +From: Chuck Lever + +[ Upstream commit 830c71502ae0ae1677ac6c08ffbcf85a6e7b2937 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 21 +++++++++------------ + 1 file changed, 9 insertions(+), 12 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index bf2a2ef6a8b97..1fcb668e4110d 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -2117,25 +2117,22 @@ nfsd4_vbuf_from_vector(struct nfsd4_compoundargs *argp, struct xdr_buf *xdr, + static __be32 + nfsd4_decode_xattr_name(struct nfsd4_compoundargs *argp, char **namep) + { +- DECODE_HEAD; + char *name, *sp, *dp; + u32 namelen, cnt; ++ __be32 *p; + +- READ_BUF(4); +- namelen = be32_to_cpup(p++); +- ++ if (xdr_stream_decode_u32(argp->xdr, &namelen) < 0) ++ return nfserr_bad_xdr; + if (namelen > (XATTR_NAME_MAX - XATTR_USER_PREFIX_LEN)) + return nfserr_nametoolong; +- + if (namelen == 0) +- goto xdr_error; +- +- READ_BUF(namelen); +- ++ return nfserr_bad_xdr; ++ p = xdr_inline_decode(argp->xdr, namelen); ++ if (!p) ++ return nfserr_bad_xdr; + name = svcxdr_tmpalloc(argp, namelen + XATTR_USER_PREFIX_LEN + 1); + if (!name) + return nfserr_jukebox; +- + memcpy(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN); + + /* +@@ -2148,14 +2145,14 @@ nfsd4_decode_xattr_name(struct nfsd4_compoundargs *argp, char **namep) + + while (cnt-- > 0) { + if (*sp == '\0') +- goto xdr_error; ++ return nfserr_bad_xdr; + *dp++ = *sp++; + } + *dp = '\0'; + + *namep = name; + +- DECODE_TAIL; ++ return nfs_ok; + } + + /* +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-that-decode-the-fattr4-acl-.patch b/queue-5.10/nfsd-replace-read-macros-that-decode-the-fattr4-acl-.patch new file mode 100644 index 00000000000..ef0a5ddfd1a --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-that-decode-the-fattr4-acl-.patch @@ -0,0 +1,145 @@ +From 27d2d86e9adc21057e11ca0c83ba1294c1118ac2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Nov 2020 13:02:54 -0500 +Subject: NFSD: Replace READ* macros that decode the fattr4 acl attribute + +From: Chuck Lever + +[ Upstream commit c941a96823cf52e742606b486b81ab346bf111c9 ] + +Refactor for clarity and to move infrequently-used code out of line. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 107 +++++++++++++++++++++++++++++----------------- + 1 file changed, 67 insertions(+), 40 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 5ec0c2dac3348..0fe57ca0f31ac 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -245,6 +245,70 @@ nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval) + DECODE_TAIL; + } + ++static __be32 ++nfsd4_decode_nfsace4(struct nfsd4_compoundargs *argp, struct nfs4_ace *ace) ++{ ++ __be32 *p, status; ++ u32 length; ++ ++ if (xdr_stream_decode_u32(argp->xdr, &ace->type) < 0) ++ return nfserr_bad_xdr; ++ if (xdr_stream_decode_u32(argp->xdr, &ace->flag) < 0) ++ return nfserr_bad_xdr; ++ if (xdr_stream_decode_u32(argp->xdr, &ace->access_mask) < 0) ++ return nfserr_bad_xdr; ++ ++ if (xdr_stream_decode_u32(argp->xdr, &length) < 0) ++ return nfserr_bad_xdr; ++ p = xdr_inline_decode(argp->xdr, length); ++ if (!p) ++ return nfserr_bad_xdr; ++ ace->whotype = nfs4_acl_get_whotype((char *)p, length); ++ if (ace->whotype != NFS4_ACL_WHO_NAMED) ++ status = nfs_ok; ++ else if (ace->flag & NFS4_ACE_IDENTIFIER_GROUP) ++ status = nfsd_map_name_to_gid(argp->rqstp, ++ (char *)p, length, &ace->who_gid); ++ else ++ status = nfsd_map_name_to_uid(argp->rqstp, ++ (char *)p, length, &ace->who_uid); ++ ++ return status; ++} ++ ++/* A counted array of nfsace4's */ ++static noinline __be32 ++nfsd4_decode_acl(struct nfsd4_compoundargs *argp, struct nfs4_acl **acl) ++{ ++ struct nfs4_ace *ace; ++ __be32 status; ++ u32 count; ++ ++ if (xdr_stream_decode_u32(argp->xdr, &count) < 0) ++ return nfserr_bad_xdr; ++ ++ if (count > xdr_stream_remaining(argp->xdr) / 20) ++ /* ++ * Even with 4-byte names there wouldn't be ++ * space for that many aces; something fishy is ++ * going on: ++ */ ++ return nfserr_fbig; ++ ++ *acl = svcxdr_tmpalloc(argp, nfs4_acl_bytes(count)); ++ if (*acl == NULL) ++ return nfserr_jukebox; ++ ++ (*acl)->naces = count; ++ for (ace = (*acl)->aces; ace < (*acl)->aces + count; ace++) { ++ status = nfsd4_decode_nfsace4(argp, ace); ++ if (status) ++ return status; ++ } ++ ++ return nfs_ok; ++} ++ + static __be32 + nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, + struct iattr *iattr, struct nfs4_acl **acl, +@@ -281,46 +345,9 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, + iattr->ia_valid |= ATTR_SIZE; + } + if (bmval[0] & FATTR4_WORD0_ACL) { +- u32 nace; +- struct nfs4_ace *ace; +- +- READ_BUF(4); +- nace = be32_to_cpup(p++); +- +- if (nace > xdr_stream_remaining(argp->xdr) / sizeof(struct nfs4_ace)) +- /* +- * Even with 4-byte names there wouldn't be +- * space for that many aces; something fishy is +- * going on: +- */ +- return nfserr_fbig; +- +- *acl = svcxdr_tmpalloc(argp, nfs4_acl_bytes(nace)); +- if (*acl == NULL) +- return nfserr_jukebox; +- +- (*acl)->naces = nace; +- for (ace = (*acl)->aces; ace < (*acl)->aces + nace; ace++) { +- READ_BUF(16); +- ace->type = be32_to_cpup(p++); +- ace->flag = be32_to_cpup(p++); +- ace->access_mask = be32_to_cpup(p++); +- dummy32 = be32_to_cpup(p++); +- READ_BUF(dummy32); +- READMEM(buf, dummy32); +- ace->whotype = nfs4_acl_get_whotype(buf, dummy32); +- status = nfs_ok; +- if (ace->whotype != NFS4_ACL_WHO_NAMED) +- ; +- else if (ace->flag & NFS4_ACE_IDENTIFIER_GROUP) +- status = nfsd_map_name_to_gid(argp->rqstp, +- buf, dummy32, &ace->who_gid); +- else +- status = nfsd_map_name_to_uid(argp->rqstp, +- buf, dummy32, &ace->who_uid); +- if (status) +- return status; +- } ++ status = nfsd4_decode_acl(argp, acl); ++ if (status) ++ return status; + } else + *acl = NULL; + if (bmval[1] & FATTR4_WORD1_MODE) { +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-that-decode-the-fattr4-mode.patch b/queue-5.10/nfsd-replace-read-macros-that-decode-the-fattr4-mode.patch new file mode 100644 index 00000000000..617a3153f07 --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-that-decode-the-fattr4-mode.patch @@ -0,0 +1,36 @@ +From f61392aea687eef865c9169f506841da11d52b7e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Nov 2020 13:54:26 -0500 +Subject: NFSD: Replace READ* macros that decode the fattr4 mode attribute + +From: Chuck Lever + +[ Upstream commit 1c8f0ad7dd35fd12307904036c7c839f77b6e3f9 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 0fe57ca0f31ac..9dc73ab95eac9 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -351,8 +351,11 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, + } else + *acl = NULL; + if (bmval[1] & FATTR4_WORD1_MODE) { +- READ_BUF(4); +- iattr->ia_mode = be32_to_cpup(p++); ++ u32 mode; ++ ++ if (xdr_stream_decode_u32(argp->xdr, &mode) < 0) ++ return nfserr_bad_xdr; ++ iattr->ia_mode = mode; + iattr->ia_mode &= (S_IFMT | S_IALLUGO); + iattr->ia_valid |= ATTR_MODE; + } +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-that-decode-the-fattr4-owne.patch b/queue-5.10/nfsd-replace-read-macros-that-decode-the-fattr4-owne.patch new file mode 100644 index 00000000000..c0985f01aaa --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-that-decode-the-fattr4-owne.patch @@ -0,0 +1,44 @@ +From c7029fc2bdb407ae85a4d2fa93998b853fdffe54 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Nov 2020 13:56:42 -0500 +Subject: NFSD: Replace READ* macros that decode the fattr4 owner attribute + +From: Chuck Lever + +[ Upstream commit 9853a5ac9be381917e9be0b4133cd4ac5a7ad875 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 15 ++++++++++----- + 1 file changed, 10 insertions(+), 5 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 9dc73ab95eac9..7dc6b79e51fd0 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -360,11 +360,16 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, + iattr->ia_valid |= ATTR_MODE; + } + if (bmval[1] & FATTR4_WORD1_OWNER) { +- READ_BUF(4); +- dummy32 = be32_to_cpup(p++); +- READ_BUF(dummy32); +- READMEM(buf, dummy32); +- if ((status = nfsd_map_name_to_uid(argp->rqstp, buf, dummy32, &iattr->ia_uid))) ++ u32 length; ++ ++ if (xdr_stream_decode_u32(argp->xdr, &length) < 0) ++ return nfserr_bad_xdr; ++ p = xdr_inline_decode(argp->xdr, length); ++ if (!p) ++ return nfserr_bad_xdr; ++ status = nfsd_map_name_to_uid(argp->rqstp, (char *)p, length, ++ &iattr->ia_uid); ++ if (status) + return status; + iattr->ia_valid |= ATTR_UID; + } +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-that-decode-the-fattr4-owne.patch-23903 b/queue-5.10/nfsd-replace-read-macros-that-decode-the-fattr4-owne.patch-23903 new file mode 100644 index 00000000000..1dac819fe84 --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-that-decode-the-fattr4-owne.patch-23903 @@ -0,0 +1,45 @@ +From cfb328ae8aeeae1e8bd22f5248cedc597bea4dce Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Nov 2020 13:58:18 -0500 +Subject: NFSD: Replace READ* macros that decode the fattr4 owner_group + attribute + +From: Chuck Lever + +[ Upstream commit 393c31dd27f83adb06b07a1b5f0a5b8966a0f01e ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 15 ++++++++++----- + 1 file changed, 10 insertions(+), 5 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 7dc6b79e51fd0..979f1d384cd0f 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -374,11 +374,16 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, + iattr->ia_valid |= ATTR_UID; + } + if (bmval[1] & FATTR4_WORD1_OWNER_GROUP) { +- READ_BUF(4); +- dummy32 = be32_to_cpup(p++); +- READ_BUF(dummy32); +- READMEM(buf, dummy32); +- if ((status = nfsd_map_name_to_gid(argp->rqstp, buf, dummy32, &iattr->ia_gid))) ++ u32 length; ++ ++ if (xdr_stream_decode_u32(argp->xdr, &length) < 0) ++ return nfserr_bad_xdr; ++ p = xdr_inline_decode(argp->xdr, length); ++ if (!p) ++ return nfserr_bad_xdr; ++ status = nfsd_map_name_to_gid(argp->rqstp, (char *)p, length, ++ &iattr->ia_gid); ++ if (status) + return status; + iattr->ia_valid |= ATTR_GID; + } +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-that-decode-the-fattr4-secu.patch b/queue-5.10/nfsd-replace-read-macros-that-decode-the-fattr4-secu.patch new file mode 100644 index 00000000000..e965035e8a8 --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-that-decode-the-fattr4-secu.patch @@ -0,0 +1,93 @@ +From e51f66ae80d60f4ffee04cb1dd063fc6e9c743e0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Nov 2020 14:05:51 -0500 +Subject: NFSD: Replace READ* macros that decode the fattr4 security label + attribute + +From: Chuck Lever + +[ Upstream commit dabe91828f92cd493e9e75efbc10f9878d2a73fe ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 46 ++++++++++++++++++++++++++++++---------------- + 1 file changed, 30 insertions(+), 16 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 09975786e71b2..453a902c7490a 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -324,6 +324,33 @@ nfsd4_decode_acl(struct nfsd4_compoundargs *argp, struct nfs4_acl **acl) + return nfs_ok; + } + ++static noinline __be32 ++nfsd4_decode_security_label(struct nfsd4_compoundargs *argp, ++ struct xdr_netobj *label) ++{ ++ u32 lfs, pi, length; ++ __be32 *p; ++ ++ if (xdr_stream_decode_u32(argp->xdr, &lfs) < 0) ++ return nfserr_bad_xdr; ++ if (xdr_stream_decode_u32(argp->xdr, &pi) < 0) ++ return nfserr_bad_xdr; ++ ++ if (xdr_stream_decode_u32(argp->xdr, &length) < 0) ++ return nfserr_bad_xdr; ++ if (length > NFS4_MAXLABELLEN) ++ return nfserr_badlabel; ++ p = xdr_inline_decode(argp->xdr, length); ++ if (!p) ++ return nfserr_bad_xdr; ++ label->len = length; ++ label->data = svcxdr_dupstr(argp, p, length); ++ if (!label->data) ++ return nfserr_jukebox; ++ ++ return nfs_ok; ++} ++ + static __be32 + nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, + struct iattr *iattr, struct nfs4_acl **acl, +@@ -332,7 +359,6 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, + unsigned int starting_pos; + u32 attrlist4_count; + u32 dummy32; +- char *buf; + + DECODE_HEAD; + iattr->ia_valid = 0; +@@ -440,24 +466,12 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, + return nfserr_bad_xdr; + } + } +- + label->len = 0; + if (IS_ENABLED(CONFIG_NFSD_V4_SECURITY_LABEL) && + bmval[2] & FATTR4_WORD2_SECURITY_LABEL) { +- READ_BUF(4); +- dummy32 = be32_to_cpup(p++); /* lfs: we don't use it */ +- READ_BUF(4); +- dummy32 = be32_to_cpup(p++); /* pi: we don't use it either */ +- READ_BUF(4); +- dummy32 = be32_to_cpup(p++); +- READ_BUF(dummy32); +- if (dummy32 > NFS4_MAXLABELLEN) +- return nfserr_badlabel; +- READMEM(buf, dummy32); +- label->len = dummy32; +- label->data = svcxdr_dupstr(argp, buf, dummy32); +- if (!label->data) +- return nfserr_jukebox; ++ status = nfsd4_decode_security_label(argp, label); ++ if (status) ++ return status; + } + if (bmval[2] & FATTR4_WORD2_MODE_UMASK) { + if (!umask) +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-that-decode-the-fattr4-size.patch b/queue-5.10/nfsd-replace-read-macros-that-decode-the-fattr4-size.patch new file mode 100644 index 00000000000..df47e3f02a7 --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-that-decode-the-fattr4-size.patch @@ -0,0 +1,36 @@ +From 8b598709dc78888d8a92880ef8ce4257f9566e2d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Nov 2020 13:47:16 -0500 +Subject: NFSD: Replace READ* macros that decode the fattr4 size attribute + +From: Chuck Lever + +[ Upstream commit 2ac1b9b2afbbacf597dbec722b23b6be62e4e41e ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index de5ac334cb8ab..5ec0c2dac3348 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -273,8 +273,11 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, + starting_pos = xdr_stream_pos(argp->xdr); + + if (bmval[0] & FATTR4_WORD0_SIZE) { +- READ_BUF(8); +- p = xdr_decode_hyper(p, &iattr->ia_size); ++ u64 size; ++ ++ if (xdr_stream_decode_u64(argp->xdr, &size) < 0) ++ return nfserr_bad_xdr; ++ iattr->ia_size = size; + iattr->ia_valid |= ATTR_SIZE; + } + if (bmval[0] & FATTR4_WORD0_ACL) { +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-that-decode-the-fattr4-time.patch b/queue-5.10/nfsd-replace-read-macros-that-decode-the-fattr4-time.patch new file mode 100644 index 00000000000..f81884b6c26 --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-that-decode-the-fattr4-time.patch @@ -0,0 +1,94 @@ +From 305400955788ce9185c80ac7a8dd49d31fd5036d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Nov 2020 14:01:08 -0500 +Subject: NFSD: Replace READ* macros that decode the fattr4 time_set attributes + +From: Chuck Lever + +[ Upstream commit 1c3eff7ea4a98c642134ee493001ae13b79ff38c ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 39 +++++++++++++++++++++++++++++---------- + 1 file changed, 29 insertions(+), 10 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 979f1d384cd0f..09975786e71b2 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -219,6 +219,21 @@ nfsd4_decode_time(struct nfsd4_compoundargs *argp, struct timespec64 *tv) + DECODE_TAIL; + } + ++static __be32 ++nfsd4_decode_nfstime4(struct nfsd4_compoundargs *argp, struct timespec64 *tv) ++{ ++ __be32 *p; ++ ++ p = xdr_inline_decode(argp->xdr, XDR_UNIT * 3); ++ if (!p) ++ return nfserr_bad_xdr; ++ p = xdr_decode_hyper(p, &tv->tv_sec); ++ tv->tv_nsec = be32_to_cpup(p++); ++ if (tv->tv_nsec >= (u32)1000000000) ++ return nfserr_inval; ++ return nfs_ok; ++} ++ + static __be32 + nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval) + { +@@ -388,11 +403,13 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, + iattr->ia_valid |= ATTR_GID; + } + if (bmval[1] & FATTR4_WORD1_TIME_ACCESS_SET) { +- READ_BUF(4); +- dummy32 = be32_to_cpup(p++); +- switch (dummy32) { ++ u32 set_it; ++ ++ if (xdr_stream_decode_u32(argp->xdr, &set_it) < 0) ++ return nfserr_bad_xdr; ++ switch (set_it) { + case NFS4_SET_TO_CLIENT_TIME: +- status = nfsd4_decode_time(argp, &iattr->ia_atime); ++ status = nfsd4_decode_nfstime4(argp, &iattr->ia_atime); + if (status) + return status; + iattr->ia_valid |= (ATTR_ATIME | ATTR_ATIME_SET); +@@ -401,15 +418,17 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, + iattr->ia_valid |= ATTR_ATIME; + break; + default: +- goto xdr_error; ++ return nfserr_bad_xdr; + } + } + if (bmval[1] & FATTR4_WORD1_TIME_MODIFY_SET) { +- READ_BUF(4); +- dummy32 = be32_to_cpup(p++); +- switch (dummy32) { ++ u32 set_it; ++ ++ if (xdr_stream_decode_u32(argp->xdr, &set_it) < 0) ++ return nfserr_bad_xdr; ++ switch (set_it) { + case NFS4_SET_TO_CLIENT_TIME: +- status = nfsd4_decode_time(argp, &iattr->ia_mtime); ++ status = nfsd4_decode_nfstime4(argp, &iattr->ia_mtime); + if (status) + return status; + iattr->ia_valid |= (ATTR_MTIME | ATTR_MTIME_SET); +@@ -418,7 +437,7 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, + iattr->ia_valid |= ATTR_MTIME; + break; + default: +- goto xdr_error; ++ return nfserr_bad_xdr; + } + } + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-read-macros-that-decode-the-fattr4-umas.patch b/queue-5.10/nfsd-replace-read-macros-that-decode-the-fattr4-umas.patch new file mode 100644 index 00000000000..f0efb7b4ee5 --- /dev/null +++ b/queue-5.10/nfsd-replace-read-macros-that-decode-the-fattr4-umas.patch @@ -0,0 +1,53 @@ +From 76b6eb44ed6d8afcfe5267b2b552cbb21ac6cfc8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 19 Nov 2020 14:07:43 -0500 +Subject: NFSD: Replace READ* macros that decode the fattr4 umask attribute + +From: Chuck Lever + +[ Upstream commit 66f0476c704c86d44aa9da19d4753df66f2dbc96 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 16 +++++++++------- + 1 file changed, 9 insertions(+), 7 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 453a902c7490a..2d97bbff13b68 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -358,7 +358,6 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, + { + unsigned int starting_pos; + u32 attrlist4_count; +- u32 dummy32; + + DECODE_HEAD; + iattr->ia_valid = 0; +@@ -474,13 +473,16 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, + return status; + } + if (bmval[2] & FATTR4_WORD2_MODE_UMASK) { ++ u32 mode, mask; ++ + if (!umask) +- goto xdr_error; +- READ_BUF(8); +- dummy32 = be32_to_cpup(p++); +- iattr->ia_mode = dummy32 & (S_IFMT | S_IALLUGO); +- dummy32 = be32_to_cpup(p++); +- *umask = dummy32 & S_IRWXUGO; ++ return nfserr_bad_xdr; ++ if (xdr_stream_decode_u32(argp->xdr, &mode) < 0) ++ return nfserr_bad_xdr; ++ iattr->ia_mode = mode & (S_IFMT | S_IALLUGO); ++ if (xdr_stream_decode_u32(argp->xdr, &mask) < 0) ++ return nfserr_bad_xdr; ++ *umask = mask & S_IRWXUGO; + iattr->ia_valid |= ATTR_MODE; + } + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-the-init-once-mechanism.patch b/queue-5.10/nfsd-replace-the-init-once-mechanism.patch new file mode 100644 index 00000000000..401fb83ac3f --- /dev/null +++ b/queue-5.10/nfsd-replace-the-init-once-mechanism.patch @@ -0,0 +1,144 @@ +From b76959ddc2df3814489cdb874c81f8bfc0d80420 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 Jul 2022 14:26:16 -0400 +Subject: NFSD: Replace the "init once" mechanism + +From: Chuck Lever + +[ Upstream commit c7b824c3d06c85e054caf86e227255112c5e3c38 ] + +In a moment, the nfsd_file_hashtbl global will be replaced with an +rhashtable. Replace the one or two spots that need to check if the +hash table is available. We can easily reuse the SHUTDOWN flag for +this purpose. + +Document that this mechanism relies on callers to hold the +nfsd_mutex to prevent init, shutdown, and purging to run +concurrently. + +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 42 ++++++++++++++++++++++++++---------------- + 1 file changed, 26 insertions(+), 16 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index 29b1f57692a60..33bb4d31b4972 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -27,7 +27,7 @@ + #define NFSD_FILE_HASH_SIZE (1 << NFSD_FILE_HASH_BITS) + #define NFSD_LAUNDRETTE_DELAY (2 * HZ) + +-#define NFSD_FILE_SHUTDOWN (1) ++#define NFSD_FILE_CACHE_UP (0) + + /* We only care about NFSD_MAY_READ/WRITE for this cache */ + #define NFSD_FILE_MAY_MASK (NFSD_MAY_READ|NFSD_MAY_WRITE) +@@ -58,7 +58,7 @@ static struct kmem_cache *nfsd_file_slab; + static struct kmem_cache *nfsd_file_mark_slab; + static struct nfsd_fcache_bucket *nfsd_file_hashtbl; + static struct list_lru nfsd_file_lru; +-static long nfsd_file_lru_flags; ++static unsigned long nfsd_file_flags; + static struct fsnotify_group *nfsd_file_fsnotify_group; + static atomic_long_t nfsd_filecache_count; + static struct delayed_work nfsd_filecache_laundrette; +@@ -66,9 +66,8 @@ static struct delayed_work nfsd_filecache_laundrette; + static void + nfsd_file_schedule_laundrette(void) + { +- long count = atomic_long_read(&nfsd_filecache_count); +- +- if (count == 0 || test_bit(NFSD_FILE_SHUTDOWN, &nfsd_file_lru_flags)) ++ if ((atomic_long_read(&nfsd_filecache_count) == 0) || ++ test_bit(NFSD_FILE_CACHE_UP, &nfsd_file_flags) == 0) + return; + + queue_delayed_work(system_wq, &nfsd_filecache_laundrette, +@@ -697,9 +696,8 @@ nfsd_file_cache_init(void) + int ret = -ENOMEM; + unsigned int i; + +- clear_bit(NFSD_FILE_SHUTDOWN, &nfsd_file_lru_flags); +- +- if (nfsd_file_hashtbl) ++ lockdep_assert_held(&nfsd_mutex); ++ if (test_and_set_bit(NFSD_FILE_CACHE_UP, &nfsd_file_flags) == 1) + return 0; + + nfsd_filecache_wq = alloc_workqueue("nfsd_filecache", 0, 0); +@@ -785,8 +783,8 @@ nfsd_file_cache_init(void) + /* + * Note this can deadlock with nfsd_file_lru_cb. + */ +-void +-nfsd_file_cache_purge(struct net *net) ++static void ++__nfsd_file_cache_purge(struct net *net) + { + unsigned int i; + struct nfsd_file *nf; +@@ -794,9 +792,6 @@ nfsd_file_cache_purge(struct net *net) + LIST_HEAD(dispose); + bool del; + +- if (!nfsd_file_hashtbl) +- return; +- + for (i = 0; i < NFSD_FILE_HASH_SIZE; i++) { + struct nfsd_fcache_bucket *nfb = &nfsd_file_hashtbl[i]; + +@@ -857,6 +852,19 @@ nfsd_file_cache_start_net(struct net *net) + return nn->fcache_disposal ? 0 : -ENOMEM; + } + ++/** ++ * nfsd_file_cache_purge - Remove all cache items associated with @net ++ * @net: target net namespace ++ * ++ */ ++void ++nfsd_file_cache_purge(struct net *net) ++{ ++ lockdep_assert_held(&nfsd_mutex); ++ if (test_bit(NFSD_FILE_CACHE_UP, &nfsd_file_flags) == 1) ++ __nfsd_file_cache_purge(net); ++} ++ + void + nfsd_file_cache_shutdown_net(struct net *net) + { +@@ -869,7 +877,9 @@ nfsd_file_cache_shutdown(void) + { + int i; + +- set_bit(NFSD_FILE_SHUTDOWN, &nfsd_file_lru_flags); ++ lockdep_assert_held(&nfsd_mutex); ++ if (test_and_clear_bit(NFSD_FILE_CACHE_UP, &nfsd_file_flags) == 0) ++ return; + + lease_unregister_notifier(&nfsd_file_lease_notifier); + unregister_shrinker(&nfsd_file_shrinker); +@@ -878,7 +888,7 @@ nfsd_file_cache_shutdown(void) + * calling nfsd_file_cache_purge + */ + cancel_delayed_work_sync(&nfsd_filecache_laundrette); +- nfsd_file_cache_purge(NULL); ++ __nfsd_file_cache_purge(NULL); + list_lru_destroy(&nfsd_file_lru); + rcu_barrier(); + fsnotify_put_group(nfsd_file_fsnotify_group); +@@ -1142,7 +1152,7 @@ static int nfsd_file_cache_stats_show(struct seq_file *m, void *v) + * don't end up racing with server shutdown + */ + mutex_lock(&nfsd_mutex); +- if (nfsd_file_hashtbl) { ++ if (test_bit(NFSD_FILE_CACHE_UP, &nfsd_file_flags) == 1) { + for (i = 0; i < NFSD_FILE_HASH_SIZE; i++) { + count += nfsd_file_hashtbl[i].nfb_count; + longest = max(longest, nfsd_file_hashtbl[i].nfb_count); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-the-internals-of-the-read_buf-macro.patch b/queue-5.10/nfsd-replace-the-internals-of-the-read_buf-macro.patch new file mode 100644 index 00000000000..05d3861f865 --- /dev/null +++ b/queue-5.10/nfsd-replace-the-internals-of-the-read_buf-macro.patch @@ -0,0 +1,411 @@ +From fb50d5ded87f4002c6002a07c896c965c4bc2520 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Nov 2020 11:54:23 -0500 +Subject: NFSD: Replace the internals of the READ_BUF() macro + +From: Chuck Lever + +[ Upstream commit c1346a1216ab5cb04a265380ac9035d91b16b6d5 ] + +Convert the READ_BUF macro in nfs4xdr.c from open code to instead +use the new xdr_stream-style decoders already in use by the encode +side (and by the in-kernel NFS client implementation). Once this +conversion is done, each individual NFSv4 argument decoder can be +independently cleaned up to replace these macros with C code. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 4 +- + fs/nfsd/nfs4xdr.c | 181 ++++++------------------------------- + fs/nfsd/xdr4.h | 10 +- + include/linux/sunrpc/xdr.h | 2 + + net/sunrpc/xdr.c | 45 +++++++++ + 5 files changed, 77 insertions(+), 165 deletions(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 55a46e7c152b9..95545a61bfc77 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -1024,8 +1024,8 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + + write->wr_how_written = write->wr_stable_how; + +- nvecs = svc_fill_write_vector(rqstp, write->wr_pagelist, +- &write->wr_head, write->wr_buflen); ++ nvecs = svc_fill_write_vector(rqstp, write->wr_payload.pages, ++ write->wr_payload.head, write->wr_buflen); + WARN_ON_ONCE(nvecs > ARRAY_SIZE(rqstp->rq_vec)); + + status = nfsd_vfs_write(rqstp, &cstate->current_fh, nf, +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 101ada3636b78..8c694844f0efb 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -131,90 +131,13 @@ xdr_error: \ + memcpy((x), p, nbytes); \ + p += XDR_QUADLEN(nbytes); \ + } while (0) +- +-/* READ_BUF, read_buf(): nbytes must be <= PAGE_SIZE */ +-#define READ_BUF(nbytes) do { \ +- if (nbytes <= (u32)((char *)argp->end - (char *)argp->p)) { \ +- p = argp->p; \ +- argp->p += XDR_QUADLEN(nbytes); \ +- } else if (!(p = read_buf(argp, nbytes))) { \ +- dprintk("NFSD: xdr error (%s:%d)\n", \ +- __FILE__, __LINE__); \ +- goto xdr_error; \ +- } \ +-} while (0) +- +-static void next_decode_page(struct nfsd4_compoundargs *argp) +-{ +- argp->p = page_address(argp->pagelist[0]); +- argp->pagelist++; +- if (argp->pagelen < PAGE_SIZE) { +- argp->end = argp->p + XDR_QUADLEN(argp->pagelen); +- argp->pagelen = 0; +- } else { +- argp->end = argp->p + (PAGE_SIZE>>2); +- argp->pagelen -= PAGE_SIZE; +- } +-} +- +-static __be32 *read_buf(struct nfsd4_compoundargs *argp, u32 nbytes) +-{ +- /* We want more bytes than seem to be available. +- * Maybe we need a new page, maybe we have just run out +- */ +- unsigned int avail = (char *)argp->end - (char *)argp->p; +- __be32 *p; +- +- if (argp->pagelen == 0) { +- struct kvec *vec = &argp->rqstp->rq_arg.tail[0]; +- +- if (!argp->tail) { +- argp->tail = true; +- avail = vec->iov_len; +- argp->p = vec->iov_base; +- argp->end = vec->iov_base + avail; +- } +- +- if (avail < nbytes) +- return NULL; +- +- p = argp->p; +- argp->p += XDR_QUADLEN(nbytes); +- return p; +- } +- +- if (avail + argp->pagelen < nbytes) +- return NULL; +- if (avail + PAGE_SIZE < nbytes) /* need more than a page !! */ +- return NULL; +- /* ok, we can do it with the current plus the next page */ +- if (nbytes <= sizeof(argp->tmp)) +- p = argp->tmp; +- else { +- kfree(argp->tmpp); +- p = argp->tmpp = kmalloc(nbytes, GFP_KERNEL); +- if (!p) +- return NULL; +- +- } +- /* +- * The following memcpy is safe because read_buf is always +- * called with nbytes > avail, and the two cases above both +- * guarantee p points to at least nbytes bytes. +- */ +- memcpy(p, argp->p, avail); +- next_decode_page(argp); +- memcpy(((char*)p)+avail, argp->p, (nbytes - avail)); +- argp->p += XDR_QUADLEN(nbytes - avail); +- return p; +-} +- +-static unsigned int compoundargs_bytes_left(struct nfsd4_compoundargs *argp) +-{ +- unsigned int this = (char *)argp->end - (char *)argp->p; +- +- return this + argp->pagelen; +-} ++#define READ_BUF(nbytes) \ ++ do { \ ++ p = xdr_inline_decode(argp->xdr,\ ++ nbytes); \ ++ if (!p) \ ++ goto xdr_error; \ ++ } while (0) + + static int zero_clientid(clientid_t *clid) + { +@@ -261,44 +184,6 @@ svcxdr_dupstr(struct nfsd4_compoundargs *argp, void *buf, u32 len) + return p; + } + +-static __be32 +-svcxdr_construct_vector(struct nfsd4_compoundargs *argp, struct kvec *head, +- struct page ***pagelist, u32 buflen) +-{ +- int avail; +- int len; +- int pages; +- +- /* Sorry .. no magic macros for this.. * +- * READ_BUF(write->wr_buflen); +- * SAVEMEM(write->wr_buf, write->wr_buflen); +- */ +- avail = (char *)argp->end - (char *)argp->p; +- if (avail + argp->pagelen < buflen) { +- dprintk("NFSD: xdr error (%s:%d)\n", +- __FILE__, __LINE__); +- return nfserr_bad_xdr; +- } +- head->iov_base = argp->p; +- head->iov_len = avail; +- *pagelist = argp->pagelist; +- +- len = XDR_QUADLEN(buflen) << 2; +- if (len >= avail) { +- len -= avail; +- +- pages = len >> PAGE_SHIFT; +- argp->pagelist += pages; +- argp->pagelen -= pages * PAGE_SIZE; +- len -= pages * PAGE_SIZE; +- +- next_decode_page(argp); +- } +- argp->p += XDR_QUADLEN(len); +- +- return 0; +-} +- + /** + * savemem - duplicate a chunk of memory for later processing + * @argp: NFSv4 compound argument structure to be freed with +@@ -398,7 +283,7 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, + READ_BUF(4); len += 4; + nace = be32_to_cpup(p++); + +- if (nace > compoundargs_bytes_left(argp)/20) ++ if (nace > xdr_stream_remaining(argp->xdr) / sizeof(struct nfs4_ace)) + /* + * Even with 4-byte names there wouldn't be + * space for that many aces; something fishy is +@@ -929,7 +814,7 @@ static __be32 nfsd4_decode_share_deny(struct nfsd4_compoundargs *argp, u32 *x) + + static __be32 nfsd4_decode_opaque(struct nfsd4_compoundargs *argp, struct xdr_netobj *o) + { +- __be32 *p; ++ DECODE_HEAD; + + READ_BUF(4); + o->len = be32_to_cpup(p++); +@@ -939,9 +824,8 @@ static __be32 nfsd4_decode_opaque(struct nfsd4_compoundargs *argp, struct xdr_ne + + READ_BUF(o->len); + SAVEMEM(o->data, o->len); +- return nfs_ok; +-xdr_error: +- return nfserr_bad_xdr; ++ ++ DECODE_TAIL; + } + + static __be32 +@@ -1319,10 +1203,8 @@ nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write) + goto xdr_error; + write->wr_buflen = be32_to_cpup(p++); + +- status = svcxdr_construct_vector(argp, &write->wr_head, +- &write->wr_pagelist, write->wr_buflen); +- if (status) +- return status; ++ if (!xdr_stream_subsegment(argp->xdr, &write->wr_payload, write->wr_buflen)) ++ goto xdr_error; + + DECODE_TAIL; + } +@@ -1891,13 +1773,14 @@ nfsd4_decode_seek(struct nfsd4_compoundargs *argp, struct nfsd4_seek *seek) + */ + + /* +- * Decode data into buffer. Uses head and pages constructed by +- * svcxdr_construct_vector. ++ * Decode data into buffer. + */ + static __be32 +-nfsd4_vbuf_from_vector(struct nfsd4_compoundargs *argp, struct kvec *head, +- struct page **pages, char **bufp, u32 buflen) ++nfsd4_vbuf_from_vector(struct nfsd4_compoundargs *argp, struct xdr_buf *xdr, ++ char **bufp, u32 buflen) + { ++ struct page **pages = xdr->pages; ++ struct kvec *head = xdr->head; + char *tmp, *dp; + u32 len; + +@@ -2012,8 +1895,6 @@ nfsd4_decode_setxattr(struct nfsd4_compoundargs *argp, + { + DECODE_HEAD; + u32 flags, maxcount, size; +- struct kvec head; +- struct page **pagelist; + + READ_BUF(4); + flags = be32_to_cpup(p++); +@@ -2036,12 +1917,12 @@ nfsd4_decode_setxattr(struct nfsd4_compoundargs *argp, + + setxattr->setxa_len = size; + if (size > 0) { +- status = svcxdr_construct_vector(argp, &head, &pagelist, size); +- if (status) +- return status; ++ struct xdr_buf payload; + +- status = nfsd4_vbuf_from_vector(argp, &head, pagelist, +- &setxattr->setxa_buf, size); ++ if (!xdr_stream_subsegment(argp->xdr, &payload, size)) ++ goto xdr_error; ++ status = nfsd4_vbuf_from_vector(argp, &payload, ++ &setxattr->setxa_buf, size); + } + + DECODE_TAIL; +@@ -5305,8 +5186,6 @@ void nfsd4_release_compoundargs(struct svc_rqst *rqstp) + kfree(args->ops); + args->ops = args->iops; + } +- kfree(args->tmpp); +- args->tmpp = NULL; + while (args->to_free) { + struct svcxdr_tmpbuf *tb = args->to_free; + args->to_free = tb->next; +@@ -5319,19 +5198,11 @@ nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, __be32 *p) + { + struct nfsd4_compoundargs *args = rqstp->rq_argp; + +- if (rqstp->rq_arg.head[0].iov_len % 4) { +- /* client is nuts */ +- dprintk("%s: compound not properly padded! (peeraddr=%pISc xid=0x%x)", +- __func__, svc_addr(rqstp), be32_to_cpu(rqstp->rq_xid)); +- return 0; +- } +- args->p = p; +- args->end = rqstp->rq_arg.head[0].iov_base + rqstp->rq_arg.head[0].iov_len; +- args->pagelist = rqstp->rq_arg.pages; +- args->pagelen = rqstp->rq_arg.page_len; +- args->tail = false; ++ /* svcxdr_tmp_alloc */ + args->tmpp = NULL; + args->to_free = NULL; ++ ++ args->xdr = &rqstp->rq_arg_stream; + args->ops = args->iops; + args->rqstp = rqstp; + +diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h +index 37f89ad5e9923..0eb13bd603ea6 100644 +--- a/fs/nfsd/xdr4.h ++++ b/fs/nfsd/xdr4.h +@@ -419,8 +419,7 @@ struct nfsd4_write { + u64 wr_offset; /* request */ + u32 wr_stable_how; /* request */ + u32 wr_buflen; /* request */ +- struct kvec wr_head; +- struct page ** wr_pagelist; /* request */ ++ struct xdr_buf wr_payload; /* request */ + + u32 wr_bytes_written; /* response */ + u32 wr_how_written; /* response */ +@@ -696,15 +695,10 @@ struct svcxdr_tmpbuf { + + struct nfsd4_compoundargs { + /* scratch variables for XDR decode */ +- __be32 * p; +- __be32 * end; +- struct page ** pagelist; +- int pagelen; +- bool tail; + __be32 tmp[8]; + __be32 * tmpp; ++ struct xdr_stream *xdr; + struct svcxdr_tmpbuf *to_free; +- + struct svc_rqst *rqstp; + + u32 taglen; +diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h +index 0c8cab6210b3b..c03f7bf585c96 100644 +--- a/include/linux/sunrpc/xdr.h ++++ b/include/linux/sunrpc/xdr.h +@@ -252,6 +252,8 @@ extern void xdr_enter_page(struct xdr_stream *xdr, unsigned int len); + extern int xdr_process_buf(struct xdr_buf *buf, unsigned int offset, unsigned int len, int (*actor)(struct scatterlist *, void *), void *data); + extern uint64_t xdr_align_data(struct xdr_stream *, uint64_t, uint32_t); + extern uint64_t xdr_expand_hole(struct xdr_stream *, uint64_t, uint64_t); ++extern bool xdr_stream_subsegment(struct xdr_stream *xdr, struct xdr_buf *subbuf, ++ unsigned int len); + + /** + * xdr_set_scratch_buffer - Attach a scratch buffer for decoding data. +diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c +index 02adc5c7f034d..722586696fade 100644 +--- a/net/sunrpc/xdr.c ++++ b/net/sunrpc/xdr.c +@@ -1412,6 +1412,51 @@ xdr_buf_subsegment(struct xdr_buf *buf, struct xdr_buf *subbuf, + } + EXPORT_SYMBOL_GPL(xdr_buf_subsegment); + ++/** ++ * xdr_stream_subsegment - set @subbuf to a portion of @xdr ++ * @xdr: an xdr_stream set up for decoding ++ * @subbuf: the result buffer ++ * @nbytes: length of @xdr to extract, in bytes ++ * ++ * Sets up @subbuf to represent a portion of @xdr. The portion ++ * starts at the current offset in @xdr, and extends for a length ++ * of @nbytes. If this is successful, @xdr is advanced to the next ++ * position following that portion. ++ * ++ * Return values: ++ * %true: @subbuf has been initialized, and @xdr has been advanced. ++ * %false: a bounds error has occurred ++ */ ++bool xdr_stream_subsegment(struct xdr_stream *xdr, struct xdr_buf *subbuf, ++ unsigned int nbytes) ++{ ++ unsigned int remaining, offset, len; ++ ++ if (xdr_buf_subsegment(xdr->buf, subbuf, xdr_stream_pos(xdr), nbytes)) ++ return false; ++ ++ if (subbuf->head[0].iov_len) ++ if (!__xdr_inline_decode(xdr, subbuf->head[0].iov_len)) ++ return false; ++ ++ remaining = subbuf->page_len; ++ offset = subbuf->page_base; ++ while (remaining) { ++ len = min_t(unsigned int, remaining, PAGE_SIZE) - offset; ++ ++ if (xdr->p == xdr->end && !xdr_set_next_buffer(xdr)) ++ return false; ++ if (!__xdr_inline_decode(xdr, len)) ++ return false; ++ ++ remaining -= len; ++ offset = 0; ++ } ++ ++ return true; ++} ++EXPORT_SYMBOL_GPL(xdr_stream_subsegment); ++ + /** + * xdr_buf_trim - lop at most "len" bytes off the end of "buf" + * @buf: buf to be trimmed +-- +2.43.0 + diff --git a/queue-5.10/nfsd-replace-the-nfsd_deleg_break-tracepoint.patch b/queue-5.10/nfsd-replace-the-nfsd_deleg_break-tracepoint.patch new file mode 100644 index 00000000000..17b7a807a43 --- /dev/null +++ b/queue-5.10/nfsd-replace-the-nfsd_deleg_break-tracepoint.patch @@ -0,0 +1,89 @@ +From 9f273995327f55cd8a13009eaccb8310bbc3528e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 14 May 2021 15:57:20 -0400 +Subject: NFSD: Replace the nfsd_deleg_break tracepoint + +From: Chuck Lever + +[ Upstream commit 17d76ddf76e4972411402743eea7243d9a46f4f9 ] + +Renamed so it can be enabled as a set with the other nfsd_cb_ +tracepoints. And, consistent with those tracepoints, report the +address of the client, the client ID the server has given it, and +the state ID being recalled. + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 2 +- + fs/nfsd/trace.h | 32 +++++++++++++++++++++++++++++++- + 2 files changed, 32 insertions(+), 2 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 89054fe68aca6..09967037eb1a3 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -4675,7 +4675,7 @@ nfsd_break_deleg_cb(struct file_lock *fl) + struct nfs4_delegation *dp = (struct nfs4_delegation *)fl->fl_owner; + struct nfs4_file *fp = dp->dl_stid.sc_file; + +- trace_nfsd_deleg_break(&dp->dl_stid.sc_stateid); ++ trace_nfsd_cb_recall(&dp->dl_stid); + + /* + * We don't want the locks code to timeout the lease for us; +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index fe32dfe1e55af..9061fd28c996d 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -459,7 +459,6 @@ DEFINE_STATEID_EVENT(layout_recall_release); + + DEFINE_STATEID_EVENT(open); + DEFINE_STATEID_EVENT(deleg_read); +-DEFINE_STATEID_EVENT(deleg_break); + DEFINE_STATEID_EVENT(deleg_recall); + + DECLARE_EVENT_CLASS(nfsd_stateseqid_class, +@@ -1027,6 +1026,37 @@ TRACE_EVENT(nfsd_cb_done, + __entry->status) + ); + ++TRACE_EVENT(nfsd_cb_recall, ++ TP_PROTO( ++ const struct nfs4_stid *stid ++ ), ++ TP_ARGS(stid), ++ TP_STRUCT__entry( ++ __field(u32, cl_boot) ++ __field(u32, cl_id) ++ __field(u32, si_id) ++ __field(u32, si_generation) ++ __array(unsigned char, addr, sizeof(struct sockaddr_in6)) ++ ), ++ TP_fast_assign( ++ const stateid_t *stp = &stid->sc_stateid; ++ const struct nfs4_client *clp = stid->sc_client; ++ ++ __entry->cl_boot = stp->si_opaque.so_clid.cl_boot; ++ __entry->cl_id = stp->si_opaque.so_clid.cl_id; ++ __entry->si_id = stp->si_opaque.so_id; ++ __entry->si_generation = stp->si_generation; ++ if (clp) ++ memcpy(__entry->addr, &clp->cl_cb_conn.cb_addr, ++ sizeof(struct sockaddr_in6)); ++ else ++ memset(__entry->addr, 0, sizeof(struct sockaddr_in6)); ++ ), ++ TP_printk("addr=%pISpc client %08x:%08x stateid %08x:%08x", ++ __entry->addr, __entry->cl_boot, __entry->cl_id, ++ __entry->si_id, __entry->si_generation) ++); ++ + TRACE_EVENT(nfsd_cb_notify_lock, + TP_PROTO( + const struct nfs4_lockowner *lo, +-- +2.43.0 + diff --git a/queue-5.10/nfsd-report-average-age-of-filecache-items.patch b/queue-5.10/nfsd-report-average-age-of-filecache-items.patch new file mode 100644 index 00000000000..dc87dd368de --- /dev/null +++ b/queue-5.10/nfsd-report-average-age-of-filecache-items.patch @@ -0,0 +1,95 @@ +From 6dd0c6d66475bf0d58b8e5a6f3389bda8149c9ab Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 Jul 2022 14:24:12 -0400 +Subject: NFSD: Report average age of filecache items + +From: Chuck Lever + +[ Upstream commit 904940e94a887701db24401e3ed6928a1d4e329f ] + +This is a measure of how long items stay in the filecache, to help +assess how efficient the cache is. + +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 11 ++++++++++- + fs/nfsd/filecache.h | 1 + + 2 files changed, 11 insertions(+), 1 deletion(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index 5d31622c23040..0cd72c20fc12d 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -44,6 +44,7 @@ struct nfsd_fcache_bucket { + static DEFINE_PER_CPU(unsigned long, nfsd_file_cache_hits); + static DEFINE_PER_CPU(unsigned long, nfsd_file_acquisitions); + static DEFINE_PER_CPU(unsigned long, nfsd_file_releases); ++static DEFINE_PER_CPU(unsigned long, nfsd_file_total_age); + + struct nfsd_fcache_disposal { + struct work_struct work; +@@ -177,6 +178,7 @@ nfsd_file_alloc(struct inode *inode, unsigned int may, unsigned int hashval, + if (nf) { + INIT_HLIST_NODE(&nf->nf_node); + INIT_LIST_HEAD(&nf->nf_lru); ++ nf->nf_birthtime = ktime_get(); + nf->nf_file = NULL; + nf->nf_cred = get_current_cred(); + nf->nf_net = net; +@@ -194,9 +196,11 @@ nfsd_file_alloc(struct inode *inode, unsigned int may, unsigned int hashval, + static bool + nfsd_file_free(struct nfsd_file *nf) + { ++ s64 age = ktime_to_ms(ktime_sub(ktime_get(), nf->nf_birthtime)); + bool flush = false; + + this_cpu_inc(nfsd_file_releases); ++ this_cpu_add(nfsd_file_total_age, age); + + trace_nfsd_file_put_final(nf); + if (nf->nf_mark) +@@ -1054,7 +1058,7 @@ static int nfsd_file_cache_stats_show(struct seq_file *m, void *v) + { + unsigned long hits = 0, acquisitions = 0, releases = 0; + unsigned int i, count = 0, longest = 0; +- unsigned long lru = 0; ++ unsigned long lru = 0, total_age = 0; + + /* + * No need for spinlocks here since we're not terribly interested in +@@ -1075,6 +1079,7 @@ static int nfsd_file_cache_stats_show(struct seq_file *m, void *v) + hits += per_cpu(nfsd_file_cache_hits, i); + acquisitions += per_cpu(nfsd_file_acquisitions, i); + releases += per_cpu(nfsd_file_releases, i); ++ total_age += per_cpu(nfsd_file_total_age, i); + } + + seq_printf(m, "total entries: %u\n", count); +@@ -1083,6 +1088,10 @@ static int nfsd_file_cache_stats_show(struct seq_file *m, void *v) + seq_printf(m, "cache hits: %lu\n", hits); + seq_printf(m, "acquisitions: %lu\n", acquisitions); + seq_printf(m, "releases: %lu\n", releases); ++ if (releases) ++ seq_printf(m, "mean age (ms): %ld\n", total_age / releases); ++ else ++ seq_printf(m, "mean age (ms): -\n"); + return 0; + } + +diff --git a/fs/nfsd/filecache.h b/fs/nfsd/filecache.h +index c9e3c6eb4776e..c6ad5fe47f12f 100644 +--- a/fs/nfsd/filecache.h ++++ b/fs/nfsd/filecache.h +@@ -44,6 +44,7 @@ struct nfsd_file { + refcount_t nf_ref; + unsigned char nf_may; + struct nfsd_file_mark *nf_mark; ++ ktime_t nf_birthtime; + }; + + int nfsd_file_cache_init(void); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-report-client-confirmation-status-in-info-file.patch b/queue-5.10/nfsd-report-client-confirmation-status-in-info-file.patch new file mode 100644 index 00000000000..f32adcd7d2c --- /dev/null +++ b/queue-5.10/nfsd-report-client-confirmation-status-in-info-file.patch @@ -0,0 +1,178 @@ +From 9c08a7643e9bc49484bba4d705341e18ccae0b7d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 20 Mar 2021 09:38:04 +1100 +Subject: nfsd: report client confirmation status in "info" file + +From: NeilBrown + +[ Upstream commit 472d155a0631bd1a09b5c0c275a254e65605d683 ] + +mountd can now monitor clients appearing and disappearing in +/proc/fs/nfsd/clients, and will log these events, in liu of the logging +of mount/unmount events for NFSv3. + +Currently it cannot distinguish between unconfirmed clients (which might +be transient and totally uninteresting) and confirmed clients. + +So add a "status: " line which reports either "confirmed" or +"unconfirmed", and use fsnotify to report that the info file +has been modified. + +This requires a bit of infrastructure to keep the dentry for the "info" +file. There is no need to take a counted reference as the dentry must +remain around until the client is removed. + +Signed-off-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 19 +++++++++++++++---- + fs/nfsd/nfsctl.c | 14 ++++++++------ + fs/nfsd/nfsd.h | 4 +++- + fs/nfsd/state.h | 4 ++++ + 4 files changed, 30 insertions(+), 11 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 0afc14b3e4593..104d563636540 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -43,6 +43,7 @@ + #include + #include + #include ++#include + #include "xdr4.h" + #include "xdr4cb.h" + #include "vfs.h" +@@ -2370,6 +2371,10 @@ static int client_info_show(struct seq_file *m, void *v) + memcpy(&clid, &clp->cl_clientid, sizeof(clid)); + seq_printf(m, "clientid: 0x%llx\n", clid); + seq_printf(m, "address: \"%pISpc\"\n", (struct sockaddr *)&clp->cl_addr); ++ if (test_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags)) ++ seq_puts(m, "status: confirmed\n"); ++ else ++ seq_puts(m, "status: unconfirmed\n"); + seq_printf(m, "name: "); + seq_quote_mem(m, clp->cl_name.data, clp->cl_name.len); + seq_printf(m, "\nminor version: %d\n", clp->cl_minorversion); +@@ -2724,6 +2729,7 @@ static struct nfs4_client *create_client(struct xdr_netobj name, + int ret; + struct net *net = SVC_NET(rqstp); + struct nfsd_net *nn = net_generic(net, nfsd_net_id); ++ struct dentry *dentries[ARRAY_SIZE(client_files)]; + + clp = alloc_client(name); + if (clp == NULL) +@@ -2743,9 +2749,11 @@ static struct nfs4_client *create_client(struct xdr_netobj name, + memcpy(&clp->cl_addr, sa, sizeof(struct sockaddr_storage)); + clp->cl_cb_session = NULL; + clp->net = net; +- clp->cl_nfsd_dentry = nfsd_client_mkdir(nn, &clp->cl_nfsdfs, +- clp->cl_clientid.cl_id - nn->clientid_base, +- client_files); ++ clp->cl_nfsd_dentry = nfsd_client_mkdir( ++ nn, &clp->cl_nfsdfs, ++ clp->cl_clientid.cl_id - nn->clientid_base, ++ client_files, dentries); ++ clp->cl_nfsd_info_dentry = dentries[0]; + if (!clp->cl_nfsd_dentry) { + free_client(clp); + return NULL; +@@ -2820,7 +2828,10 @@ move_to_confirmed(struct nfs4_client *clp) + list_move(&clp->cl_idhash, &nn->conf_id_hashtbl[idhashval]); + rb_erase(&clp->cl_namenode, &nn->unconf_name_tree); + add_clp_to_name_tree(clp, &nn->conf_name_tree); +- set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags); ++ if (!test_and_set_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags) && ++ clp->cl_nfsd_dentry && ++ clp->cl_nfsd_info_dentry) ++ fsnotify_dentry(clp->cl_nfsd_info_dentry, FS_MODIFY); + renew_client_locked(clp); + } + +diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c +index fa060f91df1b8..147ed8995a79f 100644 +--- a/fs/nfsd/nfsctl.c ++++ b/fs/nfsd/nfsctl.c +@@ -1270,7 +1270,8 @@ static void nfsdfs_remove_files(struct dentry *root) + /* XXX: cut'n'paste from simple_fill_super; figure out if we could share + * code instead. */ + static int nfsdfs_create_files(struct dentry *root, +- const struct tree_descr *files) ++ const struct tree_descr *files, ++ struct dentry **fdentries) + { + struct inode *dir = d_inode(root); + struct inode *inode; +@@ -1279,8 +1280,6 @@ static int nfsdfs_create_files(struct dentry *root, + + inode_lock(dir); + for (i = 0; files->name && files->name[0]; i++, files++) { +- if (!files->name) +- continue; + dentry = d_alloc_name(root, files->name); + if (!dentry) + goto out; +@@ -1294,6 +1293,8 @@ static int nfsdfs_create_files(struct dentry *root, + inode->i_private = __get_nfsdfs_client(dir); + d_add(dentry, inode); + fsnotify_create(dir, dentry); ++ if (fdentries) ++ fdentries[i] = dentry; + } + inode_unlock(dir); + return 0; +@@ -1305,8 +1306,9 @@ static int nfsdfs_create_files(struct dentry *root, + + /* on success, returns positive number unique to that client. */ + struct dentry *nfsd_client_mkdir(struct nfsd_net *nn, +- struct nfsdfs_client *ncl, u32 id, +- const struct tree_descr *files) ++ struct nfsdfs_client *ncl, u32 id, ++ const struct tree_descr *files, ++ struct dentry **fdentries) + { + struct dentry *dentry; + char name[11]; +@@ -1317,7 +1319,7 @@ struct dentry *nfsd_client_mkdir(struct nfsd_net *nn, + dentry = nfsd_mkdir(nn->nfsd_client_dir, ncl, name); + if (IS_ERR(dentry)) /* XXX: tossing errors? */ + return NULL; +- ret = nfsdfs_create_files(dentry, files); ++ ret = nfsdfs_create_files(dentry, files, fdentries); + if (ret) { + nfsd_client_rmdir(dentry); + return NULL; +diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h +index 27c1308ffc2ba..14dbfa75059d5 100644 +--- a/fs/nfsd/nfsd.h ++++ b/fs/nfsd/nfsd.h +@@ -106,7 +106,9 @@ struct nfsdfs_client { + + struct nfsdfs_client *get_nfsdfs_client(struct inode *); + struct dentry *nfsd_client_mkdir(struct nfsd_net *nn, +- struct nfsdfs_client *ncl, u32 id, const struct tree_descr *); ++ struct nfsdfs_client *ncl, u32 id, ++ const struct tree_descr *, ++ struct dentry **fdentries); + void nfsd_client_rmdir(struct dentry *dentry); + + +diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h +index 73deea3531699..54cab651ac1d0 100644 +--- a/fs/nfsd/state.h ++++ b/fs/nfsd/state.h +@@ -371,6 +371,10 @@ struct nfs4_client { + + /* debugging info directory under nfsd/clients/ : */ + struct dentry *cl_nfsd_dentry; ++ /* 'info' file within that directory. Ref is not counted, ++ * but will remain valid iff cl_nfsd_dentry != NULL ++ */ ++ struct dentry *cl_nfsd_info_dentry; + + /* for nfs41 callbacks */ + /* We currently support a single back channel with a single slot */ +-- +2.43.0 + diff --git a/queue-5.10/nfsd-report-count-of-calls-to-nfsd_file_acquire.patch b/queue-5.10/nfsd-report-count-of-calls-to-nfsd_file_acquire.patch new file mode 100644 index 00000000000..3ca40e02bee --- /dev/null +++ b/queue-5.10/nfsd-report-count-of-calls-to-nfsd_file_acquire.patch @@ -0,0 +1,74 @@ +From d417e2db2c171711af5e5d432f8549ba1fc97a8b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 Jul 2022 14:23:59 -0400 +Subject: NFSD: Report count of calls to nfsd_file_acquire() + +From: Chuck Lever + +[ Upstream commit 29d4bdbbb910f33d6058d2c51278f00f656df325 ] + +Count the number of successful acquisitions that did not create a +file (ie, acquisitions that do not result in a compulsory cache +miss). This count can be compared directly with the reported hit +count to compute a hit ratio. + +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index 377d8211200ff..5a09b76ae25a8 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -42,6 +42,7 @@ struct nfsd_fcache_bucket { + }; + + static DEFINE_PER_CPU(unsigned long, nfsd_file_cache_hits); ++static DEFINE_PER_CPU(unsigned long, nfsd_file_acquisitions); + + struct nfsd_fcache_disposal { + struct work_struct work; +@@ -954,6 +955,8 @@ nfsd_do_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + status = nfserrno(nfsd_open_break_lease(file_inode(nf->nf_file), may_flags)); + out: + if (status == nfs_ok) { ++ if (open) ++ this_cpu_inc(nfsd_file_acquisitions); + *pnf = nf; + } else { + nfsd_file_put(nf); +@@ -1046,8 +1049,9 @@ nfsd_file_create(struct svc_rqst *rqstp, struct svc_fh *fhp, + */ + static int nfsd_file_cache_stats_show(struct seq_file *m, void *v) + { ++ unsigned long hits = 0, acquisitions = 0; + unsigned int i, count = 0, longest = 0; +- unsigned long lru = 0, hits = 0; ++ unsigned long lru = 0; + + /* + * No need for spinlocks here since we're not terribly interested in +@@ -1064,13 +1068,16 @@ static int nfsd_file_cache_stats_show(struct seq_file *m, void *v) + } + mutex_unlock(&nfsd_mutex); + +- for_each_possible_cpu(i) ++ for_each_possible_cpu(i) { + hits += per_cpu(nfsd_file_cache_hits, i); ++ acquisitions += per_cpu(nfsd_file_acquisitions, i); ++ } + + seq_printf(m, "total entries: %u\n", count); + seq_printf(m, "longest chain: %u\n", longest); + seq_printf(m, "lru entries: %lu\n", lru); + seq_printf(m, "cache hits: %lu\n", hits); ++ seq_printf(m, "acquisitions: %lu\n", acquisitions); + return 0; + } + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-report-count-of-freed-filecache-items.patch b/queue-5.10/nfsd-report-count-of-freed-filecache-items.patch new file mode 100644 index 00000000000..cff9c45ae60 --- /dev/null +++ b/queue-5.10/nfsd-report-count-of-freed-filecache-items.patch @@ -0,0 +1,67 @@ +From 044487f7b0a28768c68e348c9c976df961eb2fbb Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 Jul 2022 14:24:05 -0400 +Subject: NFSD: Report count of freed filecache items + +From: Chuck Lever + +[ Upstream commit d63293272abb51c02457f1017dfd61c3270d9ae3 ] + +Surface the count of freed nfsd_file items. + +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 7 ++++++- + 1 file changed, 6 insertions(+), 1 deletion(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index 5a09b76ae25a8..5d31622c23040 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -43,6 +43,7 @@ struct nfsd_fcache_bucket { + + static DEFINE_PER_CPU(unsigned long, nfsd_file_cache_hits); + static DEFINE_PER_CPU(unsigned long, nfsd_file_acquisitions); ++static DEFINE_PER_CPU(unsigned long, nfsd_file_releases); + + struct nfsd_fcache_disposal { + struct work_struct work; +@@ -195,6 +196,8 @@ nfsd_file_free(struct nfsd_file *nf) + { + bool flush = false; + ++ this_cpu_inc(nfsd_file_releases); ++ + trace_nfsd_file_put_final(nf); + if (nf->nf_mark) + nfsd_file_mark_put(nf->nf_mark); +@@ -1049,7 +1052,7 @@ nfsd_file_create(struct svc_rqst *rqstp, struct svc_fh *fhp, + */ + static int nfsd_file_cache_stats_show(struct seq_file *m, void *v) + { +- unsigned long hits = 0, acquisitions = 0; ++ unsigned long hits = 0, acquisitions = 0, releases = 0; + unsigned int i, count = 0, longest = 0; + unsigned long lru = 0; + +@@ -1071,6 +1074,7 @@ static int nfsd_file_cache_stats_show(struct seq_file *m, void *v) + for_each_possible_cpu(i) { + hits += per_cpu(nfsd_file_cache_hits, i); + acquisitions += per_cpu(nfsd_file_acquisitions, i); ++ releases += per_cpu(nfsd_file_releases, i); + } + + seq_printf(m, "total entries: %u\n", count); +@@ -1078,6 +1082,7 @@ static int nfsd_file_cache_stats_show(struct seq_file *m, void *v) + seq_printf(m, "lru entries: %lu\n", lru); + seq_printf(m, "cache hits: %lu\n", hits); + seq_printf(m, "acquisitions: %lu\n", acquisitions); ++ seq_printf(m, "releases: %lu\n", releases); + return 0; + } + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-report-filecache-lru-size.patch b/queue-5.10/nfsd-report-filecache-lru-size.patch new file mode 100644 index 00000000000..f194148e717 --- /dev/null +++ b/queue-5.10/nfsd-report-filecache-lru-size.patch @@ -0,0 +1,51 @@ +From 6f9fd12003c742a9501bed8cfbc220582742c81d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 Jul 2022 14:23:52 -0400 +Subject: NFSD: Report filecache LRU size + +From: Chuck Lever + +[ Upstream commit 0fd244c115f0321fc5e34ad2291f2a572508e3f7 ] + +Surface the NFSD filecache's LRU list length to help field +troubleshooters monitor filecache issues. + +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index 1d3d13b78be0e..377d8211200ff 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -1047,7 +1047,7 @@ nfsd_file_create(struct svc_rqst *rqstp, struct svc_fh *fhp, + static int nfsd_file_cache_stats_show(struct seq_file *m, void *v) + { + unsigned int i, count = 0, longest = 0; +- unsigned long hits = 0; ++ unsigned long lru = 0, hits = 0; + + /* + * No need for spinlocks here since we're not terribly interested in +@@ -1060,6 +1060,7 @@ static int nfsd_file_cache_stats_show(struct seq_file *m, void *v) + count += nfsd_file_hashtbl[i].nfb_count; + longest = max(longest, nfsd_file_hashtbl[i].nfb_count); + } ++ lru = list_lru_count(&nfsd_file_lru); + } + mutex_unlock(&nfsd_mutex); + +@@ -1068,6 +1069,7 @@ static int nfsd_file_cache_stats_show(struct seq_file *m, void *v) + + seq_printf(m, "total entries: %u\n", count); + seq_printf(m, "longest chain: %u\n", longest); ++ seq_printf(m, "lru entries: %lu\n", lru); + seq_printf(m, "cache hits: %lu\n", hits); + return 0; + } +-- +2.43.0 + diff --git a/queue-5.10/nfsd-report-per-export-stats.patch b/queue-5.10/nfsd-report-per-export-stats.patch new file mode 100644 index 00000000000..b72c8f20800 --- /dev/null +++ b/queue-5.10/nfsd-report-per-export-stats.patch @@ -0,0 +1,325 @@ +From 551a44991aaa236a6c63247e2f2e0a3fedfe5bf7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 6 Jan 2021 09:52:36 +0200 +Subject: nfsd: report per-export stats + +From: Amir Goldstein + +[ Upstream commit 20ad856e47323e208ae8d6a9ecfe5bf0be6f505e ] + +Collect some nfsd stats per export in addition to the global stats. + +A new nfsdfs export_stats file is created. It uses the same ops as the +exports file to iterate the export entries and we use the file's name to +determine the reported info per export. For example: + + $ cat /proc/fs/nfsd/export_stats + # Version 1.1 + # Path Client Start-time + # Stats + /test localhost 92 + fh_stale: 0 + io_read: 9 + io_write: 1 + +Every export entry reports the start time when stats collection +started, so stats collecting scripts can know if stats where reset +between samples. + +Signed-off-by: Amir Goldstein +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/export.c | 68 ++++++++++++++++++++++++++++++++++++++++++------ + fs/nfsd/export.h | 15 +++++++++++ + fs/nfsd/nfsctl.c | 3 +++ + fs/nfsd/nfsd.h | 2 +- + fs/nfsd/nfsfh.c | 4 +-- + fs/nfsd/stats.h | 12 ++++++--- + fs/nfsd/vfs.c | 4 +-- + 7 files changed, 92 insertions(+), 16 deletions(-) + +diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c +index 81e7bb12aca69..7c863f2c21e0c 100644 +--- a/fs/nfsd/export.c ++++ b/fs/nfsd/export.c +@@ -331,12 +331,29 @@ static void nfsd4_fslocs_free(struct nfsd4_fs_locations *fsloc) + fsloc->locations = NULL; + } + ++static int export_stats_init(struct export_stats *stats) ++{ ++ stats->start_time = ktime_get_seconds(); ++ return nfsd_percpu_counters_init(stats->counter, EXP_STATS_COUNTERS_NUM); ++} ++ ++static void export_stats_reset(struct export_stats *stats) ++{ ++ nfsd_percpu_counters_reset(stats->counter, EXP_STATS_COUNTERS_NUM); ++} ++ ++static void export_stats_destroy(struct export_stats *stats) ++{ ++ nfsd_percpu_counters_destroy(stats->counter, EXP_STATS_COUNTERS_NUM); ++} ++ + static void svc_export_put(struct kref *ref) + { + struct svc_export *exp = container_of(ref, struct svc_export, h.ref); + path_put(&exp->ex_path); + auth_domain_put(exp->ex_client); + nfsd4_fslocs_free(&exp->ex_fslocs); ++ export_stats_destroy(&exp->ex_stats); + kfree(exp->ex_uuid); + kfree_rcu(exp, ex_rcu); + } +@@ -692,22 +709,47 @@ static void exp_flags(struct seq_file *m, int flag, int fsid, + kuid_t anonu, kgid_t anong, struct nfsd4_fs_locations *fslocs); + static void show_secinfo(struct seq_file *m, struct svc_export *exp); + ++static int is_export_stats_file(struct seq_file *m) ++{ ++ /* ++ * The export_stats file uses the same ops as the exports file. ++ * We use the file's name to determine the reported info per export. ++ * There is no rename in nsfdfs, so d_name.name is stable. ++ */ ++ return !strcmp(m->file->f_path.dentry->d_name.name, "export_stats"); ++} ++ + static int svc_export_show(struct seq_file *m, + struct cache_detail *cd, + struct cache_head *h) + { +- struct svc_export *exp ; ++ struct svc_export *exp; ++ bool export_stats = is_export_stats_file(m); + +- if (h ==NULL) { +- seq_puts(m, "#path domain(flags)\n"); ++ if (h == NULL) { ++ if (export_stats) ++ seq_puts(m, "#path domain start-time\n#\tstats\n"); ++ else ++ seq_puts(m, "#path domain(flags)\n"); + return 0; + } + exp = container_of(h, struct svc_export, h); + seq_path(m, &exp->ex_path, " \t\n\\"); + seq_putc(m, '\t'); + seq_escape(m, exp->ex_client->name, " \t\n\\"); ++ if (export_stats) { ++ seq_printf(m, "\t%lld\n", exp->ex_stats.start_time); ++ seq_printf(m, "\tfh_stale: %lld\n", ++ percpu_counter_sum_positive(&exp->ex_stats.counter[EXP_STATS_FH_STALE])); ++ seq_printf(m, "\tio_read: %lld\n", ++ percpu_counter_sum_positive(&exp->ex_stats.counter[EXP_STATS_IO_READ])); ++ seq_printf(m, "\tio_write: %lld\n", ++ percpu_counter_sum_positive(&exp->ex_stats.counter[EXP_STATS_IO_WRITE])); ++ seq_putc(m, '\n'); ++ return 0; ++ } + seq_putc(m, '('); +- if (test_bit(CACHE_VALID, &h->flags) && ++ if (test_bit(CACHE_VALID, &h->flags) && + !test_bit(CACHE_NEGATIVE, &h->flags)) { + exp_flags(m, exp->ex_flags, exp->ex_fsid, + exp->ex_anon_uid, exp->ex_anon_gid, &exp->ex_fslocs); +@@ -748,6 +790,7 @@ static void svc_export_init(struct cache_head *cnew, struct cache_head *citem) + new->ex_layout_types = 0; + new->ex_uuid = NULL; + new->cd = item->cd; ++ export_stats_reset(&new->ex_stats); + } + + static void export_update(struct cache_head *cnew, struct cache_head *citem) +@@ -780,10 +823,15 @@ static void export_update(struct cache_head *cnew, struct cache_head *citem) + static struct cache_head *svc_export_alloc(void) + { + struct svc_export *i = kmalloc(sizeof(*i), GFP_KERNEL); +- if (i) +- return &i->h; +- else ++ if (!i) ++ return NULL; ++ ++ if (export_stats_init(&i->ex_stats)) { ++ kfree(i); + return NULL; ++ } ++ ++ return &i->h; + } + + static const struct cache_detail svc_export_cache_template = { +@@ -1245,10 +1293,14 @@ static int e_show(struct seq_file *m, void *p) + struct cache_head *cp = p; + struct svc_export *exp = container_of(cp, struct svc_export, h); + struct cache_detail *cd = m->private; ++ bool export_stats = is_export_stats_file(m); + + if (p == SEQ_START_TOKEN) { + seq_puts(m, "# Version 1.1\n"); +- seq_puts(m, "# Path Client(Flags) # IPs\n"); ++ if (export_stats) ++ seq_puts(m, "# Path Client Start-time\n#\tStats\n"); ++ else ++ seq_puts(m, "# Path Client(Flags) # IPs\n"); + return 0; + } + +diff --git a/fs/nfsd/export.h b/fs/nfsd/export.h +index e7daa1f246f08..ee0e3aba4a6e5 100644 +--- a/fs/nfsd/export.h ++++ b/fs/nfsd/export.h +@@ -6,6 +6,7 @@ + #define NFSD_EXPORT_H + + #include ++#include + #include + #include + +@@ -46,6 +47,19 @@ struct exp_flavor_info { + u32 flags; + }; + ++/* Per-export stats */ ++enum { ++ EXP_STATS_FH_STALE, ++ EXP_STATS_IO_READ, ++ EXP_STATS_IO_WRITE, ++ EXP_STATS_COUNTERS_NUM ++}; ++ ++struct export_stats { ++ time64_t start_time; ++ struct percpu_counter counter[EXP_STATS_COUNTERS_NUM]; ++}; ++ + struct svc_export { + struct cache_head h; + struct auth_domain * ex_client; +@@ -62,6 +76,7 @@ struct svc_export { + struct nfsd4_deviceid_map *ex_devid_map; + struct cache_detail *cd; + struct rcu_head ex_rcu; ++ struct export_stats ex_stats; + }; + + /* an "export key" (expkey) maps a filehandlefragement to an +diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c +index 7f85c171f83aa..fa060f91df1b8 100644 +--- a/fs/nfsd/nfsctl.c ++++ b/fs/nfsd/nfsctl.c +@@ -32,6 +32,7 @@ + enum { + NFSD_Root = 1, + NFSD_List, ++ NFSD_Export_Stats, + NFSD_Export_features, + NFSD_Fh, + NFSD_FO_UnlockIP, +@@ -1352,6 +1353,8 @@ static int nfsd_fill_super(struct super_block *sb, struct fs_context *fc) + + static const struct tree_descr nfsd_files[] = { + [NFSD_List] = {"exports", &exports_nfsd_operations, S_IRUGO}, ++ /* Per-export io stats use same ops as exports file */ ++ [NFSD_Export_Stats] = {"export_stats", &exports_nfsd_operations, S_IRUGO}, + [NFSD_Export_features] = {"export_features", + &export_features_operations, S_IRUGO}, + [NFSD_FO_UnlockIP] = {"unlock_ip", +diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h +index 2326428e2c5bf..27c1308ffc2ba 100644 +--- a/fs/nfsd/nfsd.h ++++ b/fs/nfsd/nfsd.h +@@ -24,8 +24,8 @@ + #include + + #include "netns.h" +-#include "stats.h" + #include "export.h" ++#include "stats.h" + + #undef ifdebug + #ifdef CONFIG_SUNRPC_DEBUG +diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c +index 9e31b2b5c6d26..4744a276058d4 100644 +--- a/fs/nfsd/nfsfh.c ++++ b/fs/nfsd/nfsfh.c +@@ -349,7 +349,7 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp) + __be32 + fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int access) + { +- struct svc_export *exp; ++ struct svc_export *exp = NULL; + struct dentry *dentry; + __be32 error; + +@@ -422,7 +422,7 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int access) + } + out: + if (error == nfserr_stale) +- nfsd_stats_fh_stale_inc(); ++ nfsd_stats_fh_stale_inc(exp); + return error; + } + +diff --git a/fs/nfsd/stats.h b/fs/nfsd/stats.h +index 87c3150c200f0..51ecda852e23b 100644 +--- a/fs/nfsd/stats.h ++++ b/fs/nfsd/stats.h +@@ -59,19 +59,25 @@ static inline void nfsd_stats_rc_nocache_inc(void) + percpu_counter_inc(&nfsdstats.counter[NFSD_STATS_RC_NOCACHE]); + } + +-static inline void nfsd_stats_fh_stale_inc(void) ++static inline void nfsd_stats_fh_stale_inc(struct svc_export *exp) + { + percpu_counter_inc(&nfsdstats.counter[NFSD_STATS_FH_STALE]); ++ if (exp) ++ percpu_counter_inc(&exp->ex_stats.counter[EXP_STATS_FH_STALE]); + } + +-static inline void nfsd_stats_io_read_add(s64 amount) ++static inline void nfsd_stats_io_read_add(struct svc_export *exp, s64 amount) + { + percpu_counter_add(&nfsdstats.counter[NFSD_STATS_IO_READ], amount); ++ if (exp) ++ percpu_counter_add(&exp->ex_stats.counter[EXP_STATS_IO_READ], amount); + } + +-static inline void nfsd_stats_io_write_add(s64 amount) ++static inline void nfsd_stats_io_write_add(struct svc_export *exp, s64 amount) + { + percpu_counter_add(&nfsdstats.counter[NFSD_STATS_IO_WRITE], amount); ++ if (exp) ++ percpu_counter_add(&exp->ex_stats.counter[EXP_STATS_IO_WRITE], amount); + } + + static inline void nfsd_stats_payload_misses_inc(struct nfsd_net *nn) +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index 1b44d8f985be9..3e30788e0046b 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -897,7 +897,7 @@ static __be32 nfsd_finish_read(struct svc_rqst *rqstp, struct svc_fh *fhp, + unsigned long *count, u32 *eof, ssize_t host_err) + { + if (host_err >= 0) { +- nfsd_stats_io_read_add(host_err); ++ nfsd_stats_io_read_add(fhp->fh_export, host_err); + *eof = nfsd_eof_on_read(file, offset, host_err, *count); + *count = host_err; + fsnotify_access(file); +@@ -1050,7 +1050,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf, + goto out_nfserr; + } + *cnt = host_err; +- nfsd_stats_io_write_add(*cnt); ++ nfsd_stats_io_write_add(exp, *cnt); + fsnotify_modify(file); + host_err = filemap_check_wb_err(file->f_mapping, since); + if (host_err < 0) +-- +2.43.0 + diff --git a/queue-5.10/nfsd-report-the-number-of-items-evicted-by-the-lru-w.patch b/queue-5.10/nfsd-report-the-number-of-items-evicted-by-the-lru-w.patch new file mode 100644 index 00000000000..b4cb6ed6f41 --- /dev/null +++ b/queue-5.10/nfsd-report-the-number-of-items-evicted-by-the-lru-w.patch @@ -0,0 +1,127 @@ +From 3217fea59fae67c4e565ad08252ee80cbd295fe0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 Jul 2022 14:24:38 -0400 +Subject: NFSD: Report the number of items evicted by the LRU walk + +From: Chuck Lever + +[ Upstream commit 94660cc19c75083af046b0f8362e3d3bc2eba21d ] + +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 13 ++++++++++--- + fs/nfsd/trace.h | 29 +++++++++++++++++++++++++++++ + 2 files changed, 39 insertions(+), 3 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index 1d94491e5ddad..e5bd9f06492c8 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -45,6 +45,7 @@ static DEFINE_PER_CPU(unsigned long, nfsd_file_cache_hits); + static DEFINE_PER_CPU(unsigned long, nfsd_file_acquisitions); + static DEFINE_PER_CPU(unsigned long, nfsd_file_releases); + static DEFINE_PER_CPU(unsigned long, nfsd_file_total_age); ++static DEFINE_PER_CPU(unsigned long, nfsd_file_evictions); + + struct nfsd_fcache_disposal { + struct work_struct work; +@@ -445,6 +446,7 @@ nfsd_file_lru_cb(struct list_head *item, struct list_lru_one *lru, + goto out_skip; + + list_lru_isolate_move(lru, &nf->nf_lru, head); ++ this_cpu_inc(nfsd_file_evictions); + return LRU_REMOVED; + out_skip: + return LRU_SKIP; +@@ -475,9 +477,11 @@ static void + nfsd_file_gc(void) + { + LIST_HEAD(dispose); ++ unsigned long ret; + +- list_lru_walk(&nfsd_file_lru, nfsd_file_lru_cb, +- &dispose, LONG_MAX); ++ ret = list_lru_walk(&nfsd_file_lru, nfsd_file_lru_cb, ++ &dispose, LONG_MAX); ++ trace_nfsd_file_gc_removed(ret, list_lru_count(&nfsd_file_lru)); + nfsd_file_gc_dispose_list(&dispose); + } + +@@ -502,6 +506,7 @@ nfsd_file_lru_scan(struct shrinker *s, struct shrink_control *sc) + + ret = list_lru_shrink_walk(&nfsd_file_lru, sc, + nfsd_file_lru_cb, &dispose); ++ trace_nfsd_file_shrinker_removed(ret, list_lru_count(&nfsd_file_lru)); + nfsd_file_gc_dispose_list(&dispose); + return ret; + } +@@ -1064,7 +1069,7 @@ nfsd_file_create(struct svc_rqst *rqstp, struct svc_fh *fhp, + */ + static int nfsd_file_cache_stats_show(struct seq_file *m, void *v) + { +- unsigned long hits = 0, acquisitions = 0, releases = 0; ++ unsigned long hits = 0, acquisitions = 0, releases = 0, evictions = 0; + unsigned int i, count = 0, longest = 0; + unsigned long lru = 0, total_age = 0; + +@@ -1088,6 +1093,7 @@ static int nfsd_file_cache_stats_show(struct seq_file *m, void *v) + acquisitions += per_cpu(nfsd_file_acquisitions, i); + releases += per_cpu(nfsd_file_releases, i); + total_age += per_cpu(nfsd_file_total_age, i); ++ evictions += per_cpu(nfsd_file_evictions, i); + } + + seq_printf(m, "total entries: %u\n", count); +@@ -1096,6 +1102,7 @@ static int nfsd_file_cache_stats_show(struct seq_file *m, void *v) + seq_printf(m, "cache hits: %lu\n", hits); + seq_printf(m, "acquisitions: %lu\n", acquisitions); + seq_printf(m, "releases: %lu\n", releases); ++ seq_printf(m, "evictions: %lu\n", evictions); + if (releases) + seq_printf(m, "mean age (ms): %ld\n", total_age / releases); + else +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index 5c2292a1892cc..b373a161e862b 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -860,6 +860,35 @@ TRACE_EVENT(nfsd_file_fsnotify_handle_event, + __entry->nlink, __entry->mode, __entry->mask) + ); + ++DECLARE_EVENT_CLASS(nfsd_file_lruwalk_class, ++ TP_PROTO( ++ unsigned long removed, ++ unsigned long remaining ++ ), ++ TP_ARGS(removed, remaining), ++ TP_STRUCT__entry( ++ __field(unsigned long, removed) ++ __field(unsigned long, remaining) ++ ), ++ TP_fast_assign( ++ __entry->removed = removed; ++ __entry->remaining = remaining; ++ ), ++ TP_printk("%lu entries removed, %lu remaining", ++ __entry->removed, __entry->remaining) ++); ++ ++#define DEFINE_NFSD_FILE_LRUWALK_EVENT(name) \ ++DEFINE_EVENT(nfsd_file_lruwalk_class, name, \ ++ TP_PROTO( \ ++ unsigned long removed, \ ++ unsigned long remaining \ ++ ), \ ++ TP_ARGS(removed, remaining)) ++ ++DEFINE_NFSD_FILE_LRUWALK_EVENT(nfsd_file_gc_removed); ++DEFINE_NFSD_FILE_LRUWALK_EVENT(nfsd_file_shrinker_removed); ++ + #include "cache.h" + + TRACE_DEFINE_ENUM(RC_DROPIT); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-reshuffle-some-code.patch b/queue-5.10/nfsd-reshuffle-some-code.patch new file mode 100644 index 00000000000..b06a282cc22 --- /dev/null +++ b/queue-5.10/nfsd-reshuffle-some-code.patch @@ -0,0 +1,285 @@ +From a513099c2bcbb54b88fdf466a24c11d32fb6a6ff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Apr 2021 14:00:17 -0400 +Subject: nfsd: reshuffle some code + +From: J. Bruce Fields + +[ Upstream commit ebd9d2c2f5a7ebaaed2d7bb4dee148755f46033d ] + +No change in behavior, I'm just moving some code around to avoid forward +references in a following patch. + +(To do someday: figure out how to split up nfs4state.c. It's big and +disorganized.) + +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 235 ++++++++++++++++++++++---------------------- + 1 file changed, 118 insertions(+), 117 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 89d5669ce1463..9c8dacf0f2b86 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -354,6 +354,124 @@ static const struct nfsd4_callback_ops nfsd4_cb_notify_lock_ops = { + .release = nfsd4_cb_notify_lock_release, + }; + ++/* ++ * We store the NONE, READ, WRITE, and BOTH bits separately in the ++ * st_{access,deny}_bmap field of the stateid, in order to track not ++ * only what share bits are currently in force, but also what ++ * combinations of share bits previous opens have used. This allows us ++ * to enforce the recommendation of rfc 3530 14.2.19 that the server ++ * return an error if the client attempt to downgrade to a combination ++ * of share bits not explicable by closing some of its previous opens. ++ * ++ * XXX: This enforcement is actually incomplete, since we don't keep ++ * track of access/deny bit combinations; so, e.g., we allow: ++ * ++ * OPEN allow read, deny write ++ * OPEN allow both, deny none ++ * DOWNGRADE allow read, deny none ++ * ++ * which we should reject. ++ */ ++static unsigned int ++bmap_to_share_mode(unsigned long bmap) ++{ ++ int i; ++ unsigned int access = 0; ++ ++ for (i = 1; i < 4; i++) { ++ if (test_bit(i, &bmap)) ++ access |= i; ++ } ++ return access; ++} ++ ++/* set share access for a given stateid */ ++static inline void ++set_access(u32 access, struct nfs4_ol_stateid *stp) ++{ ++ unsigned char mask = 1 << access; ++ ++ WARN_ON_ONCE(access > NFS4_SHARE_ACCESS_BOTH); ++ stp->st_access_bmap |= mask; ++} ++ ++/* clear share access for a given stateid */ ++static inline void ++clear_access(u32 access, struct nfs4_ol_stateid *stp) ++{ ++ unsigned char mask = 1 << access; ++ ++ WARN_ON_ONCE(access > NFS4_SHARE_ACCESS_BOTH); ++ stp->st_access_bmap &= ~mask; ++} ++ ++/* test whether a given stateid has access */ ++static inline bool ++test_access(u32 access, struct nfs4_ol_stateid *stp) ++{ ++ unsigned char mask = 1 << access; ++ ++ return (bool)(stp->st_access_bmap & mask); ++} ++ ++/* set share deny for a given stateid */ ++static inline void ++set_deny(u32 deny, struct nfs4_ol_stateid *stp) ++{ ++ unsigned char mask = 1 << deny; ++ ++ WARN_ON_ONCE(deny > NFS4_SHARE_DENY_BOTH); ++ stp->st_deny_bmap |= mask; ++} ++ ++/* clear share deny for a given stateid */ ++static inline void ++clear_deny(u32 deny, struct nfs4_ol_stateid *stp) ++{ ++ unsigned char mask = 1 << deny; ++ ++ WARN_ON_ONCE(deny > NFS4_SHARE_DENY_BOTH); ++ stp->st_deny_bmap &= ~mask; ++} ++ ++/* test whether a given stateid is denying specific access */ ++static inline bool ++test_deny(u32 deny, struct nfs4_ol_stateid *stp) ++{ ++ unsigned char mask = 1 << deny; ++ ++ return (bool)(stp->st_deny_bmap & mask); ++} ++ ++static int nfs4_access_to_omode(u32 access) ++{ ++ switch (access & NFS4_SHARE_ACCESS_BOTH) { ++ case NFS4_SHARE_ACCESS_READ: ++ return O_RDONLY; ++ case NFS4_SHARE_ACCESS_WRITE: ++ return O_WRONLY; ++ case NFS4_SHARE_ACCESS_BOTH: ++ return O_RDWR; ++ } ++ WARN_ON_ONCE(1); ++ return O_RDONLY; ++} ++ ++static inline int ++access_permit_read(struct nfs4_ol_stateid *stp) ++{ ++ return test_access(NFS4_SHARE_ACCESS_READ, stp) || ++ test_access(NFS4_SHARE_ACCESS_BOTH, stp) || ++ test_access(NFS4_SHARE_ACCESS_WRITE, stp); ++} ++ ++static inline int ++access_permit_write(struct nfs4_ol_stateid *stp) ++{ ++ return test_access(NFS4_SHARE_ACCESS_WRITE, stp) || ++ test_access(NFS4_SHARE_ACCESS_BOTH, stp); ++} ++ + static inline struct nfs4_stateowner * + nfs4_get_stateowner(struct nfs4_stateowner *sop) + { +@@ -1167,108 +1285,6 @@ static unsigned int clientstr_hashval(struct xdr_netobj name) + return opaque_hashval(name.data, 8) & CLIENT_HASH_MASK; + } + +-/* +- * We store the NONE, READ, WRITE, and BOTH bits separately in the +- * st_{access,deny}_bmap field of the stateid, in order to track not +- * only what share bits are currently in force, but also what +- * combinations of share bits previous opens have used. This allows us +- * to enforce the recommendation of rfc 3530 14.2.19 that the server +- * return an error if the client attempt to downgrade to a combination +- * of share bits not explicable by closing some of its previous opens. +- * +- * XXX: This enforcement is actually incomplete, since we don't keep +- * track of access/deny bit combinations; so, e.g., we allow: +- * +- * OPEN allow read, deny write +- * OPEN allow both, deny none +- * DOWNGRADE allow read, deny none +- * +- * which we should reject. +- */ +-static unsigned int +-bmap_to_share_mode(unsigned long bmap) { +- int i; +- unsigned int access = 0; +- +- for (i = 1; i < 4; i++) { +- if (test_bit(i, &bmap)) +- access |= i; +- } +- return access; +-} +- +-/* set share access for a given stateid */ +-static inline void +-set_access(u32 access, struct nfs4_ol_stateid *stp) +-{ +- unsigned char mask = 1 << access; +- +- WARN_ON_ONCE(access > NFS4_SHARE_ACCESS_BOTH); +- stp->st_access_bmap |= mask; +-} +- +-/* clear share access for a given stateid */ +-static inline void +-clear_access(u32 access, struct nfs4_ol_stateid *stp) +-{ +- unsigned char mask = 1 << access; +- +- WARN_ON_ONCE(access > NFS4_SHARE_ACCESS_BOTH); +- stp->st_access_bmap &= ~mask; +-} +- +-/* test whether a given stateid has access */ +-static inline bool +-test_access(u32 access, struct nfs4_ol_stateid *stp) +-{ +- unsigned char mask = 1 << access; +- +- return (bool)(stp->st_access_bmap & mask); +-} +- +-/* set share deny for a given stateid */ +-static inline void +-set_deny(u32 deny, struct nfs4_ol_stateid *stp) +-{ +- unsigned char mask = 1 << deny; +- +- WARN_ON_ONCE(deny > NFS4_SHARE_DENY_BOTH); +- stp->st_deny_bmap |= mask; +-} +- +-/* clear share deny for a given stateid */ +-static inline void +-clear_deny(u32 deny, struct nfs4_ol_stateid *stp) +-{ +- unsigned char mask = 1 << deny; +- +- WARN_ON_ONCE(deny > NFS4_SHARE_DENY_BOTH); +- stp->st_deny_bmap &= ~mask; +-} +- +-/* test whether a given stateid is denying specific access */ +-static inline bool +-test_deny(u32 deny, struct nfs4_ol_stateid *stp) +-{ +- unsigned char mask = 1 << deny; +- +- return (bool)(stp->st_deny_bmap & mask); +-} +- +-static int nfs4_access_to_omode(u32 access) +-{ +- switch (access & NFS4_SHARE_ACCESS_BOTH) { +- case NFS4_SHARE_ACCESS_READ: +- return O_RDONLY; +- case NFS4_SHARE_ACCESS_WRITE: +- return O_WRONLY; +- case NFS4_SHARE_ACCESS_BOTH: +- return O_RDWR; +- } +- WARN_ON_ONCE(1); +- return O_RDONLY; +-} +- + /* + * A stateid that had a deny mode associated with it is being released + * or downgraded. Recalculate the deny mode on the file. +@@ -5565,21 +5581,6 @@ static inline __be32 nfs4_check_fh(struct svc_fh *fhp, struct nfs4_stid *stp) + return nfs_ok; + } + +-static inline int +-access_permit_read(struct nfs4_ol_stateid *stp) +-{ +- return test_access(NFS4_SHARE_ACCESS_READ, stp) || +- test_access(NFS4_SHARE_ACCESS_BOTH, stp) || +- test_access(NFS4_SHARE_ACCESS_WRITE, stp); +-} +- +-static inline int +-access_permit_write(struct nfs4_ol_stateid *stp) +-{ +- return test_access(NFS4_SHARE_ACCESS_WRITE, stp) || +- test_access(NFS4_SHARE_ACCESS_BOTH, stp); +-} +- + static + __be32 nfs4_check_openmode(struct nfs4_ol_stateid *stp, int flags) + { +-- +2.43.0 + diff --git a/queue-5.10/nfsd-restore-nfsv4-decoding-s-savemem-functionality.patch b/queue-5.10/nfsd-restore-nfsv4-decoding-s-savemem-functionality.patch new file mode 100644 index 00000000000..d917f0763ff --- /dev/null +++ b/queue-5.10/nfsd-restore-nfsv4-decoding-s-savemem-functionality.patch @@ -0,0 +1,154 @@ +From 73f02d3487433849118444ee45fb6c249fcadcb0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 18 Dec 2020 12:28:58 -0500 +Subject: NFSD: Restore NFSv4 decoding's SAVEMEM functionality + +From: Chuck Lever + +[ Upstream commit 7b723008f9c95624c848fad661c01b06e47b20da ] + +While converting the NFSv4 decoder to use xdr_stream-based XDR +processing, I removed the old SAVEMEM() macro. This macro wrapped +a bit of logic that avoided a memory allocation by recognizing when +the decoded item resides in a linear section of the Receive buffer. +In that case, it returned a pointer into that buffer instead of +allocating a bounce buffer. + +The bounce buffer is necessary only when xdr_inline_decode() has +placed the decoded item in the xdr_stream's scratch buffer, which +disappears the next time xdr_inline_decode() is called with that +xdr_stream. That happens only if the data item crosses a page +boundary in the receive buffer, an exceedingly rare occurrence. + +Allocating a bounce buffer every time results in a minor performance +regression that was introduced by the recent NFSv4 decoder overhaul. +Let's restore the previous behavior. On average, it saves about 1.5 +kmalloc() calls per COMPOUND. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 42 ++++++++++++++++++++++++++---------------- + 1 file changed, 26 insertions(+), 16 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index bb037e8eb8304..8d5fdae568aeb 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -147,6 +147,25 @@ svcxdr_dupstr(struct nfsd4_compoundargs *argp, void *buf, u32 len) + return p; + } + ++static void * ++svcxdr_savemem(struct nfsd4_compoundargs *argp, __be32 *p, u32 len) ++{ ++ __be32 *tmp; ++ ++ /* ++ * The location of the decoded data item is stable, ++ * so @p is OK to use. This is the common case. ++ */ ++ if (p != argp->xdr->scratch.iov_base) ++ return p; ++ ++ tmp = svcxdr_tmpalloc(argp, len); ++ if (!tmp) ++ return NULL; ++ memcpy(tmp, p, len); ++ return tmp; ++} ++ + /* + * NFSv4 basic data type decoders + */ +@@ -183,11 +202,10 @@ nfsd4_decode_opaque(struct nfsd4_compoundargs *argp, struct xdr_netobj *o) + p = xdr_inline_decode(argp->xdr, len); + if (!p) + return nfserr_bad_xdr; +- o->data = svcxdr_tmpalloc(argp, len); ++ o->data = svcxdr_savemem(argp, p, len); + if (!o->data) + return nfserr_jukebox; + o->len = len; +- memcpy(o->data, p, len); + + return nfs_ok; + } +@@ -205,10 +223,9 @@ nfsd4_decode_component4(struct nfsd4_compoundargs *argp, char **namp, u32 *lenp) + status = check_filename((char *)p, *lenp); + if (status) + return status; +- *namp = svcxdr_tmpalloc(argp, *lenp); ++ *namp = svcxdr_savemem(argp, p, *lenp); + if (!*namp) + return nfserr_jukebox; +- memcpy(*namp, p, *lenp); + + return nfs_ok; + } +@@ -1200,10 +1217,9 @@ nfsd4_decode_putfh(struct nfsd4_compoundargs *argp, struct nfsd4_putfh *putfh) + p = xdr_inline_decode(argp->xdr, putfh->pf_fhlen); + if (!p) + return nfserr_bad_xdr; +- putfh->pf_fhval = svcxdr_tmpalloc(argp, putfh->pf_fhlen); ++ putfh->pf_fhval = svcxdr_savemem(argp, p, putfh->pf_fhlen); + if (!putfh->pf_fhval) + return nfserr_jukebox; +- memcpy(putfh->pf_fhval, p, putfh->pf_fhlen); + + return nfs_ok; + } +@@ -1318,24 +1334,20 @@ nfsd4_decode_setclientid(struct nfsd4_compoundargs *argp, struct nfsd4_setclient + p = xdr_inline_decode(argp->xdr, setclientid->se_callback_netid_len); + if (!p) + return nfserr_bad_xdr; +- setclientid->se_callback_netid_val = svcxdr_tmpalloc(argp, ++ setclientid->se_callback_netid_val = svcxdr_savemem(argp, p, + setclientid->se_callback_netid_len); + if (!setclientid->se_callback_netid_val) + return nfserr_jukebox; +- memcpy(setclientid->se_callback_netid_val, p, +- setclientid->se_callback_netid_len); + + if (xdr_stream_decode_u32(argp->xdr, &setclientid->se_callback_addr_len) < 0) + return nfserr_bad_xdr; + p = xdr_inline_decode(argp->xdr, setclientid->se_callback_addr_len); + if (!p) + return nfserr_bad_xdr; +- setclientid->se_callback_addr_val = svcxdr_tmpalloc(argp, ++ setclientid->se_callback_addr_val = svcxdr_savemem(argp, p, + setclientid->se_callback_addr_len); + if (!setclientid->se_callback_addr_val) + return nfserr_jukebox; +- memcpy(setclientid->se_callback_addr_val, p, +- setclientid->se_callback_addr_len); + if (xdr_stream_decode_u32(argp->xdr, &setclientid->se_callback_ident) < 0) + return nfserr_bad_xdr; + +@@ -1375,10 +1387,9 @@ nfsd4_decode_verify(struct nfsd4_compoundargs *argp, struct nfsd4_verify *verify + p = xdr_inline_decode(argp->xdr, verify->ve_attrlen); + if (!p) + return nfserr_bad_xdr; +- verify->ve_attrval = svcxdr_tmpalloc(argp, verify->ve_attrlen); ++ verify->ve_attrval = svcxdr_savemem(argp, p, verify->ve_attrlen); + if (!verify->ve_attrval) + return nfserr_jukebox; +- memcpy(verify->ve_attrval, p, verify->ve_attrlen); + + return nfs_ok; + } +@@ -2333,10 +2344,9 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) + p = xdr_inline_decode(argp->xdr, argp->taglen); + if (!p) + return 0; +- argp->tag = svcxdr_tmpalloc(argp, argp->taglen); ++ argp->tag = svcxdr_savemem(argp, p, argp->taglen); + if (!argp->tag) + return 0; +- memcpy(argp->tag, p, argp->taglen); + max_reply += xdr_align_size(argp->taglen); + } + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-retry-once-in-nfsd_open-on-an-eopenstale-return.patch b/queue-5.10/nfsd-retry-once-in-nfsd_open-on-an-eopenstale-return.patch new file mode 100644 index 00000000000..fc3cf000e7f --- /dev/null +++ b/queue-5.10/nfsd-retry-once-in-nfsd_open-on-an-eopenstale-return.patch @@ -0,0 +1,71 @@ +From b2e7882026e462c6a2fe7f2ab2e60fa25eebea01 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 18 Dec 2021 20:37:56 -0500 +Subject: nfsd: Retry once in nfsd_open on an -EOPENSTALE return + +From: Jeff Layton + +[ Upstream commit 12bcbd40fd931472c7fc9cf3bfe66799ece93ed8 ] + +If we get back -EOPENSTALE from an NFSv4 open, then we either got some +unhandled error or the inode we got back was not the same as the one +associated with the dentry. + +We really have no recourse in that situation other than to retry the +open, and if it fails to just return nfserr_stale back to the client. + +Signed-off-by: Jeff Layton +Signed-off-by: Lance Shelton +Signed-off-by: Trond Myklebust +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsproc.c | 1 + + fs/nfsd/vfs.c | 10 +++++++++- + 2 files changed, 10 insertions(+), 1 deletion(-) + +diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c +index 6ed13754290a2..b8ddf21e70ea0 100644 +--- a/fs/nfsd/nfsproc.c ++++ b/fs/nfsd/nfsproc.c +@@ -875,6 +875,7 @@ nfserrno (int errno) + { nfserr_serverfault, -ESERVERFAULT }, + { nfserr_serverfault, -ENFILE }, + { nfserr_io, -EREMOTEIO }, ++ { nfserr_stale, -EOPENSTALE }, + { nfserr_io, -EUCLEAN }, + { nfserr_perm, -ENOKEY }, + { nfserr_no_grace, -ENOGRACE}, +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index deaf4a50550d5..b343677b01efa 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -805,6 +805,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, + int may_flags, struct file **filp) + { + __be32 err; ++ bool retried = false; + + validate_process_creds(); + /* +@@ -820,9 +821,16 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, + */ + if (type == S_IFREG) + may_flags |= NFSD_MAY_OWNER_OVERRIDE; ++retry: + err = fh_verify(rqstp, fhp, type, may_flags); +- if (!err) ++ if (!err) { + err = __nfsd_open(rqstp, fhp, type, may_flags, filp); ++ if (err == nfserr_stale && !retried) { ++ retried = true; ++ fh_put(fhp); ++ goto retry; ++ } ++ } + validate_process_creds(); + return err; + } +-- +2.43.0 + diff --git a/queue-5.10/nfsd-return-error-if-nfs4_setacl-fails.patch b/queue-5.10/nfsd-return-error-if-nfs4_setacl-fails.patch new file mode 100644 index 00000000000..87efd72aac5 --- /dev/null +++ b/queue-5.10/nfsd-return-error-if-nfs4_setacl-fails.patch @@ -0,0 +1,39 @@ +From 98482cb20e91c21e9f58474e6cb8ed91395a2955 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 7 Nov 2022 06:58:41 -0500 +Subject: nfsd: return error if nfs4_setacl fails + +From: Jeff Layton + +[ Upstream commit 01d53a88c08951f88f2a42f1f1e6568928e0590e ] + +With the addition of POSIX ACLs to struct nfsd_attrs, we no longer +return an error if setting the ACL fails. Ensure we return the na_aclerr +error on SETATTR if there is one. + +Fixes: c0cbe70742f4 ("NFSD: add posix ACLs to struct nfsd_attrs") +Cc: Neil Brown +Reported-by: Yongcheng Yang +Signed-off-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 32fccca7de185..86ab9b8ac2daf 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -1135,6 +1135,8 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + 0, (time64_t)0); + if (!status) + status = nfserrno(attrs.na_labelerr); ++ if (!status) ++ status = nfserrno(attrs.na_aclerr); + out: + nfsd_attrs_free(&attrs); + fh_drop_write(&cstate->current_fh); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-revert-nfsd-nfsv4-close-should-release-an-nfsd_.patch b/queue-5.10/nfsd-revert-nfsd-nfsv4-close-should-release-an-nfsd_.patch new file mode 100644 index 00000000000..19d1d1b082b --- /dev/null +++ b/queue-5.10/nfsd-revert-nfsd-nfsv4-close-should-release-an-nfsd_.patch @@ -0,0 +1,96 @@ +From 4889bfce4ab7f95760f6e32067b0bf905ba72900 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Oct 2022 10:46:44 -0400 +Subject: NFSD: Revert "NFSD: NFSv4 CLOSE should release an nfsd_file + immediately" + +From: Chuck Lever + +[ Upstream commit dcf3f80965ca787c70def402cdf1553c93c75529 ] + +This reverts commit 5e138c4a750dc140d881dab4a8804b094bbc08d2. + +That commit attempted to make files available to other users as soon +as all NFSv4 clients were done with them, rather than waiting until +the filecache LRU had garbage collected them. + +It gets the reference counting wrong, for one thing. + +But it also misses that DELEGRETURN should release a file in the +same fashion. In fact, any nfsd_file_put() on an file held open +by an NFSv4 client needs potentially to release the file +immediately... + +Clear the way for implementing that idea. + +Signed-off-by: Chuck Lever +Reviewed-by: Jeff Layton +Reviewed-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 18 ------------------ + fs/nfsd/filecache.h | 1 - + fs/nfsd/nfs4state.c | 4 ++-- + 3 files changed, 2 insertions(+), 21 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index dceb522f5cee9..e429fce894316 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -443,24 +443,6 @@ nfsd_file_put(struct nfsd_file *nf) + nfsd_file_put_noref(nf); + } + +-/** +- * nfsd_file_close - Close an nfsd_file +- * @nf: nfsd_file to close +- * +- * If this is the final reference for @nf, free it immediately. +- * This reflects an on-the-wire CLOSE or DELEGRETURN into the +- * VFS and exported filesystem. +- */ +-void nfsd_file_close(struct nfsd_file *nf) +-{ +- nfsd_file_put(nf); +- if (refcount_dec_if_one(&nf->nf_ref)) { +- nfsd_file_unhash(nf); +- nfsd_file_lru_remove(nf); +- nfsd_file_free(nf); +- } +-} +- + struct nfsd_file * + nfsd_file_get(struct nfsd_file *nf) + { +diff --git a/fs/nfsd/filecache.h b/fs/nfsd/filecache.h +index 357832bac736b..6b012ea4bd9da 100644 +--- a/fs/nfsd/filecache.h ++++ b/fs/nfsd/filecache.h +@@ -52,7 +52,6 @@ void nfsd_file_cache_shutdown(void); + int nfsd_file_cache_start_net(struct net *net); + void nfsd_file_cache_shutdown_net(struct net *net); + void nfsd_file_put(struct nfsd_file *nf); +-void nfsd_file_close(struct nfsd_file *nf); + struct nfsd_file *nfsd_file_get(struct nfsd_file *nf); + void nfsd_file_close_inode_sync(struct inode *inode); + bool nfsd_file_is_cached(struct inode *inode); +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 2d09977fee83d..80d8f40d1f126 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -842,9 +842,9 @@ static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag) + swap(f2, fp->fi_fds[O_RDWR]); + spin_unlock(&fp->fi_lock); + if (f1) +- nfsd_file_close(f1); ++ nfsd_file_put(f1); + if (f2) +- nfsd_file_close(f2); ++ nfsd_file_put(f2); + } + } + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-rework-hashtable-handling-in-nfsd_do_file_acqui.patch b/queue-5.10/nfsd-rework-hashtable-handling-in-nfsd_do_file_acqui.patch new file mode 100644 index 00000000000..029e69b8649 --- /dev/null +++ b/queue-5.10/nfsd-rework-hashtable-handling-in-nfsd_do_file_acqui.patch @@ -0,0 +1,125 @@ +From 467c2ed63bc7e9bc68a484f1815ba4fdc46f30f9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 4 Oct 2022 15:41:10 -0400 +Subject: nfsd: rework hashtable handling in nfsd_do_file_acquire + +From: Jeff Layton + +[ Upstream commit 243a5263014a30436c93ed3f1f864c1da845455e ] + +nfsd_file is RCU-freed, so we need to hold the rcu_read_lock long enough +to get a reference after finding it in the hash. Take the +rcu_read_lock() and call rhashtable_lookup directly. + +Switch to using rhashtable_lookup_insert_key as well, and use the usual +retry mechanism if we hit an -EEXIST. Rename the "retry" bool to +open_retry, and eliminiate the insert_err goto target. + +Signed-off-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 52 +++++++++++++++++++-------------------------- + 1 file changed, 22 insertions(+), 30 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index a0d93e797cdce..0b19eb015c6c8 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -1041,9 +1041,10 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + .need = may_flags & NFSD_FILE_MAY_MASK, + .net = SVC_NET(rqstp), + }; +- struct nfsd_file *nf, *new; +- bool retry = true; ++ bool open_retry = true; ++ struct nfsd_file *nf; + __be32 status; ++ int ret; + + status = fh_verify(rqstp, fhp, S_IFREG, + may_flags|NFSD_MAY_OWNER_OVERRIDE); +@@ -1053,35 +1054,33 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + key.cred = get_current_cred(); + + retry: +- /* Avoid allocation if the item is already in cache */ +- nf = rhashtable_lookup_fast(&nfsd_file_rhash_tbl, &key, +- nfsd_file_rhash_params); ++ rcu_read_lock(); ++ nf = rhashtable_lookup(&nfsd_file_rhash_tbl, &key, ++ nfsd_file_rhash_params); + if (nf) + nf = nfsd_file_get(nf); ++ rcu_read_unlock(); + if (nf) + goto wait_for_construction; + +- new = nfsd_file_alloc(&key, may_flags); +- if (!new) { ++ nf = nfsd_file_alloc(&key, may_flags); ++ if (!nf) { + status = nfserr_jukebox; + goto out_status; + } + +- nf = rhashtable_lookup_get_insert_key(&nfsd_file_rhash_tbl, +- &key, &new->nf_rhash, +- nfsd_file_rhash_params); +- if (!nf) { +- nf = new; +- goto open_file; +- } +- if (IS_ERR(nf)) +- goto insert_err; +- nf = nfsd_file_get(nf); +- if (nf == NULL) { +- nf = new; ++ ret = rhashtable_lookup_insert_key(&nfsd_file_rhash_tbl, ++ &key, &nf->nf_rhash, ++ nfsd_file_rhash_params); ++ if (likely(ret == 0)) + goto open_file; +- } +- nfsd_file_slab_free(&new->nf_rcu); ++ ++ nfsd_file_slab_free(&nf->nf_rcu); ++ if (ret == -EEXIST) ++ goto retry; ++ trace_nfsd_file_insert_err(rqstp, key.inode, may_flags, ret); ++ status = nfserr_jukebox; ++ goto out_status; + + wait_for_construction: + wait_on_bit(&nf->nf_flags, NFSD_FILE_PENDING, TASK_UNINTERRUPTIBLE); +@@ -1089,11 +1088,11 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + /* Did construction of this file fail? */ + if (!test_bit(NFSD_FILE_HASHED, &nf->nf_flags)) { + trace_nfsd_file_cons_err(rqstp, key.inode, may_flags, nf); +- if (!retry) { ++ if (!open_retry) { + status = nfserr_jukebox; + goto out; + } +- retry = false; ++ open_retry = false; + nfsd_file_put_noref(nf); + goto retry; + } +@@ -1141,13 +1140,6 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + smp_mb__after_atomic(); + wake_up_bit(&nf->nf_flags, NFSD_FILE_PENDING); + goto out; +- +-insert_err: +- nfsd_file_slab_free(&new->nf_rcu); +- trace_nfsd_file_insert_err(rqstp, key.inode, may_flags, PTR_ERR(nf)); +- nf = NULL; +- status = nfserr_jukebox; +- goto out_status; + } + + /** +-- +2.43.0 + diff --git a/queue-5.10/nfsd-rework-refcounting-in-filecache.patch b/queue-5.10/nfsd-rework-refcounting-in-filecache.patch new file mode 100644 index 00000000000..3124b627e1f --- /dev/null +++ b/queue-5.10/nfsd-rework-refcounting-in-filecache.patch @@ -0,0 +1,668 @@ +From 68ad7bb3cbad26d53df5d8a22029950025deb237 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 11 Dec 2022 06:19:33 -0500 +Subject: nfsd: rework refcounting in filecache + +From: Jeff Layton + +[ Upstream commit ac3a2585f018f10039b4a856dcb122da88c1c1c9 ] + +The filecache refcounting is a bit non-standard for something searchable +by RCU, in that we maintain a sentinel reference while it's hashed. This +in turn requires that we have to do things differently in the "put" +depending on whether its hashed, which we believe to have led to races. + +There are other problems in here too. nfsd_file_close_inode_sync can end +up freeing an nfsd_file while there are still outstanding references to +it, and there are a number of subtle ToC/ToU races. + +Rework the code so that the refcount is what drives the lifecycle. When +the refcount goes to zero, then unhash and rcu free the object. A task +searching for a nfsd_file is allowed to bump its refcount, but only if +it's not already 0. Ensure that we don't make any other changes to it +until a reference is held. + +With this change, the LRU carries a reference. Take special care to deal +with it when removing an entry from the list, and ensure that we only +repurpose the nf_lru list_head when the refcount is 0 to ensure +exclusive access to it. + +Signed-off-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 318 +++++++++++++++++++++++--------------------- + fs/nfsd/trace.h | 51 +++---- + 2 files changed, 189 insertions(+), 180 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index 6b8873b0c2c38..140094a44cc40 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -323,8 +323,7 @@ nfsd_file_alloc(struct nfsd_file_lookup_key *key, unsigned int may) + if (key->gc) + __set_bit(NFSD_FILE_GC, &nf->nf_flags); + nf->nf_inode = key->inode; +- /* nf_ref is pre-incremented for hash table */ +- refcount_set(&nf->nf_ref, 2); ++ refcount_set(&nf->nf_ref, 1); + nf->nf_may = key->need; + nf->nf_mark = NULL; + } +@@ -376,24 +375,35 @@ nfsd_file_unhash(struct nfsd_file *nf) + return false; + } + +-static bool ++static void + nfsd_file_free(struct nfsd_file *nf) + { + s64 age = ktime_to_ms(ktime_sub(ktime_get(), nf->nf_birthtime)); +- bool flush = false; + + trace_nfsd_file_free(nf); + + this_cpu_inc(nfsd_file_releases); + this_cpu_add(nfsd_file_total_age, age); + ++ nfsd_file_unhash(nf); ++ ++ /* ++ * We call fsync here in order to catch writeback errors. It's not ++ * strictly required by the protocol, but an nfsd_file could get ++ * evicted from the cache before a COMMIT comes in. If another ++ * task were to open that file in the interim and scrape the error, ++ * then the client may never see it. By calling fsync here, we ensure ++ * that writeback happens before the entry is freed, and that any ++ * errors reported result in the write verifier changing. ++ */ ++ nfsd_file_fsync(nf); ++ + if (nf->nf_mark) + nfsd_file_mark_put(nf->nf_mark); + if (nf->nf_file) { + get_file(nf->nf_file); + filp_close(nf->nf_file, NULL); + fput(nf->nf_file); +- flush = true; + } + + /* +@@ -401,10 +411,9 @@ nfsd_file_free(struct nfsd_file *nf) + * WARN and leak it to preserve system stability. + */ + if (WARN_ON_ONCE(!list_empty(&nf->nf_lru))) +- return flush; ++ return; + + call_rcu(&nf->nf_rcu, nfsd_file_slab_free); +- return flush; + } + + static bool +@@ -420,17 +429,23 @@ nfsd_file_check_writeback(struct nfsd_file *nf) + mapping_tagged(mapping, PAGECACHE_TAG_WRITEBACK); + } + +-static void nfsd_file_lru_add(struct nfsd_file *nf) ++static bool nfsd_file_lru_add(struct nfsd_file *nf) + { + set_bit(NFSD_FILE_REFERENCED, &nf->nf_flags); +- if (list_lru_add(&nfsd_file_lru, &nf->nf_lru)) ++ if (list_lru_add(&nfsd_file_lru, &nf->nf_lru)) { + trace_nfsd_file_lru_add(nf); ++ return true; ++ } ++ return false; + } + +-static void nfsd_file_lru_remove(struct nfsd_file *nf) ++static bool nfsd_file_lru_remove(struct nfsd_file *nf) + { +- if (list_lru_del(&nfsd_file_lru, &nf->nf_lru)) ++ if (list_lru_del(&nfsd_file_lru, &nf->nf_lru)) { + trace_nfsd_file_lru_del(nf); ++ return true; ++ } ++ return false; + } + + struct nfsd_file * +@@ -441,86 +456,60 @@ nfsd_file_get(struct nfsd_file *nf) + return NULL; + } + +-static void +-nfsd_file_unhash_and_queue(struct nfsd_file *nf, struct list_head *dispose) +-{ +- trace_nfsd_file_unhash_and_queue(nf); +- if (nfsd_file_unhash(nf)) { +- /* caller must call nfsd_file_dispose_list() later */ +- nfsd_file_lru_remove(nf); +- list_add(&nf->nf_lru, dispose); +- } +-} +- +-static void +-nfsd_file_put_noref(struct nfsd_file *nf) +-{ +- trace_nfsd_file_put(nf); +- +- if (refcount_dec_and_test(&nf->nf_ref)) { +- WARN_ON(test_bit(NFSD_FILE_HASHED, &nf->nf_flags)); +- nfsd_file_lru_remove(nf); +- nfsd_file_free(nf); +- } +-} +- +-static void +-nfsd_file_unhash_and_put(struct nfsd_file *nf) +-{ +- if (nfsd_file_unhash(nf)) +- nfsd_file_put_noref(nf); +-} +- ++/** ++ * nfsd_file_put - put the reference to a nfsd_file ++ * @nf: nfsd_file of which to put the reference ++ * ++ * Put a reference to a nfsd_file. In the non-GC case, we just put the ++ * reference immediately. In the GC case, if the reference would be ++ * the last one, the put it on the LRU instead to be cleaned up later. ++ */ + void + nfsd_file_put(struct nfsd_file *nf) + { + might_sleep(); ++ trace_nfsd_file_put(nf); + +- if (test_bit(NFSD_FILE_GC, &nf->nf_flags)) +- nfsd_file_lru_add(nf); +- else if (refcount_read(&nf->nf_ref) == 2) +- nfsd_file_unhash_and_put(nf); +- +- if (!test_bit(NFSD_FILE_HASHED, &nf->nf_flags)) { +- nfsd_file_fsync(nf); +- nfsd_file_put_noref(nf); +- } else if (nf->nf_file && test_bit(NFSD_FILE_GC, &nf->nf_flags)) { +- nfsd_file_put_noref(nf); +- nfsd_file_schedule_laundrette(); +- } else +- nfsd_file_put_noref(nf); +-} +- +-static void +-nfsd_file_dispose_list(struct list_head *dispose) +-{ +- struct nfsd_file *nf; ++ if (test_bit(NFSD_FILE_GC, &nf->nf_flags) && ++ test_bit(NFSD_FILE_HASHED, &nf->nf_flags)) { ++ /* ++ * If this is the last reference (nf_ref == 1), then try to ++ * transfer it to the LRU. ++ */ ++ if (refcount_dec_not_one(&nf->nf_ref)) ++ return; ++ ++ /* Try to add it to the LRU. If that fails, decrement. */ ++ if (nfsd_file_lru_add(nf)) { ++ /* If it's still hashed, we're done */ ++ if (test_bit(NFSD_FILE_HASHED, &nf->nf_flags)) { ++ nfsd_file_schedule_laundrette(); ++ return; ++ } + +- while(!list_empty(dispose)) { +- nf = list_first_entry(dispose, struct nfsd_file, nf_lru); +- list_del_init(&nf->nf_lru); +- nfsd_file_fsync(nf); +- nfsd_file_put_noref(nf); ++ /* ++ * We're racing with unhashing, so try to remove it from ++ * the LRU. If removal fails, then someone else already ++ * has our reference. ++ */ ++ if (!nfsd_file_lru_remove(nf)) ++ return; ++ } + } ++ if (refcount_dec_and_test(&nf->nf_ref)) ++ nfsd_file_free(nf); + } + + static void +-nfsd_file_dispose_list_sync(struct list_head *dispose) ++nfsd_file_dispose_list(struct list_head *dispose) + { +- bool flush = false; + struct nfsd_file *nf; + +- while(!list_empty(dispose)) { ++ while (!list_empty(dispose)) { + nf = list_first_entry(dispose, struct nfsd_file, nf_lru); + list_del_init(&nf->nf_lru); +- nfsd_file_fsync(nf); +- if (!refcount_dec_and_test(&nf->nf_ref)) +- continue; +- if (nfsd_file_free(nf)) +- flush = true; ++ nfsd_file_free(nf); + } +- if (flush) +- flush_delayed_fput(); + } + + static void +@@ -590,21 +579,8 @@ nfsd_file_lru_cb(struct list_head *item, struct list_lru_one *lru, + struct list_head *head = arg; + struct nfsd_file *nf = list_entry(item, struct nfsd_file, nf_lru); + +- /* +- * Do a lockless refcount check. The hashtable holds one reference, so +- * we look to see if anything else has a reference, or if any have +- * been put since the shrinker last ran. Those don't get unhashed and +- * released. +- * +- * Note that in the put path, we set the flag and then decrement the +- * counter. Here we check the counter and then test and clear the flag. +- * That order is deliberate to ensure that we can do this locklessly. +- */ +- if (refcount_read(&nf->nf_ref) > 1) { +- list_lru_isolate(lru, &nf->nf_lru); +- trace_nfsd_file_gc_in_use(nf); +- return LRU_REMOVED; +- } ++ /* We should only be dealing with GC entries here */ ++ WARN_ON_ONCE(!test_bit(NFSD_FILE_GC, &nf->nf_flags)); + + /* + * Don't throw out files that are still undergoing I/O or +@@ -615,40 +591,30 @@ nfsd_file_lru_cb(struct list_head *item, struct list_lru_one *lru, + return LRU_SKIP; + } + ++ /* If it was recently added to the list, skip it */ + if (test_and_clear_bit(NFSD_FILE_REFERENCED, &nf->nf_flags)) { + trace_nfsd_file_gc_referenced(nf); + return LRU_ROTATE; + } + +- if (!test_and_clear_bit(NFSD_FILE_HASHED, &nf->nf_flags)) { +- trace_nfsd_file_gc_hashed(nf); +- return LRU_SKIP; ++ /* ++ * Put the reference held on behalf of the LRU. If it wasn't the last ++ * one, then just remove it from the LRU and ignore it. ++ */ ++ if (!refcount_dec_and_test(&nf->nf_ref)) { ++ trace_nfsd_file_gc_in_use(nf); ++ list_lru_isolate(lru, &nf->nf_lru); ++ return LRU_REMOVED; + } + ++ /* Refcount went to zero. Unhash it and queue it to the dispose list */ ++ nfsd_file_unhash(nf); + list_lru_isolate_move(lru, &nf->nf_lru, head); + this_cpu_inc(nfsd_file_evictions); + trace_nfsd_file_gc_disposed(nf); + return LRU_REMOVED; + } + +-/* +- * Unhash items on @dispose immediately, then queue them on the +- * disposal workqueue to finish releasing them in the background. +- * +- * cel: Note that between the time list_lru_shrink_walk runs and +- * now, these items are in the hash table but marked unhashed. +- * Why release these outside of lru_cb ? There's no lock ordering +- * problem since lru_cb currently takes no lock. +- */ +-static void nfsd_file_gc_dispose_list(struct list_head *dispose) +-{ +- struct nfsd_file *nf; +- +- list_for_each_entry(nf, dispose, nf_lru) +- nfsd_file_hash_remove(nf); +- nfsd_file_dispose_list_delayed(dispose); +-} +- + static void + nfsd_file_gc(void) + { +@@ -658,7 +624,7 @@ nfsd_file_gc(void) + ret = list_lru_walk(&nfsd_file_lru, nfsd_file_lru_cb, + &dispose, list_lru_count(&nfsd_file_lru)); + trace_nfsd_file_gc_removed(ret, list_lru_count(&nfsd_file_lru)); +- nfsd_file_gc_dispose_list(&dispose); ++ nfsd_file_dispose_list_delayed(&dispose); + } + + static void +@@ -684,7 +650,7 @@ nfsd_file_lru_scan(struct shrinker *s, struct shrink_control *sc) + ret = list_lru_shrink_walk(&nfsd_file_lru, sc, + nfsd_file_lru_cb, &dispose); + trace_nfsd_file_shrinker_removed(ret, list_lru_count(&nfsd_file_lru)); +- nfsd_file_gc_dispose_list(&dispose); ++ nfsd_file_dispose_list_delayed(&dispose); + return ret; + } + +@@ -694,72 +660,111 @@ static struct shrinker nfsd_file_shrinker = { + .seeks = 1, + }; + +-/* +- * Find all cache items across all net namespaces that match @inode and +- * move them to @dispose. The lookup is atomic wrt nfsd_file_acquire(). ++/** ++ * nfsd_file_queue_for_close: try to close out any open nfsd_files for an inode ++ * @inode: inode on which to close out nfsd_files ++ * @dispose: list on which to gather nfsd_files to close out ++ * ++ * An nfsd_file represents a struct file being held open on behalf of nfsd. An ++ * open file however can block other activity (such as leases), or cause ++ * undesirable behavior (e.g. spurious silly-renames when reexporting NFS). ++ * ++ * This function is intended to find open nfsd_files when this sort of ++ * conflicting access occurs and then attempt to close those files out. ++ * ++ * Populates the dispose list with entries that have already had their ++ * refcounts go to zero. The actual free of an nfsd_file can be expensive, ++ * so we leave it up to the caller whether it wants to wait or not. + */ +-static unsigned int +-__nfsd_file_close_inode(struct inode *inode, struct list_head *dispose) ++static void ++nfsd_file_queue_for_close(struct inode *inode, struct list_head *dispose) + { + struct nfsd_file_lookup_key key = { + .type = NFSD_FILE_KEY_INODE, + .inode = inode, + }; +- unsigned int count = 0; + struct nfsd_file *nf; + + rcu_read_lock(); + do { ++ int decrement = 1; ++ + nf = rhashtable_lookup(&nfsd_file_rhash_tbl, &key, + nfsd_file_rhash_params); + if (!nf) + break; +- nfsd_file_unhash_and_queue(nf, dispose); +- count++; ++ ++ /* If we raced with someone else unhashing, ignore it */ ++ if (!nfsd_file_unhash(nf)) ++ continue; ++ ++ /* If we can't get a reference, ignore it */ ++ if (!nfsd_file_get(nf)) ++ continue; ++ ++ /* Extra decrement if we remove from the LRU */ ++ if (nfsd_file_lru_remove(nf)) ++ ++decrement; ++ ++ /* If refcount goes to 0, then put on the dispose list */ ++ if (refcount_sub_and_test(decrement, &nf->nf_ref)) { ++ list_add(&nf->nf_lru, dispose); ++ trace_nfsd_file_closing(nf); ++ } + } while (1); + rcu_read_unlock(); +- return count; + } + + /** +- * nfsd_file_close_inode_sync - attempt to forcibly close a nfsd_file ++ * nfsd_file_close_inode - attempt a delayed close of a nfsd_file + * @inode: inode of the file to attempt to remove + * +- * Unhash and put, then flush and fput all cache items associated with @inode. ++ * Close out any open nfsd_files that can be reaped for @inode. The ++ * actual freeing is deferred to the dispose_list_delayed infrastructure. ++ * ++ * This is used by the fsnotify callbacks and setlease notifier. + */ +-void +-nfsd_file_close_inode_sync(struct inode *inode) ++static void ++nfsd_file_close_inode(struct inode *inode) + { + LIST_HEAD(dispose); +- unsigned int count; + +- count = __nfsd_file_close_inode(inode, &dispose); +- trace_nfsd_file_close_inode_sync(inode, count); +- nfsd_file_dispose_list_sync(&dispose); ++ nfsd_file_queue_for_close(inode, &dispose); ++ nfsd_file_dispose_list_delayed(&dispose); + } + + /** +- * nfsd_file_close_inode - attempt a delayed close of a nfsd_file ++ * nfsd_file_close_inode_sync - attempt to forcibly close a nfsd_file + * @inode: inode of the file to attempt to remove + * +- * Unhash and put all cache item associated with @inode. ++ * Close out any open nfsd_files that can be reaped for @inode. The ++ * nfsd_files are closed out synchronously. ++ * ++ * This is called from nfsd_rename and nfsd_unlink to avoid silly-renames ++ * when reexporting NFS. + */ +-static void +-nfsd_file_close_inode(struct inode *inode) ++void ++nfsd_file_close_inode_sync(struct inode *inode) + { ++ struct nfsd_file *nf; + LIST_HEAD(dispose); +- unsigned int count; + +- count = __nfsd_file_close_inode(inode, &dispose); +- trace_nfsd_file_close_inode(inode, count); +- nfsd_file_dispose_list_delayed(&dispose); ++ trace_nfsd_file_close(inode); ++ ++ nfsd_file_queue_for_close(inode, &dispose); ++ while (!list_empty(&dispose)) { ++ nf = list_first_entry(&dispose, struct nfsd_file, nf_lru); ++ list_del_init(&nf->nf_lru); ++ nfsd_file_free(nf); ++ } ++ flush_delayed_fput(); + } + + /** + * nfsd_file_delayed_close - close unused nfsd_files + * @work: dummy + * +- * Walk the LRU list and close any entries that have not been used since ++ * Walk the LRU list and destroy any entries that have not been used since + * the last scan. + */ + static void +@@ -781,7 +786,7 @@ nfsd_file_lease_notifier_call(struct notifier_block *nb, unsigned long arg, + + /* Only close files for F_SETLEASE leases */ + if (fl->fl_flags & FL_LEASE) +- nfsd_file_close_inode_sync(file_inode(fl->fl_file)); ++ nfsd_file_close_inode(file_inode(fl->fl_file)); + return 0; + } + +@@ -902,6 +907,13 @@ nfsd_file_cache_init(void) + goto out; + } + ++/** ++ * __nfsd_file_cache_purge: clean out the cache for shutdown ++ * @net: net-namespace to shut down the cache (may be NULL) ++ * ++ * Walk the nfsd_file cache and close out any that match @net. If @net is NULL, ++ * then close out everything. Called when an nfsd instance is being shut down. ++ */ + static void + __nfsd_file_cache_purge(struct net *net) + { +@@ -915,8 +927,11 @@ __nfsd_file_cache_purge(struct net *net) + + nf = rhashtable_walk_next(&iter); + while (!IS_ERR_OR_NULL(nf)) { +- if (!net || nf->nf_net == net) +- nfsd_file_unhash_and_queue(nf, &dispose); ++ if (!net || nf->nf_net == net) { ++ nfsd_file_unhash(nf); ++ nfsd_file_lru_remove(nf); ++ list_add(&nf->nf_lru, &dispose); ++ } + nf = rhashtable_walk_next(&iter); + } + +@@ -1083,8 +1098,12 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + if (nf) + nf = nfsd_file_get(nf); + rcu_read_unlock(); +- if (nf) ++ ++ if (nf) { ++ if (nfsd_file_lru_remove(nf)) ++ WARN_ON_ONCE(refcount_dec_and_test(&nf->nf_ref)); + goto wait_for_construction; ++ } + + nf = nfsd_file_alloc(&key, may_flags); + if (!nf) { +@@ -1117,11 +1136,11 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + goto out; + } + open_retry = false; +- nfsd_file_put_noref(nf); ++ if (refcount_dec_and_test(&nf->nf_ref)) ++ nfsd_file_free(nf); + goto retry; + } + +- nfsd_file_lru_remove(nf); + this_cpu_inc(nfsd_file_cache_hits); + + status = nfserrno(nfsd_open_break_lease(file_inode(nf->nf_file), may_flags)); +@@ -1131,7 +1150,8 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + this_cpu_inc(nfsd_file_acquisitions); + *pnf = nf; + } else { +- nfsd_file_put(nf); ++ if (refcount_dec_and_test(&nf->nf_ref)) ++ nfsd_file_free(nf); + nf = NULL; + } + +@@ -1157,8 +1177,10 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + * If construction failed, or we raced with a call to unlink() + * then unhash. + */ +- if (status != nfs_ok || key.inode->i_nlink == 0) +- nfsd_file_unhash_and_put(nf); ++ if (status == nfs_ok && key.inode->i_nlink == 0) ++ status = nfserr_jukebox; ++ if (status != nfs_ok) ++ nfsd_file_unhash(nf); + clear_bit_unlock(NFSD_FILE_PENDING, &nf->nf_flags); + smp_mb__after_atomic(); + wake_up_bit(&nf->nf_flags, NFSD_FILE_PENDING); +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index 235ea38da8644..8db7eecde9e39 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -786,8 +786,8 @@ DEFINE_CLID_EVENT(confirmed_r); + __print_flags(val, "|", \ + { 1 << NFSD_FILE_HASHED, "HASHED" }, \ + { 1 << NFSD_FILE_PENDING, "PENDING" }, \ +- { 1 << NFSD_FILE_REFERENCED, "REFERENCED"}, \ +- { 1 << NFSD_FILE_GC, "GC"}) ++ { 1 << NFSD_FILE_REFERENCED, "REFERENCED" }, \ ++ { 1 << NFSD_FILE_GC, "GC" }) + + DECLARE_EVENT_CLASS(nfsd_file_class, + TP_PROTO(struct nfsd_file *nf), +@@ -822,6 +822,7 @@ DEFINE_EVENT(nfsd_file_class, name, \ + DEFINE_NFSD_FILE_EVENT(nfsd_file_free); + DEFINE_NFSD_FILE_EVENT(nfsd_file_unhash); + DEFINE_NFSD_FILE_EVENT(nfsd_file_put); ++DEFINE_NFSD_FILE_EVENT(nfsd_file_closing); + DEFINE_NFSD_FILE_EVENT(nfsd_file_unhash_and_queue); + + TRACE_EVENT(nfsd_file_alloc, +@@ -1013,35 +1014,6 @@ TRACE_EVENT(nfsd_file_open, + __entry->nf_file) + ) + +-DECLARE_EVENT_CLASS(nfsd_file_search_class, +- TP_PROTO( +- const struct inode *inode, +- unsigned int count +- ), +- TP_ARGS(inode, count), +- TP_STRUCT__entry( +- __field(const struct inode *, inode) +- __field(unsigned int, count) +- ), +- TP_fast_assign( +- __entry->inode = inode; +- __entry->count = count; +- ), +- TP_printk("inode=%p count=%u", +- __entry->inode, __entry->count) +-); +- +-#define DEFINE_NFSD_FILE_SEARCH_EVENT(name) \ +-DEFINE_EVENT(nfsd_file_search_class, name, \ +- TP_PROTO( \ +- const struct inode *inode, \ +- unsigned int count \ +- ), \ +- TP_ARGS(inode, count)) +- +-DEFINE_NFSD_FILE_SEARCH_EVENT(nfsd_file_close_inode_sync); +-DEFINE_NFSD_FILE_SEARCH_EVENT(nfsd_file_close_inode); +- + TRACE_EVENT(nfsd_file_is_cached, + TP_PROTO( + const struct inode *inode, +@@ -1119,7 +1091,6 @@ DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_lru_del_disposed); + DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_gc_in_use); + DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_gc_writeback); + DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_gc_referenced); +-DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_gc_hashed); + DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_gc_disposed); + + DECLARE_EVENT_CLASS(nfsd_file_lruwalk_class, +@@ -1151,6 +1122,22 @@ DEFINE_EVENT(nfsd_file_lruwalk_class, name, \ + DEFINE_NFSD_FILE_LRUWALK_EVENT(nfsd_file_gc_removed); + DEFINE_NFSD_FILE_LRUWALK_EVENT(nfsd_file_shrinker_removed); + ++TRACE_EVENT(nfsd_file_close, ++ TP_PROTO( ++ const struct inode *inode ++ ), ++ TP_ARGS(inode), ++ TP_STRUCT__entry( ++ __field(const void *, inode) ++ ), ++ TP_fast_assign( ++ __entry->inode = inode; ++ ), ++ TP_printk("inode=%p", ++ __entry->inode ++ ) ++); ++ + TRACE_EVENT(nfsd_file_fsync, + TP_PROTO( + const struct nfsd_file *nf, +-- +2.43.0 + diff --git a/queue-5.10/nfsd-rpc_peeraddr2str-needs-rcu-lock.patch b/queue-5.10/nfsd-rpc_peeraddr2str-needs-rcu-lock.patch new file mode 100644 index 00000000000..5d211565464 --- /dev/null +++ b/queue-5.10/nfsd-rpc_peeraddr2str-needs-rcu-lock.patch @@ -0,0 +1,38 @@ +From d98ffe935d8862c3a349135d864a7bc173843e72 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 14 Jun 2021 11:20:49 -0400 +Subject: nfsd: rpc_peeraddr2str needs rcu lock + +From: J. Bruce Fields + +[ Upstream commit 05570a2b01117209b500e1989ce8f1b0524c489f ] + +I'm not even sure cl_xprt can change here, but we're getting "suspicious +RCU usage" warnings, and other rpc_peeraddr2str callers are taking the +rcu lock. + +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4callback.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c +index 59dc80ecd3764..97f517e9b4189 100644 +--- a/fs/nfsd/nfs4callback.c ++++ b/fs/nfsd/nfs4callback.c +@@ -941,8 +941,10 @@ static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *c + clp->cl_cb_conn.cb_xprt = conn->cb_xprt; + clp->cl_cb_client = client; + clp->cl_cb_cred = cred; ++ rcu_read_lock(); + trace_nfsd_cb_setup(clp, rpc_peeraddr2str(client, RPC_DISPLAY_NETID), + args.authflavor); ++ rcu_read_unlock(); + return 0; + } + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-save-location-of-nfsv4-compound-status.patch b/queue-5.10/nfsd-save-location-of-nfsv4-compound-status.patch new file mode 100644 index 00000000000..392655ee40b --- /dev/null +++ b/queue-5.10/nfsd-save-location-of-nfsv4-compound-status.patch @@ -0,0 +1,85 @@ +From 90103fc1223492635e625c2fa4ac7f72ad22a172 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 13 Oct 2021 10:40:59 -0400 +Subject: NFSD: Save location of NFSv4 COMPOUND status + +From: Chuck Lever + +[ Upstream commit 3b0ebb255fdc49a3d340846deebf045ef58ec744 ] + +Refactor: Currently nfs4svc_encode_compoundres() relies on the NFS +dispatcher to pass in the buffer location of the COMPOUND status. +Instead, save that buffer location in struct nfsd4_compoundres. + +The compound tag follows immediately after. + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 2 +- + fs/nfsd/nfs4xdr.c | 9 +++++++-- + fs/nfsd/xdr4.h | 3 ++- + 3 files changed, 10 insertions(+), 4 deletions(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index d2ee1ba7ddc65..52f3f35533791 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -2456,11 +2456,11 @@ nfsd4_proc_compound(struct svc_rqst *rqstp) + __be32 status; + + resp->xdr = &rqstp->rq_res_stream; ++ resp->statusp = resp->xdr->p; + + /* reserve space for: NFS status code */ + xdr_reserve_space(resp->xdr, XDR_UNIT); + +- resp->tagp = resp->xdr->p; + /* reserve space for: taglen, tag, and opcnt */ + xdr_reserve_space(resp->xdr, XDR_UNIT * 2 + args->taglen); + resp->taglen = args->taglen; +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 1b33c1c93e883..3f8d23586ea79 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -5446,11 +5446,16 @@ nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p) + WARN_ON_ONCE(buf->len != buf->head[0].iov_len + buf->page_len + + buf->tail[0].iov_len); + +- *p = resp->cstate.status; ++ /* ++ * Send buffer space for the following items is reserved ++ * at the top of nfsd4_proc_compound(). ++ */ ++ p = resp->statusp; ++ ++ *p++ = resp->cstate.status; + + rqstp->rq_next_page = resp->xdr->page_ptr + 1; + +- p = resp->tagp; + *p++ = htonl(resp->taglen); + memcpy(p, resp->tag, resp->taglen); + p += XDR_QUADLEN(resp->taglen); +diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h +index 8f349640d2e97..8e11dfdc2563a 100644 +--- a/fs/nfsd/xdr4.h ++++ b/fs/nfsd/xdr4.h +@@ -702,10 +702,11 @@ struct nfsd4_compoundres { + struct xdr_stream *xdr; + struct svc_rqst * rqstp; + ++ __be32 *statusp; + u32 taglen; + char * tag; + u32 opcnt; +- __be32 * tagp; /* tag, opcount encode location */ ++ + struct nfsd4_compound_state cstate; + }; + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-separate-nfsd_last_thread-from-nfsd_put.patch b/queue-5.10/nfsd-separate-nfsd_last_thread-from-nfsd_put.patch new file mode 100644 index 00000000000..0248a9256fd --- /dev/null +++ b/queue-5.10/nfsd-separate-nfsd_last_thread-from-nfsd_put.patch @@ -0,0 +1,181 @@ +From bd6eff0ea26501a8162564c3671c462202756e3e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 31 Jul 2023 16:48:32 +1000 +Subject: nfsd: separate nfsd_last_thread() from nfsd_put() + +From: NeilBrown + +[ Upstream commit 9f28a971ee9fdf1bf8ce8c88b103f483be610277 ] + +Now that the last nfsd thread is stopped by an explicit act of calling +svc_set_num_threads() with a count of zero, we only have a limited +number of places that can happen, and don't need to call +nfsd_last_thread() in nfsd_put() + +So separate that out and call it at the two places where the number of +threads is set to zero. + +Move the clearing of ->nfsd_serv and the call to svc_xprt_destroy_all() +into nfsd_last_thread(), as they are really part of the same action. + +nfsd_put() is now a thin wrapper around svc_put(), so make it a static +inline. + +nfsd_put() cannot be called after nfsd_last_thread(), so in a couple of +places we have to use svc_put() instead. + +Signed-off-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsd.h | 7 ++++++- + fs/nfsd/nfssvc.c | 52 ++++++++++++++++++------------------------------ + 2 files changed, 25 insertions(+), 34 deletions(-) + +diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h +index fa0144a742678..867dcfd64d426 100644 +--- a/fs/nfsd/nfsd.h ++++ b/fs/nfsd/nfsd.h +@@ -96,7 +96,12 @@ int nfsd_pool_stats_open(struct inode *, struct file *); + int nfsd_pool_stats_release(struct inode *, struct file *); + void nfsd_shutdown_threads(struct net *net); + +-void nfsd_put(struct net *net); ++static inline void nfsd_put(struct net *net) ++{ ++ struct nfsd_net *nn = net_generic(net, nfsd_net_id); ++ ++ svc_put(nn->nfsd_serv); ++} + + bool i_am_nfsd(void); + +diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c +index 8907dba22c3f2..ee5713fca1870 100644 +--- a/fs/nfsd/nfssvc.c ++++ b/fs/nfsd/nfssvc.c +@@ -529,9 +529,14 @@ static struct notifier_block nfsd_inet6addr_notifier = { + /* Only used under nfsd_mutex, so this atomic may be overkill: */ + static atomic_t nfsd_notifier_refcount = ATOMIC_INIT(0); + +-static void nfsd_last_thread(struct svc_serv *serv, struct net *net) ++static void nfsd_last_thread(struct net *net) + { + struct nfsd_net *nn = net_generic(net, nfsd_net_id); ++ struct svc_serv *serv = nn->nfsd_serv; ++ ++ spin_lock(&nfsd_notifier_lock); ++ nn->nfsd_serv = NULL; ++ spin_unlock(&nfsd_notifier_lock); + + /* check if the notifier still has clients */ + if (atomic_dec_return(&nfsd_notifier_refcount) == 0) { +@@ -541,6 +546,8 @@ static void nfsd_last_thread(struct svc_serv *serv, struct net *net) + #endif + } + ++ svc_xprt_destroy_all(serv, net); ++ + /* + * write_ports can create the server without actually starting + * any threads--if we get shut down before any threads are +@@ -631,7 +638,8 @@ void nfsd_shutdown_threads(struct net *net) + svc_get(serv); + /* Kill outstanding nfsd threads */ + svc_set_num_threads(serv, NULL, 0); +- nfsd_put(net); ++ nfsd_last_thread(net); ++ svc_put(serv); + mutex_unlock(&nfsd_mutex); + } + +@@ -661,9 +669,6 @@ int nfsd_create_serv(struct net *net) + serv->sv_maxconn = nn->max_connections; + error = svc_bind(serv, net); + if (error < 0) { +- /* NOT nfsd_put() as notifiers (see below) haven't +- * been set up yet. +- */ + svc_put(serv); + return error; + } +@@ -706,29 +711,6 @@ int nfsd_get_nrthreads(int n, int *nthreads, struct net *net) + return 0; + } + +-/* This is the callback for kref_put() below. +- * There is no code here as the first thing to be done is +- * call svc_shutdown_net(), but we cannot get the 'net' from +- * the kref. So do all the work when kref_put returns true. +- */ +-static void nfsd_noop(struct kref *ref) +-{ +-} +- +-void nfsd_put(struct net *net) +-{ +- struct nfsd_net *nn = net_generic(net, nfsd_net_id); +- +- if (kref_put(&nn->nfsd_serv->sv_refcnt, nfsd_noop)) { +- svc_xprt_destroy_all(nn->nfsd_serv, net); +- nfsd_last_thread(nn->nfsd_serv, net); +- svc_destroy(&nn->nfsd_serv->sv_refcnt); +- spin_lock(&nfsd_notifier_lock); +- nn->nfsd_serv = NULL; +- spin_unlock(&nfsd_notifier_lock); +- } +-} +- + int nfsd_set_nrthreads(int n, int *nthreads, struct net *net) + { + int i = 0; +@@ -779,7 +761,7 @@ int nfsd_set_nrthreads(int n, int *nthreads, struct net *net) + if (err) + break; + } +- nfsd_put(net); ++ svc_put(nn->nfsd_serv); + return err; + } + +@@ -794,6 +776,7 @@ nfsd_svc(int nrservs, struct net *net, const struct cred *cred) + int error; + bool nfsd_up_before; + struct nfsd_net *nn = net_generic(net, nfsd_net_id); ++ struct svc_serv *serv; + + mutex_lock(&nfsd_mutex); + dprintk("nfsd: creating service\n"); +@@ -813,22 +796,25 @@ nfsd_svc(int nrservs, struct net *net, const struct cred *cred) + goto out; + + nfsd_up_before = nn->nfsd_net_up; ++ serv = nn->nfsd_serv; + + error = nfsd_startup_net(net, cred); + if (error) + goto out_put; +- error = svc_set_num_threads(nn->nfsd_serv, NULL, nrservs); ++ error = svc_set_num_threads(serv, NULL, nrservs); + if (error) + goto out_shutdown; +- error = nn->nfsd_serv->sv_nrthreads; ++ error = serv->sv_nrthreads; ++ if (error == 0) ++ nfsd_last_thread(net); + out_shutdown: + if (error < 0 && !nfsd_up_before) + nfsd_shutdown_net(net); + out_put: + /* Threads now hold service active */ + if (xchg(&nn->keep_active, 0)) +- nfsd_put(net); +- nfsd_put(net); ++ svc_put(serv); ++ svc_put(serv); + out: + mutex_unlock(&nfsd_mutex); + return error; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-separate-tracepoints-for-acquire-and-create.patch b/queue-5.10/nfsd-separate-tracepoints-for-acquire-and-create.patch new file mode 100644 index 00000000000..6e095872138 --- /dev/null +++ b/queue-5.10/nfsd-separate-tracepoints-for-acquire-and-create.patch @@ -0,0 +1,164 @@ +From 1c4b73ab0f2e7ee04406b6ee9f8ce7a7cb97a431 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 Jul 2022 14:26:43 -0400 +Subject: NFSD: Separate tracepoints for acquire and create + +From: Chuck Lever + +[ Upstream commit be0230069fcbf7d332d010b57c1d0cfd623a84d6 ] + +These tracepoints collect different information: the create case does +not open a file, so there's no nf_file available. + +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 9 ++++---- + fs/nfsd/nfs4state.c | 1 + + fs/nfsd/trace.h | 54 ++++++++++++++++++++++++++++++++++++++------- + 3 files changed, 52 insertions(+), 12 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index c6dc55c0f758b..85813affb8abf 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -1039,7 +1039,7 @@ nfsd_file_is_cached(struct inode *inode) + } + + static __be32 +-nfsd_do_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, ++nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + unsigned int may_flags, struct nfsd_file **pnf, bool open) + { + struct nfsd_file_lookup_key key = { +@@ -1120,7 +1120,8 @@ nfsd_do_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + + out_status: + put_cred(key.cred); +- trace_nfsd_file_acquire(rqstp, key.inode, may_flags, nf, status); ++ if (open) ++ trace_nfsd_file_acquire(rqstp, key.inode, may_flags, nf, status); + return status; + + open_file: +@@ -1168,7 +1169,7 @@ __be32 + nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + unsigned int may_flags, struct nfsd_file **pnf) + { +- return nfsd_do_file_acquire(rqstp, fhp, may_flags, pnf, true); ++ return nfsd_file_do_acquire(rqstp, fhp, may_flags, pnf, true); + } + + /** +@@ -1185,7 +1186,7 @@ __be32 + nfsd_file_create(struct svc_rqst *rqstp, struct svc_fh *fhp, + unsigned int may_flags, struct nfsd_file **pnf) + { +- return nfsd_do_file_acquire(rqstp, fhp, may_flags, pnf, false); ++ return nfsd_file_do_acquire(rqstp, fhp, may_flags, pnf, false); + } + + /* +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 76ec207f5e44d..587e792346579 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -5121,6 +5121,7 @@ static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp, + goto out_put_access; + nf->nf_file = open->op_filp; + open->op_filp = NULL; ++ trace_nfsd_file_create(rqstp, access, nf); + } + + spin_lock(&fp->fi_lock); +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index 33bd8618c20a6..ce391ba2f1ca5 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -747,10 +747,10 @@ DEFINE_NFSD_FILE_EVENT(nfsd_file_unhash_and_dispose); + + TRACE_EVENT(nfsd_file_acquire, + TP_PROTO( +- struct svc_rqst *rqstp, +- struct inode *inode, ++ const struct svc_rqst *rqstp, ++ const struct inode *inode, + unsigned int may_flags, +- struct nfsd_file *nf, ++ const struct nfsd_file *nf, + __be32 status + ), + +@@ -758,12 +758,12 @@ TRACE_EVENT(nfsd_file_acquire, + + TP_STRUCT__entry( + __field(u32, xid) +- __field(void *, inode) ++ __field(const void *, inode) + __field(unsigned long, may_flags) +- __field(int, nf_ref) ++ __field(unsigned int, nf_ref) + __field(unsigned long, nf_flags) + __field(unsigned long, nf_may) +- __field(struct file *, nf_file) ++ __field(const void *, nf_file) + __field(u32, status) + ), + +@@ -778,12 +778,50 @@ TRACE_EVENT(nfsd_file_acquire, + __entry->status = be32_to_cpu(status); + ), + +- TP_printk("xid=0x%x inode=%p may_flags=%s ref=%d nf_flags=%s nf_may=%s nf_file=%p status=%u", ++ TP_printk("xid=0x%x inode=%p may_flags=%s ref=%u nf_flags=%s nf_may=%s nf_file=%p status=%u", + __entry->xid, __entry->inode, + show_nfsd_may_flags(__entry->may_flags), + __entry->nf_ref, show_nf_flags(__entry->nf_flags), + show_nfsd_may_flags(__entry->nf_may), +- __entry->nf_file, __entry->status) ++ __entry->nf_file, __entry->status ++ ) ++); ++ ++TRACE_EVENT(nfsd_file_create, ++ TP_PROTO( ++ const struct svc_rqst *rqstp, ++ unsigned int may_flags, ++ const struct nfsd_file *nf ++ ), ++ ++ TP_ARGS(rqstp, may_flags, nf), ++ ++ TP_STRUCT__entry( ++ __field(const void *, nf_inode) ++ __field(const void *, nf_file) ++ __field(unsigned long, may_flags) ++ __field(unsigned long, nf_flags) ++ __field(unsigned long, nf_may) ++ __field(unsigned int, nf_ref) ++ __field(u32, xid) ++ ), ++ ++ TP_fast_assign( ++ __entry->nf_inode = nf->nf_inode; ++ __entry->nf_file = nf->nf_file; ++ __entry->may_flags = may_flags; ++ __entry->nf_flags = nf->nf_flags; ++ __entry->nf_may = nf->nf_may; ++ __entry->nf_ref = refcount_read(&nf->nf_ref); ++ __entry->xid = be32_to_cpu(rqstp->rq_xid); ++ ), ++ ++ TP_printk("xid=0x%x inode=%p may_flags=%s ref=%u nf_flags=%s nf_may=%s nf_file=%p", ++ __entry->xid, __entry->nf_inode, ++ show_nfsd_may_flags(__entry->may_flags), ++ __entry->nf_ref, show_nf_flags(__entry->nf_flags), ++ show_nfsd_may_flags(__entry->nf_may), __entry->nf_file ++ ) + ); + + TRACE_EVENT(nfsd_file_insert_err, +-- +2.43.0 + diff --git a/queue-5.10/nfsd-set-attributes-when-creating-symlinks.patch b/queue-5.10/nfsd-set-attributes-when-creating-symlinks.patch new file mode 100644 index 00000000000..4c42220f0dd --- /dev/null +++ b/queue-5.10/nfsd-set-attributes-when-creating-symlinks.patch @@ -0,0 +1,176 @@ +From c60b114136d740b8feed5f5c8ff45a624db35789 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 Jul 2022 16:45:30 +1000 +Subject: NFSD: set attributes when creating symlinks + +From: NeilBrown + +[ Upstream commit 93adc1e391a761441d783828b93979b38093d011 ] + +The NFS protocol includes attributes when creating symlinks. +Linux does store attributes for symlinks and allows them to be set, +though they are not used for permission checking. + +NFSD currently doesn't set standard (struct iattr) attributes when +creating symlinks, but for NFSv4 it does set ACLs and security labels. +This is inconsistent. + +To improve consistency, pass the provided attributes into nfsd_symlink() +and call nfsd_create_setattr() to set them. + +NOTE: this results in a behaviour change for all NFS versions when the +client sends non-default attributes with a SYMLINK request. With the +Linux client, the only attributes are: + attr.ia_mode = S_IFLNK | S_IRWXUGO; + attr.ia_valid = ATTR_MODE; +so the final outcome will be unchanged. Other clients might sent +different attributes, and if they did they probably expect them to be +honoured. + +We ignore any error from nfsd_create_setattr(). It isn't really clear +what should be done if a file is successfully created, but the +attributes cannot be set. NFS doesn't allow partial success to be +reported. Reporting failure is probably more misleading than reporting +success, so the status is ignored. + +Signed-off-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3proc.c | 5 ++++- + fs/nfsd/nfs4proc.c | 2 +- + fs/nfsd/nfsproc.c | 5 ++++- + fs/nfsd/vfs.c | 25 ++++++++++++++++++------- + fs/nfsd/vfs.h | 5 +++-- + 5 files changed, 30 insertions(+), 12 deletions(-) + +diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c +index 7b81d871f0d3c..394f6fb201974 100644 +--- a/fs/nfsd/nfs3proc.c ++++ b/fs/nfsd/nfs3proc.c +@@ -397,6 +397,9 @@ nfsd3_proc_symlink(struct svc_rqst *rqstp) + { + struct nfsd3_symlinkargs *argp = rqstp->rq_argp; + struct nfsd3_diropres *resp = rqstp->rq_resp; ++ struct nfsd_attrs attrs = { ++ .na_iattr = &argp->attrs, ++ }; + + if (argp->tlen == 0) { + resp->status = nfserr_inval; +@@ -423,7 +426,7 @@ nfsd3_proc_symlink(struct svc_rqst *rqstp) + fh_copy(&resp->dirfh, &argp->ffh); + fh_init(&resp->fh, NFS3_FHSIZE); + resp->status = nfsd_symlink(rqstp, &resp->dirfh, argp->fname, +- argp->flen, argp->tname, &resp->fh); ++ argp->flen, argp->tname, &attrs, &resp->fh); + kfree(argp->tname); + out: + return rpc_success; +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index f8a157e4bc708..43387a8f10d06 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -813,7 +813,7 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + case NF4LNK: + status = nfsd_symlink(rqstp, &cstate->current_fh, + create->cr_name, create->cr_namelen, +- create->cr_data, &resfh); ++ create->cr_data, &attrs, &resfh); + break; + + case NF4BLK: +diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c +index f061f229d5ff0..180b84b6597b0 100644 +--- a/fs/nfsd/nfsproc.c ++++ b/fs/nfsd/nfsproc.c +@@ -478,6 +478,9 @@ nfsd_proc_symlink(struct svc_rqst *rqstp) + { + struct nfsd_symlinkargs *argp = rqstp->rq_argp; + struct nfsd_stat *resp = rqstp->rq_resp; ++ struct nfsd_attrs attrs = { ++ .na_iattr = &argp->attrs, ++ }; + struct svc_fh newfh; + + if (argp->tlen > NFS_MAXPATHLEN) { +@@ -499,7 +502,7 @@ nfsd_proc_symlink(struct svc_rqst *rqstp) + + fh_init(&newfh, NFS_FHSIZE); + resp->status = nfsd_symlink(rqstp, &argp->ffh, argp->fname, argp->flen, +- argp->tname, &newfh); ++ argp->tname, &attrs, &newfh); + + kfree(argp->tname); + fh_put(&argp->ffh); +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index c86c3a8e42329..f5a1f41cddfff 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -1463,15 +1463,25 @@ nfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp) + return 0; + } + +-/* +- * Create a symlink and look up its inode ++/** ++ * nfsd_symlink - Create a symlink and look up its inode ++ * @rqstp: RPC transaction being executed ++ * @fhp: NFS filehandle of parent directory ++ * @fname: filename of the new symlink ++ * @flen: length of @fname ++ * @path: content of the new symlink (NUL-terminated) ++ * @attrs: requested attributes of new object ++ * @resfhp: NFS filehandle of new object ++ * + * N.B. After this call _both_ fhp and resfhp need an fh_put ++ * ++ * Returns nfs_ok on success, or an nfsstat in network byte order. + */ + __be32 + nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, +- char *fname, int flen, +- char *path, +- struct svc_fh *resfhp) ++ char *fname, int flen, ++ char *path, struct nfsd_attrs *attrs, ++ struct svc_fh *resfhp) + { + struct dentry *dentry, *dnew; + __be32 err, cerr; +@@ -1501,13 +1511,14 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, + + host_err = vfs_symlink(d_inode(dentry), dnew, path); + err = nfserrno(host_err); ++ cerr = fh_compose(resfhp, fhp->fh_export, dnew, fhp); ++ if (!err) ++ nfsd_create_setattr(rqstp, fhp, resfhp, attrs); + fh_unlock(fhp); + if (!err) + err = nfserrno(commit_metadata(fhp)); +- + fh_drop_write(fhp); + +- cerr = fh_compose(resfhp, fhp->fh_export, dnew, fhp); + dput(dnew); + if (err==0) err = cerr; + out: +diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h +index d8b1a36fca956..5047cec4c423c 100644 +--- a/fs/nfsd/vfs.h ++++ b/fs/nfsd/vfs.h +@@ -114,8 +114,9 @@ __be32 nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, + __be32 nfsd_readlink(struct svc_rqst *, struct svc_fh *, + char *, int *); + __be32 nfsd_symlink(struct svc_rqst *, struct svc_fh *, +- char *name, int len, char *path, +- struct svc_fh *res); ++ char *name, int len, char *path, ++ struct nfsd_attrs *attrs, ++ struct svc_fh *res); + __be32 nfsd_link(struct svc_rqst *, struct svc_fh *, + char *, int, struct svc_fh *); + ssize_t nfsd_copy_file_range(struct file *, u64, +-- +2.43.0 + diff --git a/queue-5.10/nfsd-set-pf_local_throttle-on-local-filesystems-only.patch b/queue-5.10/nfsd-set-pf_local_throttle-on-local-filesystems-only.patch new file mode 100644 index 00000000000..0af0a68ff1b --- /dev/null +++ b/queue-5.10/nfsd-set-pf_local_throttle-on-local-filesystems-only.patch @@ -0,0 +1,98 @@ +From c8cc4e81cf3ac5a58ed7dea390b4c4bef07a2941 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Nov 2020 17:03:19 -0500 +Subject: nfsd: Set PF_LOCAL_THROTTLE on local filesystems only + +From: Trond Myklebust + +[ Upstream commit 01cbf3853959feec40ec9b9a399e12a021cd4d81 ] + +Don't set PF_LOCAL_THROTTLE on remote filesystems like NFS, since they +aren't expected to ever be subject to double buffering. + +Signed-off-by: Trond Myklebust +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfs/export.c | 3 ++- + fs/nfsd/vfs.c | 13 +++++++++++-- + include/linux/exportfs.h | 1 + + 3 files changed, 14 insertions(+), 3 deletions(-) + +diff --git a/fs/nfs/export.c b/fs/nfs/export.c +index 5428713af5fee..48b879cfe6e3b 100644 +--- a/fs/nfs/export.c ++++ b/fs/nfs/export.c +@@ -171,5 +171,6 @@ const struct export_operations nfs_export_ops = { + .encode_fh = nfs_encode_fh, + .fh_to_dentry = nfs_fh_to_dentry, + .get_parent = nfs_get_parent, +- .flags = EXPORT_OP_NOWCC|EXPORT_OP_NOSUBTREECHK|EXPORT_OP_CLOSE_BEFORE_UNLINK, ++ .flags = EXPORT_OP_NOWCC|EXPORT_OP_NOSUBTREECHK| ++ EXPORT_OP_CLOSE_BEFORE_UNLINK|EXPORT_OP_REMOTE_FS, + }; +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index fb4e6c57ce0bb..a515cbd0a7d8f 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -986,6 +986,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf, + __be32 *verf) + { + struct file *file = nf->nf_file; ++ struct super_block *sb = file_inode(file)->i_sb; + struct svc_export *exp; + struct iov_iter iter; + errseq_t since; +@@ -993,12 +994,18 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf, + int host_err; + int use_wgather; + loff_t pos = offset; ++ unsigned long exp_op_flags = 0; + unsigned int pflags = current->flags; + rwf_t flags = 0; ++ bool restore_flags = false; + + trace_nfsd_write_opened(rqstp, fhp, offset, *cnt); + +- if (test_bit(RQ_LOCAL, &rqstp->rq_flags)) ++ if (sb->s_export_op) ++ exp_op_flags = sb->s_export_op->flags; ++ ++ if (test_bit(RQ_LOCAL, &rqstp->rq_flags) && ++ !(exp_op_flags & EXPORT_OP_REMOTE_FS)) { + /* + * We want throttling in balance_dirty_pages() + * and shrink_inactive_list() to only consider +@@ -1007,6 +1014,8 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf, + * the client's dirty pages or its congested queue. + */ + current->flags |= PF_LOCAL_THROTTLE; ++ restore_flags = true; ++ } + + exp = fhp->fh_export; + use_wgather = (rqstp->rq_vers == 2) && EX_WGATHER(exp); +@@ -1062,7 +1071,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf, + trace_nfsd_write_err(rqstp, fhp, offset, host_err); + nfserr = nfserrno(host_err); + } +- if (test_bit(RQ_LOCAL, &rqstp->rq_flags)) ++ if (restore_flags) + current_restore_flags(pflags, PF_LOCAL_THROTTLE); + return nfserr; + } +diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h +index 846df3c96730f..d93e8a6737bb0 100644 +--- a/include/linux/exportfs.h ++++ b/include/linux/exportfs.h +@@ -216,6 +216,7 @@ struct export_operations { + #define EXPORT_OP_NOWCC (0x1) /* don't collect v3 wcc data */ + #define EXPORT_OP_NOSUBTREECHK (0x2) /* no subtree checking */ + #define EXPORT_OP_CLOSE_BEFORE_UNLINK (0x4) /* close files before unlink */ ++#define EXPORT_OP_REMOTE_FS (0x8) /* Filesystem is remote */ + unsigned long flags; + }; + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-set-up-an-rhashtable-for-the-filecache.patch b/queue-5.10/nfsd-set-up-an-rhashtable-for-the-filecache.patch new file mode 100644 index 00000000000..f8a81074d78 --- /dev/null +++ b/queue-5.10/nfsd-set-up-an-rhashtable-for-the-filecache.patch @@ -0,0 +1,247 @@ +From 352a21396ff3ebe85b6e8f0d691ac65145561b89 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 Jul 2022 14:26:23 -0400 +Subject: NFSD: Set up an rhashtable for the filecache + +From: Chuck Lever + +[ Upstream commit fc22945ecc2a0a028f3683115f98a922d506c284 ] + +Add code to initialize and tear down an rhashtable. The rhashtable +is not used yet. + +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 160 ++++++++++++++++++++++++++++++++++++++------ + fs/nfsd/filecache.h | 1 + + 2 files changed, 140 insertions(+), 21 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index 33bb4d31b4972..95e7e15b567e2 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + + #include "vfs.h" + #include "nfsd.h" +@@ -62,6 +63,136 @@ static unsigned long nfsd_file_flags; + static struct fsnotify_group *nfsd_file_fsnotify_group; + static atomic_long_t nfsd_filecache_count; + static struct delayed_work nfsd_filecache_laundrette; ++static struct rhashtable nfsd_file_rhash_tbl ++ ____cacheline_aligned_in_smp; ++ ++enum nfsd_file_lookup_type { ++ NFSD_FILE_KEY_INODE, ++ NFSD_FILE_KEY_FULL, ++}; ++ ++struct nfsd_file_lookup_key { ++ struct inode *inode; ++ struct net *net; ++ const struct cred *cred; ++ unsigned char need; ++ enum nfsd_file_lookup_type type; ++}; ++ ++/* ++ * The returned hash value is based solely on the address of an in-code ++ * inode, a pointer to a slab-allocated object. The entropy in such a ++ * pointer is concentrated in its middle bits. ++ */ ++static u32 nfsd_file_inode_hash(const struct inode *inode, u32 seed) ++{ ++ unsigned long ptr = (unsigned long)inode; ++ u32 k; ++ ++ k = ptr >> L1_CACHE_SHIFT; ++ k &= 0x00ffffff; ++ return jhash2(&k, 1, seed); ++} ++ ++/** ++ * nfsd_file_key_hashfn - Compute the hash value of a lookup key ++ * @data: key on which to compute the hash value ++ * @len: rhash table's key_len parameter (unused) ++ * @seed: rhash table's random seed of the day ++ * ++ * Return value: ++ * Computed 32-bit hash value ++ */ ++static u32 nfsd_file_key_hashfn(const void *data, u32 len, u32 seed) ++{ ++ const struct nfsd_file_lookup_key *key = data; ++ ++ return nfsd_file_inode_hash(key->inode, seed); ++} ++ ++/** ++ * nfsd_file_obj_hashfn - Compute the hash value of an nfsd_file ++ * @data: object on which to compute the hash value ++ * @len: rhash table's key_len parameter (unused) ++ * @seed: rhash table's random seed of the day ++ * ++ * Return value: ++ * Computed 32-bit hash value ++ */ ++static u32 nfsd_file_obj_hashfn(const void *data, u32 len, u32 seed) ++{ ++ const struct nfsd_file *nf = data; ++ ++ return nfsd_file_inode_hash(nf->nf_inode, seed); ++} ++ ++static bool ++nfsd_match_cred(const struct cred *c1, const struct cred *c2) ++{ ++ int i; ++ ++ if (!uid_eq(c1->fsuid, c2->fsuid)) ++ return false; ++ if (!gid_eq(c1->fsgid, c2->fsgid)) ++ return false; ++ if (c1->group_info == NULL || c2->group_info == NULL) ++ return c1->group_info == c2->group_info; ++ if (c1->group_info->ngroups != c2->group_info->ngroups) ++ return false; ++ for (i = 0; i < c1->group_info->ngroups; i++) { ++ if (!gid_eq(c1->group_info->gid[i], c2->group_info->gid[i])) ++ return false; ++ } ++ return true; ++} ++ ++/** ++ * nfsd_file_obj_cmpfn - Match a cache item against search criteria ++ * @arg: search criteria ++ * @ptr: cache item to check ++ * ++ * Return values: ++ * %0 - Item matches search criteria ++ * %1 - Item does not match search criteria ++ */ ++static int nfsd_file_obj_cmpfn(struct rhashtable_compare_arg *arg, ++ const void *ptr) ++{ ++ const struct nfsd_file_lookup_key *key = arg->key; ++ const struct nfsd_file *nf = ptr; ++ ++ switch (key->type) { ++ case NFSD_FILE_KEY_INODE: ++ if (nf->nf_inode != key->inode) ++ return 1; ++ break; ++ case NFSD_FILE_KEY_FULL: ++ if (nf->nf_inode != key->inode) ++ return 1; ++ if (nf->nf_may != key->need) ++ return 1; ++ if (nf->nf_net != key->net) ++ return 1; ++ if (!nfsd_match_cred(nf->nf_cred, key->cred)) ++ return 1; ++ if (test_bit(NFSD_FILE_HASHED, &nf->nf_flags) == 0) ++ return 1; ++ break; ++ } ++ return 0; ++} ++ ++static const struct rhashtable_params nfsd_file_rhash_params = { ++ .key_len = sizeof_field(struct nfsd_file, nf_inode), ++ .key_offset = offsetof(struct nfsd_file, nf_inode), ++ .head_offset = offsetof(struct nfsd_file, nf_rhash), ++ .hashfn = nfsd_file_key_hashfn, ++ .obj_hashfn = nfsd_file_obj_hashfn, ++ .obj_cmpfn = nfsd_file_obj_cmpfn, ++ /* Reduce resizing churn on light workloads */ ++ .min_size = 512, /* buckets */ ++ .automatic_shrinking = true, ++}; + + static void + nfsd_file_schedule_laundrette(void) +@@ -693,13 +824,18 @@ static const struct fsnotify_ops nfsd_file_fsnotify_ops = { + int + nfsd_file_cache_init(void) + { +- int ret = -ENOMEM; ++ int ret; + unsigned int i; + + lockdep_assert_held(&nfsd_mutex); + if (test_and_set_bit(NFSD_FILE_CACHE_UP, &nfsd_file_flags) == 1) + return 0; + ++ ret = rhashtable_init(&nfsd_file_rhash_tbl, &nfsd_file_rhash_params); ++ if (ret) ++ return ret; ++ ++ ret = -ENOMEM; + nfsd_filecache_wq = alloc_workqueue("nfsd_filecache", 0, 0); + if (!nfsd_filecache_wq) + goto out; +@@ -777,6 +913,7 @@ nfsd_file_cache_init(void) + nfsd_file_hashtbl = NULL; + destroy_workqueue(nfsd_filecache_wq); + nfsd_filecache_wq = NULL; ++ rhashtable_destroy(&nfsd_file_rhash_tbl); + goto out; + } + +@@ -902,6 +1039,7 @@ nfsd_file_cache_shutdown(void) + nfsd_file_hashtbl = NULL; + destroy_workqueue(nfsd_filecache_wq); + nfsd_filecache_wq = NULL; ++ rhashtable_destroy(&nfsd_file_rhash_tbl); + + for_each_possible_cpu(i) { + per_cpu(nfsd_file_cache_hits, i) = 0; +@@ -913,26 +1051,6 @@ nfsd_file_cache_shutdown(void) + } + } + +-static bool +-nfsd_match_cred(const struct cred *c1, const struct cred *c2) +-{ +- int i; +- +- if (!uid_eq(c1->fsuid, c2->fsuid)) +- return false; +- if (!gid_eq(c1->fsgid, c2->fsgid)) +- return false; +- if (c1->group_info == NULL || c2->group_info == NULL) +- return c1->group_info == c2->group_info; +- if (c1->group_info->ngroups != c2->group_info->ngroups) +- return false; +- for (i = 0; i < c1->group_info->ngroups; i++) { +- if (!gid_eq(c1->group_info->gid[i], c2->group_info->gid[i])) +- return false; +- } +- return true; +-} +- + static struct nfsd_file * + nfsd_file_find_locked(struct inode *inode, unsigned int may_flags, + unsigned int hashval, struct net *net) +diff --git a/fs/nfsd/filecache.h b/fs/nfsd/filecache.h +index 82051e1b8420d..5cbfc61a7d7d9 100644 +--- a/fs/nfsd/filecache.h ++++ b/fs/nfsd/filecache.h +@@ -29,6 +29,7 @@ struct nfsd_file_mark { + * never be dereferenced, only used for comparison. + */ + struct nfsd_file { ++ struct rhash_head nf_rhash; + struct hlist_node nf_node; + struct list_head nf_lru; + struct rcu_head nf_rcu; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-show-state-of-courtesy-client-in-client-info.patch b/queue-5.10/nfsd-show-state-of-courtesy-client-in-client-info.patch new file mode 100644 index 00000000000..720067cc394 --- /dev/null +++ b/queue-5.10/nfsd-show-state-of-courtesy-client-in-client-info.patch @@ -0,0 +1,46 @@ +From 74bc975a3c11a0883df2ab0c985e0af876f0b050 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 2 May 2022 14:19:27 -0700 +Subject: NFSD: Show state of courtesy client in client info + +From: Dai Ngo + +[ Upstream commit e9488d5ae13c0a72223c507e2508dc2ac66cad4f ] + +Update client_info_show to show state of courtesy client +and seconds since last renew. + +Reviewed-by: J. Bruce Fields +Signed-off-by: Dai Ngo +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 6851fece3a760..9116496b476aa 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -2494,10 +2494,17 @@ static int client_info_show(struct seq_file *m, void *v) + memcpy(&clid, &clp->cl_clientid, sizeof(clid)); + seq_printf(m, "clientid: 0x%llx\n", clid); + seq_printf(m, "address: \"%pISpc\"\n", (struct sockaddr *)&clp->cl_addr); +- if (test_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags)) ++ ++ if (clp->cl_state == NFSD4_COURTESY) ++ seq_puts(m, "status: courtesy\n"); ++ else if (clp->cl_state == NFSD4_EXPIRABLE) ++ seq_puts(m, "status: expirable\n"); ++ else if (test_bit(NFSD4_CLIENT_CONFIRMED, &clp->cl_flags)) + seq_puts(m, "status: confirmed\n"); + else + seq_puts(m, "status: unconfirmed\n"); ++ seq_printf(m, "seconds from last renew: %lld\n", ++ ktime_get_boottime_seconds() - clp->cl_time); + seq_printf(m, "name: "); + seq_quote_mem(m, clp->cl_name.data, clp->cl_name.len); + seq_printf(m, "\nminor version: %d\n", clp->cl_minorversion); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-shrink-size-of-struct-nfsd4_copy.patch b/queue-5.10/nfsd-shrink-size-of-struct-nfsd4_copy.patch new file mode 100644 index 00000000000..2e261bc8a08 --- /dev/null +++ b/queue-5.10/nfsd-shrink-size-of-struct-nfsd4_copy.patch @@ -0,0 +1,103 @@ +From ca37c609fadfc7fad6c3cd7993e54b54143c2a9b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 Jul 2022 14:40:22 -0400 +Subject: NFSD: Shrink size of struct nfsd4_copy + +From: Chuck Lever + +[ Upstream commit 87689df694916c40e8e6c179ab1c8710f65cb6c6 ] + +struct nfsd4_copy is part of struct nfsd4_op, which resides in an +8-element array. + +sizeof(struct nfsd4_op): +Before: /* size: 1696, cachelines: 27, members: 5 */ +After: /* size: 672, cachelines: 11, members: 5 */ + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 8 ++++++-- + fs/nfsd/nfs4xdr.c | 5 ++++- + fs/nfsd/xdr4.h | 2 +- + 3 files changed, 11 insertions(+), 4 deletions(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 3ed9c36bc4078..7fb1ef7c4383e 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -1291,6 +1291,7 @@ void nfs4_put_copy(struct nfsd4_copy *copy) + { + if (!refcount_dec_and_test(©->refcount)) + return; ++ kfree(copy->cp_src); + kfree(copy); + } + +@@ -1544,7 +1545,7 @@ nfsd4_setup_inter_ssc(struct svc_rqst *rqstp, + if (status) + goto out; + +- status = nfsd4_interssc_connect(©->cp_src, rqstp, mount); ++ status = nfsd4_interssc_connect(copy->cp_src, rqstp, mount); + if (status) + goto out; + +@@ -1751,7 +1752,7 @@ static void dup_copy_fields(struct nfsd4_copy *src, struct nfsd4_copy *dst) + dst->nf_src = nfsd_file_get(src->nf_src); + + memcpy(&dst->cp_stateid, &src->cp_stateid, sizeof(src->cp_stateid)); +- memcpy(&dst->cp_src, &src->cp_src, sizeof(struct nl4_server)); ++ memcpy(dst->cp_src, src->cp_src, sizeof(struct nl4_server)); + memcpy(&dst->stateid, &src->stateid, sizeof(src->stateid)); + memcpy(&dst->c_fh, &src->c_fh, sizeof(src->c_fh)); + dst->ss_mnt = src->ss_mnt; +@@ -1845,6 +1846,9 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + async_copy = kzalloc(sizeof(struct nfsd4_copy), GFP_KERNEL); + if (!async_copy) + goto out_err; ++ async_copy->cp_src = kmalloc(sizeof(*async_copy->cp_src), GFP_KERNEL); ++ if (!async_copy->cp_src) ++ goto out_err; + if (!nfs4_init_copy_state(nn, copy)) + goto out_err; + refcount_set(&async_copy->refcount, 1); +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 537c358fec98c..890f1009bd4ca 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -1920,6 +1920,9 @@ nfsd4_decode_copy(struct nfsd4_compoundargs *argp, struct nfsd4_copy *copy) + + if (xdr_stream_decode_u32(argp->xdr, &count) < 0) + return nfserr_bad_xdr; ++ copy->cp_src = svcxdr_tmpalloc(argp, sizeof(*copy->cp_src)); ++ if (copy->cp_src == NULL) ++ return nfserr_jukebox; + copy->cp_intra = false; + if (count == 0) { /* intra-server copy */ + copy->cp_intra = true; +@@ -1927,7 +1930,7 @@ nfsd4_decode_copy(struct nfsd4_compoundargs *argp, struct nfsd4_copy *copy) + } + + /* decode all the supplied server addresses but use only the first */ +- status = nfsd4_decode_nl4_server(argp, ©->cp_src); ++ status = nfsd4_decode_nl4_server(argp, copy->cp_src); + if (status) + return status; + +diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h +index 27f9300fadbe0..c44c76cef40cd 100644 +--- a/fs/nfsd/xdr4.h ++++ b/fs/nfsd/xdr4.h +@@ -540,7 +540,7 @@ struct nfsd4_copy { + u64 cp_src_pos; + u64 cp_dst_pos; + u64 cp_count; +- struct nl4_server cp_src; ++ struct nl4_server *cp_src; + bool cp_intra; + + /* both */ +-- +2.43.0 + diff --git a/queue-5.10/nfsd-shrink-size-of-struct-nfsd4_copy_notify.patch b/queue-5.10/nfsd-shrink-size-of-struct-nfsd4_copy_notify.patch new file mode 100644 index 00000000000..8d7a5aa2ddf --- /dev/null +++ b/queue-5.10/nfsd-shrink-size-of-struct-nfsd4_copy_notify.patch @@ -0,0 +1,96 @@ +From fcd55bdab5b96d0b4b8b5e447f67df6cc1a8ea43 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 27 Jul 2022 14:40:16 -0400 +Subject: NFSD: Shrink size of struct nfsd4_copy_notify + +From: Chuck Lever + +[ Upstream commit 09426ef2a64ee189ca1e3298f1e874842dbf35ea ] + +struct nfsd4_copy_notify is part of struct nfsd4_op, which resides +in an 8-element array. + +sizeof(struct nfsd4_op): +Before: /* size: 2208, cachelines: 35, members: 5 */ +After: /* size: 1696, cachelines: 27, members: 5 */ + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 4 ++-- + fs/nfsd/nfs4xdr.c | 12 ++++++++++-- + fs/nfsd/xdr4.h | 4 ++-- + 3 files changed, 14 insertions(+), 6 deletions(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 1b49b4e2803c7..3ed9c36bc4078 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -1945,9 +1945,9 @@ nfsd4_copy_notify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + /* For now, only return one server address in cpn_src, the + * address used by the client to connect to this server. + */ +- cn->cpn_src.nl4_type = NL4_NETADDR; ++ cn->cpn_src->nl4_type = NL4_NETADDR; + status = nfsd4_set_netaddr((struct sockaddr *)&rqstp->rq_daddr, +- &cn->cpn_src.u.nl4_addr); ++ &cn->cpn_src->u.nl4_addr); + WARN_ON_ONCE(status); + if (status) { + nfs4_put_cpntf_state(nn, cps); +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index fcf56e396e66b..537c358fec98c 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -1952,10 +1952,17 @@ nfsd4_decode_copy_notify(struct nfsd4_compoundargs *argp, + { + __be32 status; + ++ cn->cpn_src = svcxdr_tmpalloc(argp, sizeof(*cn->cpn_src)); ++ if (cn->cpn_src == NULL) ++ return nfserr_jukebox; ++ cn->cpn_dst = svcxdr_tmpalloc(argp, sizeof(*cn->cpn_dst)); ++ if (cn->cpn_dst == NULL) ++ return nfserr_jukebox; ++ + status = nfsd4_decode_stateid4(argp, &cn->cpn_src_stateid); + if (status) + return status; +- return nfsd4_decode_nl4_server(argp, &cn->cpn_dst); ++ return nfsd4_decode_nl4_server(argp, cn->cpn_dst); + } + + static __be32 +@@ -4906,7 +4913,8 @@ nfsd4_encode_copy_notify(struct nfsd4_compoundres *resp, __be32 nfserr, + + *p++ = cpu_to_be32(1); + +- return nfsd42_encode_nl4_server(resp, &cn->cpn_src); ++ nfserr = nfsd42_encode_nl4_server(resp, cn->cpn_src); ++ return nfserr; + } + + static __be32 +diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h +index 32617639a3ece..27f9300fadbe0 100644 +--- a/fs/nfsd/xdr4.h ++++ b/fs/nfsd/xdr4.h +@@ -595,13 +595,13 @@ struct nfsd4_offload_status { + struct nfsd4_copy_notify { + /* request */ + stateid_t cpn_src_stateid; +- struct nl4_server cpn_dst; ++ struct nl4_server *cpn_dst; + + /* response */ + stateid_t cpn_cnr_stateid; + u64 cpn_sec; + u32 cpn_nsec; +- struct nl4_server cpn_src; ++ struct nl4_server *cpn_src; + }; + + struct nfsd4_op { +-- +2.43.0 + diff --git a/queue-5.10/nfsd-silence-extraneous-printk-on-nfsd.ko-insertion.patch b/queue-5.10/nfsd-silence-extraneous-printk-on-nfsd.ko-insertion.patch new file mode 100644 index 00000000000..e15c42429b4 --- /dev/null +++ b/queue-5.10/nfsd-silence-extraneous-printk-on-nfsd.ko-insertion.patch @@ -0,0 +1,36 @@ +From b6f6dc315265eb8db8f6651db51a90d1ce0b1162 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 20 Jul 2022 08:39:23 -0400 +Subject: nfsd: silence extraneous printk on nfsd.ko insertion + +From: Jeff Layton + +[ Upstream commit 3a5940bfa17fb9964bf9688b4356ca643a8f5e2d ] + +This printk pops every time nfsd.ko gets plugged in. Most kmods don't do +that and this one is not very informative. Olaf's email address seems to +be defunct at this point anyway. Just drop it. + +Cc: Olaf Kirch +Signed-off-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsctl.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c +index 164c822ae3ae9..917fa1892fd2d 100644 +--- a/fs/nfsd/nfsctl.c ++++ b/fs/nfsd/nfsctl.c +@@ -1519,7 +1519,6 @@ static struct pernet_operations nfsd_net_ops = { + static int __init init_nfsd(void) + { + int retval; +- printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n"); + + retval = nfsd4_init_slabs(); + if (retval) +-- +2.43.0 + diff --git a/queue-5.10/nfsd-simplify-code-around-svc_exit_thread-call-in-nf.patch b/queue-5.10/nfsd-simplify-code-around-svc_exit_thread-call-in-nf.patch new file mode 100644 index 00000000000..b5efc24b28e --- /dev/null +++ b/queue-5.10/nfsd-simplify-code-around-svc_exit_thread-call-in-nf.patch @@ -0,0 +1,89 @@ +From 49a3ee549083513fdc5c72e4bf8a3d9d16612b5f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 31 Jul 2023 16:48:31 +1000 +Subject: nfsd: Simplify code around svc_exit_thread() call in nfsd() + +From: NeilBrown + +[ Upstream commit 18e4cf915543257eae2925671934937163f5639b ] + +Previously a thread could exit asynchronously (due to a signal) so some +care was needed to hold nfsd_mutex over the last svc_put() call. Now a +thread can only exit when svc_set_num_threads() is called, and this is +always called under nfsd_mutex. So no care is needed. + +Not only is the mutex held when a thread exits now, but the svc refcount +is elevated, so the svc_put() in svc_exit_thread() will never be a final +put, so the mutex isn't even needed at this point in the code. + +Signed-off-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfssvc.c | 23 ----------------------- + include/linux/sunrpc/svc.h | 13 ------------- + 2 files changed, 36 deletions(-) + +diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c +index 8063fab2c0279..8907dba22c3f2 100644 +--- a/fs/nfsd/nfssvc.c ++++ b/fs/nfsd/nfssvc.c +@@ -979,31 +979,8 @@ nfsd(void *vrqstp) + atomic_dec(&nfsdstats.th_cnt); + + out: +- /* Take an extra ref so that the svc_put in svc_exit_thread() +- * doesn't call svc_destroy() +- */ +- svc_get(nn->nfsd_serv); +- + /* Release the thread */ + svc_exit_thread(rqstp); +- +- /* We need to drop a ref, but may not drop the last reference +- * without holding nfsd_mutex, and we cannot wait for nfsd_mutex as that +- * could deadlock with nfsd_shutdown_threads() waiting for us. +- * So three options are: +- * - drop a non-final reference, +- * - get the mutex without waiting +- * - sleep briefly andd try the above again +- */ +- while (!svc_put_not_last(nn->nfsd_serv)) { +- if (mutex_trylock(&nfsd_mutex)) { +- nfsd_put(net); +- mutex_unlock(&nfsd_mutex); +- break; +- } +- msleep(20); +- } +- + return 0; + } + +diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h +index 5cf6543d3c8e5..1cf7a7799cc04 100644 +--- a/include/linux/sunrpc/svc.h ++++ b/include/linux/sunrpc/svc.h +@@ -123,19 +123,6 @@ static inline void svc_put(struct svc_serv *serv) + kref_put(&serv->sv_refcnt, svc_destroy); + } + +-/** +- * svc_put_not_last - decrement non-final reference count on SUNRPC serv +- * @serv: the svc_serv to have count decremented +- * +- * Returns: %true is refcount was decremented. +- * +- * If the refcount is 1, it is not decremented and instead failure is reported. +- */ +-static inline bool svc_put_not_last(struct svc_serv *serv) +-{ +- return refcount_dec_not_one(&serv->sv_refcnt.refcount); +-} +- + /* + * Maximum payload size supported by a kernel RPC server. + * This is use to determine the max number of pages nfsd is +-- +2.43.0 + diff --git a/queue-5.10/nfsd-simplify-locking-for-network-notifier.patch b/queue-5.10/nfsd-simplify-locking-for-network-notifier.patch new file mode 100644 index 00000000000..4da841d63b4 --- /dev/null +++ b/queue-5.10/nfsd-simplify-locking-for-network-notifier.patch @@ -0,0 +1,188 @@ +From 5a4217d0820083a2df47a13394fe93e19b3deb10 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Nov 2021 15:51:25 +1100 +Subject: NFSD: simplify locking for network notifier. + +From: NeilBrown + +[ Upstream commit d057cfec4940ce6eeffa22b4a71dec203b06cd55 ] + +nfsd currently maintains an open-coded read/write semaphore (refcount +and wait queue) for each network namespace to ensure the nfs service +isn't shut down while the notifier is running. + +This is excessive. As there is unlikely to be contention between +notifiers and they run without sleeping, a single spinlock is sufficient +to avoid problems. + +Signed-off-by: NeilBrown +[ cel: ensure nfsd_notifier_lock is static ] +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/netns.h | 3 --- + fs/nfsd/nfsctl.c | 2 -- + fs/nfsd/nfssvc.c | 38 ++++++++++++++++++++------------------ + 3 files changed, 20 insertions(+), 23 deletions(-) + +diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h +index 1fd59eb0730bb..021acdc0d03bb 100644 +--- a/fs/nfsd/netns.h ++++ b/fs/nfsd/netns.h +@@ -131,9 +131,6 @@ struct nfsd_net { + */ + int keep_active; + +- wait_queue_head_t ntf_wq; +- atomic_t ntf_refcnt; +- + /* + * clientid and stateid data for construction of net unique COPY + * stateids. +diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c +index 53076c5afe62c..504b169d27881 100644 +--- a/fs/nfsd/nfsctl.c ++++ b/fs/nfsd/nfsctl.c +@@ -1484,8 +1484,6 @@ static __net_init int nfsd_init_net(struct net *net) + nn->clientid_counter = nn->clientid_base + 1; + nn->s2s_cp_cl_id = nn->clientid_counter++; + +- atomic_set(&nn->ntf_refcnt, 0); +- init_waitqueue_head(&nn->ntf_wq); + seqlock_init(&nn->boot_lock); + + return 0; +diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c +index 8d49dfbe03f85..8554bc7ff4322 100644 +--- a/fs/nfsd/nfssvc.c ++++ b/fs/nfsd/nfssvc.c +@@ -434,6 +434,7 @@ static void nfsd_shutdown_net(struct net *net) + nfsd_shutdown_generic(); + } + ++static DEFINE_SPINLOCK(nfsd_notifier_lock); + static int nfsd_inetaddr_event(struct notifier_block *this, unsigned long event, + void *ptr) + { +@@ -443,18 +444,17 @@ static int nfsd_inetaddr_event(struct notifier_block *this, unsigned long event, + struct nfsd_net *nn = net_generic(net, nfsd_net_id); + struct sockaddr_in sin; + +- if ((event != NETDEV_DOWN) || +- !atomic_inc_not_zero(&nn->ntf_refcnt)) ++ if (event != NETDEV_DOWN || !nn->nfsd_serv) + goto out; + ++ spin_lock(&nfsd_notifier_lock); + if (nn->nfsd_serv) { + dprintk("nfsd_inetaddr_event: removed %pI4\n", &ifa->ifa_local); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = ifa->ifa_local; + svc_age_temp_xprts_now(nn->nfsd_serv, (struct sockaddr *)&sin); + } +- atomic_dec(&nn->ntf_refcnt); +- wake_up(&nn->ntf_wq); ++ spin_unlock(&nfsd_notifier_lock); + + out: + return NOTIFY_DONE; +@@ -474,10 +474,10 @@ static int nfsd_inet6addr_event(struct notifier_block *this, + struct nfsd_net *nn = net_generic(net, nfsd_net_id); + struct sockaddr_in6 sin6; + +- if ((event != NETDEV_DOWN) || +- !atomic_inc_not_zero(&nn->ntf_refcnt)) ++ if (event != NETDEV_DOWN || !nn->nfsd_serv) + goto out; + ++ spin_lock(&nfsd_notifier_lock); + if (nn->nfsd_serv) { + dprintk("nfsd_inet6addr_event: removed %pI6\n", &ifa->addr); + sin6.sin6_family = AF_INET6; +@@ -486,8 +486,8 @@ static int nfsd_inet6addr_event(struct notifier_block *this, + sin6.sin6_scope_id = ifa->idev->dev->ifindex; + svc_age_temp_xprts_now(nn->nfsd_serv, (struct sockaddr *)&sin6); + } +- atomic_dec(&nn->ntf_refcnt); +- wake_up(&nn->ntf_wq); ++ spin_unlock(&nfsd_notifier_lock); ++ + out: + return NOTIFY_DONE; + } +@@ -504,7 +504,6 @@ static void nfsd_last_thread(struct svc_serv *serv, struct net *net) + { + struct nfsd_net *nn = net_generic(net, nfsd_net_id); + +- atomic_dec(&nn->ntf_refcnt); + /* check if the notifier still has clients */ + if (atomic_dec_return(&nfsd_notifier_refcount) == 0) { + unregister_inetaddr_notifier(&nfsd_inetaddr_notifier); +@@ -512,7 +511,6 @@ static void nfsd_last_thread(struct svc_serv *serv, struct net *net) + unregister_inet6addr_notifier(&nfsd_inet6addr_notifier); + #endif + } +- wait_event(nn->ntf_wq, atomic_read(&nn->ntf_refcnt) == 0); + + /* + * write_ports can create the server without actually starting +@@ -624,6 +622,7 @@ int nfsd_create_serv(struct net *net) + { + int error; + struct nfsd_net *nn = net_generic(net, nfsd_net_id); ++ struct svc_serv *serv; + + WARN_ON(!mutex_is_locked(&nfsd_mutex)); + if (nn->nfsd_serv) { +@@ -633,21 +632,23 @@ int nfsd_create_serv(struct net *net) + if (nfsd_max_blksize == 0) + nfsd_max_blksize = nfsd_get_default_max_blksize(); + nfsd_reset_versions(nn); +- nn->nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize, +- &nfsd_thread_sv_ops); +- if (nn->nfsd_serv == NULL) ++ serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize, ++ &nfsd_thread_sv_ops); ++ if (serv == NULL) + return -ENOMEM; + +- nn->nfsd_serv->sv_maxconn = nn->max_connections; +- error = svc_bind(nn->nfsd_serv, net); ++ serv->sv_maxconn = nn->max_connections; ++ error = svc_bind(serv, net); + if (error < 0) { + /* NOT nfsd_put() as notifiers (see below) haven't + * been set up yet. + */ +- svc_put(nn->nfsd_serv); +- nn->nfsd_serv = NULL; ++ svc_put(serv); + return error; + } ++ spin_lock(&nfsd_notifier_lock); ++ nn->nfsd_serv = serv; ++ spin_unlock(&nfsd_notifier_lock); + + set_max_drc(); + /* check if the notifier is already set */ +@@ -657,7 +658,6 @@ int nfsd_create_serv(struct net *net) + register_inet6addr_notifier(&nfsd_inet6addr_notifier); + #endif + } +- atomic_inc(&nn->ntf_refcnt); + nfsd_reset_boot_verifier(nn); + return 0; + } +@@ -701,7 +701,9 @@ void nfsd_put(struct net *net) + if (kref_put(&nn->nfsd_serv->sv_refcnt, nfsd_noop)) { + svc_shutdown_net(nn->nfsd_serv, net); + svc_destroy(&nn->nfsd_serv->sv_refcnt); ++ spin_lock(&nfsd_notifier_lock); + nn->nfsd_serv = NULL; ++ spin_unlock(&nfsd_notifier_lock); + } + } + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-simplify-nfsd4_change_info.patch b/queue-5.10/nfsd-simplify-nfsd4_change_info.patch new file mode 100644 index 00000000000..b47d4498251 --- /dev/null +++ b/queue-5.10/nfsd-simplify-nfsd4_change_info.patch @@ -0,0 +1,80 @@ +From 88ea7d009b4862a250e23000b39e30e8b9abd02a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Nov 2020 17:46:15 -0500 +Subject: nfsd: simplify nfsd4_change_info + +From: J. Bruce Fields + +[ Upstream commit b2140338d8dca827ad9e83f3e026e9d51748b265 ] + +It doesn't make sense to carry all these extra fields around. Just +make everything into change attribute from the start. + +This is just cleanup, there should be no change in behavior. + +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 11 ++--------- + fs/nfsd/xdr4.h | 11 ----------- + 2 files changed, 2 insertions(+), 20 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index bdcfb5f7021da..4df6c75d0eb7f 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -2459,15 +2459,8 @@ static __be32 *encode_time_delta(__be32 *p, struct inode *inode) + static __be32 *encode_cinfo(__be32 *p, struct nfsd4_change_info *c) + { + *p++ = cpu_to_be32(c->atomic); +- if (c->change_supported) { +- p = xdr_encode_hyper(p, c->before_change); +- p = xdr_encode_hyper(p, c->after_change); +- } else { +- *p++ = cpu_to_be32(c->before_ctime_sec); +- *p++ = cpu_to_be32(c->before_ctime_nsec); +- *p++ = cpu_to_be32(c->after_ctime_sec); +- *p++ = cpu_to_be32(c->after_ctime_nsec); +- } ++ p = xdr_encode_hyper(p, c->before_change); ++ p = xdr_encode_hyper(p, c->after_change); + return p; + } + +diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h +index e12fbe382e3f3..b4556e86e97c3 100644 +--- a/fs/nfsd/xdr4.h ++++ b/fs/nfsd/xdr4.h +@@ -76,12 +76,7 @@ static inline bool nfsd4_has_session(struct nfsd4_compound_state *cs) + + struct nfsd4_change_info { + u32 atomic; +- bool change_supported; +- u32 before_ctime_sec; +- u32 before_ctime_nsec; + u64 before_change; +- u32 after_ctime_sec; +- u32 after_ctime_nsec; + u64 after_change; + }; + +@@ -754,15 +749,9 @@ set_change_info(struct nfsd4_change_info *cinfo, struct svc_fh *fhp) + { + BUG_ON(!fhp->fh_pre_saved); + cinfo->atomic = (u32)fhp->fh_post_saved; +- cinfo->change_supported = IS_I_VERSION(d_inode(fhp->fh_dentry)); + + cinfo->before_change = fhp->fh_pre_change; + cinfo->after_change = fhp->fh_post_change; +- cinfo->before_ctime_sec = fhp->fh_pre_ctime.tv_sec; +- cinfo->before_ctime_nsec = fhp->fh_pre_ctime.tv_nsec; +- cinfo->after_ctime_sec = fhp->fh_post_attr.ctime.tv_sec; +- cinfo->after_ctime_nsec = fhp->fh_post_attr.ctime.tv_nsec; +- + } + + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-simplify-nfsd4_check_open_reclaim.patch b/queue-5.10/nfsd-simplify-nfsd4_check_open_reclaim.patch new file mode 100644 index 00000000000..cae28c4f62b --- /dev/null +++ b/queue-5.10/nfsd-simplify-nfsd4_check_open_reclaim.patch @@ -0,0 +1,86 @@ +From 37118fd964345b88899efa8e2ee08e2432bad99d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 Jan 2021 17:57:44 -0500 +Subject: nfsd: simplify nfsd4_check_open_reclaim + +From: J. Bruce Fields + +[ Upstream commit 1722b04624806ced51693f546edb83e8b2297a77 ] + +The set_client() was already taken care of by process_open1(). + +The comments here are mostly redundant with the code. + +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 3 +-- + fs/nfsd/nfs4state.c | 18 +++--------------- + fs/nfsd/state.h | 3 +-- + 3 files changed, 5 insertions(+), 19 deletions(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 4f64d94909ec1..5d304b51914a2 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -428,8 +428,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + goto out; + break; + case NFS4_OPEN_CLAIM_PREVIOUS: +- status = nfs4_check_open_reclaim(&open->op_clientid, +- cstate, nn); ++ status = nfs4_check_open_reclaim(cstate->clp); + if (status) + goto out; + open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index cbec87ee6bc0e..4da8467a3570d 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -7248,25 +7248,13 @@ nfsd4_find_reclaim_client(struct xdr_netobj name, struct nfsd_net *nn) + return NULL; + } + +-/* +-* Called from OPEN. Look for clientid in reclaim list. +-*/ + __be32 +-nfs4_check_open_reclaim(clientid_t *clid, +- struct nfsd4_compound_state *cstate, +- struct nfsd_net *nn) ++nfs4_check_open_reclaim(struct nfs4_client *clp) + { +- __be32 status; +- +- /* find clientid in conf_id_hashtbl */ +- status = set_client(clid, cstate, nn); +- if (status) +- return nfserr_reclaim_bad; +- +- if (test_bit(NFSD4_CLIENT_RECLAIM_COMPLETE, &cstate->clp->cl_flags)) ++ if (test_bit(NFSD4_CLIENT_RECLAIM_COMPLETE, &clp->cl_flags)) + return nfserr_no_grace; + +- if (nfsd4_client_record_check(cstate->clp)) ++ if (nfsd4_client_record_check(clp)) + return nfserr_reclaim_bad; + + return nfs_ok; +diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h +index 9eae11a9d21ca..73deea3531699 100644 +--- a/fs/nfsd/state.h ++++ b/fs/nfsd/state.h +@@ -649,8 +649,7 @@ void nfs4_remove_reclaim_record(struct nfs4_client_reclaim *, struct nfsd_net *) + extern void nfs4_release_reclaim(struct nfsd_net *); + extern struct nfs4_client_reclaim *nfsd4_find_reclaim_client(struct xdr_netobj name, + struct nfsd_net *nn); +-extern __be32 nfs4_check_open_reclaim(clientid_t *clid, +- struct nfsd4_compound_state *cstate, struct nfsd_net *nn); ++extern __be32 nfs4_check_open_reclaim(struct nfs4_client *); + extern void nfsd4_probe_callback(struct nfs4_client *clp); + extern void nfsd4_probe_callback_sync(struct nfs4_client *clp); + extern void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-simplify-nfsd_renew.patch b/queue-5.10/nfsd-simplify-nfsd_renew.patch new file mode 100644 index 00000000000..c6563fd753a --- /dev/null +++ b/queue-5.10/nfsd-simplify-nfsd_renew.patch @@ -0,0 +1,44 @@ +From a309c18cf0408bb7f140f98373251a6d4debffe4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 Jan 2021 17:57:39 -0500 +Subject: nfsd: simplify nfsd_renew + +From: J. Bruce Fields + +[ Upstream commit b4587eb2cf4b6271f67fb93b75f7de2a2026e853 ] + +You can take the single-exit thing too far, I think. + +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 9 +++------ + 1 file changed, 3 insertions(+), 6 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 15ed72b0ef55b..574c88a9da268 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -5322,15 +5322,12 @@ nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + trace_nfsd_clid_renew(clid); + status = lookup_clientid(clid, cstate, nn, false); + if (status) +- goto out; ++ return status; + clp = cstate->clp; +- status = nfserr_cb_path_down; + if (!list_empty(&clp->cl_delegations) + && clp->cl_cb_state != NFSD4_CB_UP) +- goto out; +- status = nfs_ok; +-out: +- return status; ++ return nfserr_cb_path_down; ++ return nfs_ok; + } + + void +-- +2.43.0 + diff --git a/queue-5.10/nfsd-simplify-per-net-file-cache-management.patch b/queue-5.10/nfsd-simplify-per-net-file-cache-management.patch new file mode 100644 index 00000000000..9a20f8b56bd --- /dev/null +++ b/queue-5.10/nfsd-simplify-per-net-file-cache-management.patch @@ -0,0 +1,187 @@ +From 47410849ed2ffece288a34f43ca867af67cd6983 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 1 Dec 2021 10:58:14 +1100 +Subject: NFSD: simplify per-net file cache management + +From: NeilBrown + +[ Upstream commit 1463b38e7cf34d4cc60f41daff459ad807b2e408 ] + +We currently have a 'laundrette' for closing cached files - a different +work-item for each network-namespace. + +These 'laundrettes' (aka struct nfsd_fcache_disposal) are currently on a +list, and are freed using rcu. + +The list is not necessary as we have a per-namespace structure (struct +nfsd_net) which can hold a link to the nfsd_fcache_disposal. +The use of kfree_rcu is also unnecessary as the cache is cleaned of all +files associated with a given namespace, and no new files can be added, +before the nfsd_fcache_disposal is freed. + +So add a '->fcache_disposal' link to nfsd_net, and discard the list +management and rcu usage. + +Signed-off-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 76 +++++++++------------------------------------ + fs/nfsd/netns.h | 2 ++ + 2 files changed, 17 insertions(+), 61 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index 8cd7d5d6955a0..b6ef8256c9c64 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -44,12 +44,9 @@ struct nfsd_fcache_bucket { + static DEFINE_PER_CPU(unsigned long, nfsd_file_cache_hits); + + struct nfsd_fcache_disposal { +- struct list_head list; + struct work_struct work; +- struct net *net; + spinlock_t lock; + struct list_head freeme; +- struct rcu_head rcu; + }; + + static struct workqueue_struct *nfsd_filecache_wq __read_mostly; +@@ -62,8 +59,6 @@ static long nfsd_file_lru_flags; + static struct fsnotify_group *nfsd_file_fsnotify_group; + static atomic_long_t nfsd_filecache_count; + static struct delayed_work nfsd_filecache_laundrette; +-static DEFINE_SPINLOCK(laundrette_lock); +-static LIST_HEAD(laundrettes); + + static void nfsd_file_gc(void); + +@@ -366,19 +361,13 @@ nfsd_file_list_remove_disposal(struct list_head *dst, + static void + nfsd_file_list_add_disposal(struct list_head *files, struct net *net) + { +- struct nfsd_fcache_disposal *l; ++ struct nfsd_net *nn = net_generic(net, nfsd_net_id); ++ struct nfsd_fcache_disposal *l = nn->fcache_disposal; + +- rcu_read_lock(); +- list_for_each_entry_rcu(l, &laundrettes, list) { +- if (l->net == net) { +- spin_lock(&l->lock); +- list_splice_tail_init(files, &l->freeme); +- spin_unlock(&l->lock); +- queue_work(nfsd_filecache_wq, &l->work); +- break; +- } +- } +- rcu_read_unlock(); ++ spin_lock(&l->lock); ++ list_splice_tail_init(files, &l->freeme); ++ spin_unlock(&l->lock); ++ queue_work(nfsd_filecache_wq, &l->work); + } + + static void +@@ -754,7 +743,7 @@ nfsd_file_cache_purge(struct net *net) + } + + static struct nfsd_fcache_disposal * +-nfsd_alloc_fcache_disposal(struct net *net) ++nfsd_alloc_fcache_disposal(void) + { + struct nfsd_fcache_disposal *l; + +@@ -762,7 +751,6 @@ nfsd_alloc_fcache_disposal(struct net *net) + if (!l) + return NULL; + INIT_WORK(&l->work, nfsd_file_delayed_close); +- l->net = net; + spin_lock_init(&l->lock); + INIT_LIST_HEAD(&l->freeme); + return l; +@@ -771,61 +759,27 @@ nfsd_alloc_fcache_disposal(struct net *net) + static void + nfsd_free_fcache_disposal(struct nfsd_fcache_disposal *l) + { +- rcu_assign_pointer(l->net, NULL); + cancel_work_sync(&l->work); + nfsd_file_dispose_list(&l->freeme); +- kfree_rcu(l, rcu); +-} +- +-static void +-nfsd_add_fcache_disposal(struct nfsd_fcache_disposal *l) +-{ +- spin_lock(&laundrette_lock); +- list_add_tail_rcu(&l->list, &laundrettes); +- spin_unlock(&laundrette_lock); +-} +- +-static void +-nfsd_del_fcache_disposal(struct nfsd_fcache_disposal *l) +-{ +- spin_lock(&laundrette_lock); +- list_del_rcu(&l->list); +- spin_unlock(&laundrette_lock); +-} +- +-static int +-nfsd_alloc_fcache_disposal_net(struct net *net) +-{ +- struct nfsd_fcache_disposal *l; +- +- l = nfsd_alloc_fcache_disposal(net); +- if (!l) +- return -ENOMEM; +- nfsd_add_fcache_disposal(l); +- return 0; ++ kfree(l); + } + + static void + nfsd_free_fcache_disposal_net(struct net *net) + { +- struct nfsd_fcache_disposal *l; ++ struct nfsd_net *nn = net_generic(net, nfsd_net_id); ++ struct nfsd_fcache_disposal *l = nn->fcache_disposal; + +- rcu_read_lock(); +- list_for_each_entry_rcu(l, &laundrettes, list) { +- if (l->net != net) +- continue; +- nfsd_del_fcache_disposal(l); +- rcu_read_unlock(); +- nfsd_free_fcache_disposal(l); +- return; +- } +- rcu_read_unlock(); ++ nfsd_free_fcache_disposal(l); + } + + int + nfsd_file_cache_start_net(struct net *net) + { +- return nfsd_alloc_fcache_disposal_net(net); ++ struct nfsd_net *nn = net_generic(net, nfsd_net_id); ++ ++ nn->fcache_disposal = nfsd_alloc_fcache_disposal(); ++ return nn->fcache_disposal ? 0 : -ENOMEM; + } + + void +diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h +index 021acdc0d03bb..9e8b77d2a3a47 100644 +--- a/fs/nfsd/netns.h ++++ b/fs/nfsd/netns.h +@@ -185,6 +185,8 @@ struct nfsd_net { + + /* utsname taken from the process that starts the server */ + char nfsd_name[UNX_MAXNODENAME+1]; ++ ++ struct nfsd_fcache_disposal *fcache_disposal; + }; + + /* Simple check to find out if a given net was properly initialized */ +-- +2.43.0 + diff --git a/queue-5.10/nfsd-simplify-process_lock.patch b/queue-5.10/nfsd-simplify-process_lock.patch new file mode 100644 index 00000000000..821e786ce78 --- /dev/null +++ b/queue-5.10/nfsd-simplify-process_lock.patch @@ -0,0 +1,47 @@ +From f6364d6d4f184e4c7165f055779c3707d1f8c721 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 Jan 2021 17:57:38 -0500 +Subject: nfsd: simplify process_lock + +From: J. Bruce Fields + +[ Upstream commit a9d53a75cf574d6aa41f3cb4968fffe4f64e0fad ] + +Similarly, this STALE_CLIENTID check is already handled by: + +nfs4_preprocess_confirmed_seqid_op()-> + nfs4_preprocess_seqid_op()-> + nfsd4_lookup_stateid()-> + set_client()-> + STALE_CLIENTID() + +(This may cause it to return a different error in some cases where +there are multiple things wrong; pynfs test SEQ10 regressed on this +commit because of that, but I think that's the test's fault, and I've +fixed it separately.) + +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 3f26047376368..15ed72b0ef55b 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -6720,10 +6720,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + &cstate->session->se_client->cl_clientid, + sizeof(clientid_t)); + +- status = nfserr_stale_clientid; +- if (STALE_CLIENTID(&lock->lk_new_clientid, nn)) +- goto out; +- + /* validate and update open stateid and open seqid */ + status = nfs4_preprocess_confirmed_seqid_op(cstate, + lock->lk_new_open_seqid, +-- +2.43.0 + diff --git a/queue-5.10/nfsd-simplify-read_plus.patch b/queue-5.10/nfsd-simplify-read_plus.patch new file mode 100644 index 00000000000..689d1ba52ec --- /dev/null +++ b/queue-5.10/nfsd-simplify-read_plus.patch @@ -0,0 +1,210 @@ +From 99055b63b4ddff4564ba1328be9b60ac8a39746b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 13 Sep 2022 14:01:51 -0400 +Subject: NFSD: Simplify READ_PLUS + +From: Anna Schumaker + +[ Upstream commit eeadcb75794516839078c28b3730132aeb700ce6 ] + +Chuck had suggested reverting READ_PLUS so it returns a single DATA +segment covering the requested read range. This prepares the server for +a future "sparse read" function so support can easily be added without +needing to rip out the old READ_PLUS code at the same time. + +Signed-off-by: Anna Schumaker +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 139 +++++++++++----------------------------------- + 1 file changed, 32 insertions(+), 107 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index fc587381cd087..27b38ce6f8c6e 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -4775,79 +4775,37 @@ nfsd4_encode_offload_status(struct nfsd4_compoundres *resp, __be32 nfserr, + + static __be32 + nfsd4_encode_read_plus_data(struct nfsd4_compoundres *resp, +- struct nfsd4_read *read, +- unsigned long *maxcount, u32 *eof, +- loff_t *pos) ++ struct nfsd4_read *read) + { +- struct xdr_stream *xdr = resp->xdr; ++ bool splice_ok = test_bit(RQ_SPLICE_OK, &resp->rqstp->rq_flags); + struct file *file = read->rd_nf->nf_file; +- int starting_len = xdr->buf->len; +- loff_t hole_pos; +- __be32 nfserr; +- __be32 *p, tmp; +- __be64 tmp64; +- +- hole_pos = pos ? *pos : vfs_llseek(file, read->rd_offset, SEEK_HOLE); +- if (hole_pos > read->rd_offset) +- *maxcount = min_t(unsigned long, *maxcount, hole_pos - read->rd_offset); +- *maxcount = min_t(unsigned long, *maxcount, (xdr->buf->buflen - xdr->buf->len)); ++ struct xdr_stream *xdr = resp->xdr; ++ unsigned long maxcount; ++ __be32 nfserr, *p; + + /* Content type, offset, byte count */ + p = xdr_reserve_space(xdr, 4 + 8 + 4); + if (!p) +- return nfserr_resource; ++ return nfserr_io; ++ if (resp->xdr->buf->page_len && splice_ok) { ++ WARN_ON_ONCE(splice_ok); ++ return nfserr_serverfault; ++ } + +- read->rd_vlen = xdr_reserve_space_vec(xdr, resp->rqstp->rq_vec, *maxcount); +- if (read->rd_vlen < 0) +- return nfserr_resource; ++ maxcount = min_t(unsigned long, read->rd_length, ++ (xdr->buf->buflen - xdr->buf->len)); + +- nfserr = nfsd_readv(resp->rqstp, read->rd_fhp, file, read->rd_offset, +- resp->rqstp->rq_vec, read->rd_vlen, maxcount, eof); ++ if (file->f_op->splice_read && splice_ok) ++ nfserr = nfsd4_encode_splice_read(resp, read, file, maxcount); ++ else ++ nfserr = nfsd4_encode_readv(resp, read, file, maxcount); + if (nfserr) + return nfserr; +- xdr_truncate_encode(xdr, starting_len + 16 + xdr_align_size(*maxcount)); +- +- tmp = htonl(NFS4_CONTENT_DATA); +- write_bytes_to_xdr_buf(xdr->buf, starting_len, &tmp, 4); +- tmp64 = cpu_to_be64(read->rd_offset); +- write_bytes_to_xdr_buf(xdr->buf, starting_len + 4, &tmp64, 8); +- tmp = htonl(*maxcount); +- write_bytes_to_xdr_buf(xdr->buf, starting_len + 12, &tmp, 4); +- +- tmp = xdr_zero; +- write_bytes_to_xdr_buf(xdr->buf, starting_len + 16 + *maxcount, &tmp, +- xdr_pad_size(*maxcount)); +- return nfs_ok; +-} +- +-static __be32 +-nfsd4_encode_read_plus_hole(struct nfsd4_compoundres *resp, +- struct nfsd4_read *read, +- unsigned long *maxcount, u32 *eof) +-{ +- struct file *file = read->rd_nf->nf_file; +- loff_t data_pos = vfs_llseek(file, read->rd_offset, SEEK_DATA); +- loff_t f_size = i_size_read(file_inode(file)); +- unsigned long count; +- __be32 *p; +- +- if (data_pos == -ENXIO) +- data_pos = f_size; +- else if (data_pos <= read->rd_offset || (data_pos < f_size && data_pos % PAGE_SIZE)) +- return nfsd4_encode_read_plus_data(resp, read, maxcount, eof, &f_size); +- count = data_pos - read->rd_offset; + +- /* Content type, offset, byte count */ +- p = xdr_reserve_space(resp->xdr, 4 + 8 + 8); +- if (!p) +- return nfserr_resource; +- +- *p++ = htonl(NFS4_CONTENT_HOLE); ++ *p++ = cpu_to_be32(NFS4_CONTENT_DATA); + p = xdr_encode_hyper(p, read->rd_offset); +- p = xdr_encode_hyper(p, count); ++ *p = cpu_to_be32(read->rd_length); + +- *eof = (read->rd_offset + count) >= f_size; +- *maxcount = min_t(unsigned long, count, *maxcount); + return nfs_ok; + } + +@@ -4855,69 +4813,36 @@ static __be32 + nfsd4_encode_read_plus(struct nfsd4_compoundres *resp, __be32 nfserr, + struct nfsd4_read *read) + { +- unsigned long maxcount, count; ++ struct file *file = read->rd_nf->nf_file; + struct xdr_stream *xdr = resp->xdr; +- struct file *file; + int starting_len = xdr->buf->len; +- int last_segment = xdr->buf->len; +- int segments = 0; +- __be32 *p, tmp; +- bool is_data; +- loff_t pos; +- u32 eof; ++ u32 segments = 0; ++ __be32 *p; + + if (nfserr) + return nfserr; +- file = read->rd_nf->nf_file; + + /* eof flag, segment count */ + p = xdr_reserve_space(xdr, 4 + 4); + if (!p) +- return nfserr_resource; ++ return nfserr_io; + xdr_commit_encode(xdr); + +- maxcount = min_t(unsigned long, read->rd_length, +- (xdr->buf->buflen - xdr->buf->len)); +- count = maxcount; +- +- eof = read->rd_offset >= i_size_read(file_inode(file)); +- if (eof) ++ read->rd_eof = read->rd_offset >= i_size_read(file_inode(file)); ++ if (read->rd_eof) + goto out; + +- pos = vfs_llseek(file, read->rd_offset, SEEK_HOLE); +- is_data = pos > read->rd_offset; +- +- while (count > 0 && !eof) { +- maxcount = count; +- if (is_data) +- nfserr = nfsd4_encode_read_plus_data(resp, read, &maxcount, &eof, +- segments == 0 ? &pos : NULL); +- else +- nfserr = nfsd4_encode_read_plus_hole(resp, read, &maxcount, &eof); +- if (nfserr) +- goto out; +- count -= maxcount; +- read->rd_offset += maxcount; +- is_data = !is_data; +- last_segment = xdr->buf->len; +- segments++; +- } +- +-out: +- if (nfserr && segments == 0) ++ nfserr = nfsd4_encode_read_plus_data(resp, read); ++ if (nfserr) { + xdr_truncate_encode(xdr, starting_len); +- else { +- if (nfserr) { +- xdr_truncate_encode(xdr, last_segment); +- nfserr = nfs_ok; +- eof = 0; +- } +- tmp = htonl(eof); +- write_bytes_to_xdr_buf(xdr->buf, starting_len, &tmp, 4); +- tmp = htonl(segments); +- write_bytes_to_xdr_buf(xdr->buf, starting_len + 4, &tmp, 4); ++ return nfserr; + } + ++ segments++; ++ ++out: ++ p = xdr_encode_bool(p, read->rd_eof); ++ *p = cpu_to_be32(segments); + return nfserr; + } + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-simplify-starting_len.patch b/queue-5.10/nfsd-simplify-starting_len.patch new file mode 100644 index 00000000000..f3067ef8b9c --- /dev/null +++ b/queue-5.10/nfsd-simplify-starting_len.patch @@ -0,0 +1,54 @@ +From 6733bf2d062094e935aa8aa09228673ec407f4ba Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 Jul 2022 16:09:10 -0400 +Subject: NFSD: Simplify starting_len + +From: Chuck Lever + +[ Upstream commit 071ae99feadfc55979f89287d6ad2c6a315cb46d ] + +Clean-up: Now that nfsd4_encode_readv() does not have to encode the +EOF or rd_length values, it no longer needs to subtract 8 from +@starting_len. + +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 36f0f06714dec..f67a54f7eb13e 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -3950,7 +3950,7 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp, + struct file *file, unsigned long maxcount) + { + struct xdr_stream *xdr = resp->xdr; +- int starting_len = xdr->buf->len - 8; ++ unsigned int starting_len = xdr->buf->len; + __be32 nfserr; + __be32 tmp; + int pad; +@@ -3965,14 +3965,13 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp, + read->rd_length = maxcount; + if (nfserr) + return nfserr; +- if (svc_encode_result_payload(resp->rqstp, starting_len + 8, maxcount)) ++ if (svc_encode_result_payload(resp->rqstp, starting_len, maxcount)) + return nfserr_io; +- xdr_truncate_encode(xdr, starting_len + 8 + xdr_align_size(maxcount)); ++ xdr_truncate_encode(xdr, starting_len + xdr_align_size(maxcount)); + + tmp = xdr_zero; + pad = (maxcount&3) ? 4 - (maxcount&3) : 0; +- write_bytes_to_xdr_buf(xdr->buf, starting_len + 8 + maxcount, +- &tmp, pad); ++ write_bytes_to_xdr_buf(xdr->buf, starting_len + maxcount, &tmp, pad); + return 0; + + } +-- +2.43.0 + diff --git a/queue-5.10/nfsd-simplify-struct-nfsfh.patch b/queue-5.10/nfsd-simplify-struct-nfsfh.patch new file mode 100644 index 00000000000..be4ff91355b --- /dev/null +++ b/queue-5.10/nfsd-simplify-struct-nfsfh.patch @@ -0,0 +1,334 @@ +From d05317a8b42272990e48bc738b7ae527bbd3722c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 2 Sep 2021 11:16:32 +1000 +Subject: NFSD: simplify struct nfsfh + +From: NeilBrown + +[ Upstream commit d8b26071e65e80a348602b939e333242f989221b ] + +Most of the fields in 'struct knfsd_fh' are 2 levels deep (a union and a +struct) and are accessed using macros like: + + #define fh_FOO fh_base.fh_new.fb_FOO + +This patch makes the union and struct anonymous, so that "fh_FOO" can be +a name directly within 'struct knfsd_fh' and the #defines aren't needed. + +The file handle as a whole is sometimes accessed as "fh_base" or +"fh_base.fh_pad", neither of which are particularly helpful names. +As the struct holding the filehandle is now anonymous, we +cannot use the name of that, so we union it with 'fh_raw' and use that +where the raw filehandle is needed. fh_raw also ensure the structure is +large enough for the largest possible filehandle. + +fh_raw is a 'char' array, removing any need to cast it for memcpy etc. + +SVCFH_fmt() is simplified using the "%ph" printk format. This +changes the appearance of filehandles in dprintk() debugging, making +them a little more precise. + +Reviewed-by: Christoph Hellwig +Signed-off-by: NeilBrown +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/flexfilelayout.c | 2 +- + fs/nfsd/lockd.c | 2 +- + fs/nfsd/nfs3xdr.c | 4 ++-- + fs/nfsd/nfs4callback.c | 2 +- + fs/nfsd/nfs4proc.c | 4 ++-- + fs/nfsd/nfs4state.c | 4 ++-- + fs/nfsd/nfs4xdr.c | 4 ++-- + fs/nfsd/nfsctl.c | 6 ++--- + fs/nfsd/nfsfh.c | 13 ++++------- + fs/nfsd/nfsfh.h | 50 ++++++++++++---------------------------- + fs/nfsd/nfsxdr.c | 4 ++-- + 11 files changed, 35 insertions(+), 60 deletions(-) + +diff --git a/fs/nfsd/flexfilelayout.c b/fs/nfsd/flexfilelayout.c +index db7ef07ae50c9..2e2f1d5e9f623 100644 +--- a/fs/nfsd/flexfilelayout.c ++++ b/fs/nfsd/flexfilelayout.c +@@ -61,7 +61,7 @@ nfsd4_ff_proc_layoutget(struct inode *inode, const struct svc_fh *fhp, + goto out_error; + + fl->fh.size = fhp->fh_handle.fh_size; +- memcpy(fl->fh.data, &fhp->fh_handle.fh_base, fl->fh.size); ++ memcpy(fl->fh.data, &fhp->fh_handle.fh_raw, fl->fh.size); + + /* Give whole file layout segments */ + seg->offset = 0; +diff --git a/fs/nfsd/lockd.c b/fs/nfsd/lockd.c +index 606fa155c28ad..46a7f9b813e52 100644 +--- a/fs/nfsd/lockd.c ++++ b/fs/nfsd/lockd.c +@@ -35,7 +35,7 @@ nlm_fopen(struct svc_rqst *rqstp, struct nfs_fh *f, struct file **filp, + /* must initialize before using! but maxsize doesn't matter */ + fh_init(&fh,0); + fh.fh_handle.fh_size = f->size; +- memcpy((char*)&fh.fh_handle.fh_base, f->data, f->size); ++ memcpy(&fh.fh_handle.fh_raw, f->data, f->size); + fh.fh_export = NULL; + + access = (mode == O_WRONLY) ? NFSD_MAY_WRITE : NFSD_MAY_READ; +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index 0a5ebc52e6a9c..3d37923afb06c 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -92,7 +92,7 @@ svcxdr_decode_nfs_fh3(struct xdr_stream *xdr, struct svc_fh *fhp) + return false; + fh_init(fhp, NFS3_FHSIZE); + fhp->fh_handle.fh_size = size; +- memcpy(&fhp->fh_handle.fh_base, p, size); ++ memcpy(&fhp->fh_handle.fh_raw, p, size); + + return true; + } +@@ -131,7 +131,7 @@ svcxdr_encode_nfs_fh3(struct xdr_stream *xdr, const struct svc_fh *fhp) + *p++ = cpu_to_be32(size); + if (size) + p[XDR_QUADLEN(size) - 1] = 0; +- memcpy(p, &fhp->fh_handle.fh_base, size); ++ memcpy(p, &fhp->fh_handle.fh_raw, size); + + return true; + } +diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c +index 97f517e9b4189..e1272a7f45220 100644 +--- a/fs/nfsd/nfs4callback.c ++++ b/fs/nfsd/nfs4callback.c +@@ -121,7 +121,7 @@ static void encode_nfs_fh4(struct xdr_stream *xdr, const struct knfsd_fh *fh) + + BUG_ON(length > NFS4_FHSIZE); + p = xdr_reserve_space(xdr, 4 + length); +- xdr_encode_opaque(p, &fh->fh_base, length); ++ xdr_encode_opaque(p, &fh->fh_raw, length); + } + + /* +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 1f840c72e9780..d55d9b9dbafb1 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -519,7 +519,7 @@ nfsd4_putfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + + fh_put(&cstate->current_fh); + cstate->current_fh.fh_handle.fh_size = putfh->pf_fhlen; +- memcpy(&cstate->current_fh.fh_handle.fh_base, putfh->pf_fhval, ++ memcpy(&cstate->current_fh.fh_handle.fh_raw, putfh->pf_fhval, + putfh->pf_fhlen); + ret = fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_BYPASS_GSS); + #ifdef CONFIG_NFSD_V4_2_INTER_SSC +@@ -1379,7 +1379,7 @@ nfsd4_setup_inter_ssc(struct svc_rqst *rqstp, + s_fh = &cstate->save_fh; + + copy->c_fh.size = s_fh->fh_handle.fh_size; +- memcpy(copy->c_fh.data, &s_fh->fh_handle.fh_base, copy->c_fh.size); ++ memcpy(copy->c_fh.data, &s_fh->fh_handle.fh_raw, copy->c_fh.size); + copy->stateid.seqid = cpu_to_be32(s_stid->si_generation); + memcpy(copy->stateid.other, (void *)&s_stid->si_opaque, + sizeof(stateid_opaque_t)); +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index e9ac77c28741e..68562564be6b2 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -1022,7 +1022,7 @@ static int delegation_blocked(struct knfsd_fh *fh) + } + spin_unlock(&blocked_delegations_lock); + } +- hash = jhash(&fh->fh_base, fh->fh_size, 0); ++ hash = jhash(&fh->fh_raw, fh->fh_size, 0); + if (test_bit(hash&255, bd->set[0]) && + test_bit((hash>>8)&255, bd->set[0]) && + test_bit((hash>>16)&255, bd->set[0])) +@@ -1041,7 +1041,7 @@ static void block_delegations(struct knfsd_fh *fh) + u32 hash; + struct bloom_pair *bd = &blocked_delegations; + +- hash = jhash(&fh->fh_base, fh->fh_size, 0); ++ hash = jhash(&fh->fh_raw, fh->fh_size, 0); + + spin_lock(&blocked_delegations_lock); + __set_bit(hash&255, bd->set[bd->new]); +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 262c6fec56aa6..899d961372c06 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -3110,7 +3110,7 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, + p = xdr_reserve_space(xdr, fhp->fh_handle.fh_size + 4); + if (!p) + goto out_resource; +- p = xdr_encode_opaque(p, &fhp->fh_handle.fh_base, ++ p = xdr_encode_opaque(p, &fhp->fh_handle.fh_raw, + fhp->fh_handle.fh_size); + } + if (bmval0 & FATTR4_WORD0_FILEID) { +@@ -3681,7 +3681,7 @@ nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, struct svc_fh + p = xdr_reserve_space(xdr, len + 4); + if (!p) + return nfserr_resource; +- p = xdr_encode_opaque(p, &fhp->fh_handle.fh_base, len); ++ p = xdr_encode_opaque(p, &fhp->fh_handle.fh_raw, len); + return 0; + } + +diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c +index cb73c12925629..d0761ca8cb542 100644 +--- a/fs/nfsd/nfsctl.c ++++ b/fs/nfsd/nfsctl.c +@@ -395,12 +395,12 @@ static ssize_t write_filehandle(struct file *file, char *buf, size_t size) + auth_domain_put(dom); + if (len) + return len; +- ++ + mesg = buf; + len = SIMPLE_TRANSACTION_LIMIT; +- qword_addhex(&mesg, &len, (char*)&fh.fh_base, fh.fh_size); ++ qword_addhex(&mesg, &len, fh.fh_raw, fh.fh_size); + mesg[-1] = '\n'; +- return mesg - buf; ++ return mesg - buf; + } + + /* +diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c +index 7e5a508173a04..34e201b6eb623 100644 +--- a/fs/nfsd/nfsfh.c ++++ b/fs/nfsd/nfsfh.c +@@ -639,16 +639,11 @@ fh_put(struct svc_fh *fhp) + char * SVCFH_fmt(struct svc_fh *fhp) + { + struct knfsd_fh *fh = &fhp->fh_handle; ++ static char buf[2+1+1+64*3+1]; + +- static char buf[80]; +- sprintf(buf, "%d: %08x %08x %08x %08x %08x %08x", +- fh->fh_size, +- fh->fh_base.fh_pad[0], +- fh->fh_base.fh_pad[1], +- fh->fh_base.fh_pad[2], +- fh->fh_base.fh_pad[3], +- fh->fh_base.fh_pad[4], +- fh->fh_base.fh_pad[5]); ++ if (fh->fh_size < 0 || fh->fh_size> 64) ++ return "bad-fh"; ++ sprintf(buf, "%d: %*ph", fh->fh_size, fh->fh_size, fh->fh_raw); + return buf; + } + +diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h +index 8b5587f274a7d..d11e4b6870d68 100644 +--- a/fs/nfsd/nfsfh.h ++++ b/fs/nfsd/nfsfh.h +@@ -43,44 +43,24 @@ + * filesystems must not use the values '0' or '0xff'. 'See enum fid_type' + * in include/linux/exportfs.h for currently registered values. + */ +-struct nfs_fhbase_new { +- union { +- struct { +- u8 fb_version_aux; /* == 1 */ +- u8 fb_auth_type_aux; +- u8 fb_fsid_type_aux; +- u8 fb_fileid_type_aux; +- u32 fb_auth[1]; +- /* u32 fb_fsid[0]; floating */ +- /* u32 fb_fileid[0]; floating */ +- }; +- struct { +- u8 fb_version; /* == 1 */ +- u8 fb_auth_type; +- u8 fb_fsid_type; +- u8 fb_fileid_type; +- u32 fb_auth_flex[]; /* flexible-array member */ +- }; +- }; +-}; + + struct knfsd_fh { +- unsigned int fh_size; /* significant for NFSv3. +- * Points to the current size while building +- * a new file handle ++ unsigned int fh_size; /* ++ * Points to the current size while ++ * building a new file handle. + */ + union { +- u32 fh_pad[NFS4_FHSIZE/4]; +- struct nfs_fhbase_new fh_new; +- } fh_base; ++ char fh_raw[NFS4_FHSIZE]; ++ struct { ++ u8 fh_version; /* == 1 */ ++ u8 fh_auth_type; /* deprecated */ ++ u8 fh_fsid_type; ++ u8 fh_fileid_type; ++ u32 fh_fsid[]; /* flexible-array member */ ++ }; ++ }; + }; + +-#define fh_version fh_base.fh_new.fb_version +-#define fh_fsid_type fh_base.fh_new.fb_fsid_type +-#define fh_auth_type fh_base.fh_new.fb_auth_type +-#define fh_fileid_type fh_base.fh_new.fb_fileid_type +-#define fh_fsid fh_base.fh_new.fb_auth_flex +- + static inline __u32 ino_t_to_u32(ino_t ino) + { + return (__u32) ino; +@@ -255,7 +235,7 @@ static inline void + fh_copy_shallow(struct knfsd_fh *dst, struct knfsd_fh *src) + { + dst->fh_size = src->fh_size; +- memcpy(&dst->fh_base, &src->fh_base, src->fh_size); ++ memcpy(&dst->fh_raw, &src->fh_raw, src->fh_size); + } + + static __inline__ struct svc_fh * +@@ -270,7 +250,7 @@ static inline bool fh_match(struct knfsd_fh *fh1, struct knfsd_fh *fh2) + { + if (fh1->fh_size != fh2->fh_size) + return false; +- if (memcmp(fh1->fh_base.fh_pad, fh2->fh_base.fh_pad, fh1->fh_size) != 0) ++ if (memcmp(fh1->fh_raw, fh2->fh_raw, fh1->fh_size) != 0) + return false; + return true; + } +@@ -294,7 +274,7 @@ static inline bool fh_fsid_match(struct knfsd_fh *fh1, struct knfsd_fh *fh2) + */ + static inline u32 knfsd_fh_hash(const struct knfsd_fh *fh) + { +- return ~crc32_le(0xFFFFFFFF, (unsigned char *)&fh->fh_base, fh->fh_size); ++ return ~crc32_le(0xFFFFFFFF, fh->fh_raw, fh->fh_size); + } + #else + static inline u32 knfsd_fh_hash(const struct knfsd_fh *fh) +diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c +index a06c05fe3b421..082449c7d0dbf 100644 +--- a/fs/nfsd/nfsxdr.c ++++ b/fs/nfsd/nfsxdr.c +@@ -64,7 +64,7 @@ svcxdr_decode_fhandle(struct xdr_stream *xdr, struct svc_fh *fhp) + if (!p) + return false; + fh_init(fhp, NFS_FHSIZE); +- memcpy(&fhp->fh_handle.fh_base, p, NFS_FHSIZE); ++ memcpy(&fhp->fh_handle.fh_raw, p, NFS_FHSIZE); + fhp->fh_handle.fh_size = NFS_FHSIZE; + + return true; +@@ -78,7 +78,7 @@ svcxdr_encode_fhandle(struct xdr_stream *xdr, const struct svc_fh *fhp) + p = xdr_reserve_space(xdr, NFS_FHSIZE); + if (!p) + return false; +- memcpy(p, &fhp->fh_handle.fh_base, NFS_FHSIZE); ++ memcpy(p, &fhp->fh_handle.fh_raw, NFS_FHSIZE); + + return true; + } +-- +2.43.0 + diff --git a/queue-5.10/nfsd-simplify-test_bit-return-in-nfsd_file_key_full-.patch b/queue-5.10/nfsd-simplify-test_bit-return-in-nfsd_file_key_full-.patch new file mode 100644 index 00000000000..cb995abc8a0 --- /dev/null +++ b/queue-5.10/nfsd-simplify-test_bit-return-in-nfsd_file_key_full-.patch @@ -0,0 +1,35 @@ +From e372a4aaa5cfad94ce92902521a3f52d44825d1d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Jan 2023 10:39:01 -0500 +Subject: nfsd: simplify test_bit return in NFSD_FILE_KEY_FULL comparator + +From: Jeff Layton + +[ Upstream commit d69b8dbfd0866abc5ec84652cc1c10fc3d4d91ef ] + +test_bit returns bool, so we can just compare the result of that to the +key->gc value without the "!!". + +Signed-off-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index 4ddc82b84f7c4..d61c8223082a4 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -188,7 +188,7 @@ static int nfsd_file_obj_cmpfn(struct rhashtable_compare_arg *arg, + return 1; + if (!nfsd_match_cred(nf->nf_cred, key->cred)) + return 1; +- if (!!test_bit(NFSD_FILE_GC, &nf->nf_flags) != key->gc) ++ if (test_bit(NFSD_FILE_GC, &nf->nf_flags) != key->gc) + return 1; + if (test_bit(NFSD_FILE_HASHED, &nf->nf_flags) == 0) + return 1; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-simplify-the-delayed-disposal-list-code.patch b/queue-5.10/nfsd-simplify-the-delayed-disposal-list-code.patch new file mode 100644 index 00000000000..feaa757c687 --- /dev/null +++ b/queue-5.10/nfsd-simplify-the-delayed-disposal-list-code.patch @@ -0,0 +1,119 @@ +From 41971d9545b47195080ff7c2ff4de1625baaaa65 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 14 Apr 2023 17:31:44 -0400 +Subject: nfsd: simplify the delayed disposal list code + +From: Jeff Layton + +[ Upstream commit 92e4a6733f922f0fef1d0995f7b2d0eaff86c7ea ] + +When queueing a dispose list to the appropriate "freeme" lists, it +pointlessly queues the objects one at a time to an intermediate list. + +Remove a few helpers and just open code a list_move to make it more +clear and efficient. Better document the resulting functions with +kerneldoc comments. + +Signed-off-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 64 ++++++++++++++++----------------------------- + 1 file changed, 22 insertions(+), 42 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index 52e67ec267965..6b8706f23eaf0 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -401,49 +401,26 @@ nfsd_file_dispose_list(struct list_head *dispose) + } + } + +-static void +-nfsd_file_list_remove_disposal(struct list_head *dst, +- struct nfsd_fcache_disposal *l) +-{ +- spin_lock(&l->lock); +- list_splice_init(&l->freeme, dst); +- spin_unlock(&l->lock); +-} +- +-static void +-nfsd_file_list_add_disposal(struct list_head *files, struct net *net) +-{ +- struct nfsd_net *nn = net_generic(net, nfsd_net_id); +- struct nfsd_fcache_disposal *l = nn->fcache_disposal; +- +- spin_lock(&l->lock); +- list_splice_tail_init(files, &l->freeme); +- spin_unlock(&l->lock); +- queue_work(nfsd_filecache_wq, &l->work); +-} +- +-static void +-nfsd_file_list_add_pernet(struct list_head *dst, struct list_head *src, +- struct net *net) +-{ +- struct nfsd_file *nf, *tmp; +- +- list_for_each_entry_safe(nf, tmp, src, nf_lru) { +- if (nf->nf_net == net) +- list_move_tail(&nf->nf_lru, dst); +- } +-} +- ++/** ++ * nfsd_file_dispose_list_delayed - move list of dead files to net's freeme list ++ * @dispose: list of nfsd_files to be disposed ++ * ++ * Transfers each file to the "freeme" list for its nfsd_net, to eventually ++ * be disposed of by the per-net garbage collector. ++ */ + static void + nfsd_file_dispose_list_delayed(struct list_head *dispose) + { +- LIST_HEAD(list); +- struct nfsd_file *nf; +- + while(!list_empty(dispose)) { +- nf = list_first_entry(dispose, struct nfsd_file, nf_lru); +- nfsd_file_list_add_pernet(&list, dispose, nf->nf_net); +- nfsd_file_list_add_disposal(&list, nf->nf_net); ++ struct nfsd_file *nf = list_first_entry(dispose, ++ struct nfsd_file, nf_lru); ++ struct nfsd_net *nn = net_generic(nf->nf_net, nfsd_net_id); ++ struct nfsd_fcache_disposal *l = nn->fcache_disposal; ++ ++ spin_lock(&l->lock); ++ list_move_tail(&nf->nf_lru, &l->freeme); ++ spin_unlock(&l->lock); ++ queue_work(nfsd_filecache_wq, &l->work); + } + } + +@@ -664,8 +641,8 @@ nfsd_file_close_inode_sync(struct inode *inode) + * nfsd_file_delayed_close - close unused nfsd_files + * @work: dummy + * +- * Walk the LRU list and destroy any entries that have not been used since +- * the last scan. ++ * Scrape the freeme list for this nfsd_net, and then dispose of them ++ * all. + */ + static void + nfsd_file_delayed_close(struct work_struct *work) +@@ -674,7 +651,10 @@ nfsd_file_delayed_close(struct work_struct *work) + struct nfsd_fcache_disposal *l = container_of(work, + struct nfsd_fcache_disposal, work); + +- nfsd_file_list_remove_disposal(&head, l); ++ spin_lock(&l->lock); ++ list_splice_init(&l->freeme, &head); ++ spin_unlock(&l->lock); ++ + nfsd_file_dispose_list(&head); + } + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-skip-extra-computation-for-rc_nocache-case.patch b/queue-5.10/nfsd-skip-extra-computation-for-rc_nocache-case.patch new file mode 100644 index 00000000000..997cfa2f053 --- /dev/null +++ b/queue-5.10/nfsd-skip-extra-computation-for-rc_nocache-case.patch @@ -0,0 +1,52 @@ +From d247f98fb85186fc435b24527c01c27c47acdde3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Sep 2021 11:39:02 -0400 +Subject: NFSD: Skip extra computation for RC_NOCACHE case + +From: Chuck Lever + +[ Upstream commit 0f29ce32fbc56cfdb304eec8a4deb920ccfd89c3 ] + +Force the compiler to skip unneeded initialization for cases that +don't need those values. For example, NFSv4 COMPOUND operations are +RC_NOCACHE. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfscache.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c +index f79790d367288..34087a7e4f93c 100644 +--- a/fs/nfsd/nfscache.c ++++ b/fs/nfsd/nfscache.c +@@ -421,10 +421,10 @@ nfsd_cache_insert(struct nfsd_drc_bucket *b, struct svc_cacherep *key, + */ + int nfsd_cache_lookup(struct svc_rqst *rqstp) + { +- struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); ++ struct nfsd_net *nn; + struct svc_cacherep *rp, *found; + __wsum csum; +- struct nfsd_drc_bucket *b = nfsd_cache_bucket_find(rqstp->rq_xid, nn); ++ struct nfsd_drc_bucket *b; + int type = rqstp->rq_cachetype; + int rtn = RC_DOIT; + +@@ -440,10 +440,12 @@ int nfsd_cache_lookup(struct svc_rqst *rqstp) + * Since the common case is a cache miss followed by an insert, + * preallocate an entry. + */ ++ nn = net_generic(SVC_NET(rqstp), nfsd_net_id); + rp = nfsd_reply_cache_alloc(rqstp, csum, nn); + if (!rp) + goto out; + ++ b = nfsd_cache_bucket_find(rqstp->rq_xid, nn); + spin_lock(&b->cache_lock); + found = nfsd_cache_insert(b, rp, nn); + if (found != rp) { +-- +2.43.0 + diff --git a/queue-5.10/nfsd-skip-some-unnecessary-stats-in-the-v4-case.patch b/queue-5.10/nfsd-skip-some-unnecessary-stats-in-the-v4-case.patch new file mode 100644 index 00000000000..849c3d25024 --- /dev/null +++ b/queue-5.10/nfsd-skip-some-unnecessary-stats-in-the-v4-case.patch @@ -0,0 +1,108 @@ +From 64a8b8f5a32dc8a9c3d7fd24302acc342e272625 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 Jan 2021 14:27:01 -0500 +Subject: nfsd: skip some unnecessary stats in the v4 case + +From: J. Bruce Fields + +[ Upstream commit 428a23d2bf0ca8fd4d364a464c3e468f0e81671e ] + +In the typical case of v4 and an i_version-supporting filesystem, we can +skip a stat which is only required to fake up a change attribute from +ctime. + +Signed-off-by: J. Bruce Fields +Reviewed-by: Christoph Hellwig +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3xdr.c | 44 +++++++++++++++++++++++++++----------------- + 1 file changed, 27 insertions(+), 17 deletions(-) + +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index 00a96054280a6..9d9a01ce0b270 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -364,6 +364,11 @@ encode_wcc_data(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp) + return encode_post_op_attr(rqstp, p, fhp); + } + ++static bool fs_supports_change_attribute(struct super_block *sb) ++{ ++ return sb->s_flags & SB_I_VERSION || sb->s_export_op->fetch_iversion; ++} ++ + /* + * Fill in the pre_op attr for the wcc data + */ +@@ -372,24 +377,26 @@ void fill_pre_wcc(struct svc_fh *fhp) + struct inode *inode; + struct kstat stat; + bool v4 = (fhp->fh_maxsize == NFS4_FHSIZE); +- __be32 err; + + if (fhp->fh_no_wcc || fhp->fh_pre_saved) + return; + inode = d_inode(fhp->fh_dentry); +- err = fh_getattr(fhp, &stat); +- if (err) { +- /* Grab the times from inode anyway */ +- stat.mtime = inode->i_mtime; +- stat.ctime = inode->i_ctime; +- stat.size = inode->i_size; ++ if (fs_supports_change_attribute(inode->i_sb) || !v4) { ++ __be32 err = fh_getattr(fhp, &stat); ++ ++ if (err) { ++ /* Grab the times from inode anyway */ ++ stat.mtime = inode->i_mtime; ++ stat.ctime = inode->i_ctime; ++ stat.size = inode->i_size; ++ } ++ fhp->fh_pre_mtime = stat.mtime; ++ fhp->fh_pre_ctime = stat.ctime; ++ fhp->fh_pre_size = stat.size; + } + if (v4) + fhp->fh_pre_change = nfsd4_change_attribute(&stat, inode); + +- fhp->fh_pre_mtime = stat.mtime; +- fhp->fh_pre_ctime = stat.ctime; +- fhp->fh_pre_size = stat.size; + fhp->fh_pre_saved = true; + } + +@@ -400,7 +407,6 @@ void fill_post_wcc(struct svc_fh *fhp) + { + bool v4 = (fhp->fh_maxsize == NFS4_FHSIZE); + struct inode *inode = d_inode(fhp->fh_dentry); +- __be32 err; + + if (fhp->fh_no_wcc) + return; +@@ -408,12 +414,16 @@ void fill_post_wcc(struct svc_fh *fhp) + if (fhp->fh_post_saved) + printk("nfsd: inode locked twice during operation.\n"); + +- err = fh_getattr(fhp, &fhp->fh_post_attr); +- if (err) { +- fhp->fh_post_saved = false; +- fhp->fh_post_attr.ctime = inode->i_ctime; +- } else +- fhp->fh_post_saved = true; ++ fhp->fh_post_saved = true; ++ ++ if (fs_supports_change_attribute(inode->i_sb) || !v4) { ++ __be32 err = fh_getattr(fhp, &fhp->fh_post_attr); ++ ++ if (err) { ++ fhp->fh_post_saved = false; ++ fhp->fh_post_attr.ctime = inode->i_ctime; ++ } ++ } + if (v4) + fhp->fh_post_change = + nfsd4_change_attribute(&fhp->fh_post_attr, inode); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-streamline-the-rare-found-case.patch b/queue-5.10/nfsd-streamline-the-rare-found-case.patch new file mode 100644 index 00000000000..c30164004ed --- /dev/null +++ b/queue-5.10/nfsd-streamline-the-rare-found-case.patch @@ -0,0 +1,51 @@ +From 7888d5186692bd59bde41ae0a8d68e3b908c636f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Sep 2021 11:40:59 -0400 +Subject: NFSD: Streamline the rare "found" case + +From: Chuck Lever + +[ Upstream commit add1511c38166cf1036765f8c4aa939f0275a799 ] + +Move a rarely called function call site out of the hot path. + +This is an exceptionally small improvement because the compiler +inlines most of the functions that nfsd_cache_lookup() calls. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfscache.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c +index 34087a7e4f93c..0b3f12aa37ff5 100644 +--- a/fs/nfsd/nfscache.c ++++ b/fs/nfsd/nfscache.c +@@ -448,11 +448,8 @@ int nfsd_cache_lookup(struct svc_rqst *rqstp) + b = nfsd_cache_bucket_find(rqstp->rq_xid, nn); + spin_lock(&b->cache_lock); + found = nfsd_cache_insert(b, rp, nn); +- if (found != rp) { +- nfsd_reply_cache_free_locked(NULL, rp, nn); +- rp = found; ++ if (found != rp) + goto found_entry; +- } + + nfsd_stats_rc_misses_inc(); + rqstp->rq_cacherep = rp; +@@ -470,8 +467,10 @@ int nfsd_cache_lookup(struct svc_rqst *rqstp) + + found_entry: + /* We found a matching entry which is either in progress or done. */ ++ nfsd_reply_cache_free_locked(NULL, rp, nn); + nfsd_stats_rc_hits_inc(); + rtn = RC_DROPIT; ++ rp = found; + + /* Request being processed */ + if (rp->c_state == RC_INPROG) +-- +2.43.0 + diff --git a/queue-5.10/nfsd-trace-boot-verifier-resets.patch b/queue-5.10/nfsd-trace-boot-verifier-resets.patch new file mode 100644 index 00000000000..38366b9c545 --- /dev/null +++ b/queue-5.10/nfsd-trace-boot-verifier-resets.patch @@ -0,0 +1,120 @@ +From e17f660eb21dac129ccd47afc449072189830b31 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 28 Dec 2021 14:27:56 -0500 +Subject: NFSD: Trace boot verifier resets + +From: Chuck Lever + +[ Upstream commit 75acacb6583df0b9328dc701d8eeea05af49b8b5 ] + +According to commit bbf2f098838a ("nfsd: Reset the boot verifier on +all write I/O errors"), the Linux NFS server forces all clients to +resend pending unstable writes if any server-side write or commit +operation encounters an error (say, ENOSPC). This is a rare and +quite exceptional event that could require administrative recovery +action, so it should be made trace-able. Example trace event: + +nfsd-938 [002] 7174.945558: nfsd_writeverf_reset: boot_time= 61cc920d xid=0xdcd62036 error=-28 new verifier=0x08aecc6142515904 + +[ cel: adjusted to apply to v5.10.y ] +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/trace.h | 28 ++++++++++++++++++++++++++++ + fs/nfsd/vfs.c | 13 ++++++++++--- + 2 files changed, 38 insertions(+), 3 deletions(-) + +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index 199b485c77179..8327d1601d710 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -575,6 +575,34 @@ DEFINE_EVENT(nfsd_net_class, nfsd_##name, \ + DEFINE_NET_EVENT(grace_start); + DEFINE_NET_EVENT(grace_complete); + ++TRACE_EVENT(nfsd_writeverf_reset, ++ TP_PROTO( ++ const struct nfsd_net *nn, ++ const struct svc_rqst *rqstp, ++ int error ++ ), ++ TP_ARGS(nn, rqstp, error), ++ TP_STRUCT__entry( ++ __field(unsigned long long, boot_time) ++ __field(u32, xid) ++ __field(int, error) ++ __array(unsigned char, verifier, NFS4_VERIFIER_SIZE) ++ ), ++ TP_fast_assign( ++ __entry->boot_time = nn->boot_time; ++ __entry->xid = be32_to_cpu(rqstp->rq_xid); ++ __entry->error = error; ++ ++ /* avoid seqlock inside TP_fast_assign */ ++ memcpy(__entry->verifier, nn->writeverf, ++ NFS4_VERIFIER_SIZE); ++ ), ++ TP_printk("boot_time=%16llx xid=0x%08x error=%d new verifier=0x%s", ++ __entry->boot_time, __entry->xid, __entry->error, ++ __print_hex_str(__entry->verifier, NFS4_VERIFIER_SIZE) ++ ) ++); ++ + TRACE_EVENT(nfsd_clid_cred_mismatch, + TP_PROTO( + const struct nfs4_client *clp, +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index 8cf053b698314..77f48779210d0 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -566,14 +566,17 @@ __be32 nfsd4_clone_file_range(struct svc_rqst *rqstp, + if (!status) + status = commit_inode_metadata(file_inode(src)); + if (status < 0) { ++ struct nfsd_net *nn = net_generic(nf_dst->nf_net, ++ nfsd_net_id); ++ + trace_nfsd_clone_file_range_err(rqstp, + &nfsd4_get_cstate(rqstp)->save_fh, + src_pos, + &nfsd4_get_cstate(rqstp)->current_fh, + dst_pos, + count, status); +- nfsd_reset_write_verifier(net_generic(nf_dst->nf_net, +- nfsd_net_id)); ++ nfsd_reset_write_verifier(nn); ++ trace_nfsd_writeverf_reset(nn, rqstp, status); + ret = nfserrno(status); + } + } +@@ -1043,6 +1046,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf, + host_err = vfs_iter_write(file, &iter, &pos, flags); + if (host_err < 0) { + nfsd_reset_write_verifier(nn); ++ trace_nfsd_writeverf_reset(nn, rqstp, host_err); + goto out_nfserr; + } + *cnt = host_err; +@@ -1054,8 +1058,10 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf, + + if (stable && use_wgather) { + host_err = wait_for_concurrent_writes(file); +- if (host_err < 0) ++ if (host_err < 0) { + nfsd_reset_write_verifier(nn); ++ trace_nfsd_writeverf_reset(nn, rqstp, host_err); ++ } + } + + out_nfserr: +@@ -1178,6 +1184,7 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, + break; + default: + nfsd_reset_write_verifier(nn); ++ trace_nfsd_writeverf_reset(nn, rqstp, err2); + err = nfserrno(err2); + } + } else +-- +2.43.0 + diff --git a/queue-5.10/nfsd-trace-delegation-revocations.patch b/queue-5.10/nfsd-trace-delegation-revocations.patch new file mode 100644 index 00000000000..88405051e27 --- /dev/null +++ b/queue-5.10/nfsd-trace-delegation-revocations.patch @@ -0,0 +1,111 @@ +From 18a00f1019c2b4815da280a2cf129aaab1b12f4e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Oct 2022 10:47:09 -0400 +Subject: NFSD: Trace delegation revocations + +From: Chuck Lever + +[ Upstream commit a1c74569bbde91299f24535abf711be5c84df9de ] + +Delegation revocation is an exceptional event that is not otherwise +visible externally (eg, no network traffic is emitted). Generate a +trace record when it occurs so that revocation can be observed or +other activity can be triggered. Example: + +nfsd-1104 [005] 1912.002544: nfsd_stid_revoke: client 633c9343:4e82788d stateid 00000003:00000001 ref=2 type=DELEG + +Trace infrastructure is provided for subsequent additional tracing +related to nfs4_stid activity. + +Signed-off-by: Chuck Lever +Tested-by: Jeff Layton +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 2 ++ + fs/nfsd/trace.h | 55 +++++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 57 insertions(+) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index a40a9a836fb1e..dcbf777dc58d3 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -1366,6 +1366,8 @@ static void revoke_delegation(struct nfs4_delegation *dp) + + WARN_ON(!list_empty(&dp->dl_recall_lru)); + ++ trace_nfsd_stid_revoke(&dp->dl_stid); ++ + if (clp->cl_minorversion) { + spin_lock(&clp->cl_lock); + dp->dl_stid.sc_type = NFS4_REVOKED_DELEG_STID; +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index fe76d3b2c9286..191b206379b76 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -550,6 +550,61 @@ DEFINE_EVENT(nfsd_stateseqid_class, nfsd_##name, \ + DEFINE_STATESEQID_EVENT(preprocess); + DEFINE_STATESEQID_EVENT(open_confirm); + ++TRACE_DEFINE_ENUM(NFS4_OPEN_STID); ++TRACE_DEFINE_ENUM(NFS4_LOCK_STID); ++TRACE_DEFINE_ENUM(NFS4_DELEG_STID); ++TRACE_DEFINE_ENUM(NFS4_CLOSED_STID); ++TRACE_DEFINE_ENUM(NFS4_REVOKED_DELEG_STID); ++TRACE_DEFINE_ENUM(NFS4_CLOSED_DELEG_STID); ++TRACE_DEFINE_ENUM(NFS4_LAYOUT_STID); ++ ++#define show_stid_type(x) \ ++ __print_flags(x, "|", \ ++ { NFS4_OPEN_STID, "OPEN" }, \ ++ { NFS4_LOCK_STID, "LOCK" }, \ ++ { NFS4_DELEG_STID, "DELEG" }, \ ++ { NFS4_CLOSED_STID, "CLOSED" }, \ ++ { NFS4_REVOKED_DELEG_STID, "REVOKED" }, \ ++ { NFS4_CLOSED_DELEG_STID, "CLOSED_DELEG" }, \ ++ { NFS4_LAYOUT_STID, "LAYOUT" }) ++ ++DECLARE_EVENT_CLASS(nfsd_stid_class, ++ TP_PROTO( ++ const struct nfs4_stid *stid ++ ), ++ TP_ARGS(stid), ++ TP_STRUCT__entry( ++ __field(unsigned long, sc_type) ++ __field(int, sc_count) ++ __field(u32, cl_boot) ++ __field(u32, cl_id) ++ __field(u32, si_id) ++ __field(u32, si_generation) ++ ), ++ TP_fast_assign( ++ const stateid_t *stp = &stid->sc_stateid; ++ ++ __entry->sc_type = stid->sc_type; ++ __entry->sc_count = refcount_read(&stid->sc_count); ++ __entry->cl_boot = stp->si_opaque.so_clid.cl_boot; ++ __entry->cl_id = stp->si_opaque.so_clid.cl_id; ++ __entry->si_id = stp->si_opaque.so_id; ++ __entry->si_generation = stp->si_generation; ++ ), ++ TP_printk("client %08x:%08x stateid %08x:%08x ref=%d type=%s", ++ __entry->cl_boot, __entry->cl_id, ++ __entry->si_id, __entry->si_generation, ++ __entry->sc_count, show_stid_type(__entry->sc_type) ++ ) ++); ++ ++#define DEFINE_STID_EVENT(name) \ ++DEFINE_EVENT(nfsd_stid_class, nfsd_stid_##name, \ ++ TP_PROTO(const struct nfs4_stid *stid), \ ++ TP_ARGS(stid)) ++ ++DEFINE_STID_EVENT(revoke); ++ + DECLARE_EVENT_CLASS(nfsd_clientid_class, + TP_PROTO(const clientid_t *clid), + TP_ARGS(clid), +-- +2.43.0 + diff --git a/queue-5.10/nfsd-trace-filecache-lru-activity.patch b/queue-5.10/nfsd-trace-filecache-lru-activity.patch new file mode 100644 index 00000000000..4268a361750 --- /dev/null +++ b/queue-5.10/nfsd-trace-filecache-lru-activity.patch @@ -0,0 +1,160 @@ +From 090933b3d27b5c514be9dd34e98ca55cdde90ce3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 Jul 2022 14:25:11 -0400 +Subject: NFSD: Trace filecache LRU activity + +From: Chuck Lever + +[ Upstream commit c46203acddd9b9200dbc53d0603c97355fd3a03b ] + +Observe the operation of garbage collection and the lifetime of +filecache items. + +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 44 +++++++++++++++++++++++++++++++------------- + fs/nfsd/trace.h | 39 +++++++++++++++++++++++++++++++++++++++ + 2 files changed, 70 insertions(+), 13 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index d9b5f1e183976..a995a744a7481 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -260,6 +260,18 @@ nfsd_file_flush(struct nfsd_file *nf) + nfsd_reset_write_verifier(net_generic(nf->nf_net, nfsd_net_id)); + } + ++static void nfsd_file_lru_add(struct nfsd_file *nf) ++{ ++ if (list_lru_add(&nfsd_file_lru, &nf->nf_lru)) ++ trace_nfsd_file_lru_add(nf); ++} ++ ++static void nfsd_file_lru_remove(struct nfsd_file *nf) ++{ ++ if (list_lru_del(&nfsd_file_lru, &nf->nf_lru)) ++ trace_nfsd_file_lru_del(nf); ++} ++ + static void + nfsd_file_do_unhash(struct nfsd_file *nf) + { +@@ -279,8 +291,7 @@ nfsd_file_unhash(struct nfsd_file *nf) + { + if (test_and_clear_bit(NFSD_FILE_HASHED, &nf->nf_flags)) { + nfsd_file_do_unhash(nf); +- if (!list_empty(&nf->nf_lru)) +- list_lru_del(&nfsd_file_lru, &nf->nf_lru); ++ nfsd_file_lru_remove(nf); + return true; + } + return false; +@@ -443,27 +454,34 @@ nfsd_file_lru_cb(struct list_head *item, struct list_lru_one *lru, + * counter. Here we check the counter and then test and clear the flag. + * That order is deliberate to ensure that we can do this locklessly. + */ +- if (refcount_read(&nf->nf_ref) > 1) +- goto out_skip; ++ if (refcount_read(&nf->nf_ref) > 1) { ++ trace_nfsd_file_gc_in_use(nf); ++ return LRU_SKIP; ++ } + + /* + * Don't throw out files that are still undergoing I/O or + * that have uncleared errors pending. + */ +- if (nfsd_file_check_writeback(nf)) +- goto out_skip; ++ if (nfsd_file_check_writeback(nf)) { ++ trace_nfsd_file_gc_writeback(nf); ++ return LRU_SKIP; ++ } + +- if (test_and_clear_bit(NFSD_FILE_REFERENCED, &nf->nf_flags)) +- goto out_skip; ++ if (test_and_clear_bit(NFSD_FILE_REFERENCED, &nf->nf_flags)) { ++ trace_nfsd_file_gc_referenced(nf); ++ return LRU_SKIP; ++ } + +- if (!test_and_clear_bit(NFSD_FILE_HASHED, &nf->nf_flags)) +- goto out_skip; ++ if (!test_and_clear_bit(NFSD_FILE_HASHED, &nf->nf_flags)) { ++ trace_nfsd_file_gc_hashed(nf); ++ return LRU_SKIP; ++ } + + list_lru_isolate_move(lru, &nf->nf_lru, head); + this_cpu_inc(nfsd_file_evictions); ++ trace_nfsd_file_gc_disposed(nf); + return LRU_REMOVED; +-out_skip: +- return LRU_SKIP; + } + + /* +@@ -1016,7 +1034,7 @@ nfsd_do_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + refcount_inc(&nf->nf_ref); + __set_bit(NFSD_FILE_HASHED, &nf->nf_flags); + __set_bit(NFSD_FILE_PENDING, &nf->nf_flags); +- list_lru_add(&nfsd_file_lru, &nf->nf_lru); ++ nfsd_file_lru_add(nf); + hlist_add_head_rcu(&nf->nf_node, &nfsd_file_hashtbl[hashval].nfb_head); + ++nfsd_file_hashtbl[hashval].nfb_count; + nfsd_file_hashtbl[hashval].nfb_maxcount = max(nfsd_file_hashtbl[hashval].nfb_maxcount, +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index b373a161e862b..b1aa28c062ac5 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -860,6 +860,45 @@ TRACE_EVENT(nfsd_file_fsnotify_handle_event, + __entry->nlink, __entry->mode, __entry->mask) + ); + ++DECLARE_EVENT_CLASS(nfsd_file_gc_class, ++ TP_PROTO( ++ const struct nfsd_file *nf ++ ), ++ TP_ARGS(nf), ++ TP_STRUCT__entry( ++ __field(void *, nf_inode) ++ __field(void *, nf_file) ++ __field(int, nf_ref) ++ __field(unsigned long, nf_flags) ++ ), ++ TP_fast_assign( ++ __entry->nf_inode = nf->nf_inode; ++ __entry->nf_file = nf->nf_file; ++ __entry->nf_ref = refcount_read(&nf->nf_ref); ++ __entry->nf_flags = nf->nf_flags; ++ ), ++ TP_printk("inode=%p ref=%d nf_flags=%s nf_file=%p", ++ __entry->nf_inode, __entry->nf_ref, ++ show_nf_flags(__entry->nf_flags), ++ __entry->nf_file ++ ) ++); ++ ++#define DEFINE_NFSD_FILE_GC_EVENT(name) \ ++DEFINE_EVENT(nfsd_file_gc_class, name, \ ++ TP_PROTO( \ ++ const struct nfsd_file *nf \ ++ ), \ ++ TP_ARGS(nf)) ++ ++DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_lru_add); ++DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_lru_del); ++DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_gc_in_use); ++DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_gc_writeback); ++DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_gc_referenced); ++DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_gc_hashed); ++DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_gc_disposed); ++ + DECLARE_EVENT_CLASS(nfsd_file_lruwalk_class, + TP_PROTO( + unsigned long removed, +-- +2.43.0 + diff --git a/queue-5.10/nfsd-trace-filecache-opens.patch b/queue-5.10/nfsd-trace-filecache-opens.patch new file mode 100644 index 00000000000..197b24ca701 --- /dev/null +++ b/queue-5.10/nfsd-trace-filecache-opens.patch @@ -0,0 +1,79 @@ +From e4ab492d4d2e1fe5ac810650dc2dc9cddd6d5cdd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sun, 27 Mar 2022 16:42:20 -0400 +Subject: NFSD: Trace filecache opens + +From: Chuck Lever + +[ Upstream commit 0122e882119ddbd9efa6edfeeac3f5c704a7aeea ] + +Instrument calls to nfsd_open_verified() to get a sense of the +filecache hit rate. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 5 +++-- + fs/nfsd/trace.h | 28 ++++++++++++++++++++++++++++ + 2 files changed, 31 insertions(+), 2 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index db9c68a3c1f3b..bdb5de8c08036 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -996,10 +996,11 @@ nfsd_do_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + + nf->nf_mark = nfsd_file_mark_find_or_create(nf); + if (nf->nf_mark) { +- if (open) ++ if (open) { + status = nfsd_open_verified(rqstp, fhp, may_flags, + &nf->nf_file); +- else ++ trace_nfsd_file_open(nf, status); ++ } else + status = nfs_ok; + } else + status = nfserr_jukebox; +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index 8327d1601d710..c4c073e85fdd9 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -795,6 +795,34 @@ TRACE_EVENT(nfsd_file_acquire, + __entry->nf_file, __entry->status) + ); + ++TRACE_EVENT(nfsd_file_open, ++ TP_PROTO(struct nfsd_file *nf, __be32 status), ++ TP_ARGS(nf, status), ++ TP_STRUCT__entry( ++ __field(unsigned int, nf_hashval) ++ __field(void *, nf_inode) /* cannot be dereferenced */ ++ __field(int, nf_ref) ++ __field(unsigned long, nf_flags) ++ __field(unsigned long, nf_may) ++ __field(void *, nf_file) /* cannot be dereferenced */ ++ ), ++ TP_fast_assign( ++ __entry->nf_hashval = nf->nf_hashval; ++ __entry->nf_inode = nf->nf_inode; ++ __entry->nf_ref = refcount_read(&nf->nf_ref); ++ __entry->nf_flags = nf->nf_flags; ++ __entry->nf_may = nf->nf_may; ++ __entry->nf_file = nf->nf_file; ++ ), ++ TP_printk("hash=0x%x inode=%p ref=%d flags=%s may=%s file=%p", ++ __entry->nf_hashval, ++ __entry->nf_inode, ++ __entry->nf_ref, ++ show_nf_flags(__entry->nf_flags), ++ show_nfsd_may_flags(__entry->nf_may), ++ __entry->nf_file) ++) ++ + DECLARE_EVENT_CLASS(nfsd_file_search_class, + TP_PROTO(struct inode *inode, unsigned int hash, int found), + TP_ARGS(inode, hash, found), +-- +2.43.0 + diff --git a/queue-5.10/nfsd-trace-stateids-returned-via-delegreturn.patch b/queue-5.10/nfsd-trace-stateids-returned-via-delegreturn.patch new file mode 100644 index 00000000000..ed549356e45 --- /dev/null +++ b/queue-5.10/nfsd-trace-stateids-returned-via-delegreturn.patch @@ -0,0 +1,49 @@ +From 6c0fd1ca4f9d58281f4d0056f5d7a064047d9eed Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Oct 2022 10:47:03 -0400 +Subject: NFSD: Trace stateids returned via DELEGRETURN + +From: Chuck Lever + +[ Upstream commit 20eee313ff4b8a7e71ae9560f5c4ba27cd763005 ] + +Handing out a delegation stateid is recorded with the +nfsd_deleg_read tracepoint, but there isn't a matching tracepoint +for recording when the stateid is returned. + +Signed-off-by: Chuck Lever +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 1 + + fs/nfsd/trace.h | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 80d8f40d1f126..a40a9a836fb1e 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -6929,6 +6929,7 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + if (status) + goto put_stateid; + ++ trace_nfsd_deleg_return(stateid); + wake_up_var(d_inode(cstate->current_fh.fh_dentry)); + destroy_delegation(dp); + put_stateid: +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index 03722414d6db8..fe76d3b2c9286 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -517,6 +517,7 @@ DEFINE_STATEID_EVENT(layout_recall_release); + + DEFINE_STATEID_EVENT(open); + DEFINE_STATEID_EVENT(deleg_read); ++DEFINE_STATEID_EVENT(deleg_return); + DEFINE_STATEID_EVENT(deleg_recall); + + DECLARE_EVENT_CLASS(nfsd_stateseqid_class, +-- +2.43.0 + diff --git a/queue-5.10/nfsd-track-filehandle-aliasing-in-nfs4_files.patch b/queue-5.10/nfsd-track-filehandle-aliasing-in-nfs4_files.patch new file mode 100644 index 00000000000..54e69a50c6a --- /dev/null +++ b/queue-5.10/nfsd-track-filehandle-aliasing-in-nfs4_files.patch @@ -0,0 +1,102 @@ +From d9661e72f07c0cc0d194ba7f0f1de8b927052cfa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 16 Apr 2021 14:00:16 -0400 +Subject: nfsd: track filehandle aliasing in nfs4_files + +From: J. Bruce Fields + +[ Upstream commit a0ce48375a367222989c2618fe68bf34db8c7bb7 ] + +It's unusual but possible for multiple filehandles to point to the same +file. In that case, we may end up with multiple nfs4_files referencing +the same inode. + +For delegation purposes it will turn out to be useful to flag those +cases. + +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 37 ++++++++++++++++++++++++++++--------- + fs/nfsd/state.h | 2 ++ + 2 files changed, 30 insertions(+), 9 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 8d2d6e90bfc5e..89d5669ce1463 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -4120,6 +4120,8 @@ static void nfsd4_init_file(struct svc_fh *fh, unsigned int hashval, + fp->fi_share_deny = 0; + memset(fp->fi_fds, 0, sizeof(fp->fi_fds)); + memset(fp->fi_access, 0, sizeof(fp->fi_access)); ++ fp->fi_aliased = false; ++ fp->fi_inode = d_inode(fh->fh_dentry); + #ifdef CONFIG_NFSD_PNFS + INIT_LIST_HEAD(&fp->fi_lo_states); + atomic_set(&fp->fi_lo_recalls, 0); +@@ -4472,6 +4474,31 @@ find_file_locked(struct svc_fh *fh, unsigned int hashval) + return NULL; + } + ++static struct nfs4_file *insert_file(struct nfs4_file *new, struct svc_fh *fh, ++ unsigned int hashval) ++{ ++ struct nfs4_file *fp; ++ struct nfs4_file *ret = NULL; ++ bool alias_found = false; ++ ++ spin_lock(&state_lock); ++ hlist_for_each_entry_rcu(fp, &file_hashtbl[hashval], fi_hash, ++ lockdep_is_held(&state_lock)) { ++ if (fh_match(&fp->fi_fhandle, &fh->fh_handle)) { ++ if (refcount_inc_not_zero(&fp->fi_ref)) ++ ret = fp; ++ } else if (d_inode(fh->fh_dentry) == fp->fi_inode) ++ fp->fi_aliased = alias_found = true; ++ } ++ if (likely(ret == NULL)) { ++ nfsd4_init_file(fh, hashval, new); ++ new->fi_aliased = alias_found; ++ ret = new; ++ } ++ spin_unlock(&state_lock); ++ return ret; ++} ++ + static struct nfs4_file * find_file(struct svc_fh *fh) + { + struct nfs4_file *fp; +@@ -4495,15 +4522,7 @@ find_or_add_file(struct nfs4_file *new, struct svc_fh *fh) + if (fp) + return fp; + +- spin_lock(&state_lock); +- fp = find_file_locked(fh, hashval); +- if (likely(fp == NULL)) { +- nfsd4_init_file(fh, hashval, new); +- fp = new; +- } +- spin_unlock(&state_lock); +- +- return fp; ++ return insert_file(new, fh, hashval); + } + + /* +diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h +index 61a2d95d79233..e73bdbb1634ab 100644 +--- a/fs/nfsd/state.h ++++ b/fs/nfsd/state.h +@@ -516,6 +516,8 @@ struct nfs4_clnt_odstate { + */ + struct nfs4_file { + refcount_t fi_ref; ++ struct inode * fi_inode; ++ bool fi_aliased; + spinlock_t fi_lock; + struct hlist_node fi_hash; /* hash on fi_fhandle */ + struct list_head fi_stateids; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-unregister-shrinker-when-nfsd_init_net-fails.patch b/queue-5.10/nfsd-unregister-shrinker-when-nfsd_init_net-fails.patch new file mode 100644 index 00000000000..1e633130ce1 --- /dev/null +++ b/queue-5.10/nfsd-unregister-shrinker-when-nfsd_init_net-fails.patch @@ -0,0 +1,51 @@ +From 95d56ec398cd10f2b81607d1e2ecdde4e0aa7c6f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 10 Oct 2022 14:59:02 +0900 +Subject: NFSD: unregister shrinker when nfsd_init_net() fails + +From: Tetsuo Handa + +[ Upstream commit bd86c69dae65de30f6d47249418ba7889809e31a ] + +syzbot is reporting UAF read at register_shrinker_prepared() [1], for +commit 7746b32f467b3813 ("NFSD: add shrinker to reap courtesy clients on +low memory condition") missed that nfsd4_leases_net_shutdown() from +nfsd_exit_net() is called only when nfsd_init_net() succeeded. +If nfsd_init_net() fails due to nfsd_reply_cache_init() failure, +register_shrinker() from nfsd4_init_leases_net() has to be undone +before nfsd_init_net() returns. + +Link: https://syzkaller.appspot.com/bug?extid=ff796f04613b4c84ad89 [1] +Reported-by: syzbot +Signed-off-by: Tetsuo Handa +Fixes: 7746b32f467b3813 ("NFSD: add shrinker to reap courtesy clients on low memory condition") +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsctl.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c +index 6a29bcfc93909..dc74a947a440c 100644 +--- a/fs/nfsd/nfsctl.c ++++ b/fs/nfsd/nfsctl.c +@@ -1458,12 +1458,14 @@ static __net_init int nfsd_init_net(struct net *net) + goto out_drc_error; + retval = nfsd_reply_cache_init(nn); + if (retval) +- goto out_drc_error; ++ goto out_cache_error; + get_random_bytes(&nn->siphash_key, sizeof(nn->siphash_key)); + seqlock_init(&nn->writeverf_lock); + + return 0; + ++out_cache_error: ++ nfsd4_leases_net_shutdown(nn); + out_drc_error: + nfsd_idmap_shutdown(net); + out_idmap_error: +-- +2.43.0 + diff --git a/queue-5.10/nfsd-unregister-the-cld-notifier-when-laundry_wq-cre.patch b/queue-5.10/nfsd-unregister-the-cld-notifier-when-laundry_wq-cre.patch new file mode 100644 index 00000000000..60c92bdd0f4 --- /dev/null +++ b/queue-5.10/nfsd-unregister-the-cld-notifier-when-laundry_wq-cre.patch @@ -0,0 +1,41 @@ +From 0dbb8256c02ed05844184c55e19f6b229d373390 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 21 May 2022 12:08:44 +0800 +Subject: nfsd: Unregister the cld notifier when laundry_wq create failed + +From: Zhang Xiaoxu + +[ Upstream commit 62fdb65edb6c43306c774939001f3a00974832aa ] + +If laundry_wq create failed, the cld notifier should be unregistered. + +Signed-off-by: Zhang Xiaoxu +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsctl.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c +index 322a208878f2c..55949e60897d5 100644 +--- a/fs/nfsd/nfsctl.c ++++ b/fs/nfsd/nfsctl.c +@@ -1543,12 +1543,14 @@ static int __init init_nfsd(void) + goto out_free_filesystem; + retval = register_cld_notifier(); + if (retval) +- goto out_free_all; ++ goto out_free_subsys; + retval = nfsd4_create_laundry_wq(); + if (retval) + goto out_free_all; + return 0; + out_free_all: ++ unregister_cld_notifier(); ++out_free_subsys: + unregister_pernet_subsys(&nfsd_net_ops); + out_free_filesystem: + unregister_filesystem(&nfsd_fs_type); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-access3arg-decoder-to-use-struct-xdr_str.patch b/queue-5.10/nfsd-update-access3arg-decoder-to-use-struct-xdr_str.patch new file mode 100644 index 00000000000..4bea01177f0 --- /dev/null +++ b/queue-5.10/nfsd-update-access3arg-decoder-to-use-struct-xdr_str.patch @@ -0,0 +1,56 @@ +From c0167ea4b83ef3450ca760ad259180d68ae24a22 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Oct 2020 14:32:04 -0400 +Subject: NFSD: Update ACCESS3arg decoder to use struct xdr_stream + +From: Chuck Lever + +[ Upstream commit 3b921a2b14251e9e203f1e8af76e8ade79f50e50 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3xdr.c | 9 +++++---- + fs/nfsd/xdr3.h | 2 +- + 2 files changed, 6 insertions(+), 5 deletions(-) + +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index 3a2b4abea1a42..e07cebd80ef7f 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -375,14 +375,15 @@ nfs3svc_decode_diropargs(struct svc_rqst *rqstp, __be32 *p) + int + nfs3svc_decode_accessargs(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd3_accessargs *args = rqstp->rq_argp; + +- p = decode_fh(p, &args->fh); +- if (!p) ++ if (!svcxdr_decode_nfs_fh3(xdr, &args->fh)) ++ return 0; ++ if (xdr_stream_decode_u32(xdr, &args->access) < 0) + return 0; +- args->access = ntohl(*p++); + +- return xdr_argsize_check(rqstp, p); ++ return 1; + } + + int +diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h +index 62ea669768cf3..a4dce4baec7c3 100644 +--- a/fs/nfsd/xdr3.h ++++ b/fs/nfsd/xdr3.h +@@ -25,7 +25,7 @@ struct nfsd3_diropargs { + + struct nfsd3_accessargs { + struct svc_fh fh; +- unsigned int access; ++ __u32 access; + }; + + struct nfsd3_readargs { +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-comment-over-__nfsd_file_cache_purge.patch b/queue-5.10/nfsd-update-comment-over-__nfsd_file_cache_purge.patch new file mode 100644 index 00000000000..dd9d4a72ccc --- /dev/null +++ b/queue-5.10/nfsd-update-comment-over-__nfsd_file_cache_purge.patch @@ -0,0 +1,33 @@ +From e23f571d842008aa1b68e56bf1075c4ef0f1b1fc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 26 Jan 2023 12:21:16 -0500 +Subject: nfsd: update comment over __nfsd_file_cache_purge + +From: Jeff Layton + +[ Upstream commit 972cc0e0924598cb293b919d39c848dc038b2c28 ] + +Signed-off-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index 786e06cf107ff..1d4c0387c4192 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -906,7 +906,8 @@ nfsd_file_cache_init(void) + * @net: net-namespace to shut down the cache (may be NULL) + * + * Walk the nfsd_file cache and close out any that match @net. If @net is NULL, +- * then close out everything. Called when an nfsd instance is being shut down. ++ * then close out everything. Called when an nfsd instance is being shut down, ++ * and when the exports table is flushed. + */ + static void + __nfsd_file_cache_purge(struct net *net) +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-commit3arg-decoder-to-use-struct-xdr_str.patch b/queue-5.10/nfsd-update-commit3arg-decoder-to-use-struct-xdr_str.patch new file mode 100644 index 00000000000..aa08c634e5f --- /dev/null +++ b/queue-5.10/nfsd-update-commit3arg-decoder-to-use-struct-xdr_str.patch @@ -0,0 +1,45 @@ +From 0f041039e00304542c513d260fbe4090fac31009 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Oct 2020 14:41:56 -0400 +Subject: NFSD: Update COMMIT3arg decoder to use struct xdr_stream + +From: Chuck Lever + +[ Upstream commit c8d26a0acfe77f0880e0acfe77e4209cf8f3a38b ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3xdr.c | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index eb55be106a04e..bafb84c978616 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -601,14 +601,17 @@ nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, __be32 *p) + int + nfs3svc_decode_commitargs(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd3_commitargs *args = rqstp->rq_argp; +- p = decode_fh(p, &args->fh); +- if (!p) ++ ++ if (!svcxdr_decode_nfs_fh3(xdr, &args->fh)) ++ return 0; ++ if (xdr_stream_decode_u64(xdr, &args->offset) < 0) ++ return 0; ++ if (xdr_stream_decode_u32(xdr, &args->count) < 0) + return 0; +- p = xdr_decode_hyper(p, &args->offset); +- args->count = ntohl(*p++); + +- return xdr_argsize_check(rqstp, p); ++ return 1; + } + + /* +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-create-verifier-comment.patch b/queue-5.10/nfsd-update-create-verifier-comment.patch new file mode 100644 index 00000000000..592a3a232c7 --- /dev/null +++ b/queue-5.10/nfsd-update-create-verifier-comment.patch @@ -0,0 +1,39 @@ +From 3e8ec11c86668f8970c79d5401684531df6f8e8e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 15 Oct 2021 14:42:11 -0400 +Subject: nfsd: update create verifier comment + +From: J. Bruce Fields + +[ Upstream commit 2336d696862186fd4a6ddd1ea0cb243b3e32847c ] + +I don't know if that Solaris behavior matters any more or if it's still +possible to look up that bug ID any more. The XFS behavior's definitely +still relevant, though; any but the most recent XFS filesystems will +lose the top bits. + +Reported-by: Frank S. Filz +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/vfs.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index 05b5f7e241e70..5b0abdf8de27e 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -1431,7 +1431,8 @@ do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, + + if (nfsd_create_is_exclusive(createmode)) { + /* solaris7 gets confused (bugid 4218508) if these have +- * the high bit set, so just clear the high bits. If this is ++ * the high bit set, as do xfs filesystems without the ++ * "bigtime" feature. So just clear the high bits. If this is + * ever changed to use different attrs for storing the + * verifier, then do_open_lookup() will also need to be fixed + * accordingly. +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-file_hashtbl-helpers.patch b/queue-5.10/nfsd-update-file_hashtbl-helpers.patch new file mode 100644 index 00000000000..a2ed956659e --- /dev/null +++ b/queue-5.10/nfsd-update-file_hashtbl-helpers.patch @@ -0,0 +1,45 @@ +From c151e56ad4e8856ded0f9d11b9983c9015a4b9e7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Oct 2022 10:47:22 -0400 +Subject: NFSD: Update file_hashtbl() helpers + +From: Chuck Lever + +[ Upstream commit 3fe828caddd81e68e9d29353c6e9285a658ca056 ] + +Enable callers to use const pointers for type safety. + +Signed-off-by: Chuck Lever +Reviewed-by: NeilBrown +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index dcbf777dc58d3..90505095d7e0c 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -721,7 +721,7 @@ static unsigned int ownerstr_hashval(struct xdr_netobj *ownername) + #define FILE_HASH_BITS 8 + #define FILE_HASH_SIZE (1 << FILE_HASH_BITS) + +-static unsigned int file_hashval(struct svc_fh *fh) ++static unsigned int file_hashval(const struct svc_fh *fh) + { + struct inode *inode = d_inode(fh->fh_dentry); + +@@ -4686,7 +4686,7 @@ move_to_close_lru(struct nfs4_ol_stateid *s, struct net *net) + + /* search file_hashtbl[] for file */ + static struct nfs4_file * +-find_file_locked(struct svc_fh *fh, unsigned int hashval) ++find_file_locked(const struct svc_fh *fh, unsigned int hashval) + { + struct nfs4_file *fp; + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-getattr3args-decoder-to-use-struct-xdr_s.patch b/queue-5.10/nfsd-update-getattr3args-decoder-to-use-struct-xdr_s.patch new file mode 100644 index 00000000000..a4bd6391c03 --- /dev/null +++ b/queue-5.10/nfsd-update-getattr3args-decoder-to-use-struct-xdr_s.patch @@ -0,0 +1,114 @@ +From d401952b181efdc8699faacd39052dbab1de5cf4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Oct 2020 14:30:02 -0400 +Subject: NFSD: Update GETATTR3args decoder to use struct xdr_stream + +From: Chuck Lever + +[ Upstream commit 9575363a9e4c8d7e2f9ba5e79884d623fff0be6f ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3proc.c | 3 +-- + fs/nfsd/nfs3xdr.c | 31 +++++++++++++++++++++++++------ + fs/nfsd/xdr3.h | 2 +- + 3 files changed, 27 insertions(+), 9 deletions(-) + +diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c +index 0f79e007c620f..a1d743bbb837d 100644 +--- a/fs/nfsd/nfs3proc.c ++++ b/fs/nfsd/nfs3proc.c +@@ -688,7 +688,6 @@ nfsd3_proc_commit(struct svc_rqst *rqstp) + * NFSv3 Server procedures. + * Only the results of non-idempotent operations are cached. + */ +-#define nfs3svc_decode_fhandleargs nfs3svc_decode_fhandle + #define nfs3svc_encode_attrstatres nfs3svc_encode_attrstat + #define nfs3svc_encode_wccstatres nfs3svc_encode_wccstat + #define nfsd3_mkdirargs nfsd3_createargs +@@ -720,7 +719,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { + .pc_decode = nfs3svc_decode_fhandleargs, + .pc_encode = nfs3svc_encode_attrstatres, + .pc_release = nfs3svc_release_fhandle, +- .pc_argsize = sizeof(struct nfsd3_fhandleargs), ++ .pc_argsize = sizeof(struct nfsd_fhandle), + .pc_ressize = sizeof(struct nfsd3_attrstatres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+AT, +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index 34b880211e5ea..3a2b4abea1a42 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -29,8 +29,9 @@ static u32 nfs3_ftypes[] = { + + + /* +- * XDR functions for basic NFS types ++ * Basic NFSv3 data types (RFC 1813 Sections 2.5 and 2.6) + */ ++ + static __be32 * + encode_time3(__be32 *p, struct timespec64 *time) + { +@@ -46,6 +47,26 @@ decode_time3(__be32 *p, struct timespec64 *time) + return p; + } + ++static bool ++svcxdr_decode_nfs_fh3(struct xdr_stream *xdr, struct svc_fh *fhp) ++{ ++ __be32 *p; ++ u32 size; ++ ++ if (xdr_stream_decode_u32(xdr, &size) < 0) ++ return false; ++ if (size == 0 || size > NFS3_FHSIZE) ++ return false; ++ p = xdr_inline_decode(xdr, size); ++ if (!p) ++ return false; ++ fh_init(fhp, NFS3_FHSIZE); ++ fhp->fh_handle.fh_size = size; ++ memcpy(&fhp->fh_handle.fh_base, p, size); ++ ++ return true; ++} ++ + static __be32 * + decode_fh(__be32 *p, struct svc_fh *fhp) + { +@@ -312,14 +333,12 @@ void fill_post_wcc(struct svc_fh *fhp) + */ + + int +-nfs3svc_decode_fhandle(struct svc_rqst *rqstp, __be32 *p) ++nfs3svc_decode_fhandleargs(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd_fhandle *args = rqstp->rq_argp; + +- p = decode_fh(p, &args->fh); +- if (!p) +- return 0; +- return xdr_argsize_check(rqstp, p); ++ return svcxdr_decode_nfs_fh3(xdr, &args->fh); + } + + int +diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h +index 456fcd7a10383..62ea669768cf3 100644 +--- a/fs/nfsd/xdr3.h ++++ b/fs/nfsd/xdr3.h +@@ -273,7 +273,7 @@ union nfsd3_xdrstore { + + #define NFS3_SVC_XDRSIZE sizeof(union nfsd3_xdrstore) + +-int nfs3svc_decode_fhandle(struct svc_rqst *, __be32 *); ++int nfs3svc_decode_fhandleargs(struct svc_rqst *, __be32 *); + int nfs3svc_decode_sattrargs(struct svc_rqst *, __be32 *); + int nfs3svc_decode_diropargs(struct svc_rqst *, __be32 *); + int nfs3svc_decode_accessargs(struct svc_rqst *, __be32 *); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-nfsd_cb_args-tracepoint.patch b/queue-5.10/nfsd-update-nfsd_cb_args-tracepoint.patch new file mode 100644 index 00000000000..39996f9ead2 --- /dev/null +++ b/queue-5.10/nfsd-update-nfsd_cb_args-tracepoint.patch @@ -0,0 +1,40 @@ +From b664f8394ed3c65ffde4c7276c7c15072305f5fd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 14 May 2021 15:57:39 -0400 +Subject: NFSD: Update nfsd_cb_args tracepoint + +From: Chuck Lever + +[ Upstream commit d6cbe98ff32aef795462a309ef048cfb89d1a11d ] + +Clean-up: Re-order the display of IP address and client ID to be +consistent with other _cb_ tracepoints. + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/trace.h | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h +index 87ac1f19bfd0b..68a0fecdd5f46 100644 +--- a/fs/nfsd/trace.h ++++ b/fs/nfsd/trace.h +@@ -857,9 +857,9 @@ TRACE_EVENT(nfsd_cb_args, + memcpy(__entry->addr, &conn->cb_addr, + sizeof(struct sockaddr_in6)); + ), +- TP_printk("client %08x:%08x callback addr=%pISpc prog=%u ident=%u", +- __entry->cl_boot, __entry->cl_id, +- __entry->addr, __entry->prog, __entry->ident) ++ TP_printk("addr=%pISpc client %08x:%08x prog=%u ident=%u", ++ __entry->addr, __entry->cl_boot, __entry->cl_id, ++ __entry->prog, __entry->ident) + ); + + TRACE_EVENT(nfsd_cb_nodelegs, +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-nfsv2-diropargs-decoding-to-use-struct-x.patch b/queue-5.10/nfsd-update-nfsv2-diropargs-decoding-to-use-struct-x.patch new file mode 100644 index 00000000000..0cb1569c7a2 --- /dev/null +++ b/queue-5.10/nfsd-update-nfsv2-diropargs-decoding-to-use-struct-x.patch @@ -0,0 +1,77 @@ +From 712d7d181910fb6bfdbcb837c68296061789bd36 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Oct 2020 14:33:24 -0400 +Subject: NFSD: Update NFSv2 diropargs decoding to use struct xdr_stream + +From: Chuck Lever + +[ Upstream commit 6d742c1864c18f143ea2031f1ed66bcd8f4812de ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsxdr.c | 39 ++++++++++++++++++++++++++++++++++----- + 1 file changed, 34 insertions(+), 5 deletions(-) + +diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c +index 7b33093f8d8b4..00a7db8548ebf 100644 +--- a/fs/nfsd/nfsxdr.c ++++ b/fs/nfsd/nfsxdr.c +@@ -86,6 +86,38 @@ decode_filename(__be32 *p, char **namp, unsigned int *lenp) + return p; + } + ++static bool ++svcxdr_decode_filename(struct xdr_stream *xdr, char **name, unsigned int *len) ++{ ++ u32 size, i; ++ __be32 *p; ++ char *c; ++ ++ if (xdr_stream_decode_u32(xdr, &size) < 0) ++ return false; ++ if (size == 0 || size > NFS_MAXNAMLEN) ++ return false; ++ p = xdr_inline_decode(xdr, size); ++ if (!p) ++ return false; ++ ++ *len = size; ++ *name = (char *)p; ++ for (i = 0, c = *name; i < size; i++, c++) ++ if (*c == '\0' || *c == '/') ++ return false; ++ ++ return true; ++} ++ ++static bool ++svcxdr_decode_diropargs(struct xdr_stream *xdr, struct svc_fh *fhp, ++ char **name, unsigned int *len) ++{ ++ return svcxdr_decode_fhandle(xdr, fhp) && ++ svcxdr_decode_filename(xdr, name, len); ++} ++ + static __be32 * + decode_sattr(__be32 *p, struct iattr *iap, struct user_namespace *userns) + { +@@ -234,13 +266,10 @@ nfssvc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p) + int + nfssvc_decode_diropargs(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd_diropargs *args = rqstp->rq_argp; + +- if (!(p = decode_fh(p, &args->fh)) +- || !(p = decode_filename(p, &args->name, &args->len))) +- return 0; +- +- return xdr_argsize_check(rqstp, p); ++ return svcxdr_decode_diropargs(xdr, &args->fh, &args->name, &args->len); + } + + int +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-nfsv3-readdir-entry-encoders-to-use-stru.patch b/queue-5.10/nfsd-update-nfsv3-readdir-entry-encoders-to-use-stru.patch new file mode 100644 index 00000000000..661ad1fc90c --- /dev/null +++ b/queue-5.10/nfsd-update-nfsv3-readdir-entry-encoders-to-use-stru.patch @@ -0,0 +1,358 @@ +From 539094e6d939c2a97a3fe979525d0e589519156f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Oct 2020 19:46:58 -0400 +Subject: NFSD: Update NFSv3 READDIR entry encoders to use struct xdr_stream + +From: Chuck Lever + +[ Upstream commit 7f87fc2d34d475225e78b7f5c4eabb121f4282b2 ] + +The benefit of the xdr_stream helpers is that they transparently +handle encoding an XDR data item that crosses page boundaries. +Most of the open-coded logic to do that here can be eliminated. + +A sub-buffer and sub-stream are set up as a sink buffer for the +directory entry encoder. As an entry is encoded, it is added to +the end of the content in this buffer/stream. The total length of +the directory list is tracked in the buffer's @len field. + +When it comes time to encode the Reply, the sub-buffer is merged +into rq_res's page array at the correct place using +xdr_write_pages(). + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3proc.c | 35 ++++++---- + fs/nfsd/nfs3xdr.c | 166 +++++++++++++++++++++++++++++++++++++++++---- + fs/nfsd/xdr3.h | 14 ++-- + 3 files changed, 185 insertions(+), 30 deletions(-) + +diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c +index 9e8481242dea8..781bb2b115e74 100644 +--- a/fs/nfsd/nfs3proc.c ++++ b/fs/nfsd/nfs3proc.c +@@ -446,18 +446,30 @@ static void nfsd3_init_dirlist_pages(struct svc_rqst *rqstp, + struct nfsd3_readdirres *resp, + int count) + { ++ struct xdr_buf *buf = &resp->dirlist; ++ struct xdr_stream *xdr = &resp->xdr; ++ + count = min_t(u32, count, svc_max_payload(rqstp)); + +- /* Convert byte count to number of words (i.e. >> 2), +- * and reserve room for the NULL ptr & eof flag (-2 words) */ +- resp->buflen = (count >> 2) - 2; ++ memset(buf, 0, sizeof(*buf)); + +- resp->pages = rqstp->rq_next_page; +- resp->buffer = page_address(*resp->pages); ++ /* Reserve room for the NULL ptr & eof flag (-2 words) */ ++ buf->buflen = count - XDR_UNIT * 2; ++ buf->pages = rqstp->rq_next_page; + while (count > 0) { + rqstp->rq_next_page++; + count -= PAGE_SIZE; + } ++ ++ /* This is xdr_init_encode(), but it assumes that ++ * the head kvec has already been consumed. */ ++ xdr_set_scratch_buffer(xdr, NULL, 0); ++ xdr->buf = buf; ++ xdr->page_ptr = buf->pages; ++ xdr->iov = NULL; ++ xdr->p = page_address(*buf->pages); ++ xdr->end = xdr->p + (PAGE_SIZE >> 2); ++ xdr->rqst = NULL; + } + + /* +@@ -476,16 +488,13 @@ nfsd3_proc_readdir(struct svc_rqst *rqstp) + + nfsd3_init_dirlist_pages(rqstp, resp, argp->count); + +- /* Read directory and encode entries on the fly */ + fh_copy(&resp->fh, &argp->fh); +- +- resp->count = 0; + resp->common.err = nfs_ok; ++ resp->cookie_offset = 0; + resp->rqstp = rqstp; + offset = argp->cookie; +- + resp->status = nfsd_readdir(rqstp, &resp->fh, &offset, +- &resp->common, nfs3svc_encode_entry); ++ &resp->common, nfs3svc_encode_entry3); + memcpy(resp->verf, argp->verf, 8); + nfs3svc_encode_cookie3(resp, offset); + +@@ -509,11 +518,9 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp) + + nfsd3_init_dirlist_pages(rqstp, resp, argp->count); + +- /* Read directory and encode entries on the fly */ + fh_copy(&resp->fh, &argp->fh); +- +- resp->count = 0; + resp->common.err = nfs_ok; ++ resp->cookie_offset = 0; + resp->rqstp = rqstp; + offset = argp->cookie; + +@@ -527,7 +534,7 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp) + } + + resp->status = nfsd_readdir(rqstp, &resp->fh, &offset, +- &resp->common, nfs3svc_encode_entry_plus); ++ &resp->common, nfs3svc_encode_entryplus3); + memcpy(resp->verf, argp->verf, 8); + nfs3svc_encode_cookie3(resp, offset); + +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index 3d076d3c5c7b8..f38d845ac8a0f 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -1139,6 +1139,7 @@ nfs3svc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p) + { + struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd3_readdirres *resp = rqstp->rq_resp; ++ struct xdr_buf *dirlist = &resp->dirlist; + + if (!svcxdr_encode_nfsstat3(xdr, resp->status)) + return 0; +@@ -1148,7 +1149,7 @@ nfs3svc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p) + return 0; + if (!svcxdr_encode_cookieverf3(xdr, resp->verf)) + return 0; +- xdr_write_pages(xdr, resp->pages, 0, resp->count << 2); ++ xdr_write_pages(xdr, dirlist->pages, 0, dirlist->len); + /* no more entries */ + if (xdr_stream_encode_item_absent(xdr) < 0) + return 0; +@@ -1240,21 +1241,18 @@ static __be32 *encode_entryplus_baggage(struct nfsd3_readdirres *cd, __be32 *p, + * @resp: readdir result context + * @offset: offset cookie to encode + * ++ * The buffer space for the offset cookie has already been reserved ++ * by svcxdr_encode_entry3_common(). + */ + void nfs3svc_encode_cookie3(struct nfsd3_readdirres *resp, u64 offset) + { +- if (!resp->offset) +- return; ++ __be64 cookie = cpu_to_be64(offset); + +- if (resp->offset1) { +- /* we ended up with offset on a page boundary */ +- *resp->offset = cpu_to_be32(offset >> 32); +- *resp->offset1 = cpu_to_be32(offset & 0xffffffff); +- resp->offset1 = NULL; +- } else { +- xdr_encode_hyper(resp->offset, offset); +- } +- resp->offset = NULL; ++ if (!resp->cookie_offset) ++ return; ++ write_bytes_to_xdr_buf(&resp->dirlist, resp->cookie_offset, &cookie, ++ sizeof(cookie)); ++ resp->cookie_offset = 0; + } + + /* +@@ -1403,6 +1401,150 @@ nfs3svc_encode_entry_plus(void *cd, const char *name, + return encode_entry(cd, name, namlen, offset, ino, d_type, 1); + } + ++static bool ++svcxdr_encode_entry3_common(struct nfsd3_readdirres *resp, const char *name, ++ int namlen, loff_t offset, u64 ino) ++{ ++ struct xdr_buf *dirlist = &resp->dirlist; ++ struct xdr_stream *xdr = &resp->xdr; ++ ++ if (xdr_stream_encode_item_present(xdr) < 0) ++ return false; ++ /* fileid */ ++ if (xdr_stream_encode_u64(xdr, ino) < 0) ++ return false; ++ /* name */ ++ if (xdr_stream_encode_opaque(xdr, name, min(namlen, NFS3_MAXNAMLEN)) < 0) ++ return false; ++ /* cookie */ ++ resp->cookie_offset = dirlist->len; ++ if (xdr_stream_encode_u64(xdr, NFS_OFFSET_MAX) < 0) ++ return false; ++ ++ return true; ++} ++ ++/** ++ * nfs3svc_encode_entry3 - encode one NFSv3 READDIR entry ++ * @data: directory context ++ * @name: name of the object to be encoded ++ * @namlen: length of that name, in bytes ++ * @offset: the offset of the previous entry ++ * @ino: the fileid of this entry ++ * @d_type: unused ++ * ++ * Return values: ++ * %0: Entry was successfully encoded. ++ * %-EINVAL: An encoding problem occured, secondary status code in resp->common.err ++ * ++ * On exit, the following fields are updated: ++ * - resp->xdr ++ * - resp->common.err ++ * - resp->cookie_offset ++ */ ++int nfs3svc_encode_entry3(void *data, const char *name, int namlen, ++ loff_t offset, u64 ino, unsigned int d_type) ++{ ++ struct readdir_cd *ccd = data; ++ struct nfsd3_readdirres *resp = container_of(ccd, ++ struct nfsd3_readdirres, ++ common); ++ unsigned int starting_length = resp->dirlist.len; ++ ++ /* The offset cookie for the previous entry */ ++ nfs3svc_encode_cookie3(resp, offset); ++ ++ if (!svcxdr_encode_entry3_common(resp, name, namlen, offset, ino)) ++ goto out_toosmall; ++ ++ xdr_commit_encode(&resp->xdr); ++ resp->common.err = nfs_ok; ++ return 0; ++ ++out_toosmall: ++ resp->cookie_offset = 0; ++ resp->common.err = nfserr_toosmall; ++ resp->dirlist.len = starting_length; ++ return -EINVAL; ++} ++ ++static bool ++svcxdr_encode_entry3_plus(struct nfsd3_readdirres *resp, const char *name, ++ int namlen, u64 ino) ++{ ++ struct xdr_stream *xdr = &resp->xdr; ++ struct svc_fh *fhp = &resp->scratch; ++ bool result; ++ ++ result = false; ++ fh_init(fhp, NFS3_FHSIZE); ++ if (compose_entry_fh(resp, fhp, name, namlen, ino) != nfs_ok) ++ goto out_noattrs; ++ ++ if (!svcxdr_encode_post_op_attr(resp->rqstp, xdr, fhp)) ++ goto out; ++ if (!svcxdr_encode_post_op_fh3(xdr, fhp)) ++ goto out; ++ result = true; ++ ++out: ++ fh_put(fhp); ++ return result; ++ ++out_noattrs: ++ if (xdr_stream_encode_item_absent(xdr) < 0) ++ return false; ++ if (xdr_stream_encode_item_absent(xdr) < 0) ++ return false; ++ return true; ++} ++ ++/** ++ * nfs3svc_encode_entryplus3 - encode one NFSv3 READDIRPLUS entry ++ * @data: directory context ++ * @name: name of the object to be encoded ++ * @namlen: length of that name, in bytes ++ * @offset: the offset of the previous entry ++ * @ino: the fileid of this entry ++ * @d_type: unused ++ * ++ * Return values: ++ * %0: Entry was successfully encoded. ++ * %-EINVAL: An encoding problem occured, secondary status code in resp->common.err ++ * ++ * On exit, the following fields are updated: ++ * - resp->xdr ++ * - resp->common.err ++ * - resp->cookie_offset ++ */ ++int nfs3svc_encode_entryplus3(void *data, const char *name, int namlen, ++ loff_t offset, u64 ino, unsigned int d_type) ++{ ++ struct readdir_cd *ccd = data; ++ struct nfsd3_readdirres *resp = container_of(ccd, ++ struct nfsd3_readdirres, ++ common); ++ unsigned int starting_length = resp->dirlist.len; ++ ++ /* The offset cookie for the previous entry */ ++ nfs3svc_encode_cookie3(resp, offset); ++ ++ if (!svcxdr_encode_entry3_common(resp, name, namlen, offset, ino)) ++ goto out_toosmall; ++ if (!svcxdr_encode_entry3_plus(resp, name, namlen, ino)) ++ goto out_toosmall; ++ ++ xdr_commit_encode(&resp->xdr); ++ resp->common.err = nfs_ok; ++ return 0; ++ ++out_toosmall: ++ resp->cookie_offset = 0; ++ resp->common.err = nfserr_toosmall; ++ resp->dirlist.len = starting_length; ++ return -EINVAL; ++} ++ + static bool + svcxdr_encode_fsstat3resok(struct xdr_stream *xdr, + const struct nfsd3_fsstatres *resp) +diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h +index a4cdd8ccb175a..81dea78b0f17e 100644 +--- a/fs/nfsd/xdr3.h ++++ b/fs/nfsd/xdr3.h +@@ -169,20 +169,22 @@ struct nfsd3_linkres { + }; + + struct nfsd3_readdirres { ++ /* Components of the reply */ + __be32 status; + struct svc_fh fh; +- /* Just to save kmalloc on every readdirplus entry (svc_fh is a +- * little large for the stack): */ +- struct svc_fh scratch; + int count; + __be32 verf[2]; +- struct page **pages; + ++ /* Used to encode the reply's entry list */ ++ struct xdr_stream xdr; ++ struct xdr_buf dirlist; ++ struct svc_fh scratch; + struct readdir_cd common; + __be32 * buffer; + int buflen; + __be32 * offset; + __be32 * offset1; ++ unsigned int cookie_offset; + struct svc_rqst * rqstp; + + }; +@@ -309,6 +311,10 @@ int nfs3svc_encode_entry(void *, const char *name, + int nfs3svc_encode_entry_plus(void *, const char *name, + int namlen, loff_t offset, u64 ino, + unsigned int); ++int nfs3svc_encode_entry3(void *data, const char *name, int namlen, ++ loff_t offset, u64 ino, unsigned int d_type); ++int nfs3svc_encode_entryplus3(void *data, const char *name, int namlen, ++ loff_t offset, u64 ino, unsigned int d_type); + /* Helper functions for NFSv3 ACL code */ + __be32 *nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, + struct svc_fh *fhp); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-read3arg-decoder-to-use-struct-xdr_strea.patch b/queue-5.10/nfsd-update-read3arg-decoder-to-use-struct-xdr_strea.patch new file mode 100644 index 00000000000..5b7449fa621 --- /dev/null +++ b/queue-5.10/nfsd-update-read3arg-decoder-to-use-struct-xdr_strea.patch @@ -0,0 +1,126 @@ +From fb74e55a8d5c659849397394318ee6c2a25b6143 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Oct 2020 14:34:40 -0400 +Subject: NFSD: Update READ3arg decoder to use struct xdr_stream + +From: Chuck Lever + +[ Upstream commit be63bd2ac6bbf8c065a0ef6dfbea76934326c352 ] + +The code that sets up rq_vec is refactored so that it is now +adjacent to the nfsd_read() call site where it is used. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3proc.c | 23 ++++++++++++++++++----- + fs/nfsd/nfs3xdr.c | 28 +++++++--------------------- + fs/nfsd/xdr3.h | 1 - + 3 files changed, 25 insertions(+), 27 deletions(-) + +diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c +index a1d743bbb837d..2e477cd870913 100644 +--- a/fs/nfsd/nfs3proc.c ++++ b/fs/nfsd/nfs3proc.c +@@ -144,25 +144,38 @@ nfsd3_proc_read(struct svc_rqst *rqstp) + { + struct nfsd3_readargs *argp = rqstp->rq_argp; + struct nfsd3_readres *resp = rqstp->rq_resp; +- u32 max_blocksize = svc_max_payload(rqstp); +- unsigned long cnt = min(argp->count, max_blocksize); ++ u32 max_blocksize = svc_max_payload(rqstp); ++ unsigned int len; ++ int v; ++ ++ argp->count = min_t(u32, argp->count, max_blocksize); + + dprintk("nfsd: READ(3) %s %lu bytes at %Lu\n", + SVCFH_fmt(&argp->fh), + (unsigned long) argp->count, + (unsigned long long) argp->offset); + ++ v = 0; ++ len = argp->count; ++ while (len > 0) { ++ struct page *page = *(rqstp->rq_next_page++); ++ ++ rqstp->rq_vec[v].iov_base = page_address(page); ++ rqstp->rq_vec[v].iov_len = min_t(unsigned int, len, PAGE_SIZE); ++ len -= rqstp->rq_vec[v].iov_len; ++ v++; ++ } ++ + /* Obtain buffer pointer for payload. + * 1 (status) + 22 (post_op_attr) + 1 (count) + 1 (eof) + * + 1 (xdr opaque byte count) = 26 + */ +- resp->count = cnt; ++ resp->count = argp->count; + svc_reserve_auth(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3)<<2) + resp->count +4); + + fh_copy(&resp->fh, &argp->fh); + resp->status = nfsd_read(rqstp, &resp->fh, argp->offset, +- rqstp->rq_vec, argp->vlen, &resp->count, +- &resp->eof); ++ rqstp->rq_vec, v, &resp->count, &resp->eof); + return rpc_success; + } + +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index e07cebd80ef7f..2f32df15a7e87 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -389,31 +389,17 @@ nfs3svc_decode_accessargs(struct svc_rqst *rqstp, __be32 *p) + int + nfs3svc_decode_readargs(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd3_readargs *args = rqstp->rq_argp; +- unsigned int len; +- int v; +- u32 max_blocksize = svc_max_payload(rqstp); + +- p = decode_fh(p, &args->fh); +- if (!p) ++ if (!svcxdr_decode_nfs_fh3(xdr, &args->fh)) ++ return 0; ++ if (xdr_stream_decode_u64(xdr, &args->offset) < 0) ++ return 0; ++ if (xdr_stream_decode_u32(xdr, &args->count) < 0) + return 0; +- p = xdr_decode_hyper(p, &args->offset); +- +- args->count = ntohl(*p++); +- len = min(args->count, max_blocksize); +- +- /* set up the kvec */ +- v=0; +- while (len > 0) { +- struct page *p = *(rqstp->rq_next_page++); + +- rqstp->rq_vec[v].iov_base = page_address(p); +- rqstp->rq_vec[v].iov_len = min_t(unsigned int, len, PAGE_SIZE); +- len -= rqstp->rq_vec[v].iov_len; +- v++; +- } +- args->vlen = v; +- return xdr_argsize_check(rqstp, p); ++ return 1; + } + + int +diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h +index a4dce4baec7c3..7dfeeaa4e1dfc 100644 +--- a/fs/nfsd/xdr3.h ++++ b/fs/nfsd/xdr3.h +@@ -32,7 +32,6 @@ struct nfsd3_readargs { + struct svc_fh fh; + __u64 offset; + __u32 count; +- int vlen; + }; + + struct nfsd3_writeargs { +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-readdir3args-decoders-to-use-struct-xdr_.patch b/queue-5.10/nfsd-update-readdir3args-decoders-to-use-struct-xdr_.patch new file mode 100644 index 00000000000..302ae708ecd --- /dev/null +++ b/queue-5.10/nfsd-update-readdir3args-decoders-to-use-struct-xdr_.patch @@ -0,0 +1,97 @@ +From 3d380aba7f7ad8c4a2cdc6ac81623b1ad76ee4c8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Oct 2020 13:23:52 -0400 +Subject: NFSD: Update READDIR3args decoders to use struct xdr_stream + +From: Chuck Lever + +[ Upstream commit 9cedc2e64c296efb3bebe93a0ceeb5e71e8d722d ] + +As an additional clean up, neither nfsd3_proc_readdir() nor +nfsd3_proc_readdirplus() make use of the dircount argument, so +remove it from struct nfsd3_readdirargs. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3xdr.c | 38 ++++++++++++++++++++++++-------------- + fs/nfsd/xdr3.h | 1 - + 2 files changed, 24 insertions(+), 15 deletions(-) + +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index 8394aeb8381e6..eb55be106a04e 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -559,33 +559,43 @@ nfs3svc_decode_linkargs(struct svc_rqst *rqstp, __be32 *p) + int + nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd3_readdirargs *args = rqstp->rq_argp; + +- p = decode_fh(p, &args->fh); +- if (!p) ++ if (!svcxdr_decode_nfs_fh3(xdr, &args->fh)) ++ return 0; ++ if (xdr_stream_decode_u64(xdr, &args->cookie) < 0) ++ return 0; ++ args->verf = xdr_inline_decode(xdr, NFS3_COOKIEVERFSIZE); ++ if (!args->verf) ++ return 0; ++ if (xdr_stream_decode_u32(xdr, &args->count) < 0) + return 0; +- p = xdr_decode_hyper(p, &args->cookie); +- args->verf = p; p += 2; +- args->dircount = ~0; +- args->count = ntohl(*p++); + +- return xdr_argsize_check(rqstp, p); ++ return 1; + } + + int + nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd3_readdirargs *args = rqstp->rq_argp; ++ u32 dircount; + +- p = decode_fh(p, &args->fh); +- if (!p) ++ if (!svcxdr_decode_nfs_fh3(xdr, &args->fh)) ++ return 0; ++ if (xdr_stream_decode_u64(xdr, &args->cookie) < 0) ++ return 0; ++ args->verf = xdr_inline_decode(xdr, NFS3_COOKIEVERFSIZE); ++ if (!args->verf) ++ return 0; ++ /* dircount is ignored */ ++ if (xdr_stream_decode_u32(xdr, &dircount) < 0) ++ return 0; ++ if (xdr_stream_decode_u32(xdr, &args->count) < 0) + return 0; +- p = xdr_decode_hyper(p, &args->cookie); +- args->verf = p; p += 2; +- args->dircount = ntohl(*p++); +- args->count = ntohl(*p++); + +- return xdr_argsize_check(rqstp, p); ++ return 1; + } + + int +diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h +index 789a364d5e69d..64af5b01c5d7b 100644 +--- a/fs/nfsd/xdr3.h ++++ b/fs/nfsd/xdr3.h +@@ -90,7 +90,6 @@ struct nfsd3_symlinkargs { + struct nfsd3_readdirargs { + struct svc_fh fh; + __u64 cookie; +- __u32 dircount; + __u32 count; + __be32 * verf; + }; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-readlink3arg-decoder-to-use-struct-xdr_s.patch b/queue-5.10/nfsd-update-readlink3arg-decoder-to-use-struct-xdr_s.patch new file mode 100644 index 00000000000..30101a4ce23 --- /dev/null +++ b/queue-5.10/nfsd-update-readlink3arg-decoder-to-use-struct-xdr_s.patch @@ -0,0 +1,107 @@ +From 9b25a49023b56aa0067e90be7b997e4ae4890ec8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 24 Oct 2020 12:51:18 -0400 +Subject: NFSD: Update READLINK3arg decoder to use struct xdr_stream + +From: Chuck Lever + +[ Upstream commit 224c1c894e48cd72e4dd9fb6311be80cbe1369b0 ] + +The NFSv3 READLINK request takes a single filehandle, so it can +re-use GETATTR's decoder. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3proc.c | 9 +++++---- + fs/nfsd/nfs3xdr.c | 13 ------------- + fs/nfsd/xdr3.h | 6 ------ + 3 files changed, 5 insertions(+), 23 deletions(-) + +diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c +index 2e477cd870913..71db0ed3c49ed 100644 +--- a/fs/nfsd/nfs3proc.c ++++ b/fs/nfsd/nfs3proc.c +@@ -124,15 +124,16 @@ nfsd3_proc_access(struct svc_rqst *rqstp) + static __be32 + nfsd3_proc_readlink(struct svc_rqst *rqstp) + { +- struct nfsd3_readlinkargs *argp = rqstp->rq_argp; ++ struct nfsd_fhandle *argp = rqstp->rq_argp; + struct nfsd3_readlinkres *resp = rqstp->rq_resp; ++ char *buffer = page_address(*(rqstp->rq_next_page++)); + + dprintk("nfsd: READLINK(3) %s\n", SVCFH_fmt(&argp->fh)); + + /* Read the symlink. */ + fh_copy(&resp->fh, &argp->fh); + resp->len = NFS3_MAXPATHLEN; +- resp->status = nfsd_readlink(rqstp, &resp->fh, argp->buffer, &resp->len); ++ resp->status = nfsd_readlink(rqstp, &resp->fh, buffer, &resp->len); + return rpc_success; + } + +@@ -773,10 +774,10 @@ static const struct svc_procedure nfsd_procedures3[22] = { + }, + [NFS3PROC_READLINK] = { + .pc_func = nfsd3_proc_readlink, +- .pc_decode = nfs3svc_decode_readlinkargs, ++ .pc_decode = nfs3svc_decode_fhandleargs, + .pc_encode = nfs3svc_encode_readlinkres, + .pc_release = nfs3svc_release_fhandle, +- .pc_argsize = sizeof(struct nfsd3_readlinkargs), ++ .pc_argsize = sizeof(struct nfsd_fhandle), + .pc_ressize = sizeof(struct nfsd3_readlinkres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+pAT+1+NFS3_MAXPATHLEN/4, +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index c06467e8ac829..6b6a839c1fc8c 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -543,19 +543,6 @@ nfs3svc_decode_renameargs(struct svc_rqst *rqstp, __be32 *p) + return xdr_argsize_check(rqstp, p); + } + +-int +-nfs3svc_decode_readlinkargs(struct svc_rqst *rqstp, __be32 *p) +-{ +- struct nfsd3_readlinkargs *args = rqstp->rq_argp; +- +- p = decode_fh(p, &args->fh); +- if (!p) +- return 0; +- args->buffer = page_address(*(rqstp->rq_next_page++)); +- +- return xdr_argsize_check(rqstp, p); +-} +- + int + nfs3svc_decode_linkargs(struct svc_rqst *rqstp, __be32 *p) + { +diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h +index 7dfeeaa4e1dfc..08f909142ddf7 100644 +--- a/fs/nfsd/xdr3.h ++++ b/fs/nfsd/xdr3.h +@@ -70,11 +70,6 @@ struct nfsd3_renameargs { + unsigned int tlen; + }; + +-struct nfsd3_readlinkargs { +- struct svc_fh fh; +- char * buffer; +-}; +- + struct nfsd3_linkargs { + struct svc_fh ffh; + struct svc_fh tfh; +@@ -282,7 +277,6 @@ int nfs3svc_decode_createargs(struct svc_rqst *, __be32 *); + int nfs3svc_decode_mkdirargs(struct svc_rqst *, __be32 *); + int nfs3svc_decode_mknodargs(struct svc_rqst *, __be32 *); + int nfs3svc_decode_renameargs(struct svc_rqst *, __be32 *); +-int nfs3svc_decode_readlinkargs(struct svc_rqst *, __be32 *); + int nfs3svc_decode_linkargs(struct svc_rqst *, __be32 *); + int nfs3svc_decode_symlinkargs(struct svc_rqst *, __be32 *); + int nfs3svc_decode_readdirargs(struct svc_rqst *, __be32 *); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-create3args-decoder-to-use-struct-xd.patch b/queue-5.10/nfsd-update-the-create3args-decoder-to-use-struct-xd.patch new file mode 100644 index 00000000000..60928096a35 --- /dev/null +++ b/queue-5.10/nfsd-update-the-create3args-decoder-to-use-struct-xd.patch @@ -0,0 +1,59 @@ +From 7fe35bd1e7b35aaeed2509c865b00b8ff745a8ec Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Oct 2020 15:56:11 -0400 +Subject: NFSD: Update the CREATE3args decoder to use struct xdr_stream + +From: Chuck Lever + +[ Upstream commit 6b3a11960d898b25a30103cc6a2ff0b24b90a83b ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3xdr.c | 20 ++++++++++---------- + 1 file changed, 10 insertions(+), 10 deletions(-) + +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index 6a6bf8e34d82b..24db3725a070b 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -580,26 +580,26 @@ nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p) + int + nfs3svc_decode_createargs(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd3_createargs *args = rqstp->rq_argp; + +- if (!(p = decode_fh(p, &args->fh)) +- || !(p = decode_filename(p, &args->name, &args->len))) ++ if (!svcxdr_decode_diropargs3(xdr, &args->fh, &args->name, &args->len)) + return 0; +- +- switch (args->createmode = ntohl(*p++)) { ++ if (xdr_stream_decode_u32(xdr, &args->createmode) < 0) ++ return 0; ++ switch (args->createmode) { + case NFS3_CREATE_UNCHECKED: + case NFS3_CREATE_GUARDED: +- p = decode_sattr3(p, &args->attrs, nfsd_user_namespace(rqstp)); +- break; ++ return svcxdr_decode_sattr3(rqstp, xdr, &args->attrs); + case NFS3_CREATE_EXCLUSIVE: +- args->verf = p; +- p += 2; ++ args->verf = xdr_inline_decode(xdr, NFS3_CREATEVERFSIZE); ++ if (!args->verf) ++ return 0; + break; + default: + return 0; + } +- +- return xdr_argsize_check(rqstp, p); ++ return 1; + } + + int +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-getattr3res-encoder-to-use-struct-xd.patch b/queue-5.10/nfsd-update-the-getattr3res-encoder-to-use-struct-xd.patch new file mode 100644 index 00000000000..e3992253b28 --- /dev/null +++ b/queue-5.10/nfsd-update-the-getattr3res-encoder-to-use-struct-xd.patch @@ -0,0 +1,216 @@ +From bd1aaef0ca5cd2b434fa9182b35a09416add183d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Oct 2020 11:58:41 -0400 +Subject: NFSD: Update the GETATTR3res encoder to use struct xdr_stream + +From: Chuck Lever + +[ Upstream commit 2c42f804d30f6a8d86665eca84071b316821ea08 ] + +As an additional clean up, some renaming is done to more closely +reflect the data type and variable names used in the NFSv3 XDR +definition provided in RFC 1813. "attrstat" is an NFSv2 thingie. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3proc.c | 2 +- + fs/nfsd/nfs3xdr.c | 95 ++++++++++++++++++++++++++++++++++++++++++---- + fs/nfsd/nfsfh.c | 2 +- + fs/nfsd/nfsfh.h | 2 +- + fs/nfsd/xdr3.h | 2 +- + 5 files changed, 91 insertions(+), 12 deletions(-) + +diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c +index 25f31a03c4f1b..1c3cf97ed95d2 100644 +--- a/fs/nfsd/nfs3proc.c ++++ b/fs/nfsd/nfs3proc.c +@@ -741,7 +741,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { + [NFS3PROC_GETATTR] = { + .pc_func = nfsd3_proc_getattr, + .pc_decode = nfs3svc_decode_fhandleargs, +- .pc_encode = nfs3svc_encode_attrstatres, ++ .pc_encode = nfs3svc_encode_getattrres, + .pc_release = nfs3svc_release_fhandle, + .pc_argsize = sizeof(struct nfsd_fhandle), + .pc_ressize = sizeof(struct nfsd3_attrstatres), +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index 9d9a01ce0b270..75739861d235e 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -20,7 +20,7 @@ + /* + * Mapping of S_IF* types to NFS file types + */ +-static u32 nfs3_ftypes[] = { ++static const u32 nfs3_ftypes[] = { + NF3NON, NF3FIFO, NF3CHR, NF3BAD, + NF3DIR, NF3BAD, NF3BLK, NF3BAD, + NF3REG, NF3BAD, NF3LNK, NF3BAD, +@@ -39,6 +39,15 @@ encode_time3(__be32 *p, struct timespec64 *time) + return p; + } + ++static __be32 * ++encode_nfstime3(__be32 *p, const struct timespec64 *time) ++{ ++ *p++ = cpu_to_be32((u32)time->tv_sec); ++ *p++ = cpu_to_be32(time->tv_nsec); ++ ++ return p; ++} ++ + static bool + svcxdr_decode_nfstime3(struct xdr_stream *xdr, struct timespec64 *timep) + { +@@ -82,6 +91,19 @@ svcxdr_decode_nfs_fh3(struct xdr_stream *xdr, struct svc_fh *fhp) + return true; + } + ++static bool ++svcxdr_encode_nfsstat3(struct xdr_stream *xdr, __be32 status) ++{ ++ __be32 *p; ++ ++ p = xdr_reserve_space(xdr, sizeof(status)); ++ if (!p) ++ return false; ++ *p = status; ++ ++ return true; ++} ++ + static __be32 * + encode_fh(__be32 *p, struct svc_fh *fhp) + { +@@ -253,6 +275,58 @@ svcxdr_decode_devicedata3(struct svc_rqst *rqstp, struct xdr_stream *xdr, + svcxdr_decode_specdata3(xdr, args); + } + ++static bool ++svcxdr_encode_fattr3(struct svc_rqst *rqstp, struct xdr_stream *xdr, ++ const struct svc_fh *fhp, const struct kstat *stat) ++{ ++ struct user_namespace *userns = nfsd_user_namespace(rqstp); ++ __be32 *p; ++ u64 fsid; ++ ++ p = xdr_reserve_space(xdr, XDR_UNIT * 21); ++ if (!p) ++ return false; ++ ++ *p++ = cpu_to_be32(nfs3_ftypes[(stat->mode & S_IFMT) >> 12]); ++ *p++ = cpu_to_be32((u32)(stat->mode & S_IALLUGO)); ++ *p++ = cpu_to_be32((u32)stat->nlink); ++ *p++ = cpu_to_be32((u32)from_kuid_munged(userns, stat->uid)); ++ *p++ = cpu_to_be32((u32)from_kgid_munged(userns, stat->gid)); ++ if (S_ISLNK(stat->mode) && stat->size > NFS3_MAXPATHLEN) ++ p = xdr_encode_hyper(p, (u64)NFS3_MAXPATHLEN); ++ else ++ p = xdr_encode_hyper(p, (u64)stat->size); ++ ++ /* used */ ++ p = xdr_encode_hyper(p, ((u64)stat->blocks) << 9); ++ ++ /* rdev */ ++ *p++ = cpu_to_be32((u32)MAJOR(stat->rdev)); ++ *p++ = cpu_to_be32((u32)MINOR(stat->rdev)); ++ ++ switch(fsid_source(fhp)) { ++ case FSIDSOURCE_FSID: ++ fsid = (u64)fhp->fh_export->ex_fsid; ++ break; ++ case FSIDSOURCE_UUID: ++ fsid = ((u64 *)fhp->fh_export->ex_uuid)[0]; ++ fsid ^= ((u64 *)fhp->fh_export->ex_uuid)[1]; ++ break; ++ default: ++ fsid = (u64)huge_encode_dev(fhp->fh_dentry->d_sb->s_dev); ++ } ++ p = xdr_encode_hyper(p, fsid); ++ ++ /* fileid */ ++ p = xdr_encode_hyper(p, stat->ino); ++ ++ p = encode_nfstime3(p, &stat->atime); ++ p = encode_nfstime3(p, &stat->mtime); ++ encode_nfstime3(p, &stat->ctime); ++ ++ return true; ++} ++ + static __be32 *encode_fsid(__be32 *p, struct svc_fh *fhp) + { + u64 f; +@@ -713,17 +787,22 @@ nfs3svc_decode_commitargs(struct svc_rqst *rqstp, __be32 *p) + + /* GETATTR */ + int +-nfs3svc_encode_attrstat(struct svc_rqst *rqstp, __be32 *p) ++nfs3svc_encode_getattrres(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd3_attrstat *resp = rqstp->rq_resp; + +- *p++ = resp->status; +- if (resp->status == 0) { +- lease_get_mtime(d_inode(resp->fh.fh_dentry), +- &resp->stat.mtime); +- p = encode_fattr3(rqstp, p, &resp->fh, &resp->stat); ++ if (!svcxdr_encode_nfsstat3(xdr, resp->status)) ++ return 0; ++ switch (resp->status) { ++ case nfs_ok: ++ lease_get_mtime(d_inode(resp->fh.fh_dentry), &resp->stat.mtime); ++ if (!svcxdr_encode_fattr3(rqstp, xdr, &resp->fh, &resp->stat)) ++ return 0; ++ break; + } +- return xdr_ressize_check(rqstp, p); ++ ++ return 1; + } + + /* SETATTR, REMOVE, RMDIR */ +diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c +index 4744a276058d4..04930056222b7 100644 +--- a/fs/nfsd/nfsfh.c ++++ b/fs/nfsd/nfsfh.c +@@ -710,7 +710,7 @@ char * SVCFH_fmt(struct svc_fh *fhp) + return buf; + } + +-enum fsid_source fsid_source(struct svc_fh *fhp) ++enum fsid_source fsid_source(const struct svc_fh *fhp) + { + if (fhp->fh_handle.fh_version != 1) + return FSIDSOURCE_DEV; +diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h +index f58933519f380..aff2cda5c6c33 100644 +--- a/fs/nfsd/nfsfh.h ++++ b/fs/nfsd/nfsfh.h +@@ -82,7 +82,7 @@ enum fsid_source { + FSIDSOURCE_FSID, + FSIDSOURCE_UUID, + }; +-extern enum fsid_source fsid_source(struct svc_fh *fhp); ++extern enum fsid_source fsid_source(const struct svc_fh *fhp); + + + /* +diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h +index 3e1578953f544..0822981c61b93 100644 +--- a/fs/nfsd/xdr3.h ++++ b/fs/nfsd/xdr3.h +@@ -280,7 +280,7 @@ int nfs3svc_decode_symlinkargs(struct svc_rqst *, __be32 *); + int nfs3svc_decode_readdirargs(struct svc_rqst *, __be32 *); + int nfs3svc_decode_readdirplusargs(struct svc_rqst *, __be32 *); + int nfs3svc_decode_commitargs(struct svc_rqst *, __be32 *); +-int nfs3svc_encode_attrstat(struct svc_rqst *, __be32 *); ++int nfs3svc_encode_getattrres(struct svc_rqst *, __be32 *); + int nfs3svc_encode_wccstat(struct svc_rqst *, __be32 *); + int nfs3svc_encode_diropres(struct svc_rqst *, __be32 *); + int nfs3svc_encode_accessres(struct svc_rqst *, __be32 *); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-link3args-decoder-to-use-struct-xdr_.patch b/queue-5.10/nfsd-update-the-link3args-decoder-to-use-struct-xdr_.patch new file mode 100644 index 00000000000..21f18884793 --- /dev/null +++ b/queue-5.10/nfsd-update-the-link3args-decoder-to-use-struct-xdr_.patch @@ -0,0 +1,41 @@ +From e76cee9cf55d899486433a3c1bd5500cdf9982ce Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Oct 2020 13:26:32 -0400 +Subject: NFSD: Update the LINK3args decoder to use struct xdr_stream + +From: Chuck Lever + +[ Upstream commit efaa1e7c2c7475f0a9bbeb904d9aba09b73dd52a ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3xdr.c | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) + +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index f870a068aad85..9437dda2646f2 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -574,14 +574,12 @@ nfs3svc_decode_renameargs(struct svc_rqst *rqstp, __be32 *p) + int + nfs3svc_decode_linkargs(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd3_linkargs *args = rqstp->rq_argp; + +- if (!(p = decode_fh(p, &args->ffh)) +- || !(p = decode_fh(p, &args->tfh)) +- || !(p = decode_filename(p, &args->tname, &args->tlen))) +- return 0; +- +- return xdr_argsize_check(rqstp, p); ++ return svcxdr_decode_nfs_fh3(xdr, &args->ffh) && ++ svcxdr_decode_diropargs3(xdr, &args->tfh, ++ &args->tname, &args->tlen); + } + + int +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-mkdir3args-decoder-to-use-struct-xdr.patch b/queue-5.10/nfsd-update-the-mkdir3args-decoder-to-use-struct-xdr.patch new file mode 100644 index 00000000000..ddef4ec7ca9 --- /dev/null +++ b/queue-5.10/nfsd-update-the-mkdir3args-decoder-to-use-struct-xdr.patch @@ -0,0 +1,41 @@ +From e4b7b713f1cf5285968c37768d01323af8b4b022 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Oct 2020 17:02:16 -0400 +Subject: NFSD: Update the MKDIR3args decoder to use struct xdr_stream + +From: Chuck Lever + +[ Upstream commit 83374c278db193f3e8b2608b45da1132b867a760 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3xdr.c | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) + +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index 24db3725a070b..b4071cda1d652 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -605,14 +605,12 @@ nfs3svc_decode_createargs(struct svc_rqst *rqstp, __be32 *p) + int + nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd3_createargs *args = rqstp->rq_argp; + +- if (!(p = decode_fh(p, &args->fh)) || +- !(p = decode_filename(p, &args->name, &args->len))) +- return 0; +- p = decode_sattr3(p, &args->attrs, nfsd_user_namespace(rqstp)); +- +- return xdr_argsize_check(rqstp, p); ++ return svcxdr_decode_diropargs3(xdr, &args->fh, ++ &args->name, &args->len) && ++ svcxdr_decode_sattr3(rqstp, xdr, &args->attrs); + } + + int +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-mknod3args-decoder-to-use-struct-xdr.patch b/queue-5.10/nfsd-update-the-mknod3args-decoder-to-use-struct-xdr.patch new file mode 100644 index 00000000000..3bd8bc936f7 --- /dev/null +++ b/queue-5.10/nfsd-update-the-mknod3args-decoder-to-use-struct-xdr.patch @@ -0,0 +1,162 @@ +From ebf59fffb03b034b3222108bac4b0492252ddc64 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Oct 2020 17:04:03 -0400 +Subject: NFSD: Update the MKNOD3args decoder to use struct xdr_stream + +From: Chuck Lever + +[ Upstream commit f8a38e2d6c885f9d7cd03febc515d36293de4a5b ] + +This commit removes the last usage of the original decode_sattr3(), +so it is removed as a clean-up. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3xdr.c | 107 +++++++++++++++------------------------------- + 1 file changed, 35 insertions(+), 72 deletions(-) + +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index eb17231ab1661..a30b418a51160 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -103,26 +103,6 @@ encode_fh(__be32 *p, struct svc_fh *fhp) + return p + XDR_QUADLEN(size); + } + +-/* +- * Decode a file name and make sure that the path contains +- * no slashes or null bytes. +- */ +-static __be32 * +-decode_filename(__be32 *p, char **namp, unsigned int *lenp) +-{ +- char *name; +- unsigned int i; +- +- if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS3_MAXNAMLEN)) != NULL) { +- for (i = 0, name = *namp; i < *lenp; i++, name++) { +- if (*name == '\0' || *name == '/') +- return NULL; +- } +- } +- +- return p; +-} +- + static bool + svcxdr_decode_filename3(struct xdr_stream *xdr, char **name, unsigned int *len) + { +@@ -262,49 +242,26 @@ svcxdr_decode_sattrguard3(struct xdr_stream *xdr, struct nfsd3_sattrargs *args) + return true; + } + +-static __be32 * +-decode_sattr3(__be32 *p, struct iattr *iap, struct user_namespace *userns) ++static bool ++svcxdr_decode_specdata3(struct xdr_stream *xdr, struct nfsd3_mknodargs *args) + { +- u32 tmp; ++ __be32 *p; + +- iap->ia_valid = 0; ++ p = xdr_inline_decode(xdr, XDR_UNIT * 2); ++ if (!p) ++ return false; ++ args->major = be32_to_cpup(p++); ++ args->minor = be32_to_cpup(p); + +- if (*p++) { +- iap->ia_valid |= ATTR_MODE; +- iap->ia_mode = ntohl(*p++); +- } +- if (*p++) { +- iap->ia_uid = make_kuid(userns, ntohl(*p++)); +- if (uid_valid(iap->ia_uid)) +- iap->ia_valid |= ATTR_UID; +- } +- if (*p++) { +- iap->ia_gid = make_kgid(userns, ntohl(*p++)); +- if (gid_valid(iap->ia_gid)) +- iap->ia_valid |= ATTR_GID; +- } +- if (*p++) { +- u64 newsize; ++ return true; ++} + +- iap->ia_valid |= ATTR_SIZE; +- p = xdr_decode_hyper(p, &newsize); +- iap->ia_size = min_t(u64, newsize, NFS_OFFSET_MAX); +- } +- if ((tmp = ntohl(*p++)) == 1) { /* set to server time */ +- iap->ia_valid |= ATTR_ATIME; +- } else if (tmp == 2) { /* set to client time */ +- iap->ia_valid |= ATTR_ATIME | ATTR_ATIME_SET; +- iap->ia_atime.tv_sec = ntohl(*p++); +- iap->ia_atime.tv_nsec = ntohl(*p++); +- } +- if ((tmp = ntohl(*p++)) == 1) { /* set to server time */ +- iap->ia_valid |= ATTR_MTIME; +- } else if (tmp == 2) { /* set to client time */ +- iap->ia_valid |= ATTR_MTIME | ATTR_MTIME_SET; +- iap->ia_mtime.tv_sec = ntohl(*p++); +- iap->ia_mtime.tv_nsec = ntohl(*p++); +- } +- return p; ++static bool ++svcxdr_decode_devicedata3(struct svc_rqst *rqstp, struct xdr_stream *xdr, ++ struct nfsd3_mknodargs *args) ++{ ++ return svcxdr_decode_sattr3(rqstp, xdr, &args->attrs) && ++ svcxdr_decode_specdata3(xdr, args); + } + + static __be32 *encode_fsid(__be32 *p, struct svc_fh *fhp) +@@ -644,24 +601,30 @@ nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p) + int + nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd3_mknodargs *args = rqstp->rq_argp; + +- if (!(p = decode_fh(p, &args->fh)) +- || !(p = decode_filename(p, &args->name, &args->len))) ++ if (!svcxdr_decode_diropargs3(xdr, &args->fh, &args->name, &args->len)) ++ return 0; ++ if (xdr_stream_decode_u32(xdr, &args->ftype) < 0) ++ return 0; ++ switch (args->ftype) { ++ case NF3CHR: ++ case NF3BLK: ++ return svcxdr_decode_devicedata3(rqstp, xdr, args); ++ case NF3SOCK: ++ case NF3FIFO: ++ return svcxdr_decode_sattr3(rqstp, xdr, &args->attrs); ++ case NF3REG: ++ case NF3DIR: ++ case NF3LNK: ++ /* Valid XDR but illegal file types */ ++ break; ++ default: + return 0; +- +- args->ftype = ntohl(*p++); +- +- if (args->ftype == NF3BLK || args->ftype == NF3CHR +- || args->ftype == NF3SOCK || args->ftype == NF3FIFO) +- p = decode_sattr3(p, &args->attrs, nfsd_user_namespace(rqstp)); +- +- if (args->ftype == NF3BLK || args->ftype == NF3CHR) { +- args->major = ntohl(*p++); +- args->minor = ntohl(*p++); + } + +- return xdr_argsize_check(rqstp, p); ++ return 1; + } + + int +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-nfsv2-acl-access-argument-decoder-to.patch b/queue-5.10/nfsd-update-the-nfsv2-acl-access-argument-decoder-to.patch new file mode 100644 index 00000000000..b5edc093fa0 --- /dev/null +++ b/queue-5.10/nfsd-update-the-nfsv2-acl-access-argument-decoder-to.patch @@ -0,0 +1,44 @@ +From 1be9197d0b2f5f1f25be24f5262cfe137859e83a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Nov 2020 11:49:29 -0500 +Subject: NFSD: Update the NFSv2 ACL ACCESS argument decoder to use struct + xdr_stream + +From: Chuck Lever + +[ Upstream commit 64063892efc1daa3a48882673811ff327ba75ed5 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs2acl.c | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c +index 0274348f6679e..7eeac5b81c200 100644 +--- a/fs/nfsd/nfs2acl.c ++++ b/fs/nfsd/nfs2acl.c +@@ -222,14 +222,15 @@ static int nfsaclsvc_decode_setaclargs(struct svc_rqst *rqstp, __be32 *p) + + static int nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, __be32 *p) + { +- struct nfsd3_accessargs *argp = rqstp->rq_argp; ++ struct xdr_stream *xdr = &rqstp->rq_arg_stream; ++ struct nfsd3_accessargs *args = rqstp->rq_argp; + +- p = nfs2svc_decode_fh(p, &argp->fh); +- if (!p) ++ if (!svcxdr_decode_fhandle(xdr, &args->fh)) ++ return 0; ++ if (xdr_stream_decode_u32(xdr, &args->access) < 0) + return 0; +- argp->access = ntohl(*p++); + +- return xdr_argsize_check(rqstp, p); ++ return 1; + } + + /* +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-nfsv2-acl-access-result-encoder-to-u.patch b/queue-5.10/nfsd-update-the-nfsv2-acl-access-result-encoder-to-u.patch new file mode 100644 index 00000000000..8a097812c12 --- /dev/null +++ b/queue-5.10/nfsd-update-the-nfsv2-acl-access-result-encoder-to-u.patch @@ -0,0 +1,52 @@ +From 25c15f5b8e1a5648a92badf874520b8318e13e70 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Nov 2020 14:52:09 -0500 +Subject: NFSD: Update the NFSv2 ACL ACCESS result encoder to use struct + xdr_stream + +From: Chuck Lever + +[ Upstream commit 07f5c2963c04b11603e9667f89bb430c132e9cc1 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs2acl.c | 19 ++++++++++++------- + 1 file changed, 12 insertions(+), 7 deletions(-) + +diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c +index c805ac8dd7e77..8703326fc1654 100644 +--- a/fs/nfsd/nfs2acl.c ++++ b/fs/nfsd/nfs2acl.c +@@ -280,16 +280,21 @@ static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p) + /* ACCESS */ + static int nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd3_accessres *resp = rqstp->rq_resp; + +- *p++ = resp->status; +- if (resp->status != nfs_ok) +- goto out; ++ if (!svcxdr_encode_stat(xdr, resp->status)) ++ return 0; ++ switch (resp->status) { ++ case nfs_ok: ++ if (!svcxdr_encode_fattr(rqstp, xdr, &resp->fh, &resp->stat)) ++ return 0; ++ if (xdr_stream_encode_u32(xdr, resp->access) < 0) ++ return 0; ++ break; ++ } + +- p = nfs2svc_encode_fattr(rqstp, p, &resp->fh, &resp->stat); +- *p++ = htonl(resp->access); +-out: +- return xdr_ressize_check(rqstp, p); ++ return 1; + } + + /* +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-nfsv2-acl-getattr-argument-decoder-t.patch b/queue-5.10/nfsd-update-the-nfsv2-acl-getattr-argument-decoder-t.patch new file mode 100644 index 00000000000..d4eddeaad1d --- /dev/null +++ b/queue-5.10/nfsd-update-the-nfsv2-acl-getattr-argument-decoder-t.patch @@ -0,0 +1,52 @@ +From e325d5f1a9501ae146fa8548aa779a446ab62392 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Nov 2020 11:46:50 -0500 +Subject: NFSD: Update the NFSv2 ACL GETATTR argument decoder to use struct + xdr_stream + +From: Chuck Lever + +[ Upstream commit 571d31f37a57729c9d3463b5a692a84e619b408a ] + +Since the ACL GETATTR procedure is the same as the normal GETATTR +procedure, simply re-use nfssvc_decode_fhandleargs. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs2acl.c | 12 +----------- + 1 file changed, 1 insertion(+), 11 deletions(-) + +diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c +index 123820ec79d37..0274348f6679e 100644 +--- a/fs/nfsd/nfs2acl.c ++++ b/fs/nfsd/nfs2acl.c +@@ -220,16 +220,6 @@ static int nfsaclsvc_decode_setaclargs(struct svc_rqst *rqstp, __be32 *p) + return 1; + } + +-static int nfsaclsvc_decode_fhandleargs(struct svc_rqst *rqstp, __be32 *p) +-{ +- struct nfsd_fhandle *argp = rqstp->rq_argp; +- +- p = nfs2svc_decode_fh(p, &argp->fh); +- if (!p) +- return 0; +- return xdr_argsize_check(rqstp, p); +-} +- + static int nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, __be32 *p) + { + struct nfsd3_accessargs *argp = rqstp->rq_argp; +@@ -392,7 +382,7 @@ static const struct svc_procedure nfsd_acl_procedures2[5] = { + }, + [ACLPROC2_GETATTR] = { + .pc_func = nfsacld_proc_getattr, +- .pc_decode = nfsaclsvc_decode_fhandleargs, ++ .pc_decode = nfssvc_decode_fhandleargs, + .pc_encode = nfsaclsvc_encode_attrstatres, + .pc_release = nfsaclsvc_release_attrstat, + .pc_argsize = sizeof(struct nfsd_fhandle), +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-nfsv2-acl-getattr-result-encoder-to-.patch b/queue-5.10/nfsd-update-the-nfsv2-acl-getattr-result-encoder-to-.patch new file mode 100644 index 00000000000..d5ce414c5ab --- /dev/null +++ b/queue-5.10/nfsd-update-the-nfsv2-acl-getattr-result-encoder-to-.patch @@ -0,0 +1,68 @@ +From 31ff50fc8f847e494773757d7c28975d90dbe09b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Nov 2020 14:49:57 -0500 +Subject: NFSD: Update the NFSv2 ACL GETATTR result encoder to use struct + xdr_stream + +From: Chuck Lever + +[ Upstream commit 8d2009a10b3abaa12a39deb4876b215714993fe8 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs2acl.c | 24 ++---------------------- + 1 file changed, 2 insertions(+), 22 deletions(-) + +diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c +index ef06a2a384bea..c805ac8dd7e77 100644 +--- a/fs/nfsd/nfs2acl.c ++++ b/fs/nfsd/nfs2acl.c +@@ -277,19 +277,6 @@ static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p) + return 1; + } + +-static int nfsaclsvc_encode_attrstatres(struct svc_rqst *rqstp, __be32 *p) +-{ +- struct nfsd_attrstat *resp = rqstp->rq_resp; +- +- *p++ = resp->status; +- if (resp->status != nfs_ok) +- goto out; +- +- p = nfs2svc_encode_fattr(rqstp, p, &resp->fh, &resp->stat); +-out: +- return xdr_ressize_check(rqstp, p); +-} +- + /* ACCESS */ + static int nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, __be32 *p) + { +@@ -317,13 +304,6 @@ static void nfsaclsvc_release_getacl(struct svc_rqst *rqstp) + posix_acl_release(resp->acl_default); + } + +-static void nfsaclsvc_release_attrstat(struct svc_rqst *rqstp) +-{ +- struct nfsd_attrstat *resp = rqstp->rq_resp; +- +- fh_put(&resp->fh); +-} +- + static void nfsaclsvc_release_access(struct svc_rqst *rqstp) + { + struct nfsd3_accessres *resp = rqstp->rq_resp; +@@ -374,8 +354,8 @@ static const struct svc_procedure nfsd_acl_procedures2[5] = { + [ACLPROC2_GETATTR] = { + .pc_func = nfsacld_proc_getattr, + .pc_decode = nfssvc_decode_fhandleargs, +- .pc_encode = nfsaclsvc_encode_attrstatres, +- .pc_release = nfsaclsvc_release_attrstat, ++ .pc_encode = nfssvc_encode_attrstatres, ++ .pc_release = nfssvc_release_attrstat, + .pc_argsize = sizeof(struct nfsd_fhandle), + .pc_ressize = sizeof(struct nfsd_attrstat), + .pc_cachetype = RC_NOCACHE, +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-nfsv2-attrstat-encoder-to-use-struct.patch b/queue-5.10/nfsd-update-the-nfsv2-attrstat-encoder-to-use-struct.patch new file mode 100644 index 00000000000..f6752a5b434 --- /dev/null +++ b/queue-5.10/nfsd-update-the-nfsv2-attrstat-encoder-to-use-struct.patch @@ -0,0 +1,189 @@ +From 4e0b335df68bee5294abf4fb9cd60c05ff764f4a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Oct 2020 15:28:59 -0400 +Subject: NFSD: Update the NFSv2 attrstat encoder to use struct xdr_stream + +From: Chuck Lever + +[ Upstream commit 92b54a4fa4224e6116eb0d87a39dd05af23fcdfa ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsproc.c | 6 ++-- + fs/nfsd/nfsxdr.c | 90 ++++++++++++++++++++++++++++++++++++++++++----- + fs/nfsd/xdr.h | 2 +- + 3 files changed, 86 insertions(+), 12 deletions(-) + +diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c +index 00eb722129ab3..2a30b27c9d9be 100644 +--- a/fs/nfsd/nfsproc.c ++++ b/fs/nfsd/nfsproc.c +@@ -640,7 +640,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { + [NFSPROC_GETATTR] = { + .pc_func = nfsd_proc_getattr, + .pc_decode = nfssvc_decode_fhandleargs, +- .pc_encode = nfssvc_encode_attrstat, ++ .pc_encode = nfssvc_encode_attrstatres, + .pc_release = nfssvc_release_attrstat, + .pc_argsize = sizeof(struct nfsd_fhandle), + .pc_ressize = sizeof(struct nfsd_attrstat), +@@ -651,7 +651,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { + [NFSPROC_SETATTR] = { + .pc_func = nfsd_proc_setattr, + .pc_decode = nfssvc_decode_sattrargs, +- .pc_encode = nfssvc_encode_attrstat, ++ .pc_encode = nfssvc_encode_attrstatres, + .pc_release = nfssvc_release_attrstat, + .pc_argsize = sizeof(struct nfsd_sattrargs), + .pc_ressize = sizeof(struct nfsd_attrstat), +@@ -714,7 +714,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { + [NFSPROC_WRITE] = { + .pc_func = nfsd_proc_write, + .pc_decode = nfssvc_decode_writeargs, +- .pc_encode = nfssvc_encode_attrstat, ++ .pc_encode = nfssvc_encode_attrstatres, + .pc_release = nfssvc_release_attrstat, + .pc_argsize = sizeof(struct nfsd_writeargs), + .pc_ressize = sizeof(struct nfsd_attrstat), +diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c +index 10cd120044b30..65c8f8f314443 100644 +--- a/fs/nfsd/nfsxdr.c ++++ b/fs/nfsd/nfsxdr.c +@@ -14,7 +14,7 @@ + /* + * Mapping of S_IF* types to NFS file types + */ +-static u32 nfs_ftypes[] = { ++static const u32 nfs_ftypes[] = { + NFNON, NFCHR, NFCHR, NFBAD, + NFDIR, NFBAD, NFBLK, NFBAD, + NFREG, NFBAD, NFLNK, NFBAD, +@@ -70,6 +70,17 @@ encode_fh(__be32 *p, struct svc_fh *fhp) + return p + (NFS_FHSIZE>> 2); + } + ++static __be32 * ++encode_timeval(__be32 *p, const struct timespec64 *time) ++{ ++ *p++ = cpu_to_be32((u32)time->tv_sec); ++ if (time->tv_nsec) ++ *p++ = cpu_to_be32(time->tv_nsec / NSEC_PER_USEC); ++ else ++ *p++ = xdr_zero; ++ return p; ++} ++ + static bool + svcxdr_decode_filename(struct xdr_stream *xdr, char **name, unsigned int *len) + { +@@ -233,6 +244,64 @@ encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, + return p; + } + ++static int ++svcxdr_encode_fattr(struct svc_rqst *rqstp, struct xdr_stream *xdr, ++ const struct svc_fh *fhp, const struct kstat *stat) ++{ ++ struct user_namespace *userns = nfsd_user_namespace(rqstp); ++ struct dentry *dentry = fhp->fh_dentry; ++ int type = stat->mode & S_IFMT; ++ struct timespec64 time; ++ __be32 *p; ++ u32 fsid; ++ ++ p = xdr_reserve_space(xdr, XDR_UNIT * 17); ++ if (!p) ++ return 0; ++ ++ *p++ = cpu_to_be32(nfs_ftypes[type >> 12]); ++ *p++ = cpu_to_be32((u32)stat->mode); ++ *p++ = cpu_to_be32((u32)stat->nlink); ++ *p++ = cpu_to_be32((u32)from_kuid_munged(userns, stat->uid)); ++ *p++ = cpu_to_be32((u32)from_kgid_munged(userns, stat->gid)); ++ ++ if (S_ISLNK(type) && stat->size > NFS_MAXPATHLEN) ++ *p++ = cpu_to_be32(NFS_MAXPATHLEN); ++ else ++ *p++ = cpu_to_be32((u32) stat->size); ++ *p++ = cpu_to_be32((u32) stat->blksize); ++ if (S_ISCHR(type) || S_ISBLK(type)) ++ *p++ = cpu_to_be32(new_encode_dev(stat->rdev)); ++ else ++ *p++ = cpu_to_be32(0xffffffff); ++ *p++ = cpu_to_be32((u32)stat->blocks); ++ ++ switch (fsid_source(fhp)) { ++ case FSIDSOURCE_FSID: ++ fsid = (u32)fhp->fh_export->ex_fsid; ++ break; ++ case FSIDSOURCE_UUID: ++ fsid = ((u32 *)fhp->fh_export->ex_uuid)[0]; ++ fsid ^= ((u32 *)fhp->fh_export->ex_uuid)[1]; ++ fsid ^= ((u32 *)fhp->fh_export->ex_uuid)[2]; ++ fsid ^= ((u32 *)fhp->fh_export->ex_uuid)[3]; ++ break; ++ default: ++ fsid = new_encode_dev(stat->dev); ++ break; ++ } ++ *p++ = cpu_to_be32(fsid); ++ ++ *p++ = cpu_to_be32((u32)stat->ino); ++ p = encode_timeval(p, &stat->atime); ++ time = stat->mtime; ++ lease_get_mtime(d_inode(dentry), &time); ++ p = encode_timeval(p, &time); ++ encode_timeval(p, &stat->ctime); ++ ++ return 1; ++} ++ + /* Helper function for NFSv2 ACL code */ + __be32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, struct kstat *stat) + { +@@ -412,16 +481,21 @@ nfssvc_encode_statres(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nfssvc_encode_attrstat(struct svc_rqst *rqstp, __be32 *p) ++nfssvc_encode_attrstatres(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd_attrstat *resp = rqstp->rq_resp; + +- *p++ = resp->status; +- if (resp->status != nfs_ok) +- goto out; +- p = encode_fattr(rqstp, p, &resp->fh, &resp->stat); +-out: +- return xdr_ressize_check(rqstp, p); ++ if (!svcxdr_encode_stat(xdr, resp->status)) ++ return 0; ++ switch (resp->status) { ++ case nfs_ok: ++ if (!svcxdr_encode_fattr(rqstp, xdr, &resp->fh, &resp->stat)) ++ return 0; ++ break; ++ } ++ ++ return 1; + } + + int +diff --git a/fs/nfsd/xdr.h b/fs/nfsd/xdr.h +index f040123373bf5..45aa6b75a5f87 100644 +--- a/fs/nfsd/xdr.h ++++ b/fs/nfsd/xdr.h +@@ -148,7 +148,7 @@ int nfssvc_decode_linkargs(struct svc_rqst *, __be32 *); + int nfssvc_decode_symlinkargs(struct svc_rqst *, __be32 *); + int nfssvc_decode_readdirargs(struct svc_rqst *, __be32 *); + int nfssvc_encode_statres(struct svc_rqst *, __be32 *); +-int nfssvc_encode_attrstat(struct svc_rqst *, __be32 *); ++int nfssvc_encode_attrstatres(struct svc_rqst *, __be32 *); + int nfssvc_encode_diropres(struct svc_rqst *, __be32 *); + int nfssvc_encode_readlinkres(struct svc_rqst *, __be32 *); + int nfssvc_encode_readres(struct svc_rqst *, __be32 *); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-nfsv2-create-argument-decoder-to-use.patch b/queue-5.10/nfsd-update-the-nfsv2-create-argument-decoder-to-use.patch new file mode 100644 index 00000000000..5c9caf57494 --- /dev/null +++ b/queue-5.10/nfsd-update-the-nfsv2-create-argument-decoder-to-use.patch @@ -0,0 +1,42 @@ +From 6ba31967a8a1b478e37bcf97bf045ed1f11ac098 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Oct 2020 12:43:58 -0400 +Subject: NFSD: Update the NFSv2 CREATE argument decoder to use struct + xdr_stream + +From: Chuck Lever + +[ Upstream commit 7dcf65b91ecaf60ce593e7859ae2b29b7c46ccbd ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsxdr.c | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) + +diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c +index 6c87ea8f38769..2e2806cbe7b88 100644 +--- a/fs/nfsd/nfsxdr.c ++++ b/fs/nfsd/nfsxdr.c +@@ -401,14 +401,12 @@ nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p) + int + nfssvc_decode_createargs(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd_createargs *args = rqstp->rq_argp; + +- if ( !(p = decode_fh(p, &args->fh)) +- || !(p = decode_filename(p, &args->name, &args->len))) +- return 0; +- p = decode_sattr(p, &args->attrs, nfsd_user_namespace(rqstp)); +- +- return xdr_argsize_check(rqstp, p); ++ return svcxdr_decode_diropargs(xdr, &args->fh, ++ &args->name, &args->len) && ++ svcxdr_decode_sattr(rqstp, xdr, &args->attrs); + } + + int +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-nfsv2-diropres-encoder-to-use-struct.patch b/queue-5.10/nfsd-update-the-nfsv2-diropres-encoder-to-use-struct.patch new file mode 100644 index 00000000000..c32018be614 --- /dev/null +++ b/queue-5.10/nfsd-update-the-nfsv2-diropres-encoder-to-use-struct.patch @@ -0,0 +1,99 @@ +From 0564cc939508910d46afe1205f130e23e9bd9be9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Oct 2020 16:44:16 -0400 +Subject: NFSD: Update the NFSv2 diropres encoder to use struct xdr_stream + +From: Chuck Lever + +[ Upstream commit e3b4ef221ac57c08341c97a10c8a81c041f76716 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsxdr.c | 38 +++++++++++++++++++++++++------------- + 1 file changed, 25 insertions(+), 13 deletions(-) + +diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c +index 65c8f8f314443..989144b0d5be2 100644 +--- a/fs/nfsd/nfsxdr.c ++++ b/fs/nfsd/nfsxdr.c +@@ -63,11 +63,17 @@ svcxdr_decode_fhandle(struct xdr_stream *xdr, struct svc_fh *fhp) + return true; + } + +-static __be32 * +-encode_fh(__be32 *p, struct svc_fh *fhp) ++static bool ++svcxdr_encode_fhandle(struct xdr_stream *xdr, const struct svc_fh *fhp) + { ++ __be32 *p; ++ ++ p = xdr_reserve_space(xdr, NFS_FHSIZE); ++ if (!p) ++ return false; + memcpy(p, &fhp->fh_handle.fh_base, NFS_FHSIZE); +- return p + (NFS_FHSIZE>> 2); ++ ++ return true; + } + + static __be32 * +@@ -244,7 +250,7 @@ encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, + return p; + } + +-static int ++static bool + svcxdr_encode_fattr(struct svc_rqst *rqstp, struct xdr_stream *xdr, + const struct svc_fh *fhp, const struct kstat *stat) + { +@@ -257,7 +263,7 @@ svcxdr_encode_fattr(struct svc_rqst *rqstp, struct xdr_stream *xdr, + + p = xdr_reserve_space(xdr, XDR_UNIT * 17); + if (!p) +- return 0; ++ return false; + + *p++ = cpu_to_be32(nfs_ftypes[type >> 12]); + *p++ = cpu_to_be32((u32)stat->mode); +@@ -299,7 +305,7 @@ svcxdr_encode_fattr(struct svc_rqst *rqstp, struct xdr_stream *xdr, + p = encode_timeval(p, &time); + encode_timeval(p, &stat->ctime); + +- return 1; ++ return true; + } + + /* Helper function for NFSv2 ACL code */ +@@ -501,15 +507,21 @@ nfssvc_encode_attrstatres(struct svc_rqst *rqstp, __be32 *p) + int + nfssvc_encode_diropres(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd_diropres *resp = rqstp->rq_resp; + +- *p++ = resp->status; +- if (resp->status != nfs_ok) +- goto out; +- p = encode_fh(p, &resp->fh); +- p = encode_fattr(rqstp, p, &resp->fh, &resp->stat); +-out: +- return xdr_ressize_check(rqstp, p); ++ if (!svcxdr_encode_stat(xdr, resp->status)) ++ return 0; ++ switch (resp->status) { ++ case nfs_ok: ++ if (!svcxdr_encode_fhandle(xdr, &resp->fh)) ++ return 0; ++ if (!svcxdr_encode_fattr(rqstp, xdr, &resp->fh, &resp->stat)) ++ return 0; ++ break; ++ } ++ ++ return 1; + } + + int +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-nfsv2-getacl-argument-decoder-to-use.patch b/queue-5.10/nfsd-update-the-nfsv2-getacl-argument-decoder-to-use.patch new file mode 100644 index 00000000000..e0ef271d033 --- /dev/null +++ b/queue-5.10/nfsd-update-the-nfsv2-getacl-argument-decoder-to-use.patch @@ -0,0 +1,95 @@ +From 0f8849ec332a2c47175d387270e824846080ec27 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Nov 2020 11:32:04 -0500 +Subject: NFSD: Update the NFSv2 GETACL argument decoder to use struct + xdr_stream + +From: Chuck Lever + +[ Upstream commit 635a45d34706400c59c3b18ca9fccba195147bda ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs2acl.c | 10 +++++----- + fs/nfsd/nfsxdr.c | 11 ++++++++++- + fs/nfsd/xdr.h | 1 + + fs/nfsd/xdr3.h | 2 +- + 4 files changed, 17 insertions(+), 7 deletions(-) + +diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c +index 899762da23c92..df2e145cfab0d 100644 +--- a/fs/nfsd/nfs2acl.c ++++ b/fs/nfsd/nfs2acl.c +@@ -188,17 +188,17 @@ static __be32 nfsacld_proc_access(struct svc_rqst *rqstp) + + static int nfsaclsvc_decode_getaclargs(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd3_getaclargs *argp = rqstp->rq_argp; + +- p = nfs2svc_decode_fh(p, &argp->fh); +- if (!p) ++ if (!svcxdr_decode_fhandle(xdr, &argp->fh)) ++ return 0; ++ if (xdr_stream_decode_u32(xdr, &argp->mask) < 0) + return 0; +- argp->mask = ntohl(*p); p++; + +- return xdr_argsize_check(rqstp, p); ++ return 1; + } + +- + static int nfsaclsvc_decode_setaclargs(struct svc_rqst *rqstp, __be32 *p) + { + struct nfsd3_setaclargs *argp = rqstp->rq_argp; +diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c +index f2cb4794aeaf6..5ab9fc14816c2 100644 +--- a/fs/nfsd/nfsxdr.c ++++ b/fs/nfsd/nfsxdr.c +@@ -38,7 +38,16 @@ decode_fh(__be32 *p, struct svc_fh *fhp) + return p + (NFS_FHSIZE >> 2); + } + +-static bool ++/** ++ * svcxdr_decode_fhandle - Decode an NFSv2 file handle ++ * @xdr: XDR stream positioned at an encoded NFSv2 FH ++ * @fhp: OUT: filled-in server file handle ++ * ++ * Return values: ++ * %false: The encoded file handle was not valid ++ * %true: @fhp has been initialized ++ */ ++bool + svcxdr_decode_fhandle(struct xdr_stream *xdr, struct svc_fh *fhp) + { + __be32 *p; +diff --git a/fs/nfsd/xdr.h b/fs/nfsd/xdr.h +index ff68643504c3c..77afad72c2aa1 100644 +--- a/fs/nfsd/xdr.h ++++ b/fs/nfsd/xdr.h +@@ -165,5 +165,6 @@ void nfssvc_release_readres(struct svc_rqst *rqstp); + /* Helper functions for NFSv2 ACL code */ + __be32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, struct kstat *stat); + __be32 *nfs2svc_decode_fh(__be32 *p, struct svc_fh *fhp); ++bool svcxdr_decode_fhandle(struct xdr_stream *xdr, struct svc_fh *fhp); + + #endif /* LINUX_NFSD_H */ +diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h +index 64af5b01c5d7b..43db4206cd254 100644 +--- a/fs/nfsd/xdr3.h ++++ b/fs/nfsd/xdr3.h +@@ -102,7 +102,7 @@ struct nfsd3_commitargs { + + struct nfsd3_getaclargs { + struct svc_fh fh; +- int mask; ++ __u32 mask; + }; + + struct posix_acl; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-nfsv2-getacl-result-encoder-to-use-s.patch b/queue-5.10/nfsd-update-the-nfsv2-getacl-result-encoder-to-use-s.patch new file mode 100644 index 00000000000..8d503c93573 --- /dev/null +++ b/queue-5.10/nfsd-update-the-nfsv2-getacl-result-encoder-to-use-s.patch @@ -0,0 +1,147 @@ +From 5b49900e2ce1023359f9656e9660f5f75237f1d8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Nov 2020 14:38:47 -0500 +Subject: NFSD: Update the NFSv2 GETACL result encoder to use struct xdr_stream + +From: Chuck Lever + +[ Upstream commit f8cba47344f794b54373189bec23195b51020faf ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs2acl.c | 42 ++++++++++++++++-------------------------- + fs/nfsd/nfsxdr.c | 24 ++++++++++++++++++++++-- + fs/nfsd/xdr.h | 3 +++ + 3 files changed, 41 insertions(+), 28 deletions(-) + +diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c +index 7eeac5b81c200..102f8a9a235cb 100644 +--- a/fs/nfsd/nfs2acl.c ++++ b/fs/nfsd/nfs2acl.c +@@ -240,51 +240,41 @@ static int nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, __be32 *p) + /* GETACL */ + static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd3_getaclres *resp = rqstp->rq_resp; + struct dentry *dentry = resp->fh.fh_dentry; + struct inode *inode; +- struct kvec *head = rqstp->rq_res.head; +- unsigned int base; +- int n; + int w; + +- *p++ = resp->status; +- if (resp->status != nfs_ok) +- return xdr_ressize_check(rqstp, p); ++ if (!svcxdr_encode_stat(xdr, resp->status)) ++ return 0; + +- /* +- * Since this is version 2, the check for nfserr in +- * nfsd_dispatch actually ensures the following cannot happen. +- * However, it seems fragile to depend on that. +- */ + if (dentry == NULL || d_really_is_negative(dentry)) +- return 0; ++ return 1; + inode = d_inode(dentry); + +- p = nfs2svc_encode_fattr(rqstp, p, &resp->fh, &resp->stat); +- *p++ = htonl(resp->mask); +- if (!xdr_ressize_check(rqstp, p)) ++ if (!svcxdr_encode_fattr(rqstp, xdr, &resp->fh, &resp->stat)) ++ return 0; ++ if (xdr_stream_encode_u32(xdr, resp->mask) < 0) + return 0; +- base = (char *)p - (char *)head->iov_base; + + rqstp->rq_res.page_len = w = nfsacl_size( + (resp->mask & NFS_ACL) ? resp->acl_access : NULL, + (resp->mask & NFS_DFACL) ? resp->acl_default : NULL); + while (w > 0) { + if (!*(rqstp->rq_next_page++)) +- return 0; ++ return 1; + w -= PAGE_SIZE; + } + +- n = nfsacl_encode(&rqstp->rq_res, base, inode, +- resp->acl_access, +- resp->mask & NFS_ACL, 0); +- if (n > 0) +- n = nfsacl_encode(&rqstp->rq_res, base + n, inode, +- resp->acl_default, +- resp->mask & NFS_DFACL, +- NFS_ACL_DEFAULT); +- return (n > 0); ++ if (!nfs_stream_encode_acl(xdr, inode, resp->acl_access, ++ resp->mask & NFS_ACL, 0)) ++ return 0; ++ if (!nfs_stream_encode_acl(xdr, inode, resp->acl_default, ++ resp->mask & NFS_DFACL, NFS_ACL_DEFAULT)) ++ return 0; ++ ++ return 1; + } + + static int nfsaclsvc_encode_attrstatres(struct svc_rqst *rqstp, __be32 *p) +diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c +index 5df6f00d76fd5..1fed3a8deb183 100644 +--- a/fs/nfsd/nfsxdr.c ++++ b/fs/nfsd/nfsxdr.c +@@ -26,7 +26,16 @@ static const u32 nfs_ftypes[] = { + * Basic NFSv2 data types (RFC 1094 Section 2.3) + */ + +-static bool ++/** ++ * svcxdr_encode_stat - Encode an NFSv2 status code ++ * @xdr: XDR stream ++ * @status: status value to encode ++ * ++ * Return values: ++ * %false: Send buffer space was exhausted ++ * %true: Success ++ */ ++bool + svcxdr_encode_stat(struct xdr_stream *xdr, __be32 status) + { + __be32 *p; +@@ -250,7 +259,18 @@ encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, + return p; + } + +-static bool ++/** ++ * svcxdr_encode_fattr - Encode NFSv2 file attributes ++ * @rqstp: Context of a completed RPC transaction ++ * @xdr: XDR stream ++ * @fhp: File handle to encode ++ * @stat: Attributes to encode ++ * ++ * Return values: ++ * %false: Send buffer space was exhausted ++ * %true: Success ++ */ ++bool + svcxdr_encode_fattr(struct svc_rqst *rqstp, struct xdr_stream *xdr, + const struct svc_fh *fhp, const struct kstat *stat) + { +diff --git a/fs/nfsd/xdr.h b/fs/nfsd/xdr.h +index 10f3bd25e8ccc..8bcdc37398ab5 100644 +--- a/fs/nfsd/xdr.h ++++ b/fs/nfsd/xdr.h +@@ -170,5 +170,8 @@ void nfssvc_release_readres(struct svc_rqst *rqstp); + /* Helper functions for NFSv2 ACL code */ + __be32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, struct kstat *stat); + bool svcxdr_decode_fhandle(struct xdr_stream *xdr, struct svc_fh *fhp); ++bool svcxdr_encode_stat(struct xdr_stream *xdr, __be32 status); ++bool svcxdr_encode_fattr(struct svc_rqst *rqstp, struct xdr_stream *xdr, ++ const struct svc_fh *fhp, const struct kstat *stat); + + #endif /* LINUX_NFSD_H */ +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-nfsv2-getattr-argument-decoder-to-us.patch b/queue-5.10/nfsd-update-the-nfsv2-getattr-argument-decoder-to-us.patch new file mode 100644 index 00000000000..ddf9e7451f4 --- /dev/null +++ b/queue-5.10/nfsd-update-the-nfsv2-getattr-argument-decoder-to-us.patch @@ -0,0 +1,111 @@ +From e0b867bbe8c8b8f6e4ddbdc373c94b203bda7833 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Oct 2020 12:14:23 -0400 +Subject: NFSD: Update the NFSv2 GETATTR argument decoder to use struct + xdr_stream + +From: Chuck Lever + +[ Upstream commit ebcd8e8b28535b643a4c06685bd363b3b73a96af ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsproc.c | 4 ++-- + fs/nfsd/nfsxdr.c | 26 ++++++++++++++++++++------ + fs/nfsd/xdr.h | 2 +- + 3 files changed, 23 insertions(+), 9 deletions(-) + +diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c +index f22f70f63b53e..3cac9972aa83f 100644 +--- a/fs/nfsd/nfsproc.c ++++ b/fs/nfsd/nfsproc.c +@@ -627,7 +627,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { + }, + [NFSPROC_GETATTR] = { + .pc_func = nfsd_proc_getattr, +- .pc_decode = nfssvc_decode_fhandle, ++ .pc_decode = nfssvc_decode_fhandleargs, + .pc_encode = nfssvc_encode_attrstat, + .pc_release = nfssvc_release_attrstat, + .pc_argsize = sizeof(struct nfsd_fhandle), +@@ -793,7 +793,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { + }, + [NFSPROC_STATFS] = { + .pc_func = nfsd_proc_statfs, +- .pc_decode = nfssvc_decode_fhandle, ++ .pc_decode = nfssvc_decode_fhandleargs, + .pc_encode = nfssvc_encode_statfsres, + .pc_argsize = sizeof(struct nfsd_fhandle), + .pc_ressize = sizeof(struct nfsd_statfsres), +diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c +index 7aa6e8aca2c1a..f3189e1be20fa 100644 +--- a/fs/nfsd/nfsxdr.c ++++ b/fs/nfsd/nfsxdr.c +@@ -23,8 +23,9 @@ static u32 nfs_ftypes[] = { + + + /* +- * XDR functions for basic NFS types ++ * Basic NFSv2 data types (RFC 1094 Section 2.3) + */ ++ + static __be32 * + decode_fh(__be32 *p, struct svc_fh *fhp) + { +@@ -37,6 +38,21 @@ decode_fh(__be32 *p, struct svc_fh *fhp) + return p + (NFS_FHSIZE >> 2); + } + ++static bool ++svcxdr_decode_fhandle(struct xdr_stream *xdr, struct svc_fh *fhp) ++{ ++ __be32 *p; ++ ++ p = xdr_inline_decode(xdr, NFS_FHSIZE); ++ if (!p) ++ return false; ++ fh_init(fhp, NFS_FHSIZE); ++ memcpy(&fhp->fh_handle.fh_base, p, NFS_FHSIZE); ++ fhp->fh_handle.fh_size = NFS_FHSIZE; ++ ++ return true; ++} ++ + /* Helper function for NFSv2 ACL code */ + __be32 *nfs2svc_decode_fh(__be32 *p, struct svc_fh *fhp) + { +@@ -194,14 +210,12 @@ __be32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *f + */ + + int +-nfssvc_decode_fhandle(struct svc_rqst *rqstp, __be32 *p) ++nfssvc_decode_fhandleargs(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd_fhandle *args = rqstp->rq_argp; + +- p = decode_fh(p, &args->fh); +- if (!p) +- return 0; +- return xdr_argsize_check(rqstp, p); ++ return svcxdr_decode_fhandle(xdr, &args->fh); + } + + int +diff --git a/fs/nfsd/xdr.h b/fs/nfsd/xdr.h +index edd87688ff863..50466ac6200cc 100644 +--- a/fs/nfsd/xdr.h ++++ b/fs/nfsd/xdr.h +@@ -144,7 +144,7 @@ union nfsd_xdrstore { + #define NFS2_SVC_XDRSIZE sizeof(union nfsd_xdrstore) + + +-int nfssvc_decode_fhandle(struct svc_rqst *, __be32 *); ++int nfssvc_decode_fhandleargs(struct svc_rqst *, __be32 *); + int nfssvc_decode_sattrargs(struct svc_rqst *, __be32 *); + int nfssvc_decode_diropargs(struct svc_rqst *, __be32 *); + int nfssvc_decode_readargs(struct svc_rqst *, __be32 *); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-nfsv2-link-argument-decoder-to-use-s.patch b/queue-5.10/nfsd-update-the-nfsv2-link-argument-decoder-to-use-s.patch new file mode 100644 index 00000000000..4fd2b5191e9 --- /dev/null +++ b/queue-5.10/nfsd-update-the-nfsv2-link-argument-decoder-to-use-s.patch @@ -0,0 +1,41 @@ +From ba185a6c1a8a2af79f76c93c34d032535f8a9ee7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Oct 2020 12:34:24 -0400 +Subject: NFSD: Update the NFSv2 LINK argument decoder to use struct xdr_stream + +From: Chuck Lever + +[ Upstream commit 77edcdf91f6245a9881b84e4e101738148bd039a ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsxdr.c | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) + +diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c +index d4f4729c7b1c0..3d0fe03a3fb94 100644 +--- a/fs/nfsd/nfsxdr.c ++++ b/fs/nfsd/nfsxdr.c +@@ -356,14 +356,12 @@ nfssvc_decode_renameargs(struct svc_rqst *rqstp, __be32 *p) + int + nfssvc_decode_linkargs(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd_linkargs *args = rqstp->rq_argp; + +- if (!(p = decode_fh(p, &args->ffh)) +- || !(p = decode_fh(p, &args->tfh)) +- || !(p = decode_filename(p, &args->tname, &args->tlen))) +- return 0; +- +- return xdr_argsize_check(rqstp, p); ++ return svcxdr_decode_fhandle(xdr, &args->ffh) && ++ svcxdr_decode_diropargs(xdr, &args->tfh, ++ &args->tname, &args->tlen); + } + + int +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-nfsv2-read-argument-decoder-to-use-s.patch b/queue-5.10/nfsd-update-the-nfsv2-read-argument-decoder-to-use-s.patch new file mode 100644 index 00000000000..303fa83f91a --- /dev/null +++ b/queue-5.10/nfsd-update-the-nfsv2-read-argument-decoder-to-use-s.patch @@ -0,0 +1,140 @@ +From 47ab06e7b9936f8e14d20219b4fec1599e852552 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Oct 2020 12:15:51 -0400 +Subject: NFSD: Update the NFSv2 READ argument decoder to use struct xdr_stream + +From: Chuck Lever + +[ Upstream commit 8c293ef993c8df0b1bea9ecb0de6eb96dec3ac9d ] + +The code that sets up rq_vec is refactored so that it is now +adjacent to the nfsd_read() call site where it is used. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsproc.c | 32 ++++++++++++++++++-------------- + fs/nfsd/nfsxdr.c | 36 ++++++++++++------------------------ + fs/nfsd/xdr.h | 1 - + 3 files changed, 30 insertions(+), 39 deletions(-) + +diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c +index 3cac9972aa83f..c70ae20e54c49 100644 +--- a/fs/nfsd/nfsproc.c ++++ b/fs/nfsd/nfsproc.c +@@ -171,32 +171,36 @@ nfsd_proc_read(struct svc_rqst *rqstp) + { + struct nfsd_readargs *argp = rqstp->rq_argp; + struct nfsd_readres *resp = rqstp->rq_resp; ++ unsigned int len; + u32 eof; ++ int v; + + dprintk("nfsd: READ %s %d bytes at %d\n", + SVCFH_fmt(&argp->fh), + argp->count, argp->offset); + ++ argp->count = min_t(u32, argp->count, NFSSVC_MAXBLKSIZE_V2); ++ ++ v = 0; ++ len = argp->count; ++ while (len > 0) { ++ struct page *page = *(rqstp->rq_next_page++); ++ ++ rqstp->rq_vec[v].iov_base = page_address(page); ++ rqstp->rq_vec[v].iov_len = min_t(unsigned int, len, PAGE_SIZE); ++ len -= rqstp->rq_vec[v].iov_len; ++ v++; ++ } ++ + /* Obtain buffer pointer for payload. 19 is 1 word for + * status, 17 words for fattr, and 1 word for the byte count. + */ +- +- if (NFSSVC_MAXBLKSIZE_V2 < argp->count) { +- char buf[RPC_MAX_ADDRBUFLEN]; +- printk(KERN_NOTICE +- "oversized read request from %s (%d bytes)\n", +- svc_print_addr(rqstp, buf, sizeof(buf)), +- argp->count); +- argp->count = NFSSVC_MAXBLKSIZE_V2; +- } + svc_reserve_auth(rqstp, (19<<2) + argp->count + 4); + + resp->count = argp->count; +- resp->status = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh), +- argp->offset, +- rqstp->rq_vec, argp->vlen, +- &resp->count, +- &eof); ++ fh_copy(&resp->fh, &argp->fh); ++ resp->status = nfsd_read(rqstp, &resp->fh, argp->offset, ++ rqstp->rq_vec, v, &resp->count, &eof); + if (resp->status == nfs_ok) + resp->status = fh_getattr(&resp->fh, &resp->stat); + else if (resp->status == nfserr_jukebox) +diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c +index f3189e1be20fa..1eacaa2c13a95 100644 +--- a/fs/nfsd/nfsxdr.c ++++ b/fs/nfsd/nfsxdr.c +@@ -246,33 +246,21 @@ nfssvc_decode_diropargs(struct svc_rqst *rqstp, __be32 *p) + int + nfssvc_decode_readargs(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd_readargs *args = rqstp->rq_argp; +- unsigned int len; +- int v; +- p = decode_fh(p, &args->fh); +- if (!p) +- return 0; ++ u32 totalcount; + +- args->offset = ntohl(*p++); +- len = args->count = ntohl(*p++); +- p++; /* totalcount - unused */ +- +- len = min_t(unsigned int, len, NFSSVC_MAXBLKSIZE_V2); ++ if (!svcxdr_decode_fhandle(xdr, &args->fh)) ++ return 0; ++ if (xdr_stream_decode_u32(xdr, &args->offset) < 0) ++ return 0; ++ if (xdr_stream_decode_u32(xdr, &args->count) < 0) ++ return 0; ++ /* totalcount is ignored */ ++ if (xdr_stream_decode_u32(xdr, &totalcount) < 0) ++ return 0; + +- /* set up somewhere to store response. +- * We take pages, put them on reslist and include in iovec +- */ +- v=0; +- while (len > 0) { +- struct page *p = *(rqstp->rq_next_page++); +- +- rqstp->rq_vec[v].iov_base = page_address(p); +- rqstp->rq_vec[v].iov_len = min_t(unsigned int, len, PAGE_SIZE); +- len -= rqstp->rq_vec[v].iov_len; +- v++; +- } +- args->vlen = v; +- return xdr_argsize_check(rqstp, p); ++ return 1; + } + + int +diff --git a/fs/nfsd/xdr.h b/fs/nfsd/xdr.h +index 50466ac6200cc..7c704fa3215eb 100644 +--- a/fs/nfsd/xdr.h ++++ b/fs/nfsd/xdr.h +@@ -27,7 +27,6 @@ struct nfsd_readargs { + struct svc_fh fh; + __u32 offset; + __u32 count; +- int vlen; + }; + + struct nfsd_writeargs { +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-nfsv2-read-result-encoder-to-use-str.patch b/queue-5.10/nfsd-update-the-nfsv2-read-result-encoder-to-use-str.patch new file mode 100644 index 00000000000..ac40e49de0a --- /dev/null +++ b/queue-5.10/nfsd-update-the-nfsv2-read-result-encoder-to-use-str.patch @@ -0,0 +1,91 @@ +From ce02c08f7cbd07dcb20f05f5940584f818f63cd3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Oct 2020 16:40:11 -0400 +Subject: NFSD: Update the NFSv2 READ result encoder to use struct xdr_stream + +From: Chuck Lever + +[ Upstream commit a6f8d9dc9e44b51303d9abde4643460137d19b28 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsproc.c | 1 + + fs/nfsd/nfsxdr.c | 32 +++++++++++++++----------------- + fs/nfsd/xdr.h | 1 + + 3 files changed, 17 insertions(+), 17 deletions(-) + +diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c +index fa9a18897bc29..1fd91e00b97ba 100644 +--- a/fs/nfsd/nfsproc.c ++++ b/fs/nfsd/nfsproc.c +@@ -185,6 +185,7 @@ nfsd_proc_read(struct svc_rqst *rqstp) + + v = 0; + len = argp->count; ++ resp->pages = rqstp->rq_next_page; + while (len > 0) { + struct page *page = *(rqstp->rq_next_page++); + +diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c +index 74d9d11949c6c..d6d7d07dbb1b2 100644 +--- a/fs/nfsd/nfsxdr.c ++++ b/fs/nfsd/nfsxdr.c +@@ -549,27 +549,25 @@ nfssvc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p) + int + nfssvc_encode_readres(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd_readres *resp = rqstp->rq_resp; + struct kvec *head = rqstp->rq_res.head; + +- *p++ = resp->status; +- if (resp->status != nfs_ok) +- return xdr_ressize_check(rqstp, p); +- +- p = encode_fattr(rqstp, p, &resp->fh, &resp->stat); +- *p++ = htonl(resp->count); +- xdr_ressize_check(rqstp, p); +- +- /* now update rqstp->rq_res to reflect data as well */ +- rqstp->rq_res.page_len = resp->count; +- if (resp->count & 3) { +- /* need to pad the tail */ +- rqstp->rq_res.tail[0].iov_base = p; +- *p = 0; +- rqstp->rq_res.tail[0].iov_len = 4 - (resp->count&3); +- } +- if (svc_encode_result_payload(rqstp, head->iov_len, resp->count)) ++ if (!svcxdr_encode_stat(xdr, resp->status)) + return 0; ++ switch (resp->status) { ++ case nfs_ok: ++ if (!svcxdr_encode_fattr(rqstp, xdr, &resp->fh, &resp->stat)) ++ return 0; ++ if (xdr_stream_encode_u32(xdr, resp->count) < 0) ++ return 0; ++ xdr_write_pages(xdr, resp->pages, rqstp->rq_res.page_base, ++ resp->count); ++ if (svc_encode_result_payload(rqstp, head->iov_len, resp->count) < 0) ++ return 0; ++ break; ++ } ++ + return 1; + } + +diff --git a/fs/nfsd/xdr.h b/fs/nfsd/xdr.h +index b17fd72c69a6a..337c581e15b4c 100644 +--- a/fs/nfsd/xdr.h ++++ b/fs/nfsd/xdr.h +@@ -102,6 +102,7 @@ struct nfsd_readres { + struct svc_fh fh; + unsigned long count; + struct kstat stat; ++ struct page **pages; + }; + + struct nfsd_readdirres { +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-nfsv2-readdir-argument-decoder-to-us.patch b/queue-5.10/nfsd-update-the-nfsv2-readdir-argument-decoder-to-us.patch new file mode 100644 index 00000000000..b08b53ab283 --- /dev/null +++ b/queue-5.10/nfsd-update-the-nfsv2-readdir-argument-decoder-to-us.patch @@ -0,0 +1,49 @@ +From c88d11b03d0deb96531c667b7862892b0388e856 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 19 Oct 2020 14:15:51 -0400 +Subject: NFSD: Update the NFSv2 READDIR argument decoder to use struct + xdr_stream + +From: Chuck Lever + +[ Upstream commit 8688361ae2edb8f7e61d926dc5000c9a44f29370 ] + +As an additional clean up, move code not related to XDR decoding +into readdir's .pc_func call out. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsxdr.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c +index 3d72334e16733..7b33093f8d8b4 100644 +--- a/fs/nfsd/nfsxdr.c ++++ b/fs/nfsd/nfsxdr.c +@@ -381,15 +381,17 @@ nfssvc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p) + int + nfssvc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd_readdirargs *args = rqstp->rq_argp; + +- p = decode_fh(p, &args->fh); +- if (!p) ++ if (!svcxdr_decode_fhandle(xdr, &args->fh)) ++ return 0; ++ if (xdr_stream_decode_u32(xdr, &args->cookie) < 0) ++ return 0; ++ if (xdr_stream_decode_u32(xdr, &args->count) < 0) + return 0; +- args->cookie = ntohl(*p++); +- args->count = ntohl(*p++); + +- return xdr_argsize_check(rqstp, p); ++ return 1; + } + + /* +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-nfsv2-readdir-entry-encoder-to-use-s.patch b/queue-5.10/nfsd-update-the-nfsv2-readdir-entry-encoder-to-use-s.patch new file mode 100644 index 00000000000..522ff924945 --- /dev/null +++ b/queue-5.10/nfsd-update-the-nfsv2-readdir-entry-encoder-to-use-s.patch @@ -0,0 +1,214 @@ +From 280af864c03b25fcf73b61a2f7ef76ce997da2e7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 14 Nov 2020 13:45:35 -0500 +Subject: NFSD: Update the NFSv2 READDIR entry encoder to use struct xdr_stream + +From: Chuck Lever + +[ Upstream commit f5dcccd647da513a89f3b6ca392b0c1eb050b9fc ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsproc.c | 26 +++++++++++---- + fs/nfsd/nfsxdr.c | 81 ++++++++++++++++++++++++++++++++++++++++++++--- + fs/nfsd/xdr.h | 7 ++++ + 3 files changed, 103 insertions(+), 11 deletions(-) + +diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c +index 23b2a900cb79d..135c0bc468bce 100644 +--- a/fs/nfsd/nfsproc.c ++++ b/fs/nfsd/nfsproc.c +@@ -559,14 +559,27 @@ static void nfsd_init_dirlist_pages(struct svc_rqst *rqstp, + struct nfsd_readdirres *resp, + int count) + { ++ struct xdr_buf *buf = &resp->dirlist; ++ struct xdr_stream *xdr = &resp->xdr; ++ + count = min_t(u32, count, PAGE_SIZE); + +- /* Convert byte count to number of words (i.e. >> 2), +- * and reserve room for the NULL ptr & eof flag (-2 words) */ +- resp->buflen = (count >> 2) - 2; ++ memset(buf, 0, sizeof(*buf)); + +- resp->buffer = page_address(*rqstp->rq_next_page); ++ /* Reserve room for the NULL ptr & eof flag (-2 words) */ ++ buf->buflen = count - sizeof(__be32) * 2; ++ buf->pages = rqstp->rq_next_page; + rqstp->rq_next_page++; ++ ++ /* This is xdr_init_encode(), but it assumes that ++ * the head kvec has already been consumed. */ ++ xdr_set_scratch_buffer(xdr, NULL, 0); ++ xdr->buf = buf; ++ xdr->page_ptr = buf->pages; ++ xdr->iov = NULL; ++ xdr->p = page_address(*buf->pages); ++ xdr->end = xdr->p + (PAGE_SIZE >> 2); ++ xdr->rqst = NULL; + } + + /* +@@ -585,12 +598,11 @@ nfsd_proc_readdir(struct svc_rqst *rqstp) + + nfsd_init_dirlist_pages(rqstp, resp, argp->count); + +- resp->offset = NULL; + resp->common.err = nfs_ok; +- /* Read directory and encode entries on the fly */ ++ resp->cookie_offset = 0; + offset = argp->cookie; + resp->status = nfsd_readdir(rqstp, &argp->fh, &offset, +- &resp->common, nfssvc_encode_entry); ++ &resp->common, nfs2svc_encode_entry); + nfssvc_encode_nfscookie(resp, offset); + + fh_put(&argp->fh); +diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c +index 9522e5c5f49db..1102d40ded03f 100644 +--- a/fs/nfsd/nfsxdr.c ++++ b/fs/nfsd/nfsxdr.c +@@ -576,12 +576,13 @@ nfssvc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p) + { + struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd_readdirres *resp = rqstp->rq_resp; ++ struct xdr_buf *dirlist = &resp->dirlist; + + if (!svcxdr_encode_stat(xdr, resp->status)) + return 0; + switch (resp->status) { + case nfs_ok: +- xdr_write_pages(xdr, &resp->page, 0, resp->count << 2); ++ xdr_write_pages(xdr, dirlist->pages, 0, dirlist->len); + /* no more entries */ + if (xdr_stream_encode_item_absent(xdr) < 0) + return 0; +@@ -623,14 +624,86 @@ nfssvc_encode_statfsres(struct svc_rqst *rqstp, __be32 *p) + * @resp: readdir result context + * @offset: offset cookie to encode + * ++ * The buffer space for the offset cookie has already been reserved ++ * by svcxdr_encode_entry_common(). + */ + void nfssvc_encode_nfscookie(struct nfsd_readdirres *resp, u32 offset) + { +- if (!resp->offset) ++ __be32 cookie = cpu_to_be32(offset); ++ ++ if (!resp->cookie_offset) + return; + +- *resp->offset = cpu_to_be32(offset); +- resp->offset = NULL; ++ write_bytes_to_xdr_buf(&resp->dirlist, resp->cookie_offset, &cookie, ++ sizeof(cookie)); ++ resp->cookie_offset = 0; ++} ++ ++static bool ++svcxdr_encode_entry_common(struct nfsd_readdirres *resp, const char *name, ++ int namlen, loff_t offset, u64 ino) ++{ ++ struct xdr_buf *dirlist = &resp->dirlist; ++ struct xdr_stream *xdr = &resp->xdr; ++ ++ if (xdr_stream_encode_item_present(xdr) < 0) ++ return false; ++ /* fileid */ ++ if (xdr_stream_encode_u32(xdr, (u32)ino) < 0) ++ return false; ++ /* name */ ++ if (xdr_stream_encode_opaque(xdr, name, min(namlen, NFS2_MAXNAMLEN)) < 0) ++ return false; ++ /* cookie */ ++ resp->cookie_offset = dirlist->len; ++ if (xdr_stream_encode_u32(xdr, ~0U) < 0) ++ return false; ++ ++ return true; ++} ++ ++/** ++ * nfs2svc_encode_entry - encode one NFSv2 READDIR entry ++ * @data: directory context ++ * @name: name of the object to be encoded ++ * @namlen: length of that name, in bytes ++ * @offset: the offset of the previous entry ++ * @ino: the fileid of this entry ++ * @d_type: unused ++ * ++ * Return values: ++ * %0: Entry was successfully encoded. ++ * %-EINVAL: An encoding problem occured, secondary status code in resp->common.err ++ * ++ * On exit, the following fields are updated: ++ * - resp->xdr ++ * - resp->common.err ++ * - resp->cookie_offset ++ */ ++int nfs2svc_encode_entry(void *data, const char *name, int namlen, ++ loff_t offset, u64 ino, unsigned int d_type) ++{ ++ struct readdir_cd *ccd = data; ++ struct nfsd_readdirres *resp = container_of(ccd, ++ struct nfsd_readdirres, ++ common); ++ unsigned int starting_length = resp->dirlist.len; ++ ++ /* The offset cookie for the previous entry */ ++ nfssvc_encode_nfscookie(resp, offset); ++ ++ if (!svcxdr_encode_entry_common(resp, name, namlen, offset, ino)) ++ goto out_toosmall; ++ ++ xdr_commit_encode(&resp->xdr); ++ resp->common.err = nfs_ok; ++ return 0; ++ ++out_toosmall: ++ resp->cookie_offset = 0; ++ resp->common.err = nfserr_toosmall; ++ resp->dirlist.len = starting_length; ++ return -EINVAL; + } + + int +diff --git a/fs/nfsd/xdr.h b/fs/nfsd/xdr.h +index d7beef2c2ed5b..a065852c9ea86 100644 +--- a/fs/nfsd/xdr.h ++++ b/fs/nfsd/xdr.h +@@ -106,15 +106,20 @@ struct nfsd_readres { + }; + + struct nfsd_readdirres { ++ /* Components of the reply */ + __be32 status; + + int count; + ++ /* Used to encode the reply's entry list */ ++ struct xdr_stream xdr; ++ struct xdr_buf dirlist; + struct readdir_cd common; + __be32 * buffer; + int buflen; + __be32 * offset; + struct page *page; ++ unsigned int cookie_offset; + }; + + struct nfsd_statfsres { +@@ -159,6 +164,8 @@ int nfssvc_encode_statfsres(struct svc_rqst *, __be32 *); + int nfssvc_encode_readdirres(struct svc_rqst *, __be32 *); + + void nfssvc_encode_nfscookie(struct nfsd_readdirres *resp, u32 offset); ++int nfs2svc_encode_entry(void *data, const char *name, int namlen, ++ loff_t offset, u64 ino, unsigned int d_type); + int nfssvc_encode_entry(void *, const char *name, + int namlen, loff_t offset, u64 ino, unsigned int); + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-nfsv2-readdir-result-encoder-to-use-.patch b/queue-5.10/nfsd-update-the-nfsv2-readdir-result-encoder-to-use-.patch new file mode 100644 index 00000000000..d1c601d8ce5 --- /dev/null +++ b/queue-5.10/nfsd-update-the-nfsv2-readdir-result-encoder-to-use-.patch @@ -0,0 +1,67 @@ +From a701335aa7eb190e114ab100cdb1919a3813f854 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Oct 2020 16:49:01 -0400 +Subject: NFSD: Update the NFSv2 READDIR result encoder to use struct + xdr_stream + +From: Chuck Lever + +[ Upstream commit 94c8f8c682a6497af7ea71351b18f637c6337d42 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsxdr.c | 22 +++++++++++++--------- + fs/nfsd/xdr.h | 1 + + 2 files changed, 14 insertions(+), 9 deletions(-) + +diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c +index 8ae23ed6dc5db..9522e5c5f49db 100644 +--- a/fs/nfsd/nfsxdr.c ++++ b/fs/nfsd/nfsxdr.c +@@ -574,17 +574,21 @@ nfssvc_encode_readres(struct svc_rqst *rqstp, __be32 *p) + int + nfssvc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd_readdirres *resp = rqstp->rq_resp; + +- *p++ = resp->status; +- if (resp->status != nfs_ok) +- return xdr_ressize_check(rqstp, p); +- +- xdr_ressize_check(rqstp, p); +- p = resp->buffer; +- *p++ = 0; /* no more entries */ +- *p++ = htonl((resp->common.err == nfserr_eof)); +- rqstp->rq_res.page_len = resp->count << 2; ++ if (!svcxdr_encode_stat(xdr, resp->status)) ++ return 0; ++ switch (resp->status) { ++ case nfs_ok: ++ xdr_write_pages(xdr, &resp->page, 0, resp->count << 2); ++ /* no more entries */ ++ if (xdr_stream_encode_item_absent(xdr) < 0) ++ return 0; ++ if (xdr_stream_encode_bool(xdr, resp->common.err == nfserr_eof) < 0) ++ return 0; ++ break; ++ } + + return 1; + } +diff --git a/fs/nfsd/xdr.h b/fs/nfsd/xdr.h +index 75b3b31445340..d7beef2c2ed5b 100644 +--- a/fs/nfsd/xdr.h ++++ b/fs/nfsd/xdr.h +@@ -114,6 +114,7 @@ struct nfsd_readdirres { + __be32 * buffer; + int buflen; + __be32 * offset; ++ struct page *page; + }; + + struct nfsd_statfsres { +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-nfsv2-readlink-argument-decoder-to-u.patch b/queue-5.10/nfsd-update-the-nfsv2-readlink-argument-decoder-to-u.patch new file mode 100644 index 00000000000..539dca55235 --- /dev/null +++ b/queue-5.10/nfsd-update-the-nfsv2-readlink-argument-decoder-to-u.patch @@ -0,0 +1,108 @@ +From 6b93ab2cc5cca35519becbc7eda51029a9874a68 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Oct 2020 12:21:25 -0400 +Subject: NFSD: Update the NFSv2 READLINK argument decoder to use struct + xdr_stream + +From: Chuck Lever + +[ Upstream commit 1fcbd1c9456ba129d38420e345e91c4b6363db47 ] + +If the code that sets up the sink buffer for nfsd_readlink() is +moved adjacent to the nfsd_readlink() call site that uses it, then +the only argument is a file handle, and the fhandle decoder can be +used instead. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsproc.c | 9 +++++---- + fs/nfsd/nfsxdr.c | 13 ------------- + fs/nfsd/xdr.h | 6 ------ + 3 files changed, 5 insertions(+), 23 deletions(-) + +diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c +index c70ae20e54c49..6352da0168e04 100644 +--- a/fs/nfsd/nfsproc.c ++++ b/fs/nfsd/nfsproc.c +@@ -149,14 +149,15 @@ nfsd_proc_lookup(struct svc_rqst *rqstp) + static __be32 + nfsd_proc_readlink(struct svc_rqst *rqstp) + { +- struct nfsd_readlinkargs *argp = rqstp->rq_argp; ++ struct nfsd_fhandle *argp = rqstp->rq_argp; + struct nfsd_readlinkres *resp = rqstp->rq_resp; ++ char *buffer = page_address(*(rqstp->rq_next_page++)); + + dprintk("nfsd: READLINK %s\n", SVCFH_fmt(&argp->fh)); + + /* Read the symlink. */ + resp->len = NFS_MAXPATHLEN; +- resp->status = nfsd_readlink(rqstp, &argp->fh, argp->buffer, &resp->len); ++ resp->status = nfsd_readlink(rqstp, &argp->fh, buffer, &resp->len); + + fh_put(&argp->fh); + return rpc_success; +@@ -674,9 +675,9 @@ static const struct svc_procedure nfsd_procedures2[18] = { + }, + [NFSPROC_READLINK] = { + .pc_func = nfsd_proc_readlink, +- .pc_decode = nfssvc_decode_readlinkargs, ++ .pc_decode = nfssvc_decode_fhandleargs, + .pc_encode = nfssvc_encode_readlinkres, +- .pc_argsize = sizeof(struct nfsd_readlinkargs), ++ .pc_argsize = sizeof(struct nfsd_fhandle), + .pc_ressize = sizeof(struct nfsd_readlinkres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+1+NFS_MAXPATHLEN/4, +diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c +index 11d27b219cff2..02dd9888d93b2 100644 +--- a/fs/nfsd/nfsxdr.c ++++ b/fs/nfsd/nfsxdr.c +@@ -326,19 +326,6 @@ nfssvc_decode_renameargs(struct svc_rqst *rqstp, __be32 *p) + return xdr_argsize_check(rqstp, p); + } + +-int +-nfssvc_decode_readlinkargs(struct svc_rqst *rqstp, __be32 *p) +-{ +- struct nfsd_readlinkargs *args = rqstp->rq_argp; +- +- p = decode_fh(p, &args->fh); +- if (!p) +- return 0; +- args->buffer = page_address(*(rqstp->rq_next_page++)); +- +- return xdr_argsize_check(rqstp, p); +-} +- + int + nfssvc_decode_linkargs(struct svc_rqst *rqstp, __be32 *p) + { +diff --git a/fs/nfsd/xdr.h b/fs/nfsd/xdr.h +index 7c704fa3215eb..1338551de828e 100644 +--- a/fs/nfsd/xdr.h ++++ b/fs/nfsd/xdr.h +@@ -52,11 +52,6 @@ struct nfsd_renameargs { + unsigned int tlen; + }; + +-struct nfsd_readlinkargs { +- struct svc_fh fh; +- char * buffer; +-}; +- + struct nfsd_linkargs { + struct svc_fh ffh; + struct svc_fh tfh; +@@ -150,7 +145,6 @@ int nfssvc_decode_readargs(struct svc_rqst *, __be32 *); + int nfssvc_decode_writeargs(struct svc_rqst *, __be32 *); + int nfssvc_decode_createargs(struct svc_rqst *, __be32 *); + int nfssvc_decode_renameargs(struct svc_rqst *, __be32 *); +-int nfssvc_decode_readlinkargs(struct svc_rqst *, __be32 *); + int nfssvc_decode_linkargs(struct svc_rqst *, __be32 *); + int nfssvc_decode_symlinkargs(struct svc_rqst *, __be32 *); + int nfssvc_decode_readdirargs(struct svc_rqst *, __be32 *); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-nfsv2-readlink-result-encoder-to-use.patch b/queue-5.10/nfsd-update-the-nfsv2-readlink-result-encoder-to-use.patch new file mode 100644 index 00000000000..ab9fb9da85d --- /dev/null +++ b/queue-5.10/nfsd-update-the-nfsv2-readlink-result-encoder-to-use.patch @@ -0,0 +1,95 @@ +From 0b802e113c456bc1dad9bad1b048b33912b6d7e3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Oct 2020 15:41:09 -0400 +Subject: NFSD: Update the NFSv2 READLINK result encoder to use struct + xdr_stream + +From: Chuck Lever + +[ Upstream commit d9014b0f8fae11f22a3d356553844e06ddcdce4a ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsproc.c | 5 +++-- + fs/nfsd/nfsxdr.c | 26 ++++++++++++-------------- + fs/nfsd/xdr.h | 1 + + 3 files changed, 16 insertions(+), 16 deletions(-) + +diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c +index 2a30b27c9d9be..fa9a18897bc29 100644 +--- a/fs/nfsd/nfsproc.c ++++ b/fs/nfsd/nfsproc.c +@@ -151,13 +151,14 @@ nfsd_proc_readlink(struct svc_rqst *rqstp) + { + struct nfsd_fhandle *argp = rqstp->rq_argp; + struct nfsd_readlinkres *resp = rqstp->rq_resp; +- char *buffer = page_address(*(rqstp->rq_next_page++)); + + dprintk("nfsd: READLINK %s\n", SVCFH_fmt(&argp->fh)); + + /* Read the symlink. */ + resp->len = NFS_MAXPATHLEN; +- resp->status = nfsd_readlink(rqstp, &argp->fh, buffer, &resp->len); ++ resp->page = *(rqstp->rq_next_page++); ++ resp->status = nfsd_readlink(rqstp, &argp->fh, ++ page_address(resp->page), &resp->len); + + fh_put(&argp->fh); + return rpc_success; +diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c +index 989144b0d5be2..74d9d11949c6c 100644 +--- a/fs/nfsd/nfsxdr.c ++++ b/fs/nfsd/nfsxdr.c +@@ -527,24 +527,22 @@ nfssvc_encode_diropres(struct svc_rqst *rqstp, __be32 *p) + int + nfssvc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd_readlinkres *resp = rqstp->rq_resp; + struct kvec *head = rqstp->rq_res.head; + +- *p++ = resp->status; +- if (resp->status != nfs_ok) +- return xdr_ressize_check(rqstp, p); +- +- *p++ = htonl(resp->len); +- xdr_ressize_check(rqstp, p); +- rqstp->rq_res.page_len = resp->len; +- if (resp->len & 3) { +- /* need to pad the tail */ +- rqstp->rq_res.tail[0].iov_base = p; +- *p = 0; +- rqstp->rq_res.tail[0].iov_len = 4 - (resp->len&3); +- } +- if (svc_encode_result_payload(rqstp, head->iov_len, resp->len)) ++ if (!svcxdr_encode_stat(xdr, resp->status)) + return 0; ++ switch (resp->status) { ++ case nfs_ok: ++ if (xdr_stream_encode_u32(xdr, resp->len) < 0) ++ return 0; ++ xdr_write_pages(xdr, &resp->page, 0, resp->len); ++ if (svc_encode_result_payload(rqstp, head->iov_len, resp->len) < 0) ++ return 0; ++ break; ++ } ++ + return 1; + } + +diff --git a/fs/nfsd/xdr.h b/fs/nfsd/xdr.h +index 45aa6b75a5f87..b17fd72c69a6a 100644 +--- a/fs/nfsd/xdr.h ++++ b/fs/nfsd/xdr.h +@@ -94,6 +94,7 @@ struct nfsd_diropres { + struct nfsd_readlinkres { + __be32 status; + int len; ++ struct page *page; + }; + + struct nfsd_readres { +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-nfsv2-rename-argument-decoder-to-use.patch b/queue-5.10/nfsd-update-the-nfsv2-rename-argument-decoder-to-use.patch new file mode 100644 index 00000000000..29dac7a7377 --- /dev/null +++ b/queue-5.10/nfsd-update-the-nfsv2-rename-argument-decoder-to-use.patch @@ -0,0 +1,44 @@ +From cbe0e7633bf443ee6a8a4f2ed41b11eba28e8d31 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Oct 2020 12:35:41 -0400 +Subject: NFSD: Update the NFSv2 RENAME argument decoder to use struct + xdr_stream + +From: Chuck Lever + +[ Upstream commit 62aa557efb81ea3339fabe7f5b1a343e742bbbdf ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsxdr.c | 12 +++++------- + 1 file changed, 5 insertions(+), 7 deletions(-) + +diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c +index 00a7db8548ebf..d4f4729c7b1c0 100644 +--- a/fs/nfsd/nfsxdr.c ++++ b/fs/nfsd/nfsxdr.c +@@ -344,15 +344,13 @@ nfssvc_decode_createargs(struct svc_rqst *rqstp, __be32 *p) + int + nfssvc_decode_renameargs(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd_renameargs *args = rqstp->rq_argp; + +- if (!(p = decode_fh(p, &args->ffh)) +- || !(p = decode_filename(p, &args->fname, &args->flen)) +- || !(p = decode_fh(p, &args->tfh)) +- || !(p = decode_filename(p, &args->tname, &args->tlen))) +- return 0; +- +- return xdr_argsize_check(rqstp, p); ++ return svcxdr_decode_diropargs(xdr, &args->ffh, ++ &args->fname, &args->flen) && ++ svcxdr_decode_diropargs(xdr, &args->tfh, ++ &args->tname, &args->tlen); + } + + int +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-nfsv2-setacl-argument-decoder-to-use.patch b/queue-5.10/nfsd-update-the-nfsv2-setacl-argument-decoder-to-use.patch new file mode 100644 index 00000000000..9b1563a0756 --- /dev/null +++ b/queue-5.10/nfsd-update-the-nfsv2-setacl-argument-decoder-to-use.patch @@ -0,0 +1,78 @@ +From d8a36907aa8aa22ac73560b82711049f937b0581 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Nov 2020 11:37:35 -0500 +Subject: NFSD: Update the NFSv2 SETACL argument decoder to use struct + xdr_stream + +From: Chuck Lever + +[ Upstream commit 427eab3ba22891845265f9a3846de6ac152ec836 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs2acl.c | 29 ++++++++++++----------------- + fs/nfsd/xdr3.h | 2 +- + 2 files changed, 13 insertions(+), 18 deletions(-) + +diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c +index df2e145cfab0d..123820ec79d37 100644 +--- a/fs/nfsd/nfs2acl.c ++++ b/fs/nfsd/nfs2acl.c +@@ -201,28 +201,23 @@ static int nfsaclsvc_decode_getaclargs(struct svc_rqst *rqstp, __be32 *p) + + static int nfsaclsvc_decode_setaclargs(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd3_setaclargs *argp = rqstp->rq_argp; +- struct kvec *head = rqstp->rq_arg.head; +- unsigned int base; +- int n; + +- p = nfs2svc_decode_fh(p, &argp->fh); +- if (!p) ++ if (!svcxdr_decode_fhandle(xdr, &argp->fh)) ++ return 0; ++ if (xdr_stream_decode_u32(xdr, &argp->mask) < 0) ++ return 0; ++ if (argp->mask & ~NFS_ACL_MASK) + return 0; +- argp->mask = ntohl(*p++); +- if (argp->mask & ~NFS_ACL_MASK || +- !xdr_argsize_check(rqstp, p)) ++ if (!nfs_stream_decode_acl(xdr, NULL, (argp->mask & NFS_ACL) ? ++ &argp->acl_access : NULL)) ++ return 0; ++ if (!nfs_stream_decode_acl(xdr, NULL, (argp->mask & NFS_DFACL) ? ++ &argp->acl_default : NULL)) + return 0; + +- base = (char *)p - (char *)head->iov_base; +- n = nfsacl_decode(&rqstp->rq_arg, base, NULL, +- (argp->mask & NFS_ACL) ? +- &argp->acl_access : NULL); +- if (n > 0) +- n = nfsacl_decode(&rqstp->rq_arg, base + n, NULL, +- (argp->mask & NFS_DFACL) ? +- &argp->acl_default : NULL); +- return (n > 0); ++ return 1; + } + + static int nfsaclsvc_decode_fhandleargs(struct svc_rqst *rqstp, __be32 *p) +diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h +index 43db4206cd254..5afb3ce4f0622 100644 +--- a/fs/nfsd/xdr3.h ++++ b/fs/nfsd/xdr3.h +@@ -108,7 +108,7 @@ struct nfsd3_getaclargs { + struct posix_acl; + struct nfsd3_setaclargs { + struct svc_fh fh; +- int mask; ++ __u32 mask; + struct posix_acl *acl_access; + struct posix_acl *acl_default; + }; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-nfsv2-setacl-argument-decoder-to-use.patch-31348 b/queue-5.10/nfsd-update-the-nfsv2-setacl-argument-decoder-to-use.patch-31348 new file mode 100644 index 00000000000..c7b26744fc6 --- /dev/null +++ b/queue-5.10/nfsd-update-the-nfsv2-setacl-argument-decoder-to-use.patch-31348 @@ -0,0 +1,65 @@ +From da026acf196f450d22b1dfa809f3aa74395da008 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Nov 2020 11:56:26 -0500 +Subject: NFSD: Update the NFSv2 SETACL argument decoder to use struct + xdr_stream + +From: Chuck Lever + +[ Upstream commit 68519ff2a1c72c67fcdc4b81671acda59f420af9 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3acl.c | 31 +++++++++++++------------------ + 1 file changed, 13 insertions(+), 18 deletions(-) + +diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c +index addb0d7d5500f..a568b842e9ebe 100644 +--- a/fs/nfsd/nfs3acl.c ++++ b/fs/nfsd/nfs3acl.c +@@ -140,28 +140,23 @@ static int nfs3svc_decode_getaclargs(struct svc_rqst *rqstp, __be32 *p) + + static int nfs3svc_decode_setaclargs(struct svc_rqst *rqstp, __be32 *p) + { +- struct nfsd3_setaclargs *args = rqstp->rq_argp; +- struct kvec *head = rqstp->rq_arg.head; +- unsigned int base; +- int n; ++ struct xdr_stream *xdr = &rqstp->rq_arg_stream; ++ struct nfsd3_setaclargs *argp = rqstp->rq_argp; + +- p = nfs3svc_decode_fh(p, &args->fh); +- if (!p) ++ if (!svcxdr_decode_nfs_fh3(xdr, &argp->fh)) ++ return 0; ++ if (xdr_stream_decode_u32(xdr, &argp->mask) < 0) + return 0; +- args->mask = ntohl(*p++); +- if (args->mask & ~NFS_ACL_MASK || +- !xdr_argsize_check(rqstp, p)) ++ if (argp->mask & ~NFS_ACL_MASK) ++ return 0; ++ if (!nfs_stream_decode_acl(xdr, NULL, (argp->mask & NFS_ACL) ? ++ &argp->acl_access : NULL)) ++ return 0; ++ if (!nfs_stream_decode_acl(xdr, NULL, (argp->mask & NFS_DFACL) ? ++ &argp->acl_default : NULL)) + return 0; + +- base = (char *)p - (char *)head->iov_base; +- n = nfsacl_decode(&rqstp->rq_arg, base, NULL, +- (args->mask & NFS_ACL) ? +- &args->acl_access : NULL); +- if (n > 0) +- n = nfsacl_decode(&rqstp->rq_arg, base + n, NULL, +- (args->mask & NFS_DFACL) ? +- &args->acl_default : NULL); +- return (n > 0); ++ return 1; + } + + /* +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-nfsv2-setacl-result-encoder-to-use-s.patch b/queue-5.10/nfsd-update-the-nfsv2-setacl-result-encoder-to-use-s.patch new file mode 100644 index 00000000000..3e5627b8664 --- /dev/null +++ b/queue-5.10/nfsd-update-the-nfsv2-setacl-result-encoder-to-use-s.patch @@ -0,0 +1,36 @@ +From bbe6d556c9a78ee2159a5a6a2ca2175dc3e272f6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Nov 2020 14:47:56 -0500 +Subject: NFSD: Update the NFSv2 SETACL result encoder to use struct xdr_stream + +From: Chuck Lever + +[ Upstream commit 778f068fa0c0846b650ebdb8795fd51b5badc332 ] + +The SETACL result encoder is exactly the same as the NFSv2 +attrstatres decoder. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs2acl.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c +index 102f8a9a235cb..ef06a2a384bea 100644 +--- a/fs/nfsd/nfs2acl.c ++++ b/fs/nfsd/nfs2acl.c +@@ -363,8 +363,8 @@ static const struct svc_procedure nfsd_acl_procedures2[5] = { + [ACLPROC2_SETACL] = { + .pc_func = nfsacld_proc_setacl, + .pc_decode = nfsaclsvc_decode_setaclargs, +- .pc_encode = nfsaclsvc_encode_attrstatres, +- .pc_release = nfsaclsvc_release_attrstat, ++ .pc_encode = nfssvc_encode_attrstatres, ++ .pc_release = nfssvc_release_attrstat, + .pc_argsize = sizeof(struct nfsd3_setaclargs), + .pc_ressize = sizeof(struct nfsd_attrstat), + .pc_cachetype = RC_NOCACHE, +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-nfsv2-setattr-argument-decoder-to-us.patch b/queue-5.10/nfsd-update-the-nfsv2-setattr-argument-decoder-to-us.patch new file mode 100644 index 00000000000..afbd52ad89a --- /dev/null +++ b/queue-5.10/nfsd-update-the-nfsv2-setattr-argument-decoder-to-us.patch @@ -0,0 +1,121 @@ +From e9f03d6236920fc98ca86fe19a2bec6c7abd82a1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Oct 2020 12:39:06 -0400 +Subject: NFSD: Update the NFSv2 SETATTR argument decoder to use struct + xdr_stream + +From: Chuck Lever + +[ Upstream commit 2fdd6bd293b9e7dda61220538b2759fbf06f5af0 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsxdr.c | 82 ++++++++++++++++++++++++++++++++++++++++++++---- + 1 file changed, 76 insertions(+), 6 deletions(-) + +diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c +index 3d0fe03a3fb94..6c87ea8f38769 100644 +--- a/fs/nfsd/nfsxdr.c ++++ b/fs/nfsd/nfsxdr.c +@@ -173,6 +173,79 @@ decode_sattr(__be32 *p, struct iattr *iap, struct user_namespace *userns) + return p; + } + ++static bool ++svcxdr_decode_sattr(struct svc_rqst *rqstp, struct xdr_stream *xdr, ++ struct iattr *iap) ++{ ++ u32 tmp1, tmp2; ++ __be32 *p; ++ ++ p = xdr_inline_decode(xdr, XDR_UNIT * 8); ++ if (!p) ++ return false; ++ ++ iap->ia_valid = 0; ++ ++ /* ++ * Some Sun clients put 0xffff in the mode field when they ++ * mean 0xffffffff. ++ */ ++ tmp1 = be32_to_cpup(p++); ++ if (tmp1 != (u32)-1 && tmp1 != 0xffff) { ++ iap->ia_valid |= ATTR_MODE; ++ iap->ia_mode = tmp1; ++ } ++ ++ tmp1 = be32_to_cpup(p++); ++ if (tmp1 != (u32)-1) { ++ iap->ia_uid = make_kuid(nfsd_user_namespace(rqstp), tmp1); ++ if (uid_valid(iap->ia_uid)) ++ iap->ia_valid |= ATTR_UID; ++ } ++ ++ tmp1 = be32_to_cpup(p++); ++ if (tmp1 != (u32)-1) { ++ iap->ia_gid = make_kgid(nfsd_user_namespace(rqstp), tmp1); ++ if (gid_valid(iap->ia_gid)) ++ iap->ia_valid |= ATTR_GID; ++ } ++ ++ tmp1 = be32_to_cpup(p++); ++ if (tmp1 != (u32)-1) { ++ iap->ia_valid |= ATTR_SIZE; ++ iap->ia_size = tmp1; ++ } ++ ++ tmp1 = be32_to_cpup(p++); ++ tmp2 = be32_to_cpup(p++); ++ if (tmp1 != (u32)-1 && tmp2 != (u32)-1) { ++ iap->ia_valid |= ATTR_ATIME | ATTR_ATIME_SET; ++ iap->ia_atime.tv_sec = tmp1; ++ iap->ia_atime.tv_nsec = tmp2 * NSEC_PER_USEC; ++ } ++ ++ tmp1 = be32_to_cpup(p++); ++ tmp2 = be32_to_cpup(p++); ++ if (tmp1 != (u32)-1 && tmp2 != (u32)-1) { ++ iap->ia_valid |= ATTR_MTIME | ATTR_MTIME_SET; ++ iap->ia_mtime.tv_sec = tmp1; ++ iap->ia_mtime.tv_nsec = tmp2 * NSEC_PER_USEC; ++ /* ++ * Passing the invalid value useconds=1000000 for mtime ++ * is a Sun convention for "set both mtime and atime to ++ * current server time". It's needed to make permissions ++ * checks for the "touch" program across v2 mounts to ++ * Solaris and Irix boxes work correctly. See description of ++ * sattr in section 6.1 of "NFS Illustrated" by ++ * Brent Callaghan, Addison-Wesley, ISBN 0-201-32750-5 ++ */ ++ if (tmp2 == 1000000) ++ iap->ia_valid &= ~(ATTR_ATIME_SET|ATTR_MTIME_SET); ++ } ++ ++ return true; ++} ++ + static __be32 * + encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, + struct kstat *stat) +@@ -253,14 +326,11 @@ nfssvc_decode_fhandleargs(struct svc_rqst *rqstp, __be32 *p) + int + nfssvc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd_sattrargs *args = rqstp->rq_argp; + +- p = decode_fh(p, &args->fh); +- if (!p) +- return 0; +- p = decode_sattr(p, &args->attrs, nfsd_user_namespace(rqstp)); +- +- return xdr_argsize_check(rqstp, p); ++ return svcxdr_decode_fhandle(xdr, &args->fh) && ++ svcxdr_decode_sattr(rqstp, xdr, &args->attrs); + } + + int +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-nfsv2-stat-encoder-to-use-struct-xdr.patch b/queue-5.10/nfsd-update-the-nfsv2-stat-encoder-to-use-struct-xdr.patch new file mode 100644 index 00000000000..e07162bc5ee --- /dev/null +++ b/queue-5.10/nfsd-update-the-nfsv2-stat-encoder-to-use-struct-xdr.patch @@ -0,0 +1,122 @@ +From 14ae83588e23a4a2c1e08308c1b39a117f5577af Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Oct 2020 11:08:02 -0400 +Subject: NFSD: Update the NFSv2 stat encoder to use struct xdr_stream + +From: Chuck Lever + +[ Upstream commit a887eaed2a964754334cd3f8c5fe87e413e68fef ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsproc.c | 10 +++++----- + fs/nfsd/nfsxdr.c | 19 ++++++++++++++++--- + fs/nfsd/xdr.h | 2 +- + 3 files changed, 22 insertions(+), 9 deletions(-) + +diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c +index a628ea4d66ead..00eb722129ab3 100644 +--- a/fs/nfsd/nfsproc.c ++++ b/fs/nfsd/nfsproc.c +@@ -736,7 +736,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { + [NFSPROC_REMOVE] = { + .pc_func = nfsd_proc_remove, + .pc_decode = nfssvc_decode_diropargs, +- .pc_encode = nfssvc_encode_stat, ++ .pc_encode = nfssvc_encode_statres, + .pc_argsize = sizeof(struct nfsd_diropargs), + .pc_ressize = sizeof(struct nfsd_stat), + .pc_cachetype = RC_REPLSTAT, +@@ -746,7 +746,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { + [NFSPROC_RENAME] = { + .pc_func = nfsd_proc_rename, + .pc_decode = nfssvc_decode_renameargs, +- .pc_encode = nfssvc_encode_stat, ++ .pc_encode = nfssvc_encode_statres, + .pc_argsize = sizeof(struct nfsd_renameargs), + .pc_ressize = sizeof(struct nfsd_stat), + .pc_cachetype = RC_REPLSTAT, +@@ -756,7 +756,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { + [NFSPROC_LINK] = { + .pc_func = nfsd_proc_link, + .pc_decode = nfssvc_decode_linkargs, +- .pc_encode = nfssvc_encode_stat, ++ .pc_encode = nfssvc_encode_statres, + .pc_argsize = sizeof(struct nfsd_linkargs), + .pc_ressize = sizeof(struct nfsd_stat), + .pc_cachetype = RC_REPLSTAT, +@@ -766,7 +766,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { + [NFSPROC_SYMLINK] = { + .pc_func = nfsd_proc_symlink, + .pc_decode = nfssvc_decode_symlinkargs, +- .pc_encode = nfssvc_encode_stat, ++ .pc_encode = nfssvc_encode_statres, + .pc_argsize = sizeof(struct nfsd_symlinkargs), + .pc_ressize = sizeof(struct nfsd_stat), + .pc_cachetype = RC_REPLSTAT, +@@ -787,7 +787,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { + [NFSPROC_RMDIR] = { + .pc_func = nfsd_proc_rmdir, + .pc_decode = nfssvc_decode_diropargs, +- .pc_encode = nfssvc_encode_stat, ++ .pc_encode = nfssvc_encode_statres, + .pc_argsize = sizeof(struct nfsd_diropargs), + .pc_ressize = sizeof(struct nfsd_stat), + .pc_cachetype = RC_REPLSTAT, +diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c +index 5d79ef6a0c7fc..10cd120044b30 100644 +--- a/fs/nfsd/nfsxdr.c ++++ b/fs/nfsd/nfsxdr.c +@@ -26,6 +26,19 @@ static u32 nfs_ftypes[] = { + * Basic NFSv2 data types (RFC 1094 Section 2.3) + */ + ++static bool ++svcxdr_encode_stat(struct xdr_stream *xdr, __be32 status) ++{ ++ __be32 *p; ++ ++ p = xdr_reserve_space(xdr, sizeof(status)); ++ if (!p) ++ return false; ++ *p = status; ++ ++ return true; ++} ++ + /** + * svcxdr_decode_fhandle - Decode an NFSv2 file handle + * @xdr: XDR stream positioned at an encoded NFSv2 FH +@@ -390,12 +403,12 @@ nfssvc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p) + */ + + int +-nfssvc_encode_stat(struct svc_rqst *rqstp, __be32 *p) ++nfssvc_encode_statres(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd_stat *resp = rqstp->rq_resp; + +- *p++ = resp->status; +- return xdr_ressize_check(rqstp, p); ++ return svcxdr_encode_stat(xdr, resp->status); + } + + int +diff --git a/fs/nfsd/xdr.h b/fs/nfsd/xdr.h +index b92f1acec9e77..f040123373bf5 100644 +--- a/fs/nfsd/xdr.h ++++ b/fs/nfsd/xdr.h +@@ -147,7 +147,7 @@ int nfssvc_decode_renameargs(struct svc_rqst *, __be32 *); + int nfssvc_decode_linkargs(struct svc_rqst *, __be32 *); + int nfssvc_decode_symlinkargs(struct svc_rqst *, __be32 *); + int nfssvc_decode_readdirargs(struct svc_rqst *, __be32 *); +-int nfssvc_encode_stat(struct svc_rqst *, __be32 *); ++int nfssvc_encode_statres(struct svc_rqst *, __be32 *); + int nfssvc_encode_attrstat(struct svc_rqst *, __be32 *); + int nfssvc_encode_diropres(struct svc_rqst *, __be32 *); + int nfssvc_encode_readlinkres(struct svc_rqst *, __be32 *); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-nfsv2-statfs-result-encoder-to-use-s.patch b/queue-5.10/nfsd-update-the-nfsv2-statfs-result-encoder-to-use-s.patch new file mode 100644 index 00000000000..a8c92306de5 --- /dev/null +++ b/queue-5.10/nfsd-update-the-nfsv2-statfs-result-encoder-to-use-s.patch @@ -0,0 +1,58 @@ +From 579834a760884d6e9710d47226a40e2cc1413a02 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Oct 2020 19:01:38 -0400 +Subject: NFSD: Update the NFSv2 STATFS result encoder to use struct xdr_stream + +From: Chuck Lever + +[ Upstream commit bf15229f2ced4f14946eef958336f764e30f8efb ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsxdr.c | 25 ++++++++++++++++--------- + 1 file changed, 16 insertions(+), 9 deletions(-) + +diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c +index d6d7d07dbb1b2..39d296aecd3e7 100644 +--- a/fs/nfsd/nfsxdr.c ++++ b/fs/nfsd/nfsxdr.c +@@ -592,19 +592,26 @@ nfssvc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p) + int + nfssvc_encode_statfsres(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd_statfsres *resp = rqstp->rq_resp; + struct kstatfs *stat = &resp->stats; + +- *p++ = resp->status; +- if (resp->status != nfs_ok) +- return xdr_ressize_check(rqstp, p); ++ if (!svcxdr_encode_stat(xdr, resp->status)) ++ return 0; ++ switch (resp->status) { ++ case nfs_ok: ++ p = xdr_reserve_space(xdr, XDR_UNIT * 5); ++ if (!p) ++ return 0; ++ *p++ = cpu_to_be32(NFSSVC_MAXBLKSIZE_V2); ++ *p++ = cpu_to_be32(stat->f_bsize); ++ *p++ = cpu_to_be32(stat->f_blocks); ++ *p++ = cpu_to_be32(stat->f_bfree); ++ *p = cpu_to_be32(stat->f_bavail); ++ break; ++ } + +- *p++ = htonl(NFSSVC_MAXBLKSIZE_V2); /* max transfer size */ +- *p++ = htonl(stat->f_bsize); +- *p++ = htonl(stat->f_blocks); +- *p++ = htonl(stat->f_bfree); +- *p++ = htonl(stat->f_bavail); +- return xdr_ressize_check(rqstp, p); ++ return 1; + } + + int +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-nfsv2-symlink-argument-decoder-to-us.patch b/queue-5.10/nfsd-update-the-nfsv2-symlink-argument-decoder-to-us.patch new file mode 100644 index 00000000000..81327a3d07a --- /dev/null +++ b/queue-5.10/nfsd-update-the-nfsv2-symlink-argument-decoder-to-us.patch @@ -0,0 +1,163 @@ +From 69c5449b25e090a360518820e37ebd2c8491ebc4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Oct 2020 12:46:03 -0400 +Subject: NFSD: Update the NFSv2 SYMLINK argument decoder to use struct + xdr_stream + +From: Chuck Lever + +[ Upstream commit 09f75a5375ac61f4adb94da0accc1cfc60eb4f2b ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsxdr.c | 113 +++++------------------------------------------ + 1 file changed, 10 insertions(+), 103 deletions(-) + +diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c +index 2e2806cbe7b88..f2cb4794aeaf6 100644 +--- a/fs/nfsd/nfsxdr.c ++++ b/fs/nfsd/nfsxdr.c +@@ -66,26 +66,6 @@ encode_fh(__be32 *p, struct svc_fh *fhp) + return p + (NFS_FHSIZE>> 2); + } + +-/* +- * Decode a file name and make sure that the path contains +- * no slashes or null bytes. +- */ +-static __be32 * +-decode_filename(__be32 *p, char **namp, unsigned int *lenp) +-{ +- char *name; +- unsigned int i; +- +- if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS_MAXNAMLEN)) != NULL) { +- for (i = 0, name = *namp; i < *lenp; i++, name++) { +- if (*name == '\0' || *name == '/') +- return NULL; +- } +- } +- +- return p; +-} +- + static bool + svcxdr_decode_filename(struct xdr_stream *xdr, char **name, unsigned int *len) + { +@@ -118,61 +98,6 @@ svcxdr_decode_diropargs(struct xdr_stream *xdr, struct svc_fh *fhp, + svcxdr_decode_filename(xdr, name, len); + } + +-static __be32 * +-decode_sattr(__be32 *p, struct iattr *iap, struct user_namespace *userns) +-{ +- u32 tmp, tmp1; +- +- iap->ia_valid = 0; +- +- /* Sun client bug compatibility check: some sun clients seem to +- * put 0xffff in the mode field when they mean 0xffffffff. +- * Quoting the 4.4BSD nfs server code: Nah nah nah nah na nah. +- */ +- if ((tmp = ntohl(*p++)) != (u32)-1 && tmp != 0xffff) { +- iap->ia_valid |= ATTR_MODE; +- iap->ia_mode = tmp; +- } +- if ((tmp = ntohl(*p++)) != (u32)-1) { +- iap->ia_uid = make_kuid(userns, tmp); +- if (uid_valid(iap->ia_uid)) +- iap->ia_valid |= ATTR_UID; +- } +- if ((tmp = ntohl(*p++)) != (u32)-1) { +- iap->ia_gid = make_kgid(userns, tmp); +- if (gid_valid(iap->ia_gid)) +- iap->ia_valid |= ATTR_GID; +- } +- if ((tmp = ntohl(*p++)) != (u32)-1) { +- iap->ia_valid |= ATTR_SIZE; +- iap->ia_size = tmp; +- } +- tmp = ntohl(*p++); tmp1 = ntohl(*p++); +- if (tmp != (u32)-1 && tmp1 != (u32)-1) { +- iap->ia_valid |= ATTR_ATIME | ATTR_ATIME_SET; +- iap->ia_atime.tv_sec = tmp; +- iap->ia_atime.tv_nsec = tmp1 * 1000; +- } +- tmp = ntohl(*p++); tmp1 = ntohl(*p++); +- if (tmp != (u32)-1 && tmp1 != (u32)-1) { +- iap->ia_valid |= ATTR_MTIME | ATTR_MTIME_SET; +- iap->ia_mtime.tv_sec = tmp; +- iap->ia_mtime.tv_nsec = tmp1 * 1000; +- /* +- * Passing the invalid value useconds=1000000 for mtime +- * is a Sun convention for "set both mtime and atime to +- * current server time". It's needed to make permissions +- * checks for the "touch" program across v2 mounts to +- * Solaris and Irix boxes work correctly. See description of +- * sattr in section 6.1 of "NFS Illustrated" by +- * Brent Callaghan, Addison-Wesley, ISBN 0-201-32750-5 +- */ +- if (tmp1 == 1000000) +- iap->ia_valid &= ~(ATTR_ATIME_SET|ATTR_MTIME_SET); +- } +- return p; +-} +- + static bool + svcxdr_decode_sattr(struct svc_rqst *rqstp, struct xdr_stream *xdr, + struct iattr *iap) +@@ -435,40 +360,22 @@ nfssvc_decode_linkargs(struct svc_rqst *rqstp, __be32 *p) + int + nfssvc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd_symlinkargs *args = rqstp->rq_argp; +- char *base = (char *)p; +- size_t xdrlen; ++ struct kvec *head = rqstp->rq_arg.head; + +- if ( !(p = decode_fh(p, &args->ffh)) +- || !(p = decode_filename(p, &args->fname, &args->flen))) ++ if (!svcxdr_decode_diropargs(xdr, &args->ffh, &args->fname, &args->flen)) ++ return 0; ++ if (xdr_stream_decode_u32(xdr, &args->tlen) < 0) + return 0; +- +- args->tlen = ntohl(*p++); + if (args->tlen == 0) + return 0; + +- args->first.iov_base = p; +- args->first.iov_len = rqstp->rq_arg.head[0].iov_len; +- args->first.iov_len -= (char *)p - base; +- +- /* This request is never larger than a page. Therefore, +- * transport will deliver either: +- * 1. pathname in the pagelist -> sattr is in the tail. +- * 2. everything in the head buffer -> sattr is in the head. +- */ +- if (rqstp->rq_arg.page_len) { +- if (args->tlen != rqstp->rq_arg.page_len) +- return 0; +- p = rqstp->rq_arg.tail[0].iov_base; +- } else { +- xdrlen = XDR_QUADLEN(args->tlen); +- if (xdrlen > args->first.iov_len - (8 * sizeof(__be32))) +- return 0; +- p += xdrlen; +- } +- decode_sattr(p, &args->attrs, nfsd_user_namespace(rqstp)); +- +- return 1; ++ args->first.iov_len = head->iov_len - xdr_stream_pos(xdr); ++ args->first.iov_base = xdr_inline_decode(xdr, args->tlen); ++ if (!args->first.iov_base) ++ return 0; ++ return svcxdr_decode_sattr(rqstp, xdr, &args->attrs); + } + + int +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-nfsv2-write-argument-decoder-to-use-.patch b/queue-5.10/nfsd-update-the-nfsv2-write-argument-decoder-to-use-.patch new file mode 100644 index 00000000000..218899329f0 --- /dev/null +++ b/queue-5.10/nfsd-update-the-nfsv2-write-argument-decoder-to-use-.patch @@ -0,0 +1,91 @@ +From 77394e205ac85fb39e0ebfb8aa6dc4576bc9642c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 21 Oct 2020 12:18:36 -0400 +Subject: NFSD: Update the NFSv2 WRITE argument decoder to use struct + xdr_stream + +From: Chuck Lever + +[ Upstream commit a51b5b737a0be93fae6ea2a18df03ab2359a3f4b ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsxdr.c | 52 +++++++++++++++++++----------------------------- + 1 file changed, 21 insertions(+), 31 deletions(-) + +diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c +index 1eacaa2c13a95..11d27b219cff2 100644 +--- a/fs/nfsd/nfsxdr.c ++++ b/fs/nfsd/nfsxdr.c +@@ -266,46 +266,36 @@ nfssvc_decode_readargs(struct svc_rqst *rqstp, __be32 *p) + int + nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd_writeargs *args = rqstp->rq_argp; +- unsigned int len, hdr, dlen; + struct kvec *head = rqstp->rq_arg.head; ++ struct kvec *tail = rqstp->rq_arg.tail; ++ u32 beginoffset, totalcount; ++ size_t remaining; + +- p = decode_fh(p, &args->fh); +- if (!p) ++ if (!svcxdr_decode_fhandle(xdr, &args->fh)) + return 0; +- +- p++; /* beginoffset */ +- args->offset = ntohl(*p++); /* offset */ +- p++; /* totalcount */ +- len = args->len = ntohl(*p++); +- /* +- * The protocol specifies a maximum of 8192 bytes. +- */ +- if (len > NFSSVC_MAXBLKSIZE_V2) ++ /* beginoffset is ignored */ ++ if (xdr_stream_decode_u32(xdr, &beginoffset) < 0) + return 0; +- +- /* +- * Check to make sure that we got the right number of +- * bytes. +- */ +- hdr = (void*)p - head->iov_base; +- if (hdr > head->iov_len) ++ if (xdr_stream_decode_u32(xdr, &args->offset) < 0) ++ return 0; ++ /* totalcount is ignored */ ++ if (xdr_stream_decode_u32(xdr, &totalcount) < 0) + return 0; +- dlen = head->iov_len + rqstp->rq_arg.page_len - hdr; + +- /* +- * Round the length of the data which was specified up to +- * the next multiple of XDR units and then compare that +- * against the length which was actually received. +- * Note that when RPCSEC/GSS (for example) is used, the +- * data buffer can be padded so dlen might be larger +- * than required. It must never be smaller. +- */ +- if (dlen < XDR_QUADLEN(len)*4) ++ /* opaque data */ ++ if (xdr_stream_decode_u32(xdr, &args->len) < 0) ++ return 0; ++ if (args->len > NFSSVC_MAXBLKSIZE_V2) ++ return 0; ++ remaining = head->iov_len + rqstp->rq_arg.page_len + tail->iov_len; ++ remaining -= xdr_stream_pos(xdr); ++ if (remaining < xdr_align_size(args->len)) + return 0; ++ args->first.iov_base = xdr->p; ++ args->first.iov_len = head->iov_len - xdr_stream_pos(xdr); + +- args->first.iov_base = (void *)p; +- args->first.iov_len = head->iov_len - hdr; + return 1; + } + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-nfsv3-access3res-encoder-to-use-stru.patch b/queue-5.10/nfsd-update-the-nfsv3-access3res-encoder-to-use-stru.patch new file mode 100644 index 00000000000..125a692337c --- /dev/null +++ b/queue-5.10/nfsd-update-the-nfsv3-access3res-encoder-to-use-stru.patch @@ -0,0 +1,102 @@ +From 90a01b87c9c6ebd8cb400f76b021d81856c4dc4f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Oct 2020 13:56:58 -0400 +Subject: NFSD: Update the NFSv3 ACCESS3res encoder to use struct xdr_stream + +From: Chuck Lever + +[ Upstream commit 907c38227fb57f5c537491ca76dd0b9636029393 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3xdr.c | 50 ++++++++++++++++++++++++++++++++++++++++++----- + fs/nfsd/vfs.h | 2 +- + 2 files changed, 46 insertions(+), 6 deletions(-) + +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index 75739861d235e..9d6c989df6d8d 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -383,6 +383,35 @@ encode_saved_post_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp) + return encode_fattr3(rqstp, p, fhp, &fhp->fh_post_attr); + } + ++static bool ++svcxdr_encode_post_op_attr(struct svc_rqst *rqstp, struct xdr_stream *xdr, ++ const struct svc_fh *fhp) ++{ ++ struct dentry *dentry = fhp->fh_dentry; ++ struct kstat stat; ++ ++ /* ++ * The inode may be NULL if the call failed because of a ++ * stale file handle. In this case, no attributes are ++ * returned. ++ */ ++ if (fhp->fh_no_wcc || !dentry || !d_really_is_positive(dentry)) ++ goto no_post_op_attrs; ++ if (fh_getattr(fhp, &stat) != nfs_ok) ++ goto no_post_op_attrs; ++ ++ if (xdr_stream_encode_item_present(xdr) < 0) ++ return false; ++ lease_get_mtime(d_inode(dentry), &stat.mtime); ++ if (!svcxdr_encode_fattr3(rqstp, xdr, fhp, &stat)) ++ return false; ++ ++ return true; ++ ++no_post_op_attrs: ++ return xdr_stream_encode_item_absent(xdr) > 0; ++} ++ + /* + * Encode post-operation attributes. + * The inode may be NULL if the call failed because of a stale file +@@ -835,13 +864,24 @@ nfs3svc_encode_diropres(struct svc_rqst *rqstp, __be32 *p) + int + nfs3svc_encode_accessres(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd3_accessres *resp = rqstp->rq_resp; + +- *p++ = resp->status; +- p = encode_post_op_attr(rqstp, p, &resp->fh); +- if (resp->status == 0) +- *p++ = htonl(resp->access); +- return xdr_ressize_check(rqstp, p); ++ if (!svcxdr_encode_nfsstat3(xdr, resp->status)) ++ return 0; ++ switch (resp->status) { ++ case nfs_ok: ++ if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) ++ return 0; ++ if (xdr_stream_encode_u32(xdr, resp->access) < 0) ++ return 0; ++ break; ++ default: ++ if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) ++ return 0; ++ } ++ ++ return 1; + } + + /* READLINK */ +diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h +index a2442ebe5acf6..b21b76e6b9a87 100644 +--- a/fs/nfsd/vfs.h ++++ b/fs/nfsd/vfs.h +@@ -152,7 +152,7 @@ static inline void fh_drop_write(struct svc_fh *fh) + } + } + +-static inline __be32 fh_getattr(struct svc_fh *fh, struct kstat *stat) ++static inline __be32 fh_getattr(const struct svc_fh *fh, struct kstat *stat) + { + struct path p = {.mnt = fh->fh_export->ex_path.mnt, + .dentry = fh->fh_dentry}; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-nfsv3-commit3res-encoder-to-use-stru.patch b/queue-5.10/nfsd-update-the-nfsv3-commit3res-encoder-to-use-stru.patch new file mode 100644 index 00000000000..de6ef376f62 --- /dev/null +++ b/queue-5.10/nfsd-update-the-nfsv3-commit3res-encoder-to-use-stru.patch @@ -0,0 +1,103 @@ +From 63e63318f4d78436a3671fde254d7bb01f76f9ab Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Oct 2020 15:35:46 -0400 +Subject: NFSD: Update the NFSv3 COMMIT3res encoder to use struct xdr_stream + +From: Chuck Lever + +[ Upstream commit 5ef2826c761079e27904c85034df34e601b82d94 ] + +As an additional clean up, encode_wcc_data() is removed because it +is now no longer used. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3xdr.c | 54 +++++++++++++---------------------------------- + 1 file changed, 15 insertions(+), 39 deletions(-) + +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index 1467bba02e180..eab14b52db202 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -432,14 +432,6 @@ encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, + return p; + } + +-static __be32 * +-encode_saved_post_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp) +-{ +- /* Attributes to follow */ +- *p++ = xdr_one; +- return encode_fattr3(rqstp, p, fhp, &fhp->fh_post_attr); +-} +- + static bool + svcxdr_encode_wcc_attr(struct xdr_stream *xdr, const struct svc_fh *fhp) + { +@@ -562,30 +554,6 @@ svcxdr_encode_wcc_data(struct svc_rqst *rqstp, struct xdr_stream *xdr, + return true; + } + +-/* +- * Enocde weak cache consistency data +- */ +-static __be32 * +-encode_wcc_data(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp) +-{ +- struct dentry *dentry = fhp->fh_dentry; +- +- if (dentry && d_really_is_positive(dentry) && fhp->fh_post_saved) { +- if (fhp->fh_pre_saved) { +- *p++ = xdr_one; +- p = xdr_encode_hyper(p, (u64) fhp->fh_pre_size); +- p = encode_time3(p, &fhp->fh_pre_mtime); +- p = encode_time3(p, &fhp->fh_pre_ctime); +- } else { +- *p++ = xdr_zero; +- } +- return encode_saved_post_attr(rqstp, p, fhp); +- } +- /* no pre- or post-attrs */ +- *p++ = xdr_zero; +- return encode_post_op_attr(rqstp, p, fhp); +-} +- + static bool fs_supports_change_attribute(struct super_block *sb) + { + return sb->s_flags & SB_I_VERSION || sb->s_export_op->fetch_iversion; +@@ -1548,16 +1516,24 @@ nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, __be32 *p) + int + nfs3svc_encode_commitres(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd3_commitres *resp = rqstp->rq_resp; + +- *p++ = resp->status; +- p = encode_wcc_data(rqstp, p, &resp->fh); +- /* Write verifier */ +- if (resp->status == 0) { +- *p++ = resp->verf[0]; +- *p++ = resp->verf[1]; ++ if (!svcxdr_encode_nfsstat3(xdr, resp->status)) ++ return 0; ++ switch (resp->status) { ++ case nfs_ok: ++ if (!svcxdr_encode_wcc_data(rqstp, xdr, &resp->fh)) ++ return 0; ++ if (!svcxdr_encode_writeverf3(xdr, resp->verf)) ++ return 0; ++ break; ++ default: ++ if (!svcxdr_encode_wcc_data(rqstp, xdr, &resp->fh)) ++ return 0; + } +- return xdr_ressize_check(rqstp, p); ++ ++ return 1; + } + + /* +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-nfsv3-create-family-of-encoders-to-u.patch b/queue-5.10/nfsd-update-the-nfsv3-create-family-of-encoders-to-u.patch new file mode 100644 index 00000000000..cacbf0a9e8a --- /dev/null +++ b/queue-5.10/nfsd-update-the-nfsv3-create-family-of-encoders-to-u.patch @@ -0,0 +1,75 @@ +From 6d9f8c5d49ff346cbbb8fe2c43c933b1447108b3 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Oct 2020 15:27:23 -0400 +Subject: NFSD: Update the NFSv3 CREATE family of encoders to use struct + xdr_stream + +From: Chuck Lever + +[ Upstream commit 78315b36781d259dcbdc102ff22c3f2f25712223 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3xdr.c | 35 ++++++++++++++++++++++++++++------- + 1 file changed, 28 insertions(+), 7 deletions(-) + +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index 0191cbfc486b8..052376a65f723 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -121,6 +121,17 @@ svcxdr_encode_nfs_fh3(struct xdr_stream *xdr, const struct svc_fh *fhp) + return true; + } + ++static bool ++svcxdr_encode_post_op_fh3(struct xdr_stream *xdr, const struct svc_fh *fhp) ++{ ++ if (xdr_stream_encode_item_present(xdr) < 0) ++ return false; ++ if (!svcxdr_encode_nfs_fh3(xdr, fhp)) ++ return false; ++ ++ return true; ++} ++ + static __be32 * + encode_fh(__be32 *p, struct svc_fh *fhp) + { +@@ -1079,16 +1090,26 @@ nfs3svc_encode_writeres(struct svc_rqst *rqstp, __be32 *p) + int + nfs3svc_encode_createres(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd3_diropres *resp = rqstp->rq_resp; + +- *p++ = resp->status; +- if (resp->status == 0) { +- *p++ = xdr_one; +- p = encode_fh(p, &resp->fh); +- p = encode_post_op_attr(rqstp, p, &resp->fh); ++ if (!svcxdr_encode_nfsstat3(xdr, resp->status)) ++ return 0; ++ switch (resp->status) { ++ case nfs_ok: ++ if (!svcxdr_encode_post_op_fh3(xdr, &resp->fh)) ++ return 0; ++ if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) ++ return 0; ++ if (!svcxdr_encode_wcc_data(rqstp, xdr, &resp->dirfh)) ++ return 0; ++ break; ++ default: ++ if (!svcxdr_encode_wcc_data(rqstp, xdr, &resp->dirfh)) ++ return 0; + } +- p = encode_wcc_data(rqstp, p, &resp->dirfh); +- return xdr_ressize_check(rqstp, p); ++ ++ return 1; + } + + /* RENAME */ +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-nfsv3-diropargs-decoder-to-use-struc.patch b/queue-5.10/nfsd-update-the-nfsv3-diropargs-decoder-to-use-struc.patch new file mode 100644 index 00000000000..3f5b19b3dd0 --- /dev/null +++ b/queue-5.10/nfsd-update-the-nfsv3-diropargs-decoder-to-use-struc.patch @@ -0,0 +1,78 @@ +From 1dc69f981c4a072ab19115902ef99b1d63fa3e05 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Oct 2020 15:42:33 -0400 +Subject: NFSD: Update the NFSv3 DIROPargs decoder to use struct xdr_stream + +From: Chuck Lever + +[ Upstream commit 54d1d43dc709f58be38d278bfc38e9bfb38d35fc ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3xdr.c | 40 +++++++++++++++++++++++++++++++++++----- + 1 file changed, 35 insertions(+), 5 deletions(-) + +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index bafb84c978616..299ea8bbd685f 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -117,6 +117,39 @@ decode_filename(__be32 *p, char **namp, unsigned int *lenp) + return p; + } + ++static bool ++svcxdr_decode_filename3(struct xdr_stream *xdr, char **name, unsigned int *len) ++{ ++ u32 size, i; ++ __be32 *p; ++ char *c; ++ ++ if (xdr_stream_decode_u32(xdr, &size) < 0) ++ return false; ++ if (size == 0 || size > NFS3_MAXNAMLEN) ++ return false; ++ p = xdr_inline_decode(xdr, size); ++ if (!p) ++ return false; ++ ++ *len = size; ++ *name = (char *)p; ++ for (i = 0, c = *name; i < size; i++, c++) { ++ if (*c == '\0' || *c == '/') ++ return false; ++ } ++ ++ return true; ++} ++ ++static bool ++svcxdr_decode_diropargs3(struct xdr_stream *xdr, struct svc_fh *fhp, ++ char **name, unsigned int *len) ++{ ++ return svcxdr_decode_nfs_fh3(xdr, fhp) && ++ svcxdr_decode_filename3(xdr, name, len); ++} ++ + static __be32 * + decode_sattr3(__be32 *p, struct iattr *iap, struct user_namespace *userns) + { +@@ -363,13 +396,10 @@ nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p) + int + nfs3svc_decode_diropargs(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd3_diropargs *args = rqstp->rq_argp; + +- if (!(p = decode_fh(p, &args->fh)) +- || !(p = decode_filename(p, &args->name, &args->len))) +- return 0; +- +- return xdr_argsize_check(rqstp, p); ++ return svcxdr_decode_diropargs3(xdr, &args->fh, &args->name, &args->len); + } + + int +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-nfsv3-fsinfo3res-encoder-to-use-stru.patch b/queue-5.10/nfsd-update-the-nfsv3-fsinfo3res-encoder-to-use-stru.patch new file mode 100644 index 00000000000..9e667d1f5ba --- /dev/null +++ b/queue-5.10/nfsd-update-the-nfsv3-fsinfo3res-encoder-to-use-stru.patch @@ -0,0 +1,106 @@ +From df756f0ea3676bc5297648831e4eafd89c874621 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Oct 2020 13:42:13 -0400 +Subject: NFSD: Update the NFSv3 FSINFO3res encoder to use struct xdr_stream + +From: Chuck Lever + +[ Upstream commit 0a139d1b7f327010acc36e8162936d3108c7addb ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3xdr.c | 62 +++++++++++++++++++++++++++++++++++------------ + 1 file changed, 46 insertions(+), 16 deletions(-) + +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index e4a569e7216d5..514f53ad73020 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -24,6 +24,15 @@ static const struct svc_fh nfs3svc_null_fh = { + .fh_no_wcc = true, + }; + ++/* ++ * time_delta. {1, 0} means the server is accurate only ++ * to the nearest second. ++ */ ++static const struct timespec64 nfs3svc_time_delta = { ++ .tv_sec = 1, ++ .tv_nsec = 0, ++}; ++ + /* + * Mapping of S_IF* types to NFS file types + */ +@@ -1445,30 +1454,51 @@ nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, __be32 *p) + return 1; + } + ++static bool ++svcxdr_encode_fsinfo3resok(struct xdr_stream *xdr, ++ const struct nfsd3_fsinfores *resp) ++{ ++ __be32 *p; ++ ++ p = xdr_reserve_space(xdr, XDR_UNIT * 12); ++ if (!p) ++ return false; ++ *p++ = cpu_to_be32(resp->f_rtmax); ++ *p++ = cpu_to_be32(resp->f_rtpref); ++ *p++ = cpu_to_be32(resp->f_rtmult); ++ *p++ = cpu_to_be32(resp->f_wtmax); ++ *p++ = cpu_to_be32(resp->f_wtpref); ++ *p++ = cpu_to_be32(resp->f_wtmult); ++ *p++ = cpu_to_be32(resp->f_dtpref); ++ p = xdr_encode_hyper(p, resp->f_maxfilesize); ++ p = encode_nfstime3(p, &nfs3svc_time_delta); ++ *p = cpu_to_be32(resp->f_properties); ++ ++ return true; ++} ++ + /* FSINFO */ + int + nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd3_fsinfores *resp = rqstp->rq_resp; + +- *p++ = resp->status; +- *p++ = xdr_zero; /* no post_op_attr */ +- +- if (resp->status == 0) { +- *p++ = htonl(resp->f_rtmax); +- *p++ = htonl(resp->f_rtpref); +- *p++ = htonl(resp->f_rtmult); +- *p++ = htonl(resp->f_wtmax); +- *p++ = htonl(resp->f_wtpref); +- *p++ = htonl(resp->f_wtmult); +- *p++ = htonl(resp->f_dtpref); +- p = xdr_encode_hyper(p, resp->f_maxfilesize); +- *p++ = xdr_one; +- *p++ = xdr_zero; +- *p++ = htonl(resp->f_properties); ++ if (!svcxdr_encode_nfsstat3(xdr, resp->status)) ++ return 0; ++ switch (resp->status) { ++ case nfs_ok: ++ if (!svcxdr_encode_post_op_attr(rqstp, xdr, &nfs3svc_null_fh)) ++ return 0; ++ if (!svcxdr_encode_fsinfo3resok(xdr, resp)) ++ return 0; ++ break; ++ default: ++ if (!svcxdr_encode_post_op_attr(rqstp, xdr, &nfs3svc_null_fh)) ++ return 0; + } + +- return xdr_ressize_check(rqstp, p); ++ return 1; + } + + /* PATHCONF */ +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-nfsv3-fsstat3res-encoder-to-use-stru.patch b/queue-5.10/nfsd-update-the-nfsv3-fsstat3res-encoder-to-use-stru.patch new file mode 100644 index 00000000000..d8ed0b012ea --- /dev/null +++ b/queue-5.10/nfsd-update-the-nfsv3-fsstat3res-encoder-to-use-stru.patch @@ -0,0 +1,101 @@ +From 9bbdad49164182dd2536c94487951632c0edea3d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Nov 2020 13:08:45 -0500 +Subject: NFSD: Update the NFSv3 FSSTAT3res encoder to use struct xdr_stream + +From: Chuck Lever + +[ Upstream commit 8b7044984fd6eeadf72285e3617116bd15e9e676 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3xdr.c | 58 +++++++++++++++++++++++++++++++++++------------ + 1 file changed, 44 insertions(+), 14 deletions(-) + +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index e159e45574288..e4a569e7216d5 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -17,6 +17,13 @@ + #define NFSDDBG_FACILITY NFSDDBG_XDR + + ++/* ++ * Force construction of an empty post-op attr ++ */ ++static const struct svc_fh nfs3svc_null_fh = { ++ .fh_no_wcc = true, ++}; ++ + /* + * Mapping of S_IF* types to NFS file types + */ +@@ -1392,27 +1399,50 @@ nfs3svc_encode_entry_plus(void *cd, const char *name, + return encode_entry(cd, name, namlen, offset, ino, d_type, 1); + } + ++static bool ++svcxdr_encode_fsstat3resok(struct xdr_stream *xdr, ++ const struct nfsd3_fsstatres *resp) ++{ ++ const struct kstatfs *s = &resp->stats; ++ u64 bs = s->f_bsize; ++ __be32 *p; ++ ++ p = xdr_reserve_space(xdr, XDR_UNIT * 13); ++ if (!p) ++ return false; ++ p = xdr_encode_hyper(p, bs * s->f_blocks); /* total bytes */ ++ p = xdr_encode_hyper(p, bs * s->f_bfree); /* free bytes */ ++ p = xdr_encode_hyper(p, bs * s->f_bavail); /* user available bytes */ ++ p = xdr_encode_hyper(p, s->f_files); /* total inodes */ ++ p = xdr_encode_hyper(p, s->f_ffree); /* free inodes */ ++ p = xdr_encode_hyper(p, s->f_ffree); /* user available inodes */ ++ *p = cpu_to_be32(resp->invarsec); /* mean unchanged time */ ++ ++ return true; ++} ++ + /* FSSTAT */ + int + nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd3_fsstatres *resp = rqstp->rq_resp; +- struct kstatfs *s = &resp->stats; +- u64 bs = s->f_bsize; + +- *p++ = resp->status; +- *p++ = xdr_zero; /* no post_op_attr */ +- +- if (resp->status == 0) { +- p = xdr_encode_hyper(p, bs * s->f_blocks); /* total bytes */ +- p = xdr_encode_hyper(p, bs * s->f_bfree); /* free bytes */ +- p = xdr_encode_hyper(p, bs * s->f_bavail); /* user available bytes */ +- p = xdr_encode_hyper(p, s->f_files); /* total inodes */ +- p = xdr_encode_hyper(p, s->f_ffree); /* free inodes */ +- p = xdr_encode_hyper(p, s->f_ffree); /* user available inodes */ +- *p++ = htonl(resp->invarsec); /* mean unchanged time */ ++ if (!svcxdr_encode_nfsstat3(xdr, resp->status)) ++ return 0; ++ switch (resp->status) { ++ case nfs_ok: ++ if (!svcxdr_encode_post_op_attr(rqstp, xdr, &nfs3svc_null_fh)) ++ return 0; ++ if (!svcxdr_encode_fsstat3resok(xdr, resp)) ++ return 0; ++ break; ++ default: ++ if (!svcxdr_encode_post_op_attr(rqstp, xdr, &nfs3svc_null_fh)) ++ return 0; + } +- return xdr_ressize_check(rqstp, p); ++ ++ return 1; + } + + /* FSINFO */ +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-nfsv3-getacl-argument-decoder-to-use.patch b/queue-5.10/nfsd-update-the-nfsv3-getacl-argument-decoder-to-use.patch new file mode 100644 index 00000000000..a94d8b13ba3 --- /dev/null +++ b/queue-5.10/nfsd-update-the-nfsv3-getacl-argument-decoder-to-use.patch @@ -0,0 +1,85 @@ +From 48539d59e6bc506607d6318674e44761210b630e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 17 Nov 2020 11:52:04 -0500 +Subject: NFSD: Update the NFSv3 GETACL argument decoder to use struct + xdr_stream + +From: Chuck Lever + +[ Upstream commit 05027eafc266487c6e056d10ab352861df95b5d4 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3acl.c | 11 ++++++----- + fs/nfsd/nfs3xdr.c | 11 ++++++++++- + fs/nfsd/xdr3.h | 1 + + 3 files changed, 17 insertions(+), 6 deletions(-) + +diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c +index 9e1a92fb97712..addb0d7d5500f 100644 +--- a/fs/nfsd/nfs3acl.c ++++ b/fs/nfsd/nfs3acl.c +@@ -124,19 +124,20 @@ static __be32 nfsd3_proc_setacl(struct svc_rqst *rqstp) + /* + * XDR decode functions + */ ++ + static int nfs3svc_decode_getaclargs(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd3_getaclargs *args = rqstp->rq_argp; + +- p = nfs3svc_decode_fh(p, &args->fh); +- if (!p) ++ if (!svcxdr_decode_nfs_fh3(xdr, &args->fh)) ++ return 0; ++ if (xdr_stream_decode_u32(xdr, &args->mask) < 0) + return 0; +- args->mask = ntohl(*p); p++; + +- return xdr_argsize_check(rqstp, p); ++ return 1; + } + +- + static int nfs3svc_decode_setaclargs(struct svc_rqst *rqstp, __be32 *p) + { + struct nfsd3_setaclargs *args = rqstp->rq_argp; +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index a30b418a51160..aa55d0ba2a548 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -53,7 +53,16 @@ svcxdr_decode_nfstime3(struct xdr_stream *xdr, struct timespec64 *timep) + return true; + } + +-static bool ++/** ++ * svcxdr_decode_nfs_fh3 - Decode an NFSv3 file handle ++ * @xdr: XDR stream positioned at an undecoded NFSv3 FH ++ * @fhp: OUT: filled-in server file handle ++ * ++ * Return values: ++ * %false: The encoded file handle was not valid ++ * %true: @fhp has been initialized ++ */ ++bool + svcxdr_decode_nfs_fh3(struct xdr_stream *xdr, struct svc_fh *fhp) + { + __be32 *p; +diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h +index 5afb3ce4f0622..7456aee74f3df 100644 +--- a/fs/nfsd/xdr3.h ++++ b/fs/nfsd/xdr3.h +@@ -308,6 +308,7 @@ int nfs3svc_encode_entry_plus(void *, const char *name, + __be32 *nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, + struct svc_fh *fhp); + __be32 *nfs3svc_decode_fh(__be32 *p, struct svc_fh *fhp); ++bool svcxdr_decode_nfs_fh3(struct xdr_stream *xdr, struct svc_fh *fhp); + + + #endif /* _LINUX_NFSD_XDR3_H */ +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-nfsv3-getacl-result-encoder-to-use-s.patch b/queue-5.10/nfsd-update-the-nfsv3-getacl-result-encoder-to-use-s.patch new file mode 100644 index 00000000000..8a3ede4078b --- /dev/null +++ b/queue-5.10/nfsd-update-the-nfsv3-getacl-result-encoder-to-use-s.patch @@ -0,0 +1,130 @@ +From 65a67ac319c42ca47f6756bf35dafdf108248858 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Nov 2020 16:11:42 -0500 +Subject: NFSD: Update the NFSv3 GETACL result encoder to use struct xdr_stream + +From: Chuck Lever + +[ Upstream commit 20798dfe249a01ad1b12eec7dbc572db5003244a ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3acl.c | 33 +++++++++++++++++++-------------- + fs/nfsd/nfs3xdr.c | 23 +++++++++++++++++++++-- + fs/nfsd/xdr3.h | 3 +++ + 3 files changed, 43 insertions(+), 16 deletions(-) + +diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c +index a568b842e9ebe..04e157b0b201a 100644 +--- a/fs/nfsd/nfs3acl.c ++++ b/fs/nfsd/nfs3acl.c +@@ -166,22 +166,25 @@ static int nfs3svc_decode_setaclargs(struct svc_rqst *rqstp, __be32 *p) + /* GETACL */ + static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd3_getaclres *resp = rqstp->rq_resp; + struct dentry *dentry = resp->fh.fh_dentry; ++ struct kvec *head = rqstp->rq_res.head; ++ struct inode *inode = d_inode(dentry); ++ unsigned int base; ++ int n; ++ int w; + +- *p++ = resp->status; +- p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh); +- if (resp->status == 0 && dentry && d_really_is_positive(dentry)) { +- struct inode *inode = d_inode(dentry); +- struct kvec *head = rqstp->rq_res.head; +- unsigned int base; +- int n; +- int w; +- +- *p++ = htonl(resp->mask); +- if (!xdr_ressize_check(rqstp, p)) ++ if (!svcxdr_encode_nfsstat3(xdr, resp->status)) ++ return 0; ++ switch (resp->status) { ++ case nfs_ok: ++ if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) + return 0; +- base = (char *)p - (char *)head->iov_base; ++ if (xdr_stream_encode_u32(xdr, resp->mask) < 0) ++ return 0; ++ ++ base = (char *)xdr->p - (char *)head->iov_base; + + rqstp->rq_res.page_len = w = nfsacl_size( + (resp->mask & NFS_ACL) ? resp->acl_access : NULL, +@@ -202,9 +205,11 @@ static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p) + NFS_ACL_DEFAULT); + if (n <= 0) + return 0; +- } else +- if (!xdr_ressize_check(rqstp, p)) ++ break; ++ default: ++ if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) + return 0; ++ } + + return 1; + } +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index 646bbfc5b7794..941740a97f8f5 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -107,7 +107,16 @@ svcxdr_decode_nfs_fh3(struct xdr_stream *xdr, struct svc_fh *fhp) + return true; + } + +-static bool ++/** ++ * svcxdr_encode_nfsstat3 - Encode an NFSv3 status code ++ * @xdr: XDR stream ++ * @status: status value to encode ++ * ++ * Return values: ++ * %false: Send buffer space was exhausted ++ * %true: Success ++ */ ++bool + svcxdr_encode_nfsstat3(struct xdr_stream *xdr, __be32 status) + { + __be32 *p; +@@ -464,7 +473,17 @@ svcxdr_encode_pre_op_attr(struct xdr_stream *xdr, const struct svc_fh *fhp) + return svcxdr_encode_wcc_attr(xdr, fhp); + } + +-static bool ++/** ++ * svcxdr_encode_post_op_attr - Encode NFSv3 post-op attributes ++ * @rqstp: Context of a completed RPC transaction ++ * @xdr: XDR stream ++ * @fhp: File handle to encode ++ * ++ * Return values: ++ * %false: Send buffer space was exhausted ++ * %true: Success ++ */ ++bool + svcxdr_encode_post_op_attr(struct svc_rqst *rqstp, struct xdr_stream *xdr, + const struct svc_fh *fhp) + { +diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h +index b851458373db6..746c5f79964f1 100644 +--- a/fs/nfsd/xdr3.h ++++ b/fs/nfsd/xdr3.h +@@ -308,5 +308,8 @@ int nfs3svc_encode_entryplus3(void *data, const char *name, int namlen, + __be32 *nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, + struct svc_fh *fhp); + bool svcxdr_decode_nfs_fh3(struct xdr_stream *xdr, struct svc_fh *fhp); ++bool svcxdr_encode_nfsstat3(struct xdr_stream *xdr, __be32 status); ++bool svcxdr_encode_post_op_attr(struct svc_rqst *rqstp, struct xdr_stream *xdr, ++ const struct svc_fh *fhp); + + #endif /* _LINUX_NFSD_XDR3_H */ +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-nfsv3-link3res-encoder-to-use-struct.patch b/queue-5.10/nfsd-update-the-nfsv3-link3res-encoder-to-use-struct.patch new file mode 100644 index 00000000000..dd14eb42618 --- /dev/null +++ b/queue-5.10/nfsd-update-the-nfsv3-link3res-encoder-to-use-struct.patch @@ -0,0 +1,39 @@ +From c7073de9e5d84eb43d0d89a2a33c2a5974cd0932 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Oct 2020 15:08:29 -0400 +Subject: NFSD: Update the NFSv3 LINK3res encoder to use struct xdr_stream + +From: Chuck Lever + +[ Upstream commit 4d74380a446f75eebb2171687d9b8baf0025bdf1 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3xdr.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index 1d52a69562b82..e159e45574288 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -1128,12 +1128,12 @@ nfs3svc_encode_renameres(struct svc_rqst *rqstp, __be32 *p) + int + nfs3svc_encode_linkres(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd3_linkres *resp = rqstp->rq_resp; + +- *p++ = resp->status; +- p = encode_post_op_attr(rqstp, p, &resp->fh); +- p = encode_wcc_data(rqstp, p, &resp->tfh); +- return xdr_ressize_check(rqstp, p); ++ return svcxdr_encode_nfsstat3(xdr, resp->status) && ++ svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh) && ++ svcxdr_encode_wcc_data(rqstp, xdr, &resp->tfh); + } + + /* READDIR */ +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-nfsv3-lookup3res-encoder-to-use-stru.patch b/queue-5.10/nfsd-update-the-nfsv3-lookup3res-encoder-to-use-stru.patch new file mode 100644 index 00000000000..dc773682679 --- /dev/null +++ b/queue-5.10/nfsd-update-the-nfsv3-lookup3res-encoder-to-use-stru.patch @@ -0,0 +1,115 @@ +From 092d101a8da77c1e4507544a4c429195ebca86f4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Oct 2020 14:46:58 -0400 +Subject: NFSD: Update the NFSv3 LOOKUP3res encoder to use struct xdr_stream + +From: Chuck Lever + +[ Upstream commit 5cf353354af1a385f29dec4609a1532d32c83a25 ] + +Also, clean up: Rename the encoder function to match the name of +the result structure in RFC 1813, consistent with other encoder +function names in nfs3xdr.c. "diropres" is an NFSv2 thingie. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3proc.c | 2 +- + fs/nfsd/nfs3xdr.c | 43 +++++++++++++++++++++++++++++++++++-------- + fs/nfsd/xdr3.h | 2 +- + 3 files changed, 37 insertions(+), 10 deletions(-) + +diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c +index 1c3cf97ed95d2..60e8c25be7571 100644 +--- a/fs/nfsd/nfs3proc.c ++++ b/fs/nfsd/nfs3proc.c +@@ -763,7 +763,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { + [NFS3PROC_LOOKUP] = { + .pc_func = nfsd3_proc_lookup, + .pc_decode = nfs3svc_decode_diropargs, +- .pc_encode = nfs3svc_encode_diropres, ++ .pc_encode = nfs3svc_encode_lookupres, + .pc_release = nfs3svc_release_fhandle2, + .pc_argsize = sizeof(struct nfsd3_diropargs), + .pc_ressize = sizeof(struct nfsd3_diropres), +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index 9d6c989df6d8d..2bb998b3834bf 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -104,6 +104,23 @@ svcxdr_encode_nfsstat3(struct xdr_stream *xdr, __be32 status) + return true; + } + ++static bool ++svcxdr_encode_nfs_fh3(struct xdr_stream *xdr, const struct svc_fh *fhp) ++{ ++ u32 size = fhp->fh_handle.fh_size; ++ __be32 *p; ++ ++ p = xdr_reserve_space(xdr, XDR_UNIT + size); ++ if (!p) ++ return false; ++ *p++ = cpu_to_be32(size); ++ if (size) ++ p[XDR_QUADLEN(size) - 1] = 0; ++ memcpy(p, &fhp->fh_handle.fh_base, size); ++ ++ return true; ++} ++ + static __be32 * + encode_fh(__be32 *p, struct svc_fh *fhp) + { +@@ -846,18 +863,28 @@ nfs3svc_encode_wccstat(struct svc_rqst *rqstp, __be32 *p) + } + + /* LOOKUP */ +-int +-nfs3svc_encode_diropres(struct svc_rqst *rqstp, __be32 *p) ++int nfs3svc_encode_lookupres(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd3_diropres *resp = rqstp->rq_resp; + +- *p++ = resp->status; +- if (resp->status == 0) { +- p = encode_fh(p, &resp->fh); +- p = encode_post_op_attr(rqstp, p, &resp->fh); ++ if (!svcxdr_encode_nfsstat3(xdr, resp->status)) ++ return 0; ++ switch (resp->status) { ++ case nfs_ok: ++ if (!svcxdr_encode_nfs_fh3(xdr, &resp->fh)) ++ return 0; ++ if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) ++ return 0; ++ if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->dirfh)) ++ return 0; ++ break; ++ default: ++ if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->dirfh)) ++ return 0; + } +- p = encode_post_op_attr(rqstp, p, &resp->dirfh); +- return xdr_ressize_check(rqstp, p); ++ ++ return 1; + } + + /* ACCESS */ +diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h +index 0822981c61b93..7db4ee17aa209 100644 +--- a/fs/nfsd/xdr3.h ++++ b/fs/nfsd/xdr3.h +@@ -282,7 +282,7 @@ int nfs3svc_decode_readdirplusargs(struct svc_rqst *, __be32 *); + int nfs3svc_decode_commitargs(struct svc_rqst *, __be32 *); + int nfs3svc_encode_getattrres(struct svc_rqst *, __be32 *); + int nfs3svc_encode_wccstat(struct svc_rqst *, __be32 *); +-int nfs3svc_encode_diropres(struct svc_rqst *, __be32 *); ++int nfs3svc_encode_lookupres(struct svc_rqst *, __be32 *); + int nfs3svc_encode_accessres(struct svc_rqst *, __be32 *); + int nfs3svc_encode_readlinkres(struct svc_rqst *, __be32 *); + int nfs3svc_encode_readres(struct svc_rqst *, __be32 *); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-nfsv3-pathconf3res-encoder-to-use-st.patch b/queue-5.10/nfsd-update-the-nfsv3-pathconf3res-encoder-to-use-st.patch new file mode 100644 index 00000000000..552c752a79c --- /dev/null +++ b/queue-5.10/nfsd-update-the-nfsv3-pathconf3res-encoder-to-use-st.patch @@ -0,0 +1,118 @@ +From 859ddcd96dfcb43b26a10e11baf01ad54c4456a1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Nov 2020 13:15:09 -0500 +Subject: NFSD: Update the NFSv3 PATHCONF3res encoder to use struct xdr_stream + +From: Chuck Lever + +[ Upstream commit ded04a587f6ceaaba3caefad4021f2212b46c9ff ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3xdr.c | 44 ++++++++++++++++++++++++++++---------- + include/linux/sunrpc/xdr.h | 18 ++++++++++++++-- + 2 files changed, 49 insertions(+), 13 deletions(-) + +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index 514f53ad73020..1467bba02e180 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -1501,25 +1501,47 @@ nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, __be32 *p) + return 1; + } + ++static bool ++svcxdr_encode_pathconf3resok(struct xdr_stream *xdr, ++ const struct nfsd3_pathconfres *resp) ++{ ++ __be32 *p; ++ ++ p = xdr_reserve_space(xdr, XDR_UNIT * 6); ++ if (!p) ++ return false; ++ *p++ = cpu_to_be32(resp->p_link_max); ++ *p++ = cpu_to_be32(resp->p_name_max); ++ p = xdr_encode_bool(p, resp->p_no_trunc); ++ p = xdr_encode_bool(p, resp->p_chown_restricted); ++ p = xdr_encode_bool(p, resp->p_case_insensitive); ++ xdr_encode_bool(p, resp->p_case_preserving); ++ ++ return true; ++} ++ + /* PATHCONF */ + int + nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd3_pathconfres *resp = rqstp->rq_resp; + +- *p++ = resp->status; +- *p++ = xdr_zero; /* no post_op_attr */ +- +- if (resp->status == 0) { +- *p++ = htonl(resp->p_link_max); +- *p++ = htonl(resp->p_name_max); +- *p++ = htonl(resp->p_no_trunc); +- *p++ = htonl(resp->p_chown_restricted); +- *p++ = htonl(resp->p_case_insensitive); +- *p++ = htonl(resp->p_case_preserving); ++ if (!svcxdr_encode_nfsstat3(xdr, resp->status)) ++ return 0; ++ switch (resp->status) { ++ case nfs_ok: ++ if (!svcxdr_encode_post_op_attr(rqstp, xdr, &nfs3svc_null_fh)) ++ return 0; ++ if (!svcxdr_encode_pathconf3resok(xdr, resp)) ++ return 0; ++ break; ++ default: ++ if (!svcxdr_encode_post_op_attr(rqstp, xdr, &nfs3svc_null_fh)) ++ return 0; + } + +- return xdr_ressize_check(rqstp, p); ++ return 1; + } + + /* COMMIT */ +diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h +index 237b78146c7d6..927f1458bcab9 100644 +--- a/include/linux/sunrpc/xdr.h ++++ b/include/linux/sunrpc/xdr.h +@@ -395,7 +395,21 @@ static inline int xdr_stream_encode_item_absent(struct xdr_stream *xdr) + } + + /** +- * xdr_stream_encode_bool - Encode a "not present" list item ++ * xdr_encode_bool - Encode a boolean item ++ * @p: address in a buffer into which to encode ++ * @n: boolean value to encode ++ * ++ * Return value: ++ * Address of item following the encoded boolean ++ */ ++static inline __be32 *xdr_encode_bool(__be32 *p, u32 n) ++{ ++ *p = n ? xdr_one : xdr_zero; ++ return p++; ++} ++ ++/** ++ * xdr_stream_encode_bool - Encode a boolean item + * @xdr: pointer to xdr_stream + * @n: boolean value to encode + * +@@ -410,7 +424,7 @@ static inline int xdr_stream_encode_bool(struct xdr_stream *xdr, __u32 n) + + if (unlikely(!p)) + return -EMSGSIZE; +- *p = n ? xdr_one : xdr_zero; ++ xdr_encode_bool(p, n); + return len; + } + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-nfsv3-read3res-encode-to-use-struct-.patch b/queue-5.10/nfsd-update-the-nfsv3-read3res-encode-to-use-struct-.patch new file mode 100644 index 00000000000..163b54f5a31 --- /dev/null +++ b/queue-5.10/nfsd-update-the-nfsv3-read3res-encode-to-use-struct-.patch @@ -0,0 +1,134 @@ +From 5820b7a3de6080c0a270d749c45c282620b98de0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Oct 2020 15:23:50 -0400 +Subject: NFSD: Update the NFSv3 READ3res encode to use struct xdr_stream + +From: Chuck Lever + +[ Upstream commit cc9bcdad7773c295375e66c892c7ac00524706f2 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3proc.c | 1 + + fs/nfsd/nfs3xdr.c | 43 ++++++++++++++++++++------------------ + fs/nfsd/xdr3.h | 1 + + include/linux/sunrpc/xdr.h | 20 ++++++++++++++++++ + 4 files changed, 45 insertions(+), 20 deletions(-) + +diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c +index e8d772f2c7769..201f2009b540b 100644 +--- a/fs/nfsd/nfs3proc.c ++++ b/fs/nfsd/nfs3proc.c +@@ -159,6 +159,7 @@ nfsd3_proc_read(struct svc_rqst *rqstp) + + v = 0; + len = argp->count; ++ resp->pages = rqstp->rq_next_page; + while (len > 0) { + struct page *page = *(rqstp->rq_next_page++); + +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index 352691c3e246a..859cc6c51c1a5 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -1005,30 +1005,33 @@ nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p) + int + nfs3svc_encode_readres(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd3_readres *resp = rqstp->rq_resp; + struct kvec *head = rqstp->rq_res.head; + +- *p++ = resp->status; +- p = encode_post_op_attr(rqstp, p, &resp->fh); +- if (resp->status == 0) { +- *p++ = htonl(resp->count); +- *p++ = htonl(resp->eof); +- *p++ = htonl(resp->count); /* xdr opaque count */ +- xdr_ressize_check(rqstp, p); +- /* now update rqstp->rq_res to reflect data as well */ +- rqstp->rq_res.page_len = resp->count; +- if (resp->count & 3) { +- /* need to pad the tail */ +- rqstp->rq_res.tail[0].iov_base = p; +- *p = 0; +- rqstp->rq_res.tail[0].iov_len = 4 - (resp->count & 3); +- } +- if (svc_encode_result_payload(rqstp, head->iov_len, +- resp->count)) ++ if (!svcxdr_encode_nfsstat3(xdr, resp->status)) ++ return 0; ++ switch (resp->status) { ++ case nfs_ok: ++ if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) + return 0; +- return 1; +- } else +- return xdr_ressize_check(rqstp, p); ++ if (xdr_stream_encode_u32(xdr, resp->count) < 0) ++ return 0; ++ if (xdr_stream_encode_bool(xdr, resp->eof) < 0) ++ return 0; ++ if (xdr_stream_encode_u32(xdr, resp->count) < 0) ++ return 0; ++ xdr_write_pages(xdr, resp->pages, rqstp->rq_res.page_base, ++ resp->count); ++ if (svc_encode_result_payload(rqstp, head->iov_len, resp->count) < 0) ++ return 0; ++ break; ++ default: ++ if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) ++ return 0; ++ } ++ ++ return 1; + } + + /* WRITE */ +diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h +index 1d633c5d5fa28..8073350418ae0 100644 +--- a/fs/nfsd/xdr3.h ++++ b/fs/nfsd/xdr3.h +@@ -145,6 +145,7 @@ struct nfsd3_readres { + struct svc_fh fh; + unsigned long count; + __u32 eof; ++ struct page **pages; + }; + + struct nfsd3_writeres { +diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h +index eba6204330b3c..237b78146c7d6 100644 +--- a/include/linux/sunrpc/xdr.h ++++ b/include/linux/sunrpc/xdr.h +@@ -394,6 +394,26 @@ static inline int xdr_stream_encode_item_absent(struct xdr_stream *xdr) + return len; + } + ++/** ++ * xdr_stream_encode_bool - Encode a "not present" list item ++ * @xdr: pointer to xdr_stream ++ * @n: boolean value to encode ++ * ++ * Return values: ++ * On success, returns length in bytes of XDR buffer consumed ++ * %-EMSGSIZE on XDR buffer overflow ++ */ ++static inline int xdr_stream_encode_bool(struct xdr_stream *xdr, __u32 n) ++{ ++ const size_t len = XDR_UNIT; ++ __be32 *p = xdr_reserve_space(xdr, len); ++ ++ if (unlikely(!p)) ++ return -EMSGSIZE; ++ *p = n ? xdr_one : xdr_zero; ++ return len; ++} ++ + /** + * xdr_stream_encode_u32 - Encode a 32-bit integer + * @xdr: pointer to xdr_stream +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-nfsv3-readdir3res-encoder-to-use-str.patch b/queue-5.10/nfsd-update-the-nfsv3-readdir3res-encoder-to-use-str.patch new file mode 100644 index 00000000000..954df97e0d4 --- /dev/null +++ b/queue-5.10/nfsd-update-the-nfsv3-readdir3res-encoder-to-use-str.patch @@ -0,0 +1,120 @@ +From 8e30d8317598815afb51c65be62c0114d3f521ff Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Oct 2020 19:31:48 -0400 +Subject: NFSD: Update the NFSv3 READDIR3res encoder to use struct xdr_stream + +From: Chuck Lever + +[ Upstream commit e4ccfe3014de435984939a3d84b7f241d3b57b0d ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3proc.c | 3 ++- + fs/nfsd/nfs3xdr.c | 54 ++++++++++++++++++++++++++++++---------------- + fs/nfsd/xdr3.h | 1 + + 3 files changed, 38 insertions(+), 20 deletions(-) + +diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c +index 7dcc7abb1f346..9e8481242dea8 100644 +--- a/fs/nfsd/nfs3proc.c ++++ b/fs/nfsd/nfs3proc.c +@@ -452,7 +452,8 @@ static void nfsd3_init_dirlist_pages(struct svc_rqst *rqstp, + * and reserve room for the NULL ptr & eof flag (-2 words) */ + resp->buflen = (count >> 2) - 2; + +- resp->buffer = page_address(*rqstp->rq_next_page); ++ resp->pages = rqstp->rq_next_page; ++ resp->buffer = page_address(*resp->pages); + while (count > 0) { + rqstp->rq_next_page++; + count -= PAGE_SIZE; +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index 523b2dca04944..3d076d3c5c7b8 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -158,6 +158,19 @@ encode_fh(__be32 *p, struct svc_fh *fhp) + return p + XDR_QUADLEN(size); + } + ++static bool ++svcxdr_encode_cookieverf3(struct xdr_stream *xdr, const __be32 *verf) ++{ ++ __be32 *p; ++ ++ p = xdr_reserve_space(xdr, NFS3_COOKIEVERFSIZE); ++ if (!p) ++ return false; ++ memcpy(p, verf, NFS3_COOKIEVERFSIZE); ++ ++ return true; ++} ++ + static bool + svcxdr_encode_writeverf3(struct xdr_stream *xdr, const __be32 *verf) + { +@@ -1124,27 +1137,30 @@ nfs3svc_encode_linkres(struct svc_rqst *rqstp, __be32 *p) + int + nfs3svc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd3_readdirres *resp = rqstp->rq_resp; + +- *p++ = resp->status; +- p = encode_post_op_attr(rqstp, p, &resp->fh); +- +- if (resp->status == 0) { +- /* stupid readdir cookie */ +- memcpy(p, resp->verf, 8); p += 2; +- xdr_ressize_check(rqstp, p); +- if (rqstp->rq_res.head[0].iov_len + (2<<2) > PAGE_SIZE) +- return 1; /*No room for trailer */ +- rqstp->rq_res.page_len = (resp->count) << 2; +- +- /* add the 'tail' to the end of the 'head' page - page 0. */ +- rqstp->rq_res.tail[0].iov_base = p; +- *p++ = 0; /* no more entries */ +- *p++ = htonl(resp->common.err == nfserr_eof); +- rqstp->rq_res.tail[0].iov_len = 2<<2; +- return 1; +- } else +- return xdr_ressize_check(rqstp, p); ++ if (!svcxdr_encode_nfsstat3(xdr, resp->status)) ++ return 0; ++ switch (resp->status) { ++ case nfs_ok: ++ if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) ++ return 0; ++ if (!svcxdr_encode_cookieverf3(xdr, resp->verf)) ++ return 0; ++ xdr_write_pages(xdr, resp->pages, 0, resp->count << 2); ++ /* no more entries */ ++ if (xdr_stream_encode_item_absent(xdr) < 0) ++ return 0; ++ if (xdr_stream_encode_bool(xdr, resp->common.err == nfserr_eof) < 0) ++ return 0; ++ break; ++ default: ++ if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) ++ return 0; ++ } ++ ++ return 1; + } + + static __be32 * +diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h +index e76e9230827e4..a4cdd8ccb175a 100644 +--- a/fs/nfsd/xdr3.h ++++ b/fs/nfsd/xdr3.h +@@ -176,6 +176,7 @@ struct nfsd3_readdirres { + struct svc_fh scratch; + int count; + __be32 verf[2]; ++ struct page **pages; + + struct readdir_cd common; + __be32 * buffer; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-nfsv3-readlink3res-encoder-to-use-st.patch b/queue-5.10/nfsd-update-the-nfsv3-readlink3res-encoder-to-use-st.patch new file mode 100644 index 00000000000..92d620068aa --- /dev/null +++ b/queue-5.10/nfsd-update-the-nfsv3-readlink3res-encoder-to-use-st.patch @@ -0,0 +1,103 @@ +From d7618630e606083ed7fd3d4d545dbe56506f7f2f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Oct 2020 15:18:40 -0400 +Subject: NFSD: Update the NFSv3 READLINK3res encoder to use struct xdr_stream + +From: Chuck Lever + +[ Upstream commit 9a9c8923b3efd593d0e6a405efef9d58c6e6804b ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3proc.c | 5 +++-- + fs/nfsd/nfs3xdr.c | 34 ++++++++++++++++++---------------- + fs/nfsd/xdr3.h | 1 + + 3 files changed, 22 insertions(+), 18 deletions(-) + +diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c +index 60e8c25be7571..e8d772f2c7769 100644 +--- a/fs/nfsd/nfs3proc.c ++++ b/fs/nfsd/nfs3proc.c +@@ -126,14 +126,15 @@ nfsd3_proc_readlink(struct svc_rqst *rqstp) + { + struct nfsd_fhandle *argp = rqstp->rq_argp; + struct nfsd3_readlinkres *resp = rqstp->rq_resp; +- char *buffer = page_address(*(rqstp->rq_next_page++)); + + dprintk("nfsd: READLINK(3) %s\n", SVCFH_fmt(&argp->fh)); + + /* Read the symlink. */ + fh_copy(&resp->fh, &argp->fh); + resp->len = NFS3_MAXPATHLEN; +- resp->status = nfsd_readlink(rqstp, &resp->fh, buffer, &resp->len); ++ resp->pages = rqstp->rq_next_page++; ++ resp->status = nfsd_readlink(rqstp, &resp->fh, ++ page_address(*resp->pages), &resp->len); + return rpc_success; + } + +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index 29b923a497f48..352691c3e246a 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -977,26 +977,28 @@ nfs3svc_encode_accessres(struct svc_rqst *rqstp, __be32 *p) + int + nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd3_readlinkres *resp = rqstp->rq_resp; + struct kvec *head = rqstp->rq_res.head; + +- *p++ = resp->status; +- p = encode_post_op_attr(rqstp, p, &resp->fh); +- if (resp->status == 0) { +- *p++ = htonl(resp->len); +- xdr_ressize_check(rqstp, p); +- rqstp->rq_res.page_len = resp->len; +- if (resp->len & 3) { +- /* need to pad the tail */ +- rqstp->rq_res.tail[0].iov_base = p; +- *p = 0; +- rqstp->rq_res.tail[0].iov_len = 4 - (resp->len&3); +- } +- if (svc_encode_result_payload(rqstp, head->iov_len, resp->len)) ++ if (!svcxdr_encode_nfsstat3(xdr, resp->status)) ++ return 0; ++ switch (resp->status) { ++ case nfs_ok: ++ if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) + return 0; +- return 1; +- } else +- return xdr_ressize_check(rqstp, p); ++ if (xdr_stream_encode_u32(xdr, resp->len) < 0) ++ return 0; ++ xdr_write_pages(xdr, resp->pages, 0, resp->len); ++ if (svc_encode_result_payload(rqstp, head->iov_len, resp->len) < 0) ++ return 0; ++ break; ++ default: ++ if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) ++ return 0; ++ } ++ ++ return 1; + } + + /* READ */ +diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h +index 7db4ee17aa209..1d633c5d5fa28 100644 +--- a/fs/nfsd/xdr3.h ++++ b/fs/nfsd/xdr3.h +@@ -137,6 +137,7 @@ struct nfsd3_readlinkres { + __be32 status; + struct svc_fh fh; + __u32 len; ++ struct page **pages; + }; + + struct nfsd3_readres { +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-nfsv3-renamev3res-encoder-to-use-str.patch b/queue-5.10/nfsd-update-the-nfsv3-renamev3res-encoder-to-use-str.patch new file mode 100644 index 00000000000..65cd7075f0a --- /dev/null +++ b/queue-5.10/nfsd-update-the-nfsv3-renamev3res-encoder-to-use-str.patch @@ -0,0 +1,39 @@ +From c15f18c05a9ea249eb8c6490ff377228e8b7ea75 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Oct 2020 15:33:05 -0400 +Subject: NFSD: Update the NFSv3 RENAMEv3res encoder to use struct xdr_stream + +From: Chuck Lever + +[ Upstream commit 89d79e9672dfa6d0cc416699c16f2d312da58ff2 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3xdr.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index 052376a65f723..1d52a69562b82 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -1116,12 +1116,12 @@ nfs3svc_encode_createres(struct svc_rqst *rqstp, __be32 *p) + int + nfs3svc_encode_renameres(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd3_renameres *resp = rqstp->rq_resp; + +- *p++ = resp->status; +- p = encode_wcc_data(rqstp, p, &resp->ffh); +- p = encode_wcc_data(rqstp, p, &resp->tfh); +- return xdr_ressize_check(rqstp, p); ++ return svcxdr_encode_nfsstat3(xdr, resp->status) && ++ svcxdr_encode_wcc_data(rqstp, xdr, &resp->ffh) && ++ svcxdr_encode_wcc_data(rqstp, xdr, &resp->tfh); + } + + /* LINK */ +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-nfsv3-setacl-result-encoder-to-use-s.patch b/queue-5.10/nfsd-update-the-nfsv3-setacl-result-encoder-to-use-s.patch new file mode 100644 index 00000000000..a4e6b17eee3 --- /dev/null +++ b/queue-5.10/nfsd-update-the-nfsv3-setacl-result-encoder-to-use-s.patch @@ -0,0 +1,37 @@ +From 27ab74ef4e09aad440171366fef9b5542f1146e8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 18 Nov 2020 16:21:24 -0500 +Subject: NFSD: Update the NFSv3 SETACL result encoder to use struct xdr_stream + +From: Chuck Lever + +[ Upstream commit 15e432bf0cfd1e6aebfa9ffd4e0cc2ff4f3ae2db ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3acl.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c +index 04e157b0b201a..cfb686f23e571 100644 +--- a/fs/nfsd/nfs3acl.c ++++ b/fs/nfsd/nfs3acl.c +@@ -217,11 +217,11 @@ static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p) + /* SETACL */ + static int nfs3svc_encode_setaclres(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd3_attrstat *resp = rqstp->rq_resp; + +- *p++ = resp->status; +- p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh); +- return xdr_ressize_check(rqstp, p); ++ return svcxdr_encode_nfsstat3(xdr, resp->status) && ++ svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh); + } + + /* +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-nfsv3-wccstat-result-encoder-to-use-.patch b/queue-5.10/nfsd-update-the-nfsv3-wccstat-result-encoder-to-use-.patch new file mode 100644 index 00000000000..f30d8366e24 --- /dev/null +++ b/queue-5.10/nfsd-update-the-nfsv3-wccstat-result-encoder-to-use-.patch @@ -0,0 +1,114 @@ +From 9346222f795874963c98a77d7e34fff17ed06c0f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Oct 2020 15:12:38 -0400 +Subject: NFSD: Update the NFSv3 wccstat result encoder to use struct + xdr_stream + +From: Chuck Lever + +[ Upstream commit 70f8e839859a994e324e1d18889f8319bbd5bff9 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3xdr.c | 68 ++++++++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 65 insertions(+), 3 deletions(-) + +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index 2bb998b3834bf..29b923a497f48 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -400,6 +400,35 @@ encode_saved_post_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp) + return encode_fattr3(rqstp, p, fhp, &fhp->fh_post_attr); + } + ++static bool ++svcxdr_encode_wcc_attr(struct xdr_stream *xdr, const struct svc_fh *fhp) ++{ ++ __be32 *p; ++ ++ p = xdr_reserve_space(xdr, XDR_UNIT * 6); ++ if (!p) ++ return false; ++ p = xdr_encode_hyper(p, (u64)fhp->fh_pre_size); ++ p = encode_nfstime3(p, &fhp->fh_pre_mtime); ++ encode_nfstime3(p, &fhp->fh_pre_ctime); ++ ++ return true; ++} ++ ++static bool ++svcxdr_encode_pre_op_attr(struct xdr_stream *xdr, const struct svc_fh *fhp) ++{ ++ if (!fhp->fh_pre_saved) { ++ if (xdr_stream_encode_item_absent(xdr) < 0) ++ return false; ++ return true; ++ } ++ ++ if (xdr_stream_encode_item_present(xdr) < 0) ++ return false; ++ return svcxdr_encode_wcc_attr(xdr, fhp); ++} ++ + static bool + svcxdr_encode_post_op_attr(struct svc_rqst *rqstp, struct xdr_stream *xdr, + const struct svc_fh *fhp) +@@ -460,6 +489,39 @@ nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fh + return encode_post_op_attr(rqstp, p, fhp); + } + ++/* ++ * Encode weak cache consistency data ++ */ ++static bool ++svcxdr_encode_wcc_data(struct svc_rqst *rqstp, struct xdr_stream *xdr, ++ const struct svc_fh *fhp) ++{ ++ struct dentry *dentry = fhp->fh_dentry; ++ ++ if (!dentry || !d_really_is_positive(dentry) || !fhp->fh_post_saved) ++ goto neither; ++ ++ /* before */ ++ if (!svcxdr_encode_pre_op_attr(xdr, fhp)) ++ return false; ++ ++ /* after */ ++ if (xdr_stream_encode_item_present(xdr) < 0) ++ return false; ++ if (!svcxdr_encode_fattr3(rqstp, xdr, fhp, &fhp->fh_post_attr)) ++ return false; ++ ++ return true; ++ ++neither: ++ if (xdr_stream_encode_item_absent(xdr) < 0) ++ return false; ++ if (!svcxdr_encode_post_op_attr(rqstp, xdr, fhp)) ++ return false; ++ ++ return true; ++} ++ + /* + * Enocde weak cache consistency data + */ +@@ -855,11 +917,11 @@ nfs3svc_encode_getattrres(struct svc_rqst *rqstp, __be32 *p) + int + nfs3svc_encode_wccstat(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd3_attrstat *resp = rqstp->rq_resp; + +- *p++ = resp->status; +- p = encode_wcc_data(rqstp, p, &resp->fh); +- return xdr_ressize_check(rqstp, p); ++ return svcxdr_encode_nfsstat3(xdr, resp->status) && ++ svcxdr_encode_wcc_data(rqstp, xdr, &resp->fh); + } + + /* LOOKUP */ +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-nfsv3-write3res-encoder-to-use-struc.patch b/queue-5.10/nfsd-update-the-nfsv3-write3res-encoder-to-use-struc.patch new file mode 100644 index 00000000000..5a40434a3c1 --- /dev/null +++ b/queue-5.10/nfsd-update-the-nfsv3-write3res-encoder-to-use-struc.patch @@ -0,0 +1,79 @@ +From b4eb2eb310bc03268dd42e17b132289572edb4bc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Oct 2020 15:26:31 -0400 +Subject: NFSD: Update the NFSv3 WRITE3res encoder to use struct xdr_stream + +From: Chuck Lever + +[ Upstream commit ecb7a085ac15a8844ebf12fca6ae51ce71ac9b3b ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3xdr.c | 40 ++++++++++++++++++++++++++++++++-------- + 1 file changed, 32 insertions(+), 8 deletions(-) + +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index 859cc6c51c1a5..0191cbfc486b8 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -131,6 +131,19 @@ encode_fh(__be32 *p, struct svc_fh *fhp) + return p + XDR_QUADLEN(size); + } + ++static bool ++svcxdr_encode_writeverf3(struct xdr_stream *xdr, const __be32 *verf) ++{ ++ __be32 *p; ++ ++ p = xdr_reserve_space(xdr, NFS3_WRITEVERFSIZE); ++ if (!p) ++ return false; ++ memcpy(p, verf, NFS3_WRITEVERFSIZE); ++ ++ return true; ++} ++ + static bool + svcxdr_decode_filename3(struct xdr_stream *xdr, char **name, unsigned int *len) + { +@@ -1038,17 +1051,28 @@ nfs3svc_encode_readres(struct svc_rqst *rqstp, __be32 *p) + int + nfs3svc_encode_writeres(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd3_writeres *resp = rqstp->rq_resp; + +- *p++ = resp->status; +- p = encode_wcc_data(rqstp, p, &resp->fh); +- if (resp->status == 0) { +- *p++ = htonl(resp->count); +- *p++ = htonl(resp->committed); +- *p++ = resp->verf[0]; +- *p++ = resp->verf[1]; ++ if (!svcxdr_encode_nfsstat3(xdr, resp->status)) ++ return 0; ++ switch (resp->status) { ++ case nfs_ok: ++ if (!svcxdr_encode_wcc_data(rqstp, xdr, &resp->fh)) ++ return 0; ++ if (xdr_stream_encode_u32(xdr, resp->count) < 0) ++ return 0; ++ if (xdr_stream_encode_u32(xdr, resp->committed) < 0) ++ return 0; ++ if (!svcxdr_encode_writeverf3(xdr, resp->verf)) ++ return 0; ++ break; ++ default: ++ if (!svcxdr_encode_wcc_data(rqstp, xdr, &resp->fh)) ++ return 0; + } +- return xdr_ressize_check(rqstp, p); ++ ++ return 1; + } + + /* CREATE, MKDIR, SYMLINK, MKNOD */ +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-rename3args-decoder-to-use-struct-xd.patch b/queue-5.10/nfsd-update-the-rename3args-decoder-to-use-struct-xd.patch new file mode 100644 index 00000000000..32f2c76df8c --- /dev/null +++ b/queue-5.10/nfsd-update-the-rename3args-decoder-to-use-struct-xd.patch @@ -0,0 +1,43 @@ +From cfbaf923c36ff1850872483cdd8726aeadda5eed Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Oct 2020 15:44:12 -0400 +Subject: NFSD: Update the RENAME3args decoder to use struct xdr_stream + +From: Chuck Lever + +[ Upstream commit d181e0a4bef36ee74d1338e5b5c2561d7463a5d0 ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3xdr.c | 12 +++++------- + 1 file changed, 5 insertions(+), 7 deletions(-) + +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index 299ea8bbd685f..f870a068aad85 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -562,15 +562,13 @@ nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, __be32 *p) + int + nfs3svc_decode_renameargs(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd3_renameargs *args = rqstp->rq_argp; + +- if (!(p = decode_fh(p, &args->ffh)) +- || !(p = decode_filename(p, &args->fname, &args->flen)) +- || !(p = decode_fh(p, &args->tfh)) +- || !(p = decode_filename(p, &args->tname, &args->tlen))) +- return 0; +- +- return xdr_argsize_check(rqstp, p); ++ return svcxdr_decode_diropargs3(xdr, &args->ffh, ++ &args->fname, &args->flen) && ++ svcxdr_decode_diropargs3(xdr, &args->tfh, ++ &args->tname, &args->tlen); + } + + int +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-setattr3args-decoder-to-use-struct-x.patch b/queue-5.10/nfsd-update-the-setattr3args-decoder-to-use-struct-x.patch new file mode 100644 index 00000000000..054619205fb --- /dev/null +++ b/queue-5.10/nfsd-update-the-setattr3args-decoder-to-use-struct-x.patch @@ -0,0 +1,202 @@ +From 6e06745cf6b46530ea84db121c2587c31b377de0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Oct 2020 15:48:22 -0400 +Subject: NFSD: Update the SETATTR3args decoder to use struct xdr_stream + +From: Chuck Lever + +[ Upstream commit 9cde9360d18d8b352b737d10f90f2aecccf93dbe ] + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3xdr.c | 138 +++++++++++++++++++++++++++++++++----- + include/uapi/linux/nfs3.h | 6 ++ + 2 files changed, 127 insertions(+), 17 deletions(-) + +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index 9437dda2646f2..6a6bf8e34d82b 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -39,12 +39,18 @@ encode_time3(__be32 *p, struct timespec64 *time) + return p; + } + +-static __be32 * +-decode_time3(__be32 *p, struct timespec64 *time) ++static bool ++svcxdr_decode_nfstime3(struct xdr_stream *xdr, struct timespec64 *timep) + { +- time->tv_sec = ntohl(*p++); +- time->tv_nsec = ntohl(*p++); +- return p; ++ __be32 *p; ++ ++ p = xdr_inline_decode(xdr, XDR_UNIT * 2); ++ if (!p) ++ return false; ++ timep->tv_sec = be32_to_cpup(p++); ++ timep->tv_nsec = be32_to_cpup(p); ++ ++ return true; + } + + static bool +@@ -150,6 +156,112 @@ svcxdr_decode_diropargs3(struct xdr_stream *xdr, struct svc_fh *fhp, + svcxdr_decode_filename3(xdr, name, len); + } + ++static bool ++svcxdr_decode_sattr3(struct svc_rqst *rqstp, struct xdr_stream *xdr, ++ struct iattr *iap) ++{ ++ u32 set_it; ++ ++ iap->ia_valid = 0; ++ ++ if (xdr_stream_decode_bool(xdr, &set_it) < 0) ++ return false; ++ if (set_it) { ++ u32 mode; ++ ++ if (xdr_stream_decode_u32(xdr, &mode) < 0) ++ return false; ++ iap->ia_valid |= ATTR_MODE; ++ iap->ia_mode = mode; ++ } ++ if (xdr_stream_decode_bool(xdr, &set_it) < 0) ++ return false; ++ if (set_it) { ++ u32 uid; ++ ++ if (xdr_stream_decode_u32(xdr, &uid) < 0) ++ return false; ++ iap->ia_uid = make_kuid(nfsd_user_namespace(rqstp), uid); ++ if (uid_valid(iap->ia_uid)) ++ iap->ia_valid |= ATTR_UID; ++ } ++ if (xdr_stream_decode_bool(xdr, &set_it) < 0) ++ return false; ++ if (set_it) { ++ u32 gid; ++ ++ if (xdr_stream_decode_u32(xdr, &gid) < 0) ++ return false; ++ iap->ia_gid = make_kgid(nfsd_user_namespace(rqstp), gid); ++ if (gid_valid(iap->ia_gid)) ++ iap->ia_valid |= ATTR_GID; ++ } ++ if (xdr_stream_decode_bool(xdr, &set_it) < 0) ++ return false; ++ if (set_it) { ++ u64 newsize; ++ ++ if (xdr_stream_decode_u64(xdr, &newsize) < 0) ++ return false; ++ iap->ia_valid |= ATTR_SIZE; ++ iap->ia_size = min_t(u64, newsize, NFS_OFFSET_MAX); ++ } ++ if (xdr_stream_decode_u32(xdr, &set_it) < 0) ++ return false; ++ switch (set_it) { ++ case DONT_CHANGE: ++ break; ++ case SET_TO_SERVER_TIME: ++ iap->ia_valid |= ATTR_ATIME; ++ break; ++ case SET_TO_CLIENT_TIME: ++ if (!svcxdr_decode_nfstime3(xdr, &iap->ia_atime)) ++ return false; ++ iap->ia_valid |= ATTR_ATIME | ATTR_ATIME_SET; ++ break; ++ default: ++ return false; ++ } ++ if (xdr_stream_decode_u32(xdr, &set_it) < 0) ++ return false; ++ switch (set_it) { ++ case DONT_CHANGE: ++ break; ++ case SET_TO_SERVER_TIME: ++ iap->ia_valid |= ATTR_MTIME; ++ break; ++ case SET_TO_CLIENT_TIME: ++ if (!svcxdr_decode_nfstime3(xdr, &iap->ia_mtime)) ++ return false; ++ iap->ia_valid |= ATTR_MTIME | ATTR_MTIME_SET; ++ break; ++ default: ++ return false; ++ } ++ ++ return true; ++} ++ ++static bool ++svcxdr_decode_sattrguard3(struct xdr_stream *xdr, struct nfsd3_sattrargs *args) ++{ ++ __be32 *p; ++ u32 check; ++ ++ if (xdr_stream_decode_bool(xdr, &check) < 0) ++ return false; ++ if (check) { ++ p = xdr_inline_decode(xdr, XDR_UNIT * 2); ++ if (!p) ++ return false; ++ args->check_guard = 1; ++ args->guardtime = be32_to_cpup(p); ++ } else ++ args->check_guard = 0; ++ ++ return true; ++} ++ + static __be32 * + decode_sattr3(__be32 *p, struct iattr *iap, struct user_namespace *userns) + { +@@ -377,20 +489,12 @@ nfs3svc_decode_fhandleargs(struct svc_rqst *rqstp, __be32 *p) + int + nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd3_sattrargs *args = rqstp->rq_argp; + +- p = decode_fh(p, &args->fh); +- if (!p) +- return 0; +- p = decode_sattr3(p, &args->attrs, nfsd_user_namespace(rqstp)); +- +- if ((args->check_guard = ntohl(*p++)) != 0) { +- struct timespec64 time; +- p = decode_time3(p, &time); +- args->guardtime = time.tv_sec; +- } +- +- return xdr_argsize_check(rqstp, p); ++ return svcxdr_decode_nfs_fh3(xdr, &args->fh) && ++ svcxdr_decode_sattr3(rqstp, xdr, &args->attrs) && ++ svcxdr_decode_sattrguard3(xdr, args); + } + + int +diff --git a/include/uapi/linux/nfs3.h b/include/uapi/linux/nfs3.h +index 37e4b34e6b435..c22ab77713bd0 100644 +--- a/include/uapi/linux/nfs3.h ++++ b/include/uapi/linux/nfs3.h +@@ -63,6 +63,12 @@ enum nfs3_ftype { + NF3BAD = 8 + }; + ++enum nfs3_time_how { ++ DONT_CHANGE = 0, ++ SET_TO_SERVER_TIME = 1, ++ SET_TO_CLIENT_TIME = 2, ++}; ++ + struct nfs3_fh { + unsigned short size; + unsigned char data[NFS3_FHSIZE]; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-the-symlink3args-decoder-to-use-struct-x.patch b/queue-5.10/nfsd-update-the-symlink3args-decoder-to-use-struct-x.patch new file mode 100644 index 00000000000..f05533b8e88 --- /dev/null +++ b/queue-5.10/nfsd-update-the-symlink3args-decoder-to-use-struct-x.patch @@ -0,0 +1,67 @@ +From 1aa40c8117b59a34f170d4093b81f9841d1a91d1 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 20 Oct 2020 16:01:16 -0400 +Subject: NFSD: Update the SYMLINK3args decoder to use struct xdr_stream + +From: Chuck Lever + +[ Upstream commit da39201637297460c13134c29286a00f3a1c92fe ] + +Similar to the WRITE decoder, code that checks the sanity of the +payload size is re-wired to work with xdr_stream infrastructure. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3xdr.c | 29 ++++++++++++++++------------- + 1 file changed, 16 insertions(+), 13 deletions(-) + +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index b4071cda1d652..eb17231ab1661 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -616,25 +616,28 @@ nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, __be32 *p) + int + nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd3_symlinkargs *args = rqstp->rq_argp; +- char *base = (char *)p; +- size_t dlen; ++ struct kvec *head = rqstp->rq_arg.head; ++ struct kvec *tail = rqstp->rq_arg.tail; ++ size_t remaining; + +- if (!(p = decode_fh(p, &args->ffh)) || +- !(p = decode_filename(p, &args->fname, &args->flen))) ++ if (!svcxdr_decode_diropargs3(xdr, &args->ffh, &args->fname, &args->flen)) ++ return 0; ++ if (!svcxdr_decode_sattr3(rqstp, xdr, &args->attrs)) ++ return 0; ++ if (xdr_stream_decode_u32(xdr, &args->tlen) < 0) + return 0; +- p = decode_sattr3(p, &args->attrs, nfsd_user_namespace(rqstp)); + +- args->tlen = ntohl(*p++); ++ /* request sanity */ ++ remaining = head->iov_len + rqstp->rq_arg.page_len + tail->iov_len; ++ remaining -= xdr_stream_pos(xdr); ++ if (remaining < xdr_align_size(args->tlen)) ++ return 0; + +- args->first.iov_base = p; +- args->first.iov_len = rqstp->rq_arg.head[0].iov_len; +- args->first.iov_len -= (char *)p - base; ++ args->first.iov_base = xdr->p; ++ args->first.iov_len = head->iov_len - xdr_stream_pos(xdr); + +- dlen = args->first.iov_len + rqstp->rq_arg.page_len + +- rqstp->rq_arg.tail[0].iov_len; +- if (dlen < XDR_QUADLEN(args->tlen) << 2) +- return 0; + return 1; + } + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-update-write3arg-decoder-to-use-struct-xdr_stre.patch b/queue-5.10/nfsd-update-write3arg-decoder-to-use-struct-xdr_stre.patch new file mode 100644 index 00000000000..7c373f53602 --- /dev/null +++ b/queue-5.10/nfsd-update-write3arg-decoder-to-use-struct-xdr_stre.patch @@ -0,0 +1,99 @@ +From c1c2bdab8e427062ad35f7bd0bd69ccfcc3e0ee5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Oct 2020 11:14:55 -0400 +Subject: NFSD: Update WRITE3arg decoder to use struct xdr_stream + +From: Chuck Lever + +[ Upstream commit c43b2f229a01969a7ccf94b033c5085e0ec2040c ] + +As part of the update, open code that sanity-checks the size of the +data payload against the length of the RPC Call message has to be +re-implemented to use xdr_stream infrastructure. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3xdr.c | 51 +++++++++++++++++++---------------------------- + 1 file changed, 20 insertions(+), 31 deletions(-) + +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index 2f32df15a7e87..c06467e8ac829 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -405,52 +405,41 @@ nfs3svc_decode_readargs(struct svc_rqst *rqstp, __be32 *p) + int + nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p) + { ++ struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd3_writeargs *args = rqstp->rq_argp; +- unsigned int len, hdr, dlen; + u32 max_blocksize = svc_max_payload(rqstp); + struct kvec *head = rqstp->rq_arg.head; + struct kvec *tail = rqstp->rq_arg.tail; ++ size_t remaining; + +- p = decode_fh(p, &args->fh); +- if (!p) ++ if (!svcxdr_decode_nfs_fh3(xdr, &args->fh)) + return 0; +- p = xdr_decode_hyper(p, &args->offset); +- +- args->count = ntohl(*p++); +- args->stable = ntohl(*p++); +- len = args->len = ntohl(*p++); +- if ((void *)p > head->iov_base + head->iov_len) ++ if (xdr_stream_decode_u64(xdr, &args->offset) < 0) + return 0; +- /* +- * The count must equal the amount of data passed. +- */ +- if (args->count != args->len) ++ if (xdr_stream_decode_u32(xdr, &args->count) < 0) ++ return 0; ++ if (xdr_stream_decode_u32(xdr, &args->stable) < 0) + return 0; + +- /* +- * Check to make sure that we got the right number of +- * bytes. +- */ +- hdr = (void*)p - head->iov_base; +- dlen = head->iov_len + rqstp->rq_arg.page_len + tail->iov_len - hdr; +- /* +- * Round the length of the data which was specified up to +- * the next multiple of XDR units and then compare that +- * against the length which was actually received. +- * Note that when RPCSEC/GSS (for example) is used, the +- * data buffer can be padded so dlen might be larger +- * than required. It must never be smaller. +- */ +- if (dlen < XDR_QUADLEN(len)*4) ++ /* opaque data */ ++ if (xdr_stream_decode_u32(xdr, &args->len) < 0) + return 0; + ++ /* request sanity */ ++ if (args->count != args->len) ++ return 0; ++ remaining = head->iov_len + rqstp->rq_arg.page_len + tail->iov_len; ++ remaining -= xdr_stream_pos(xdr); ++ if (remaining < xdr_align_size(args->len)) ++ return 0; + if (args->count > max_blocksize) { + args->count = max_blocksize; +- len = args->len = max_blocksize; ++ args->len = max_blocksize; + } + +- args->first.iov_base = (void *)p; +- args->first.iov_len = head->iov_len - hdr; ++ args->first.iov_base = xdr->p; ++ args->first.iov_len = head->iov_len - xdr_stream_pos(xdr); ++ + return 1; + } + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-use-const-pointers-as-parameters-to-fh_-helpers.patch b/queue-5.10/nfsd-use-const-pointers-as-parameters-to-fh_-helpers.patch new file mode 100644 index 00000000000..80be5b5a05c --- /dev/null +++ b/queue-5.10/nfsd-use-const-pointers-as-parameters-to-fh_-helpers.patch @@ -0,0 +1,66 @@ +From 04723ac918ac5eae4ad92367fa92caa0f806d15e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Oct 2022 10:47:16 -0400 +Subject: NFSD: Use const pointers as parameters to fh_ helpers + +From: Chuck Lever + +[ Upstream commit b48f8056c034f28dd54668399f1d22be421b0bef ] + +Enable callers to use const pointers where they are able to. + +Signed-off-by: Chuck Lever +Tested-by: Jeff Layton +Reviewed-by: Jeff Layton +Reviewed-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsfh.h | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h +index c3ae6414fc5cf..513e028b0bbee 100644 +--- a/fs/nfsd/nfsfh.h ++++ b/fs/nfsd/nfsfh.h +@@ -220,7 +220,7 @@ __be32 fh_update(struct svc_fh *); + void fh_put(struct svc_fh *); + + static __inline__ struct svc_fh * +-fh_copy(struct svc_fh *dst, struct svc_fh *src) ++fh_copy(struct svc_fh *dst, const struct svc_fh *src) + { + WARN_ON(src->fh_dentry); + +@@ -229,7 +229,7 @@ fh_copy(struct svc_fh *dst, struct svc_fh *src) + } + + static inline void +-fh_copy_shallow(struct knfsd_fh *dst, struct knfsd_fh *src) ++fh_copy_shallow(struct knfsd_fh *dst, const struct knfsd_fh *src) + { + dst->fh_size = src->fh_size; + memcpy(&dst->fh_raw, &src->fh_raw, src->fh_size); +@@ -243,7 +243,8 @@ fh_init(struct svc_fh *fhp, int maxsize) + return fhp; + } + +-static inline bool fh_match(struct knfsd_fh *fh1, struct knfsd_fh *fh2) ++static inline bool fh_match(const struct knfsd_fh *fh1, ++ const struct knfsd_fh *fh2) + { + if (fh1->fh_size != fh2->fh_size) + return false; +@@ -252,7 +253,8 @@ static inline bool fh_match(struct knfsd_fh *fh1, struct knfsd_fh *fh2) + return true; + } + +-static inline bool fh_fsid_match(struct knfsd_fh *fh1, struct knfsd_fh *fh2) ++static inline bool fh_fsid_match(const struct knfsd_fh *fh1, ++ const struct knfsd_fh *fh2) + { + if (fh1->fh_fsid_type != fh2->fh_fsid_type) + return false; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-use-define_proc_show_attribute-to-define-nfsd_p.patch b/queue-5.10/nfsd-use-define_proc_show_attribute-to-define-nfsd_p.patch new file mode 100644 index 00000000000..796f9a3d205 --- /dev/null +++ b/queue-5.10/nfsd-use-define_proc_show_attribute-to-define-nfsd_p.patch @@ -0,0 +1,53 @@ +From f0a3daf3405694210d915099b54c22c6de21b9b0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Sep 2022 00:31:52 +0800 +Subject: nfsd: use DEFINE_PROC_SHOW_ATTRIBUTE to define nfsd_proc_ops + +From: ChenXiaoSong + +[ Upstream commit 0cfb0c4228a5c8e2ed2b58f8309b660b187cef02 ] + +Use DEFINE_PROC_SHOW_ATTRIBUTE helper macro to simplify the code. + +Signed-off-by: ChenXiaoSong +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/stats.c | 14 ++------------ + 1 file changed, 2 insertions(+), 12 deletions(-) + +diff --git a/fs/nfsd/stats.c b/fs/nfsd/stats.c +index a8c5a02a84f04..777e24e5da33b 100644 +--- a/fs/nfsd/stats.c ++++ b/fs/nfsd/stats.c +@@ -32,7 +32,7 @@ struct svc_stat nfsd_svcstats = { + .program = &nfsd_program, + }; + +-static int nfsd_proc_show(struct seq_file *seq, void *v) ++static int nfsd_show(struct seq_file *seq, void *v) + { + int i; + +@@ -72,17 +72,7 @@ static int nfsd_proc_show(struct seq_file *seq, void *v) + return 0; + } + +-static int nfsd_proc_open(struct inode *inode, struct file *file) +-{ +- return single_open(file, nfsd_proc_show, NULL); +-} +- +-static const struct proc_ops nfsd_proc_ops = { +- .proc_open = nfsd_proc_open, +- .proc_read = seq_read, +- .proc_lseek = seq_lseek, +- .proc_release = single_release, +-}; ++DEFINE_PROC_SHOW_ATTRIBUTE(nfsd); + + int nfsd_percpu_counters_init(struct percpu_counter counters[], int num) + { +-- +2.43.0 + diff --git a/queue-5.10/nfsd-use-define_show_attribute-to-define-client_info.patch b/queue-5.10/nfsd-use-define_show_attribute-to-define-client_info.patch new file mode 100644 index 00000000000..96e14f89cad --- /dev/null +++ b/queue-5.10/nfsd-use-define_show_attribute-to-define-client_info.patch @@ -0,0 +1,56 @@ +From 29481fd9b66d40682e9b121d4fe9df007af75c94 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Sep 2022 00:31:54 +0800 +Subject: nfsd: use DEFINE_SHOW_ATTRIBUTE to define client_info_fops + +From: ChenXiaoSong + +[ Upstream commit 1d7f6b302b75ff7acb9eb3cab0c631b10cfa7542 ] + +Use DEFINE_SHOW_ATTRIBUTE helper macro to simplify the code. + +inode is converted from seq_file->file instead of seq_file->private in +client_info_show(). + +Signed-off-by: ChenXiaoSong +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 14 ++------------ + 1 file changed, 2 insertions(+), 12 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index d2468a408328d..fce62a4388a26 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -2503,7 +2503,7 @@ static const char *cb_state2str(int state) + + static int client_info_show(struct seq_file *m, void *v) + { +- struct inode *inode = m->private; ++ struct inode *inode = file_inode(m->file); + struct nfs4_client *clp; + u64 clid; + +@@ -2543,17 +2543,7 @@ static int client_info_show(struct seq_file *m, void *v) + return 0; + } + +-static int client_info_open(struct inode *inode, struct file *file) +-{ +- return single_open(file, client_info_show, inode); +-} +- +-static const struct file_operations client_info_fops = { +- .open = client_info_open, +- .read = seq_read, +- .llseek = seq_lseek, +- .release = single_release, +-}; ++DEFINE_SHOW_ATTRIBUTE(client_info); + + static void *states_start(struct seq_file *s, loff_t *pos) + __acquires(&clp->cl_lock) +-- +2.43.0 + diff --git a/queue-5.10/nfsd-use-define_show_attribute-to-define-export_feat.patch b/queue-5.10/nfsd-use-define_show_attribute-to-define-export_feat.patch new file mode 100644 index 00000000000..4d05d5e9933 --- /dev/null +++ b/queue-5.10/nfsd-use-define_show_attribute-to-define-export_feat.patch @@ -0,0 +1,84 @@ +From cb957d7fcd70e9028b150ac36a09f8567601902b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Sep 2022 00:31:53 +0800 +Subject: nfsd: use DEFINE_SHOW_ATTRIBUTE to define export_features_fops and + supported_enctypes_fops + +From: ChenXiaoSong + +[ Upstream commit 9beeaab8e05d353d709103cafa1941714b4d5d94 ] + +Use DEFINE_SHOW_ATTRIBUTE helper macro to simplify the code. + +Signed-off-by: ChenXiaoSong +[ cel: reduce line length ] +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsctl.c | 29 +++++------------------------ + 1 file changed, 5 insertions(+), 24 deletions(-) + +diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c +index 597a26ad4183f..3ed0cfdb0c0b5 100644 +--- a/fs/nfsd/nfsctl.c ++++ b/fs/nfsd/nfsctl.c +@@ -185,17 +185,7 @@ static int export_features_show(struct seq_file *m, void *v) + return 0; + } + +-static int export_features_open(struct inode *inode, struct file *file) +-{ +- return single_open(file, export_features_show, NULL); +-} +- +-static const struct file_operations export_features_operations = { +- .open = export_features_open, +- .read = seq_read, +- .llseek = seq_lseek, +- .release = single_release, +-}; ++DEFINE_SHOW_ATTRIBUTE(export_features); + + #if defined(CONFIG_SUNRPC_GSS) || defined(CONFIG_SUNRPC_GSS_MODULE) + static int supported_enctypes_show(struct seq_file *m, void *v) +@@ -204,17 +194,7 @@ static int supported_enctypes_show(struct seq_file *m, void *v) + return 0; + } + +-static int supported_enctypes_open(struct inode *inode, struct file *file) +-{ +- return single_open(file, supported_enctypes_show, NULL); +-} +- +-static const struct file_operations supported_enctypes_ops = { +- .open = supported_enctypes_open, +- .read = seq_read, +- .llseek = seq_lseek, +- .release = single_release, +-}; ++DEFINE_SHOW_ATTRIBUTE(supported_enctypes); + #endif /* CONFIG_SUNRPC_GSS or CONFIG_SUNRPC_GSS_MODULE */ + + static const struct file_operations pool_stats_operations = { +@@ -1365,7 +1345,7 @@ static int nfsd_fill_super(struct super_block *sb, struct fs_context *fc) + /* Per-export io stats use same ops as exports file */ + [NFSD_Export_Stats] = {"export_stats", &exports_nfsd_operations, S_IRUGO}, + [NFSD_Export_features] = {"export_features", +- &export_features_operations, S_IRUGO}, ++ &export_features_fops, S_IRUGO}, + [NFSD_FO_UnlockIP] = {"unlock_ip", + &transaction_ops, S_IWUSR|S_IRUSR}, + [NFSD_FO_UnlockFS] = {"unlock_filesystem", +@@ -1381,7 +1361,8 @@ static int nfsd_fill_super(struct super_block *sb, struct fs_context *fc) + [NFSD_MaxConnections] = {"max_connections", &transaction_ops, S_IWUSR|S_IRUGO}, + [NFSD_Filecache] = {"filecache", &filecache_ops, S_IRUGO}, + #if defined(CONFIG_SUNRPC_GSS) || defined(CONFIG_SUNRPC_GSS_MODULE) +- [NFSD_SupportedEnctypes] = {"supported_krb5_enctypes", &supported_enctypes_ops, S_IRUGO}, ++ [NFSD_SupportedEnctypes] = {"supported_krb5_enctypes", ++ &supported_enctypes_fops, S_IRUGO}, + #endif /* CONFIG_SUNRPC_GSS or CONFIG_SUNRPC_GSS_MODULE */ + #ifdef CONFIG_NFSD_V4 + [NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR}, +-- +2.43.0 + diff --git a/queue-5.10/nfsd-use-define_show_attribute-to-define-nfsd_file_c.patch b/queue-5.10/nfsd-use-define_show_attribute-to-define-nfsd_file_c.patch new file mode 100644 index 00000000000..ce605f6889c --- /dev/null +++ b/queue-5.10/nfsd-use-define_show_attribute-to-define-nfsd_file_c.patch @@ -0,0 +1,83 @@ +From 1a1a7f9a59d7790f6841c07e261247cc2b093783 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Sep 2022 00:31:56 +0800 +Subject: nfsd: use DEFINE_SHOW_ATTRIBUTE to define nfsd_file_cache_stats_fops + +From: ChenXiaoSong + +[ Upstream commit 1342f9dd3fc219089deeb2620f6790f19b4129b1 ] + +Use DEFINE_SHOW_ATTRIBUTE helper macro to simplify the code. + +Signed-off-by: ChenXiaoSong +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 7 +------ + fs/nfsd/filecache.h | 2 +- + fs/nfsd/nfsctl.c | 9 ++------- + 3 files changed, 4 insertions(+), 14 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index 55478d411e5a0..fa8e1546e0206 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -1211,7 +1211,7 @@ nfsd_file_create(struct svc_rqst *rqstp, struct svc_fh *fhp, + * scraping this file for info should test the labels to ensure they're + * getting the correct field. + */ +-static int nfsd_file_cache_stats_show(struct seq_file *m, void *v) ++int nfsd_file_cache_stats_show(struct seq_file *m, void *v) + { + unsigned long releases = 0, pages_flushed = 0, evictions = 0; + unsigned long hits = 0, acquisitions = 0; +@@ -1258,8 +1258,3 @@ static int nfsd_file_cache_stats_show(struct seq_file *m, void *v) + seq_printf(m, "pages flushed: %lu\n", pages_flushed); + return 0; + } +- +-int nfsd_file_cache_stats_open(struct inode *inode, struct file *file) +-{ +- return single_open(file, nfsd_file_cache_stats_show, NULL); +-} +diff --git a/fs/nfsd/filecache.h b/fs/nfsd/filecache.h +index 8e8c0c47d67df..357832bac736b 100644 +--- a/fs/nfsd/filecache.h ++++ b/fs/nfsd/filecache.h +@@ -60,5 +60,5 @@ __be32 nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, + unsigned int may_flags, struct nfsd_file **nfp); + __be32 nfsd_file_create(struct svc_rqst *rqstp, struct svc_fh *fhp, + unsigned int may_flags, struct nfsd_file **nfp); +-int nfsd_file_cache_stats_open(struct inode *, struct file *); ++int nfsd_file_cache_stats_show(struct seq_file *m, void *v); + #endif /* _FS_NFSD_FILECACHE_H */ +diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c +index 1983f4f2908d9..6a29bcfc93909 100644 +--- a/fs/nfsd/nfsctl.c ++++ b/fs/nfsd/nfsctl.c +@@ -206,12 +206,7 @@ static const struct file_operations pool_stats_operations = { + + DEFINE_SHOW_ATTRIBUTE(nfsd_reply_cache_stats); + +-static const struct file_operations filecache_ops = { +- .open = nfsd_file_cache_stats_open, +- .read = seq_read, +- .llseek = seq_lseek, +- .release = single_release, +-}; ++DEFINE_SHOW_ATTRIBUTE(nfsd_file_cache_stats); + + /*----------------------------------------------------------------------------*/ + /* +@@ -1355,7 +1350,7 @@ static int nfsd_fill_super(struct super_block *sb, struct fs_context *fc) + [NFSD_Ports] = {"portlist", &transaction_ops, S_IWUSR|S_IRUGO}, + [NFSD_MaxBlkSize] = {"max_block_size", &transaction_ops, S_IWUSR|S_IRUGO}, + [NFSD_MaxConnections] = {"max_connections", &transaction_ops, S_IWUSR|S_IRUGO}, +- [NFSD_Filecache] = {"filecache", &filecache_ops, S_IRUGO}, ++ [NFSD_Filecache] = {"filecache", &nfsd_file_cache_stats_fops, S_IRUGO}, + #if defined(CONFIG_SUNRPC_GSS) || defined(CONFIG_SUNRPC_GSS_MODULE) + [NFSD_SupportedEnctypes] = {"supported_krb5_enctypes", + &supported_enctypes_fops, S_IRUGO}, +-- +2.43.0 + diff --git a/queue-5.10/nfsd-use-define_show_attribute-to-define-nfsd_reply_.patch b/queue-5.10/nfsd-use-define_show_attribute-to-define-nfsd_reply_.patch new file mode 100644 index 00000000000..67a590da973 --- /dev/null +++ b/queue-5.10/nfsd-use-define_show_attribute-to-define-nfsd_reply_.patch @@ -0,0 +1,96 @@ +From a247183e3c1be221d5fa599e4cedb61ba68526e9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 23 Sep 2022 00:31:55 +0800 +Subject: nfsd: use DEFINE_SHOW_ATTRIBUTE to define nfsd_reply_cache_stats_fops + +From: ChenXiaoSong + +[ Upstream commit 64776611a06322b99386f8dfe3b3ba1aa0347a38 ] + +Use DEFINE_SHOW_ATTRIBUTE helper macro to simplify the code. + +nfsd_net is converted from seq_file->file instead of seq_file->private in +nfsd_reply_cache_stats_show(). + +Signed-off-by: ChenXiaoSong +[ cel: reduce line length ] +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/cache.h | 2 +- + fs/nfsd/nfscache.c | 13 +++---------- + fs/nfsd/nfsctl.c | 10 +++------- + 3 files changed, 7 insertions(+), 18 deletions(-) + +diff --git a/fs/nfsd/cache.h b/fs/nfsd/cache.h +index 65c331f75e9c7..f21259ead64bb 100644 +--- a/fs/nfsd/cache.h ++++ b/fs/nfsd/cache.h +@@ -84,6 +84,6 @@ int nfsd_reply_cache_init(struct nfsd_net *); + void nfsd_reply_cache_shutdown(struct nfsd_net *); + int nfsd_cache_lookup(struct svc_rqst *); + void nfsd_cache_update(struct svc_rqst *, int, __be32 *); +-int nfsd_reply_cache_stats_open(struct inode *, struct file *); ++int nfsd_reply_cache_stats_show(struct seq_file *m, void *v); + + #endif /* NFSCACHE_H */ +diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c +index 7da88bdc0d6c3..2b5417e06d80d 100644 +--- a/fs/nfsd/nfscache.c ++++ b/fs/nfsd/nfscache.c +@@ -603,9 +603,10 @@ nfsd_cache_append(struct svc_rqst *rqstp, struct kvec *data) + * scraping this file for info should test the labels to ensure they're + * getting the correct field. + */ +-static int nfsd_reply_cache_stats_show(struct seq_file *m, void *v) ++int nfsd_reply_cache_stats_show(struct seq_file *m, void *v) + { +- struct nfsd_net *nn = m->private; ++ struct nfsd_net *nn = net_generic(file_inode(m->file)->i_sb->s_fs_info, ++ nfsd_net_id); + + seq_printf(m, "max entries: %u\n", nn->max_drc_entries); + seq_printf(m, "num entries: %u\n", +@@ -625,11 +626,3 @@ static int nfsd_reply_cache_stats_show(struct seq_file *m, void *v) + seq_printf(m, "cachesize at longest: %u\n", nn->longest_chain_cachesize); + return 0; + } +- +-int nfsd_reply_cache_stats_open(struct inode *inode, struct file *file) +-{ +- struct nfsd_net *nn = net_generic(file_inode(file)->i_sb->s_fs_info, +- nfsd_net_id); +- +- return single_open(file, nfsd_reply_cache_stats_show, nn); +-} +diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c +index 3ed0cfdb0c0b5..1983f4f2908d9 100644 +--- a/fs/nfsd/nfsctl.c ++++ b/fs/nfsd/nfsctl.c +@@ -204,12 +204,7 @@ static const struct file_operations pool_stats_operations = { + .release = nfsd_pool_stats_release, + }; + +-static const struct file_operations reply_cache_stats_operations = { +- .open = nfsd_reply_cache_stats_open, +- .read = seq_read, +- .llseek = seq_lseek, +- .release = single_release, +-}; ++DEFINE_SHOW_ATTRIBUTE(nfsd_reply_cache_stats); + + static const struct file_operations filecache_ops = { + .open = nfsd_file_cache_stats_open, +@@ -1354,7 +1349,8 @@ static int nfsd_fill_super(struct super_block *sb, struct fs_context *fc) + [NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR}, + [NFSD_Pool_Threads] = {"pool_threads", &transaction_ops, S_IWUSR|S_IRUSR}, + [NFSD_Pool_Stats] = {"pool_stats", &pool_stats_operations, S_IRUGO}, +- [NFSD_Reply_Cache_Stats] = {"reply_cache_stats", &reply_cache_stats_operations, S_IRUGO}, ++ [NFSD_Reply_Cache_Stats] = {"reply_cache_stats", ++ &nfsd_reply_cache_stats_fops, S_IRUGO}, + [NFSD_Versions] = {"versions", &transaction_ops, S_IWUSR|S_IRUSR}, + [NFSD_Ports] = {"portlist", &transaction_ops, S_IWUSR|S_IRUGO}, + [NFSD_MaxBlkSize] = {"max_block_size", &transaction_ops, S_IWUSR|S_IRUGO}, +-- +2.43.0 + diff --git a/queue-5.10/nfsd-use-define_spinlock-for-spinlock.patch b/queue-5.10/nfsd-use-define_spinlock-for-spinlock.patch new file mode 100644 index 00000000000..222e1b2f2c6 --- /dev/null +++ b/queue-5.10/nfsd-use-define_spinlock-for-spinlock.patch @@ -0,0 +1,44 @@ +From 14108aa1f74b80395c047ca3d1964c05e5a2e9dc Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 6 Apr 2021 20:08:18 +0800 +Subject: NFSD: Use DEFINE_SPINLOCK() for spinlock + +From: Guobin Huang + +[ Upstream commit b73ac6808b0f7994a05ebc38571e2e9eaf98a0f4 ] + +spinlock can be initialized automatically with DEFINE_SPINLOCK() +rather than explicitly calling spin_lock_init(). + +Reported-by: Hulk Robot +Signed-off-by: Guobin Huang +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfssvc.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c +index 0666ef4b87b7a..79bc75d415226 100644 +--- a/fs/nfsd/nfssvc.c ++++ b/fs/nfsd/nfssvc.c +@@ -84,7 +84,7 @@ DEFINE_MUTEX(nfsd_mutex); + * version 4.1 DRC caches. + * nfsd_drc_pages_used tracks the current version 4.1 DRC memory usage. + */ +-spinlock_t nfsd_drc_lock; ++DEFINE_SPINLOCK(nfsd_drc_lock); + unsigned long nfsd_drc_max_mem; + unsigned long nfsd_drc_mem_used; + +@@ -563,7 +563,6 @@ static void set_max_drc(void) + nfsd_drc_max_mem = (nr_free_buffer_pages() + >> NFSD_DRC_SIZE_SHIFT) * PAGE_SIZE; + nfsd_drc_mem_used = 0; +- spin_lock_init(&nfsd_drc_lock); + dprintk("%s nfsd_drc_max_mem %lu \n", __func__, nfsd_drc_max_mem); + } + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-use-explicit-lock-unlock-for-directory-ops.patch b/queue-5.10/nfsd-use-explicit-lock-unlock-for-directory-ops.patch new file mode 100644 index 00000000000..889ccc9071b --- /dev/null +++ b/queue-5.10/nfsd-use-explicit-lock-unlock-for-directory-ops.patch @@ -0,0 +1,265 @@ +From 2a3d2dc516ee55effad797ca1c02a8b8e0b4db39 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 Jul 2022 16:45:30 +1000 +Subject: NFSD: use explicit lock/unlock for directory ops + +From: NeilBrown + +[ Upstream commit debf16f0c671cb8db154a9ebcd6014cfff683b80 ] + +When creating or unlinking a name in a directory use explicit +inode_lock_nested() instead of fh_lock(), and explicit calls to +fh_fill_pre_attrs() and fh_fill_post_attrs(). This is already done +for renames, with lock_rename() as the explicit locking. + +Also move the 'fill' calls closer to the operation that might change the +attributes. This way they are avoided on some error paths. + +For the v2-only code in nfsproc.c, the fill calls are not replaced as +they aren't needed. + +Making the locking explicit will simplify proposed future changes to +locking for directories. It also makes it easily visible exactly where +pre/post attributes are used - not all callers of fh_lock() actually +need the pre/post attributes. + +Reviewed-by: Jeff Layton +Signed-off-by: NeilBrown +[ cel: backported to 5.10.y, prior to idmapped mounts ] +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3proc.c | 6 ++++-- + fs/nfsd/nfs4proc.c | 6 ++++-- + fs/nfsd/nfsproc.c | 5 ++--- + fs/nfsd/vfs.c | 36 ++++++++++++++++++++++++++---------- + 4 files changed, 36 insertions(+), 17 deletions(-) + +diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c +index d78dbb214c5c3..1a52f0b06ec32 100644 +--- a/fs/nfsd/nfs3proc.c ++++ b/fs/nfsd/nfs3proc.c +@@ -260,7 +260,7 @@ nfsd3_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp, + if (host_err) + return nfserrno(host_err); + +- fh_lock_nested(fhp, I_MUTEX_PARENT); ++ inode_lock_nested(inode, I_MUTEX_PARENT); + + child = lookup_one_len(argp->name, parent, argp->len); + if (IS_ERR(child)) { +@@ -318,11 +318,13 @@ nfsd3_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp, + if (!IS_POSIXACL(inode)) + iap->ia_mode &= ~current_umask(); + ++ fh_fill_pre_attrs(fhp); + host_err = vfs_create(inode, child, iap->ia_mode, true); + if (host_err < 0) { + status = nfserrno(host_err); + goto out; + } ++ fh_fill_post_attrs(fhp); + + /* A newly created file already has a file size of zero. */ + if ((iap->ia_valid & ATTR_SIZE) && (iap->ia_size == 0)) +@@ -340,7 +342,7 @@ nfsd3_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp, + status = nfsd_create_setattr(rqstp, fhp, resfhp, &attrs); + + out: +- fh_unlock(fhp); ++ inode_unlock(inode); + if (child && !IS_ERR(child)) + dput(child); + fh_drop_write(fhp); +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 9cf4298817c4b..193b84a0f3a59 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -264,7 +264,7 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp, + if (is_create_with_attrs(open)) + nfsd4_acl_to_attr(NF4REG, open->op_acl, &attrs); + +- fh_lock_nested(fhp, I_MUTEX_PARENT); ++ inode_lock_nested(inode, I_MUTEX_PARENT); + + child = lookup_one_len(open->op_fname, parent, open->op_fnamelen); + if (IS_ERR(child)) { +@@ -348,10 +348,12 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp, + if (!IS_POSIXACL(inode)) + iap->ia_mode &= ~current_umask(); + ++ fh_fill_pre_attrs(fhp); + status = nfsd4_vfs_create(fhp, child, open); + if (status != nfs_ok) + goto out; + open->op_created = true; ++ fh_fill_post_attrs(fhp); + + /* A newly created file already has a file size of zero. */ + if ((iap->ia_valid & ATTR_SIZE) && (iap->ia_size == 0)) +@@ -373,7 +375,7 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp, + if (attrs.na_aclerr) + open->op_bmval[0] &= ~FATTR4_WORD0_ACL; + out: +- fh_unlock(fhp); ++ inode_unlock(inode); + nfsd_attrs_free(&attrs); + if (child && !IS_ERR(child)) + dput(child); +diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c +index 180b84b6597b0..e533550a26db5 100644 +--- a/fs/nfsd/nfsproc.c ++++ b/fs/nfsd/nfsproc.c +@@ -291,7 +291,7 @@ nfsd_proc_create(struct svc_rqst *rqstp) + goto done; + } + +- fh_lock_nested(dirfhp, I_MUTEX_PARENT); ++ inode_lock_nested(dirfhp->fh_dentry->d_inode, I_MUTEX_PARENT); + dchild = lookup_one_len(argp->name, dirfhp->fh_dentry, argp->len); + if (IS_ERR(dchild)) { + resp->status = nfserrno(PTR_ERR(dchild)); +@@ -407,8 +407,7 @@ nfsd_proc_create(struct svc_rqst *rqstp) + } + + out_unlock: +- /* We don't really need to unlock, as fh_put does it. */ +- fh_unlock(dirfhp); ++ inode_unlock(dirfhp->fh_dentry->d_inode); + fh_drop_write(dirfhp); + done: + fh_put(dirfhp); +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index 03f6dd2ec653b..3364e562b00e5 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -1386,7 +1386,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, + if (host_err) + return nfserrno(host_err); + +- fh_lock_nested(fhp, I_MUTEX_PARENT); ++ inode_lock_nested(dentry->d_inode, I_MUTEX_PARENT); + dchild = lookup_one_len(fname, dentry, flen); + host_err = PTR_ERR(dchild); + if (IS_ERR(dchild)) { +@@ -1401,10 +1401,12 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, + dput(dchild); + if (err) + goto out_unlock; ++ fh_fill_pre_attrs(fhp); + err = nfsd_create_locked(rqstp, fhp, fname, flen, attrs, type, + rdev, resfhp); ++ fh_fill_post_attrs(fhp); + out_unlock: +- fh_unlock(fhp); ++ inode_unlock(dentry->d_inode); + return err; + } + +@@ -1487,20 +1489,22 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, + goto out; + } + +- fh_lock(fhp); + dentry = fhp->fh_dentry; ++ inode_lock_nested(dentry->d_inode, I_MUTEX_PARENT); + dnew = lookup_one_len(fname, dentry, flen); + if (IS_ERR(dnew)) { + err = nfserrno(PTR_ERR(dnew)); +- fh_unlock(fhp); ++ inode_unlock(dentry->d_inode); + goto out_drop_write; + } ++ fh_fill_pre_attrs(fhp); + host_err = vfs_symlink(d_inode(dentry), dnew, path); + err = nfserrno(host_err); + cerr = fh_compose(resfhp, fhp->fh_export, dnew, fhp); + if (!err) + nfsd_create_setattr(rqstp, fhp, resfhp, attrs); +- fh_unlock(fhp); ++ fh_fill_post_attrs(fhp); ++ inode_unlock(dentry->d_inode); + if (!err) + err = nfserrno(commit_metadata(fhp)); + dput(dnew); +@@ -1546,9 +1550,9 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, + goto out; + } + +- fh_lock_nested(ffhp, I_MUTEX_PARENT); + ddir = ffhp->fh_dentry; + dirp = d_inode(ddir); ++ inode_lock_nested(dirp, I_MUTEX_PARENT); + + dnew = lookup_one_len(name, ddir, len); + if (IS_ERR(dnew)) { +@@ -1561,8 +1565,18 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, + err = nfserr_noent; + if (d_really_is_negative(dold)) + goto out_dput; ++<<<<<<< current + host_err = vfs_link(dold, dirp, dnew, NULL); + fh_unlock(ffhp); ++||||||| constructed merge base ++ host_err = vfs_link(dold, &init_user_ns, dirp, dnew, NULL); ++ fh_unlock(ffhp); ++======= ++ fh_fill_pre_attrs(ffhp); ++ host_err = vfs_link(dold, &init_user_ns, dirp, dnew, NULL); ++ fh_fill_post_attrs(ffhp); ++ inode_unlock(dirp); ++>>>>>>> patched + if (!host_err) { + err = nfserrno(commit_metadata(ffhp)); + if (!err) +@@ -1582,7 +1596,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, + out_dput: + dput(dnew); + out_unlock: +- fh_unlock(ffhp); ++ inode_unlock(dirp); + goto out_drop_write; + } + +@@ -1755,9 +1769,9 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, + if (host_err) + goto out_nfserr; + +- fh_lock_nested(fhp, I_MUTEX_PARENT); + dentry = fhp->fh_dentry; + dirp = d_inode(dentry); ++ inode_lock_nested(dirp, I_MUTEX_PARENT); + + rdentry = lookup_one_len(fname, dentry, flen); + host_err = PTR_ERR(rdentry); +@@ -1775,6 +1789,7 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, + if (!type) + type = d_inode(rdentry)->i_mode & S_IFMT; + ++ fh_fill_pre_attrs(fhp); + if (type != S_IFDIR) { + if (rdentry->d_sb->s_export_op->flags & EXPORT_OP_CLOSE_BEFORE_UNLINK) + nfsd_close_cached_files(rdentry); +@@ -1782,8 +1797,9 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, + } else { + host_err = vfs_rmdir(dirp, rdentry); + } ++ fh_fill_post_attrs(fhp); + +- fh_unlock(fhp); ++ inode_unlock(dirp); + if (!host_err) + host_err = commit_metadata(fhp); + dput(rdentry); +@@ -1806,7 +1822,7 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, + out: + return err; + out_unlock: +- fh_unlock(fhp); ++ inode_unlock(dirp); + goto out_drop_write; + } + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-use-fsnotify-group-lock-helpers.patch b/queue-5.10/nfsd-use-fsnotify-group-lock-helpers.patch new file mode 100644 index 00000000000..09255074c22 --- /dev/null +++ b/queue-5.10/nfsd-use-fsnotify-group-lock-helpers.patch @@ -0,0 +1,75 @@ +From 33f915cd1085aa1e7cd70547ceac9f84db96e053 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 Apr 2022 15:03:20 +0300 +Subject: nfsd: use fsnotify group lock helpers + +From: Amir Goldstein + +[ Upstream commit b8962a9d8cc2d8c93362e2f684091c79f702f6f3 ] + +Before commit 9542e6a643fc6 ("nfsd: Containerise filecache laundrette") +nfsd would close open files in direct reclaim context and that could +cause a deadlock when fsnotify mark allocation went into direct reclaim +and nfsd shrinker tried to free existing fsnotify marks. + +To avoid issues like this in future code, set the FSNOTIFY_GROUP_NOFS +flag on nfsd fsnotify group to prevent going into direct reclaim from +fsnotify_add_inode_mark(). + +Link: https://lore.kernel.org/r/20220422120327.3459282-10-amir73il@gmail.com +Suggested-by: Jan Kara +Link: https://lore.kernel.org/r/20220321112310.vpr7oxro2xkz5llh@quack3.lan/ +Signed-off-by: Amir Goldstein +Signed-off-by: Jan Kara +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 13 +++++++------ + 1 file changed, 7 insertions(+), 6 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index 7ae2b6611fb29..7e99e75b75d73 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -118,14 +118,14 @@ nfsd_file_mark_find_or_create(struct nfsd_file *nf) + struct inode *inode = nf->nf_inode; + + do { +- mutex_lock(&nfsd_file_fsnotify_group->mark_mutex); ++ fsnotify_group_lock(nfsd_file_fsnotify_group); + mark = fsnotify_find_mark(&inode->i_fsnotify_marks, +- nfsd_file_fsnotify_group); ++ nfsd_file_fsnotify_group); + if (mark) { + nfm = nfsd_file_mark_get(container_of(mark, + struct nfsd_file_mark, + nfm_mark)); +- mutex_unlock(&nfsd_file_fsnotify_group->mark_mutex); ++ fsnotify_group_unlock(nfsd_file_fsnotify_group); + if (nfm) { + fsnotify_put_mark(mark); + break; +@@ -133,8 +133,9 @@ nfsd_file_mark_find_or_create(struct nfsd_file *nf) + /* Avoid soft lockup race with nfsd_file_mark_put() */ + fsnotify_destroy_mark(mark, nfsd_file_fsnotify_group); + fsnotify_put_mark(mark); +- } else +- mutex_unlock(&nfsd_file_fsnotify_group->mark_mutex); ++ } else { ++ fsnotify_group_unlock(nfsd_file_fsnotify_group); ++ } + + /* allocate a new nfm */ + new = kmem_cache_alloc(nfsd_file_mark_slab, GFP_KERNEL); +@@ -678,7 +679,7 @@ nfsd_file_cache_init(void) + } + + nfsd_file_fsnotify_group = fsnotify_alloc_group(&nfsd_file_fsnotify_ops, +- 0); ++ FSNOTIFY_GROUP_NOFS); + if (IS_ERR(nfsd_file_fsnotify_group)) { + pr_err("nfsd: unable to create fsnotify group: %ld\n", + PTR_ERR(nfsd_file_fsnotify_group)); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-use-locks_inode_context-helper.patch b/queue-5.10/nfsd-use-locks_inode_context-helper.patch new file mode 100644 index 00000000000..1ff671e1de0 --- /dev/null +++ b/queue-5.10/nfsd-use-locks_inode_context-helper.patch @@ -0,0 +1,56 @@ +From 2af362ef864c9c8f36a491676fbe70cd0e507613 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 16 Nov 2022 09:36:07 -0500 +Subject: nfsd: use locks_inode_context helper + +From: Jeff Layton + +[ Upstream commit 77c67530e1f95ac25c7075635f32f04367380894 ] + +nfsd currently doesn't access i_flctx safely everywhere. This requires a +smp_load_acquire, as the pointer is set via cmpxchg (a release +operation). + +Acked-by: Chuck Lever +Reviewed-by: Christoph Hellwig +Signed-off-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 10915c72c7815..2d09977fee83d 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -4773,7 +4773,7 @@ nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type) + + static bool nfsd4_deleg_present(const struct inode *inode) + { +- struct file_lock_context *ctx = smp_load_acquire(&inode->i_flctx); ++ struct file_lock_context *ctx = locks_inode_context(inode); + + return ctx && !list_empty_careful(&ctx->flc_lease); + } +@@ -5912,7 +5912,7 @@ nfs4_lockowner_has_blockers(struct nfs4_lockowner *lo) + + list_for_each_entry(stp, &lo->lo_owner.so_stateids, st_perstateowner) { + nf = stp->st_stid.sc_file; +- ctx = nf->fi_inode->i_flctx; ++ ctx = locks_inode_context(nf->fi_inode); + if (!ctx) + continue; + if (locks_owner_has_blockers(ctx, lo)) +@@ -7740,7 +7740,7 @@ check_for_locks(struct nfs4_file *fp, struct nfs4_lockowner *lowner) + } + + inode = locks_inode(nf->nf_file); +- flctx = inode->i_flctx; ++ flctx = locks_inode_context(inode); + + if (flctx && !list_empty_careful(&flctx->flc_posix)) { + spin_lock(&flctx->flc_lock); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-use-only-rq_dropme-to-signal-the-need-to-drop-a.patch b/queue-5.10/nfsd-use-only-rq_dropme-to-signal-the-need-to-drop-a.patch new file mode 100644 index 00000000000..dd4440131e9 --- /dev/null +++ b/queue-5.10/nfsd-use-only-rq_dropme-to-signal-the-need-to-drop-a.patch @@ -0,0 +1,61 @@ +From 3bf11469b5b12e76bcd43aca1897cf24acfe92cd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 26 Nov 2022 15:55:30 -0500 +Subject: NFSD: Use only RQ_DROPME to signal the need to drop a reply + +From: Chuck Lever + +[ Upstream commit 9315564747cb6a570e99196b3a4880fb817635fd ] + +Clean up: NFSv2 has the only two usages of rpc_drop_reply in the +NFSD code base. Since NFSv2 is going away at some point, replace +these in order to simplify the "drop this reply?" check in +nfsd_dispatch(). + +Signed-off-by: Chuck Lever +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsproc.c | 4 ++-- + fs/nfsd/nfssvc.c | 2 +- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c +index 3777b5be4253a..c32a871f0e275 100644 +--- a/fs/nfsd/nfsproc.c ++++ b/fs/nfsd/nfsproc.c +@@ -211,7 +211,7 @@ nfsd_proc_read(struct svc_rqst *rqstp) + if (resp->status == nfs_ok) + resp->status = fh_getattr(&resp->fh, &resp->stat); + else if (resp->status == nfserr_jukebox) +- return rpc_drop_reply; ++ __set_bit(RQ_DROPME, &rqstp->rq_flags); + return rpc_success; + } + +@@ -246,7 +246,7 @@ nfsd_proc_write(struct svc_rqst *rqstp) + if (resp->status == nfs_ok) + resp->status = fh_getattr(&resp->fh, &resp->stat); + else if (resp->status == nfserr_jukebox) +- return rpc_drop_reply; ++ __set_bit(RQ_DROPME, &rqstp->rq_flags); + return rpc_success; + } + +diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c +index 429f38c986280..325d3d3f12110 100644 +--- a/fs/nfsd/nfssvc.c ++++ b/fs/nfsd/nfssvc.c +@@ -1060,7 +1060,7 @@ int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) + svcxdr_init_encode(rqstp); + + *statp = proc->pc_func(rqstp); +- if (*statp == rpc_drop_reply || test_bit(RQ_DROPME, &rqstp->rq_flags)) ++ if (test_bit(RQ_DROPME, &rqstp->rq_flags)) + goto out_update_drop; + + if (!proc->pc_encode(rqstp, &rqstp->rq_res_stream)) +-- +2.43.0 + diff --git a/queue-5.10/nfsd-use-rhashtable-for-managing-nfs4_file-objects.patch b/queue-5.10/nfsd-use-rhashtable-for-managing-nfs4_file-objects.patch new file mode 100644 index 00000000000..c31c500378a --- /dev/null +++ b/queue-5.10/nfsd-use-rhashtable-for-managing-nfs4_file-objects.patch @@ -0,0 +1,251 @@ +From 2b627d255f5dd840c7a2d0bfe96bfbcf078c14f9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 28 Oct 2022 10:47:53 -0400 +Subject: NFSD: Use rhashtable for managing nfs4_file objects + +From: Chuck Lever + +[ Upstream commit d47b295e8d76a4d69f0e2ea0cd8a79c9d3488280 ] + +fh_match() is costly, especially when filehandles are large (as is +the case for NFSv4). It needs to be used sparingly when searching +data structures. Unfortunately, with common workloads, I see +multiple thousands of objects stored in file_hashtbl[], which has +just 256 buckets, making its bucket hash chains quite lengthy. + +Walking long hash chains with the state_lock held blocks other +activity that needs that lock. Sizable hash chains are a common +occurrance once the server has handed out some delegations, for +example -- IIUC, each delegated file is held open on the server by +an nfs4_file object. + +To help mitigate the cost of searching with fh_match(), replace the +nfs4_file hash table with an rhashtable, which can dynamically +resize its bucket array to minimize hash chain length. + +The result of this modification is an improvement in the latency of +NFSv4 operations, and the reduction of nfsd CPU utilization due to +eliminating the cost of multiple calls to fh_match() and reducing +the CPU cache misses incurred while walking long hash chains in the +nfs4_file hash table. + +Signed-off-by: Chuck Lever +Reviewed-by: NeilBrown +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 97 +++++++++++++++++++++++++++++---------------- + fs/nfsd/state.h | 5 +-- + 2 files changed, 63 insertions(+), 39 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 69329dc159f64..d490b19d95ddf 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -44,7 +44,9 @@ + #include + #include + #include ++#include + #include ++ + #include "xdr4.h" + #include "xdr4cb.h" + #include "vfs.h" +@@ -589,11 +591,8 @@ static void nfsd4_free_file_rcu(struct rcu_head *rcu) + void + put_nfs4_file(struct nfs4_file *fi) + { +- might_lock(&state_lock); +- +- if (refcount_dec_and_lock(&fi->fi_ref, &state_lock)) { ++ if (refcount_dec_and_test(&fi->fi_ref)) { + nfsd4_file_hash_remove(fi); +- spin_unlock(&state_lock); + WARN_ON_ONCE(!list_empty(&fi->fi_clnt_odstate)); + WARN_ON_ONCE(!list_empty(&fi->fi_delegations)); + call_rcu(&fi->fi_rcu, nfsd4_free_file_rcu); +@@ -718,19 +717,20 @@ static unsigned int ownerstr_hashval(struct xdr_netobj *ownername) + return ret & OWNER_HASH_MASK; + } + +-/* hash table for nfs4_file */ +-#define FILE_HASH_BITS 8 +-#define FILE_HASH_SIZE (1 << FILE_HASH_BITS) +- +-static unsigned int file_hashval(const struct svc_fh *fh) +-{ +- struct inode *inode = d_inode(fh->fh_dentry); ++static struct rhltable nfs4_file_rhltable ____cacheline_aligned_in_smp; + +- /* XXX: why not (here & in file cache) use inode? */ +- return (unsigned int)hash_long(inode->i_ino, FILE_HASH_BITS); +-} ++static const struct rhashtable_params nfs4_file_rhash_params = { ++ .key_len = sizeof_field(struct nfs4_file, fi_inode), ++ .key_offset = offsetof(struct nfs4_file, fi_inode), ++ .head_offset = offsetof(struct nfs4_file, fi_rlist), + +-static struct hlist_head file_hashtbl[FILE_HASH_SIZE]; ++ /* ++ * Start with a single page hash table to reduce resizing churn ++ * on light workloads. ++ */ ++ .min_size = 256, ++ .automatic_shrinking = true, ++}; + + /* + * Check if courtesy clients have conflicting access and resolve it if possible +@@ -4685,12 +4685,14 @@ move_to_close_lru(struct nfs4_ol_stateid *s, struct net *net) + static noinline_for_stack struct nfs4_file * + nfsd4_file_hash_lookup(const struct svc_fh *fhp) + { +- unsigned int hashval = file_hashval(fhp); ++ struct inode *inode = d_inode(fhp->fh_dentry); ++ struct rhlist_head *tmp, *list; + struct nfs4_file *fi; + + rcu_read_lock(); +- hlist_for_each_entry_rcu(fi, &file_hashtbl[hashval], fi_hash, +- lockdep_is_held(&state_lock)) { ++ list = rhltable_lookup(&nfs4_file_rhltable, &inode, ++ nfs4_file_rhash_params); ++ rhl_for_each_entry_rcu(fi, tmp, list, fi_rlist) { + if (fh_match(&fi->fi_fhandle, &fhp->fh_handle)) { + if (refcount_inc_not_zero(&fi->fi_ref)) { + rcu_read_unlock(); +@@ -4704,40 +4706,56 @@ nfsd4_file_hash_lookup(const struct svc_fh *fhp) + + /* + * On hash insertion, identify entries with the same inode but +- * distinct filehandles. They will all be in the same hash bucket +- * because nfs4_file's are hashed by the address in the fi_inode +- * field. ++ * distinct filehandles. They will all be on the list returned ++ * by rhltable_lookup(). ++ * ++ * inode->i_lock prevents racing insertions from adding an entry ++ * for the same inode/fhp pair twice. + */ + static noinline_for_stack struct nfs4_file * + nfsd4_file_hash_insert(struct nfs4_file *new, const struct svc_fh *fhp) + { +- unsigned int hashval = file_hashval(fhp); ++ struct inode *inode = d_inode(fhp->fh_dentry); ++ struct rhlist_head *tmp, *list; + struct nfs4_file *ret = NULL; + bool alias_found = false; + struct nfs4_file *fi; ++ int err; + +- spin_lock(&state_lock); +- hlist_for_each_entry_rcu(fi, &file_hashtbl[hashval], fi_hash, +- lockdep_is_held(&state_lock)) { ++ rcu_read_lock(); ++ spin_lock(&inode->i_lock); ++ ++ list = rhltable_lookup(&nfs4_file_rhltable, &inode, ++ nfs4_file_rhash_params); ++ rhl_for_each_entry_rcu(fi, tmp, list, fi_rlist) { + if (fh_match(&fi->fi_fhandle, &fhp->fh_handle)) { + if (refcount_inc_not_zero(&fi->fi_ref)) + ret = fi; +- } else if (d_inode(fhp->fh_dentry) == fi->fi_inode) ++ } else + fi->fi_aliased = alias_found = true; + } +- if (likely(ret == NULL)) { +- nfsd4_file_init(fhp, new); +- hlist_add_head_rcu(&new->fi_hash, &file_hashtbl[hashval]); +- new->fi_aliased = alias_found; +- ret = new; +- } +- spin_unlock(&state_lock); ++ if (ret) ++ goto out_unlock; ++ ++ nfsd4_file_init(fhp, new); ++ err = rhltable_insert(&nfs4_file_rhltable, &new->fi_rlist, ++ nfs4_file_rhash_params); ++ if (err) ++ goto out_unlock; ++ ++ new->fi_aliased = alias_found; ++ ret = new; ++ ++out_unlock: ++ spin_unlock(&inode->i_lock); ++ rcu_read_unlock(); + return ret; + } + + static noinline_for_stack void nfsd4_file_hash_remove(struct nfs4_file *fi) + { +- hlist_del_rcu(&fi->fi_hash); ++ rhltable_remove(&nfs4_file_rhltable, &fi->fi_rlist, ++ nfs4_file_rhash_params); + } + + /* +@@ -5628,6 +5646,8 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf + * If not found, create the nfs4_file struct + */ + fp = nfsd4_file_hash_insert(open->op_file, current_fh); ++ if (unlikely(!fp)) ++ return nfserr_jukebox; + if (fp != open->op_file) { + status = nfs4_check_deleg(cl, open, &dp); + if (status) +@@ -8054,10 +8074,16 @@ nfs4_state_start(void) + { + int ret; + +- ret = nfsd4_create_callback_queue(); ++ ret = rhltable_init(&nfs4_file_rhltable, &nfs4_file_rhash_params); + if (ret) + return ret; + ++ ret = nfsd4_create_callback_queue(); ++ if (ret) { ++ rhltable_destroy(&nfs4_file_rhltable); ++ return ret; ++ } ++ + set_max_delegations(); + return 0; + } +@@ -8088,6 +8114,7 @@ nfs4_state_shutdown_net(struct net *net) + + nfsd4_client_tracking_exit(net); + nfs4_state_destroy_net(net); ++ rhltable_destroy(&nfs4_file_rhltable); + #ifdef CONFIG_NFSD_V4_2_INTER_SSC + nfsd4_ssc_shutdown_umount(nn); + #endif +diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h +index e2daef3cc0034..eadd7f465bf52 100644 +--- a/fs/nfsd/state.h ++++ b/fs/nfsd/state.h +@@ -536,16 +536,13 @@ struct nfs4_clnt_odstate { + * inode can have multiple filehandles associated with it, so there is + * (potentially) a many to one relationship between this struct and struct + * inode. +- * +- * These are hashed by filehandle in the file_hashtbl, which is protected by +- * the global state_lock spinlock. + */ + struct nfs4_file { + refcount_t fi_ref; + struct inode * fi_inode; + bool fi_aliased; + spinlock_t fi_lock; +- struct hlist_node fi_hash; /* hash on fi_fhandle */ ++ struct rhlist_head fi_rlist; + struct list_head fi_stateids; + union { + struct list_head fi_delegations; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-use-set_bit-rq_dropme.patch b/queue-5.10/nfsd-use-set_bit-rq_dropme.patch new file mode 100644 index 00000000000..e75d2f2c70b --- /dev/null +++ b/queue-5.10/nfsd-use-set_bit-rq_dropme.patch @@ -0,0 +1,46 @@ +From 40b5fa7158ac54c920f8b3ff31bc1389140a2b8c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 7 Jan 2023 10:15:35 -0500 +Subject: NFSD: Use set_bit(RQ_DROPME) + +From: Chuck Lever + +[ Upstream commit 5304930dbae82d259bcf7e5611db7c81e7a42eff ] + +The premise that "Once an svc thread is scheduled and executing an +RPC, no other processes will touch svc_rqst::rq_flags" is false. +svc_xprt_enqueue() examines the RQ_BUSY flag in scheduled nfsd +threads when determining which thread to wake up next. + +Fixes: 9315564747cb ("NFSD: Use only RQ_DROPME to signal the need to drop a reply") +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsproc.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c +index c32a871f0e275..96426dea7d412 100644 +--- a/fs/nfsd/nfsproc.c ++++ b/fs/nfsd/nfsproc.c +@@ -211,7 +211,7 @@ nfsd_proc_read(struct svc_rqst *rqstp) + if (resp->status == nfs_ok) + resp->status = fh_getattr(&resp->fh, &resp->stat); + else if (resp->status == nfserr_jukebox) +- __set_bit(RQ_DROPME, &rqstp->rq_flags); ++ set_bit(RQ_DROPME, &rqstp->rq_flags); + return rpc_success; + } + +@@ -246,7 +246,7 @@ nfsd_proc_write(struct svc_rqst *rqstp) + if (resp->status == nfs_ok) + resp->status = fh_getattr(&resp->fh, &resp->stat); + else if (resp->status == nfserr_jukebox) +- __set_bit(RQ_DROPME, &rqstp->rq_flags); ++ set_bit(RQ_DROPME, &rqstp->rq_flags); + return rpc_success; + } + +-- +2.43.0 + diff --git a/queue-5.10/nfsd-use-struct_size-helper-in-alloc_session.patch b/queue-5.10/nfsd-use-struct_size-helper-in-alloc_session.patch new file mode 100644 index 00000000000..31c802140a3 --- /dev/null +++ b/queue-5.10/nfsd-use-struct_size-helper-in-alloc_session.patch @@ -0,0 +1,44 @@ +From 455ab4a9b59aa8b9119105788eca592d927ecf29 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 11 Nov 2022 17:18:35 +0800 +Subject: NFSD: Use struct_size() helper in alloc_session() + +From: Xiu Jianfeng + +[ Upstream commit 85a0d0c9a58002ef7d1bf5e3ea630f4fbd42a4f0 ] + +Use struct_size() helper to simplify the code, no functional changes. + +Signed-off-by: Xiu Jianfeng +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index d490b19d95ddf..9a8038bfaa0d5 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -1833,13 +1833,12 @@ static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fattrs, + int numslots = fattrs->maxreqs; + int slotsize = slot_bytes(fattrs); + struct nfsd4_session *new; +- int mem, i; ++ int i; + +- BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot *) +- + sizeof(struct nfsd4_session) > PAGE_SIZE); +- mem = numslots * sizeof(struct nfsd4_slot *); ++ BUILD_BUG_ON(struct_size(new, se_slots, NFSD_MAX_SLOTS_PER_SESSION) ++ > PAGE_SIZE); + +- new = kzalloc(sizeof(*new) + mem, GFP_KERNEL); ++ new = kzalloc(struct_size(new, se_slots, numslots), GFP_KERNEL); + if (!new) + return NULL; + /* allocate each struct nfsd4_slot and data cache in one piece */ +-- +2.43.0 + diff --git a/queue-5.10/nfsd-use-un-lock_inode-instead-of-fh_-un-lock-for-fi.patch b/queue-5.10/nfsd-use-un-lock_inode-instead-of-fh_-un-lock-for-fi.patch new file mode 100644 index 00000000000..bc22feb0669 --- /dev/null +++ b/queue-5.10/nfsd-use-un-lock_inode-instead-of-fh_-un-lock-for-fi.patch @@ -0,0 +1,217 @@ +From ae7ef280f6256835c8294940638a56a0200b7ee8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 Jul 2022 16:45:30 +1000 +Subject: NFSD: use (un)lock_inode instead of fh_(un)lock for file operations + +From: NeilBrown + +[ Upstream commit bb4d53d66e4b8c8b8e5634802262e53851a2d2db ] + +When locking a file to access ACLs and xattrs etc, use explicit locking +with inode_lock() instead of fh_lock(). This means that the calls to +fh_fill_pre/post_attr() are also explicit which improves readability and +allows us to place them only where they are needed. Only the xattr +calls need pre/post information. + +When locking a file we don't need I_MUTEX_PARENT as the file is not a +parent of anything, so we can use inode_lock() directly rather than the +inode_lock_nested() call that fh_lock() uses. + +Reviewed-by: Jeff Layton +Signed-off-by: NeilBrown +[ cel: backported to 5.10.y, prior to idmapped mounts ] +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs2acl.c | 6 +++--- + fs/nfsd/nfs3acl.c | 4 ++-- + fs/nfsd/nfs4state.c | 9 +++++---- + fs/nfsd/vfs.c | 44 +++++++++++++++++++++----------------------- + 4 files changed, 31 insertions(+), 32 deletions(-) + +diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c +index 03703b22c81ef..f7d166f056afa 100644 +--- a/fs/nfsd/nfs2acl.c ++++ b/fs/nfsd/nfs2acl.c +@@ -111,7 +111,7 @@ static __be32 nfsacld_proc_setacl(struct svc_rqst *rqstp) + if (error) + goto out_errno; + +- fh_lock(fh); ++ inode_lock(inode); + + error = set_posix_acl(inode, ACL_TYPE_ACCESS, argp->acl_access); + if (error) +@@ -120,7 +120,7 @@ static __be32 nfsacld_proc_setacl(struct svc_rqst *rqstp) + if (error) + goto out_drop_lock; + +- fh_unlock(fh); ++ inode_unlock(inode); + + fh_drop_write(fh); + +@@ -134,7 +134,7 @@ static __be32 nfsacld_proc_setacl(struct svc_rqst *rqstp) + return rpc_success; + + out_drop_lock: +- fh_unlock(fh); ++ inode_unlock(inode); + fh_drop_write(fh); + out_errno: + resp->status = nfserrno(error); +diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c +index 350fae92ae045..15bee0339c764 100644 +--- a/fs/nfsd/nfs3acl.c ++++ b/fs/nfsd/nfs3acl.c +@@ -101,7 +101,7 @@ static __be32 nfsd3_proc_setacl(struct svc_rqst *rqstp) + if (error) + goto out_errno; + +- fh_lock(fh); ++ inode_lock(inode); + + error = set_posix_acl(inode, ACL_TYPE_ACCESS, argp->acl_access); + if (error) +@@ -109,7 +109,7 @@ static __be32 nfsd3_proc_setacl(struct svc_rqst *rqstp) + error = set_posix_acl(inode, ACL_TYPE_DEFAULT, argp->acl_default); + + out_drop_lock: +- fh_unlock(fh); ++ inode_unlock(inode); + fh_drop_write(fh); + out_errno: + resp->status = nfserrno(error); +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index e44d9c8d5065a..7a4baa41b5362 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -7429,21 +7429,22 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + static __be32 nfsd_test_lock(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file_lock *lock) + { + struct nfsd_file *nf; ++ struct inode *inode; + __be32 err; + + err = nfsd_file_acquire(rqstp, fhp, NFSD_MAY_READ, &nf); + if (err) + return err; +- fh_lock(fhp); /* to block new leases till after test_lock: */ +- err = nfserrno(nfsd_open_break_lease(fhp->fh_dentry->d_inode, +- NFSD_MAY_READ)); ++ inode = fhp->fh_dentry->d_inode; ++ inode_lock(inode); /* to block new leases till after test_lock: */ ++ err = nfserrno(nfsd_open_break_lease(inode, NFSD_MAY_READ)); + if (err) + goto out; + lock->fl_file = nf->nf_file; + err = nfserrno(vfs_test_lock(nf->nf_file, lock)); + lock->fl_file = NULL; + out: +- fh_unlock(fhp); ++ inode_unlock(inode); + nfsd_file_put(nf); + return err; + } +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index 3364e562b00e5..504a3ddfaf75b 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -429,7 +429,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, + return err; + } + +- fh_lock(fhp); ++ inode_lock(inode); + if (size_change) { + /* + * RFC5661, Section 18.30.4: +@@ -475,7 +475,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, + !attr->na_aclerr && attr->na_dpacl && S_ISDIR(inode->i_mode)) + attr->na_aclerr = set_posix_acl(inode, ACL_TYPE_DEFAULT, + attr->na_dpacl); +- fh_unlock(fhp); ++ inode_unlock(inode); + if (size_change) + put_write_access(inode); + out: +@@ -1565,18 +1565,10 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, + err = nfserr_noent; + if (d_really_is_negative(dold)) + goto out_dput; +-<<<<<<< current +- host_err = vfs_link(dold, dirp, dnew, NULL); +- fh_unlock(ffhp); +-||||||| constructed merge base +- host_err = vfs_link(dold, &init_user_ns, dirp, dnew, NULL); +- fh_unlock(ffhp); +-======= + fh_fill_pre_attrs(ffhp); +- host_err = vfs_link(dold, &init_user_ns, dirp, dnew, NULL); ++ host_err = vfs_link(dold, dirp, dnew, NULL); + fh_fill_post_attrs(ffhp); + inode_unlock(dirp); +->>>>>>> patched + if (!host_err) { + err = nfserrno(commit_metadata(ffhp)); + if (!err) +@@ -2177,13 +2169,16 @@ nfsd_listxattr(struct svc_rqst *rqstp, struct svc_fh *fhp, char **bufp, + return err; + } + +-/* +- * Removexattr and setxattr need to call fh_lock to both lock the inode +- * and set the change attribute. Since the top-level vfs_removexattr +- * and vfs_setxattr calls already do their own inode_lock calls, call +- * the _locked variant. Pass in a NULL pointer for delegated_inode, +- * and let the client deal with NFS4ERR_DELAY (same as with e.g. +- * setattr and remove). ++/** ++ * nfsd_removexattr - Remove an extended attribute ++ * @rqstp: RPC transaction being executed ++ * @fhp: NFS filehandle of object with xattr to remove ++ * @name: name of xattr to remove (NUL-terminate) ++ * ++ * Pass in a NULL pointer for delegated_inode, and let the client deal ++ * with NFS4ERR_DELAY (same as with e.g. setattr and remove). ++ * ++ * Returns nfs_ok on success, or an nfsstat in network byte order. + */ + __be32 + nfsd_removexattr(struct svc_rqst *rqstp, struct svc_fh *fhp, char *name) +@@ -2199,11 +2194,13 @@ nfsd_removexattr(struct svc_rqst *rqstp, struct svc_fh *fhp, char *name) + if (ret) + return nfserrno(ret); + +- fh_lock(fhp); ++ inode_lock(fhp->fh_dentry->d_inode); ++ fh_fill_pre_attrs(fhp); + + ret = __vfs_removexattr_locked(fhp->fh_dentry, name, NULL); + +- fh_unlock(fhp); ++ fh_fill_post_attrs(fhp); ++ inode_unlock(fhp->fh_dentry->d_inode); + fh_drop_write(fhp); + + return nfsd_xattr_errno(ret); +@@ -2223,12 +2220,13 @@ nfsd_setxattr(struct svc_rqst *rqstp, struct svc_fh *fhp, char *name, + ret = fh_want_write(fhp); + if (ret) + return nfserrno(ret); +- fh_lock(fhp); ++ inode_lock(fhp->fh_dentry->d_inode); ++ fh_fill_pre_attrs(fhp); + + ret = __vfs_setxattr_locked(fhp->fh_dentry, name, buf, len, flags, + NULL); +- +- fh_unlock(fhp); ++ fh_fill_post_attrs(fhp); ++ inode_unlock(fhp->fh_dentry->d_inode); + fh_drop_write(fhp); + + return nfsd_xattr_errno(ret); +-- +2.43.0 + diff --git a/queue-5.10/nfsd-use-xdr_inline_decode-to-decode-nfsv3-symlinks.patch b/queue-5.10/nfsd-use-xdr_inline_decode-to-decode-nfsv3-symlinks.patch new file mode 100644 index 00000000000..164cce6ce11 --- /dev/null +++ b/queue-5.10/nfsd-use-xdr_inline_decode-to-decode-nfsv3-symlinks.patch @@ -0,0 +1,57 @@ +From 3f313123b6b5256edab59005e5fe3c8e2c07cff6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Sep 2022 17:23:02 -0400 +Subject: NFSD: Use xdr_inline_decode() to decode NFSv3 symlinks + +From: Chuck Lever + +[ Upstream commit c3d2a04f05c590303c125a176e6e43df4a436fdb ] + +Replace the check for buffer over/underflow with a helper that is +commonly used for this purpose. The helper also sets xdr->nwords +correctly after successfully linearizing the symlink argument into +the stream's scratch buffer. + +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3xdr.c | 14 +++----------- + 1 file changed, 3 insertions(+), 11 deletions(-) + +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index 0293b8d65f10f..71e32cf288854 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -616,8 +616,6 @@ nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd3_symlinkargs *args = rqstp->rq_argp; + struct kvec *head = rqstp->rq_arg.head; +- struct kvec *tail = rqstp->rq_arg.tail; +- size_t remaining; + + if (!svcxdr_decode_diropargs3(xdr, &args->ffh, &args->fname, &args->flen)) + return false; +@@ -626,16 +624,10 @@ nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + if (xdr_stream_decode_u32(xdr, &args->tlen) < 0) + return false; + +- /* request sanity */ +- remaining = head->iov_len + rqstp->rq_arg.page_len + tail->iov_len; +- remaining -= xdr_stream_pos(xdr); +- if (remaining < xdr_align_size(args->tlen)) +- return false; +- +- args->first.iov_base = xdr->p; ++ /* symlink_data */ + args->first.iov_len = head->iov_len - xdr_stream_pos(xdr); +- +- return true; ++ args->first.iov_base = xdr_inline_decode(xdr, args->tlen); ++ return args->first.iov_base != NULL; + } + + bool +-- +2.43.0 + diff --git a/queue-5.10/nfsd-use-xdr_pad_size.patch b/queue-5.10/nfsd-use-xdr_pad_size.patch new file mode 100644 index 00000000000..8373285a017 --- /dev/null +++ b/queue-5.10/nfsd-use-xdr_pad_size.patch @@ -0,0 +1,52 @@ +From d0c05cdea771c6f856f8ba36d0fb100530f06635 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 22 Jul 2022 16:09:16 -0400 +Subject: NFSD: Use xdr_pad_size() + +From: Chuck Lever + +[ Upstream commit 5e64d85c7d0c59cfcd61d899720b8ccfe895d743 ] + +Clean up: Use a helper instead of open-coding the calculation of +the XDR pad size. + +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 11 ++++------- + 1 file changed, 4 insertions(+), 7 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index f67a54f7eb13e..4d74eb1fee8f1 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -3951,9 +3951,8 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp, + { + struct xdr_stream *xdr = resp->xdr; + unsigned int starting_len = xdr->buf->len; ++ __be32 zero = xdr_zero; + __be32 nfserr; +- __be32 tmp; +- int pad; + + read->rd_vlen = xdr_reserve_space_vec(xdr, resp->rqstp->rq_vec, maxcount); + if (read->rd_vlen < 0) +@@ -3969,11 +3968,9 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp, + return nfserr_io; + xdr_truncate_encode(xdr, starting_len + xdr_align_size(maxcount)); + +- tmp = xdr_zero; +- pad = (maxcount&3) ? 4 - (maxcount&3) : 0; +- write_bytes_to_xdr_buf(xdr->buf, starting_len + maxcount, &tmp, pad); +- return 0; +- ++ write_bytes_to_xdr_buf(xdr->buf, starting_len + maxcount, &zero, ++ xdr_pad_size(maxcount)); ++ return nfs_ok; + } + + static __be32 +-- +2.43.0 + diff --git a/queue-5.10/nfsd-verify-the-opened-dentry-after-setting-a-delega.patch b/queue-5.10/nfsd-verify-the-opened-dentry-after-setting-a-delega.patch new file mode 100644 index 00000000000..7c38957dc96 --- /dev/null +++ b/queue-5.10/nfsd-verify-the-opened-dentry-after-setting-a-delega.patch @@ -0,0 +1,169 @@ +From 36c288d1166d1ab713f161bc6c1c74930f55742e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 Jul 2022 16:45:30 +1000 +Subject: NFSD: verify the opened dentry after setting a delegation + +From: Jeff Layton + +[ Upstream commit 876c553cb41026cb6ad3cef970a35e5f69c42a25 ] + +Between opening a file and setting a delegation on it, someone could +rename or unlink the dentry. If this happens, we do not want to grant a +delegation on the open. + +On a CLAIM_NULL open, we're opening by filename, and we may (in the +non-create case) or may not (in the create case) be holding i_rwsem +when attempting to set a delegation. The latter case allows a +race. + +After getting a lease, redo the lookup of the file being opened and +validate that the resulting dentry matches the one in the open file +description. + +To properly redo the lookup we need an rqst pointer to pass to +nfsd_lookup_dentry(), so make sure that is available. + +Signed-off-by: Jeff Layton +Signed-off-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 1 + + fs/nfsd/nfs4state.c | 54 ++++++++++++++++++++++++++++++++++++++++----- + fs/nfsd/xdr4.h | 1 + + 3 files changed, 51 insertions(+), 5 deletions(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index fdde7eca8d438..7685bbe9d78dd 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -547,6 +547,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + open->op_openowner); + + open->op_filp = NULL; ++ open->op_rqstp = rqstp; + + /* This check required by spec. */ + if (open->op_create && open->op_claim_type != NFS4_OPEN_CLAIM_NULL) +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 194d8aeb1fd46..b3ab112695837 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -5305,11 +5305,44 @@ static int nfsd4_check_conflicting_opens(struct nfs4_client *clp, + return 0; + } + ++/* ++ * It's possible that between opening the dentry and setting the delegation, ++ * that it has been renamed or unlinked. Redo the lookup to verify that this ++ * hasn't happened. ++ */ ++static int ++nfsd4_verify_deleg_dentry(struct nfsd4_open *open, struct nfs4_file *fp, ++ struct svc_fh *parent) ++{ ++ struct svc_export *exp; ++ struct dentry *child; ++ __be32 err; ++ ++ /* parent may already be locked, and it may get unlocked by ++ * this call, but that is safe. ++ */ ++ err = nfsd_lookup_dentry(open->op_rqstp, parent, ++ open->op_fname, open->op_fnamelen, ++ &exp, &child); ++ ++ if (err) ++ return -EAGAIN; ++ ++ dput(child); ++ if (child != file_dentry(fp->fi_deleg_file->nf_file)) ++ return -EAGAIN; ++ ++ return 0; ++} ++ + static struct nfs4_delegation * +-nfs4_set_delegation(struct nfs4_client *clp, +- struct nfs4_file *fp, struct nfs4_clnt_odstate *odstate) ++nfs4_set_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp, ++ struct svc_fh *parent) + { + int status = 0; ++ struct nfs4_client *clp = stp->st_stid.sc_client; ++ struct nfs4_file *fp = stp->st_stid.sc_file; ++ struct nfs4_clnt_odstate *odstate = stp->st_clnt_odstate; + struct nfs4_delegation *dp; + struct nfsd_file *nf; + struct file_lock *fl; +@@ -5364,6 +5397,13 @@ nfs4_set_delegation(struct nfs4_client *clp, + locks_free_lock(fl); + if (status) + goto out_clnt_odstate; ++ ++ if (parent) { ++ status = nfsd4_verify_deleg_dentry(open, fp, parent); ++ if (status) ++ goto out_unlock; ++ } ++ + status = nfsd4_check_conflicting_opens(clp, fp); + if (status) + goto out_unlock; +@@ -5419,11 +5459,13 @@ static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status) + * proper support for them. + */ + static void +-nfs4_open_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp) ++nfs4_open_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp, ++ struct svc_fh *currentfh) + { + struct nfs4_delegation *dp; + struct nfs4_openowner *oo = openowner(stp->st_stateowner); + struct nfs4_client *clp = stp->st_stid.sc_client; ++ struct svc_fh *parent = NULL; + int cb_up; + int status = 0; + +@@ -5437,6 +5479,8 @@ nfs4_open_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp) + goto out_no_deleg; + break; + case NFS4_OPEN_CLAIM_NULL: ++ parent = currentfh; ++ fallthrough; + case NFS4_OPEN_CLAIM_FH: + /* + * Let's not give out any delegations till everyone's +@@ -5451,7 +5495,7 @@ nfs4_open_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp) + default: + goto out_no_deleg; + } +- dp = nfs4_set_delegation(clp, stp->st_stid.sc_file, stp->st_clnt_odstate); ++ dp = nfs4_set_delegation(open, stp, parent); + if (IS_ERR(dp)) + goto out_no_deleg; + +@@ -5583,7 +5627,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf + * Attempt to hand out a delegation. No error return, because the + * OPEN succeeds even if we fail. + */ +- nfs4_open_delegation(open, stp); ++ nfs4_open_delegation(open, stp, &resp->cstate.current_fh); + nodeleg: + status = nfs_ok; + trace_nfsd_open(&stp->st_stid.sc_stateid); +diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h +index 3b9e60249aea9..14b87141de343 100644 +--- a/fs/nfsd/xdr4.h ++++ b/fs/nfsd/xdr4.h +@@ -279,6 +279,7 @@ struct nfsd4_open { + struct nfs4_clnt_odstate *op_odstate; /* used during processing */ + struct nfs4_acl *op_acl; + struct xdr_netobj op_label; ++ struct svc_rqst *op_rqstp; + }; + + struct nfsd4_open_confirm { +-- +2.43.0 + diff --git a/queue-5.10/nfsd-warn-when-freeing-an-item-still-linked-via-nf_l.patch b/queue-5.10/nfsd-warn-when-freeing-an-item-still-linked-via-nf_l.patch new file mode 100644 index 00000000000..ec5047c90d5 --- /dev/null +++ b/queue-5.10/nfsd-warn-when-freeing-an-item-still-linked-via-nf_l.patch @@ -0,0 +1,63 @@ +From 1e48f9b8cf76ccd36573e2655421b1c7f694f819 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 Jul 2022 14:25:04 -0400 +Subject: NFSD: WARN when freeing an item still linked via nf_lru + +From: Chuck Lever + +[ Upstream commit 668ed92e651d3c25f9b6e8cb7ceca54d00daa96d ] + +Add a guardrail to prevent freeing memory that is still on a list. +This includes either a dispose list or the LRU list. + +This is the sign of a bug, but this class of bugs can be detected +so that they don't endanger system stability, especially while +debugging. + +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index 60c51a4d8e0d7..d9b5f1e183976 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -213,6 +213,14 @@ nfsd_file_free(struct nfsd_file *nf) + fput(nf->nf_file); + flush = true; + } ++ ++ /* ++ * If this item is still linked via nf_lru, that's a bug. ++ * WARN and leak it to preserve system stability. ++ */ ++ if (WARN_ON_ONCE(!list_empty(&nf->nf_lru))) ++ return flush; ++ + call_rcu(&nf->nf_rcu, nfsd_file_slab_free); + return flush; + } +@@ -342,7 +350,7 @@ nfsd_file_dispose_list(struct list_head *dispose) + + while(!list_empty(dispose)) { + nf = list_first_entry(dispose, struct nfsd_file, nf_lru); +- list_del(&nf->nf_lru); ++ list_del_init(&nf->nf_lru); + nfsd_file_flush(nf); + nfsd_file_put_noref(nf); + } +@@ -356,7 +364,7 @@ nfsd_file_dispose_list_sync(struct list_head *dispose) + + while(!list_empty(dispose)) { + nf = list_first_entry(dispose, struct nfsd_file, nf_lru); +- list_del(&nf->nf_lru); ++ list_del_init(&nf->nf_lru); + nfsd_file_flush(nf); + if (!refcount_dec_and_test(&nf->nf_ref)) + continue; +-- +2.43.0 + diff --git a/queue-5.10/nfsd-write-verifier-might-go-backwards.patch b/queue-5.10/nfsd-write-verifier-might-go-backwards.patch new file mode 100644 index 00000000000..2181483e3a5 --- /dev/null +++ b/queue-5.10/nfsd-write-verifier-might-go-backwards.patch @@ -0,0 +1,38 @@ +From ac7c51dbd998700f576c755682c3eeee39fcf321 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 30 Dec 2021 10:26:18 -0500 +Subject: NFSD: Write verifier might go backwards + +From: Chuck Lever + +[ Upstream commit cdc556600c0133575487cc69fb3128440b3c3e92 ] + +When vfs_iter_write() starts to fail because a file system is full, +a bunch of writes can fail at once with ENOSPC. These writes +repeatedly invoke nfsd_reset_boot_verifier() in quick succession. + +Ensure that the time it grabs doesn't go backwards due to an ntp +adjustment going on at the same time. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfssvc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c +index 8554bc7ff4322..4d1d8aa6d7f9d 100644 +--- a/fs/nfsd/nfssvc.c ++++ b/fs/nfsd/nfssvc.c +@@ -363,7 +363,7 @@ void nfsd_copy_boot_verifier(__be32 verf[2], struct nfsd_net *nn) + + static void nfsd_reset_boot_verifier_locked(struct nfsd_net *nn) + { +- ktime_get_real_ts64(&nn->nfssvc_boot); ++ ktime_get_raw_ts64(&nn->nfssvc_boot); + } + + void nfsd_reset_boot_verifier(struct nfsd_net *nn) +-- +2.43.0 + diff --git a/queue-5.10/nfsd-zero-counters-when-the-filecache-is-re-initiali.patch b/queue-5.10/nfsd-zero-counters-when-the-filecache-is-re-initiali.patch new file mode 100644 index 00000000000..1b8efd35f09 --- /dev/null +++ b/queue-5.10/nfsd-zero-counters-when-the-filecache-is-re-initiali.patch @@ -0,0 +1,51 @@ +From 44acdd278577721178142f1209072cb230597a36 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 8 Jul 2022 14:24:51 -0400 +Subject: NFSD: Zero counters when the filecache is re-initialized + +From: Chuck Lever + +[ Upstream commit 8b330f78040cbe16cf8029df70391b2a491f17e2 ] + +If nfsd_file_cache_init() is called after a shutdown, be sure the +stat counters are reset. + +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/filecache.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c +index b9941d4ef20d6..60c51a4d8e0d7 100644 +--- a/fs/nfsd/filecache.c ++++ b/fs/nfsd/filecache.c +@@ -823,6 +823,8 @@ nfsd_file_cache_shutdown_net(struct net *net) + void + nfsd_file_cache_shutdown(void) + { ++ int i; ++ + set_bit(NFSD_FILE_SHUTDOWN, &nfsd_file_lru_flags); + + lease_unregister_notifier(&nfsd_file_lease_notifier); +@@ -846,6 +848,15 @@ nfsd_file_cache_shutdown(void) + nfsd_file_hashtbl = NULL; + destroy_workqueue(nfsd_filecache_wq); + nfsd_filecache_wq = NULL; ++ ++ for_each_possible_cpu(i) { ++ per_cpu(nfsd_file_cache_hits, i) = 0; ++ per_cpu(nfsd_file_acquisitions, i) = 0; ++ per_cpu(nfsd_file_releases, i) = 0; ++ per_cpu(nfsd_file_total_age, i) = 0; ++ per_cpu(nfsd_file_pages_flushed, i) = 0; ++ per_cpu(nfsd_file_evictions, i) = 0; ++ } + } + + static bool +-- +2.43.0 + diff --git a/queue-5.10/nfsd4-add-refcount-for-nfsd4_blocked_lock.patch b/queue-5.10/nfsd4-add-refcount-for-nfsd4_blocked_lock.patch new file mode 100644 index 00000000000..1c7a9f6ad21 --- /dev/null +++ b/queue-5.10/nfsd4-add-refcount-for-nfsd4_blocked_lock.patch @@ -0,0 +1,138 @@ +From a2dc7aea07c93bd860e874c3c2fc2af325924ddd Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 17 Dec 2021 09:49:39 +0300 +Subject: nfsd4: add refcount for nfsd4_blocked_lock + +From: Vasily Averin + +[ Upstream commit 47446d74f1707049067fee038507cdffda805631 ] + +nbl allocated in nfsd4_lock can be released by a several ways: +directly in nfsd4_lock(), via nfs4_laundromat(), via another nfs +command RELEASE_LOCKOWNER or via nfsd4_callback. +This structure should be refcounted to be used and released correctly +in all these cases. + +Refcount is initialized to 1 during allocation and is incremented +when nbl is added into nbl_list/nbl_lru lists. + +Usually nbl is linked into both lists together, so only one refcount +is used for both lists. + +However nfsd4_lock() should keep in mind that nbl can be present +in one of lists only. This can happen if nbl was handled already +by nfs4_laundromat/nfsd4_callback/etc. + +Refcount is decremented if vfs_lock_file() returns FILE_LOCK_DEFERRED, +because nbl can be handled already by nfs4_laundromat/nfsd4_callback/etc. + +Refcount is not changed in find_blocked_lock() because of it reuses counter +released after removing nbl from lists. + +Signed-off-by: Vasily Averin +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 25 ++++++++++++++++++++++--- + fs/nfsd/state.h | 1 + + 2 files changed, 23 insertions(+), 3 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 36ae55fbfbc67..4161a4854c430 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -246,6 +246,7 @@ find_blocked_lock(struct nfs4_lockowner *lo, struct knfsd_fh *fh, + list_for_each_entry(cur, &lo->lo_blocked, nbl_list) { + if (fh_match(fh, &cur->nbl_fh)) { + list_del_init(&cur->nbl_list); ++ WARN_ON(list_empty(&cur->nbl_lru)); + list_del_init(&cur->nbl_lru); + found = cur; + break; +@@ -271,6 +272,7 @@ find_or_allocate_block(struct nfs4_lockowner *lo, struct knfsd_fh *fh, + INIT_LIST_HEAD(&nbl->nbl_lru); + fh_copy_shallow(&nbl->nbl_fh, fh); + locks_init_lock(&nbl->nbl_lock); ++ kref_init(&nbl->nbl_kref); + nfsd4_init_cb(&nbl->nbl_cb, lo->lo_owner.so_client, + &nfsd4_cb_notify_lock_ops, + NFSPROC4_CLNT_CB_NOTIFY_LOCK); +@@ -279,12 +281,21 @@ find_or_allocate_block(struct nfs4_lockowner *lo, struct knfsd_fh *fh, + return nbl; + } + ++static void ++free_nbl(struct kref *kref) ++{ ++ struct nfsd4_blocked_lock *nbl; ++ ++ nbl = container_of(kref, struct nfsd4_blocked_lock, nbl_kref); ++ kfree(nbl); ++} ++ + static void + free_blocked_lock(struct nfsd4_blocked_lock *nbl) + { + locks_delete_block(&nbl->nbl_lock); + locks_release_private(&nbl->nbl_lock); +- kfree(nbl); ++ kref_put(&nbl->nbl_kref, free_nbl); + } + + static void +@@ -302,6 +313,7 @@ remove_blocked_locks(struct nfs4_lockowner *lo) + struct nfsd4_blocked_lock, + nbl_list); + list_del_init(&nbl->nbl_list); ++ WARN_ON(list_empty(&nbl->nbl_lru)); + list_move(&nbl->nbl_lru, &reaplist); + } + spin_unlock(&nn->blocked_locks_lock); +@@ -7029,6 +7041,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + spin_lock(&nn->blocked_locks_lock); + list_add_tail(&nbl->nbl_list, &lock_sop->lo_blocked); + list_add_tail(&nbl->nbl_lru, &nn->blocked_locks_lru); ++ kref_get(&nbl->nbl_kref); + spin_unlock(&nn->blocked_locks_lock); + } + +@@ -7041,6 +7054,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + nn->somebody_reclaimed = true; + break; + case FILE_LOCK_DEFERRED: ++ kref_put(&nbl->nbl_kref, free_nbl); + nbl = NULL; + fallthrough; + case -EAGAIN: /* conflock holds conflicting lock */ +@@ -7061,8 +7075,13 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + /* dequeue it if we queued it before */ + if (fl_flags & FL_SLEEP) { + spin_lock(&nn->blocked_locks_lock); +- list_del_init(&nbl->nbl_list); +- list_del_init(&nbl->nbl_lru); ++ if (!list_empty(&nbl->nbl_list) && ++ !list_empty(&nbl->nbl_lru)) { ++ list_del_init(&nbl->nbl_list); ++ list_del_init(&nbl->nbl_lru); ++ kref_put(&nbl->nbl_kref, free_nbl); ++ } ++ /* nbl can use one of lists to be linked to reaplist */ + spin_unlock(&nn->blocked_locks_lock); + } + free_blocked_lock(nbl); +diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h +index 6eb3c7157214b..95457cfd37fc0 100644 +--- a/fs/nfsd/state.h ++++ b/fs/nfsd/state.h +@@ -633,6 +633,7 @@ struct nfsd4_blocked_lock { + struct file_lock nbl_lock; + struct knfsd_fh nbl_fh; + struct nfsd4_callback nbl_cb; ++ struct kref nbl_kref; + }; + + struct nfsd4_compound_state; +-- +2.43.0 + diff --git a/queue-5.10/nfsd4-don-t-query-change-attribute-in-v2-v3-case.patch b/queue-5.10/nfsd4-don-t-query-change-attribute-in-v2-v3-case.patch new file mode 100644 index 00000000000..a6be919a0b2 --- /dev/null +++ b/queue-5.10/nfsd4-don-t-query-change-attribute-in-v2-v3-case.patch @@ -0,0 +1,82 @@ +From 7a4eea3a9e11a76c54a3c0ad0aebebd6b8f2e398 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Nov 2020 17:46:17 -0500 +Subject: nfsd4: don't query change attribute in v2/v3 case + +From: J. Bruce Fields + +[ Upstream commit 942b20dc245590327ee0187c15c78174cd96dd52 ] + +inode_query_iversion() has side effects, and there's no point calling it +when we're not even going to use it. + +We check whether we're currently processing a v4 request by checking +fh_maxsize, which is arguably a little hacky; we could add a flag to +svc_fh instead. + +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3xdr.c | 14 +++++++++----- + 1 file changed, 9 insertions(+), 5 deletions(-) + +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index 5956b0317c55e..7d44e10a5f5dd 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -259,11 +259,11 @@ void fill_pre_wcc(struct svc_fh *fhp) + { + struct inode *inode; + struct kstat stat; ++ bool v4 = (fhp->fh_maxsize == NFS4_FHSIZE); + __be32 err; + + if (fhp->fh_pre_saved) + return; +- + inode = d_inode(fhp->fh_dentry); + err = fh_getattr(fhp, &stat); + if (err) { +@@ -272,11 +272,12 @@ void fill_pre_wcc(struct svc_fh *fhp) + stat.ctime = inode->i_ctime; + stat.size = inode->i_size; + } ++ if (v4) ++ fhp->fh_pre_change = nfsd4_change_attribute(&stat, inode); + + fhp->fh_pre_mtime = stat.mtime; + fhp->fh_pre_ctime = stat.ctime; + fhp->fh_pre_size = stat.size; +- fhp->fh_pre_change = nfsd4_change_attribute(&stat, inode); + fhp->fh_pre_saved = true; + } + +@@ -285,6 +286,8 @@ void fill_pre_wcc(struct svc_fh *fhp) + */ + void fill_post_wcc(struct svc_fh *fhp) + { ++ bool v4 = (fhp->fh_maxsize == NFS4_FHSIZE); ++ struct inode *inode = d_inode(fhp->fh_dentry); + __be32 err; + + if (fhp->fh_post_saved) +@@ -293,11 +296,12 @@ void fill_post_wcc(struct svc_fh *fhp) + err = fh_getattr(fhp, &fhp->fh_post_attr); + if (err) { + fhp->fh_post_saved = false; +- fhp->fh_post_attr.ctime = d_inode(fhp->fh_dentry)->i_ctime; ++ fhp->fh_post_attr.ctime = inode->i_ctime; + } else + fhp->fh_post_saved = true; +- fhp->fh_post_change = nfsd4_change_attribute(&fhp->fh_post_attr, +- d_inode(fhp->fh_dentry)); ++ if (v4) ++ fhp->fh_post_change = ++ nfsd4_change_attribute(&fhp->fh_post_attr, inode); + } + + /* +-- +2.43.0 + diff --git a/queue-5.10/nfsd4-expose-the-callback-address-and-state-of-each-.patch b/queue-5.10/nfsd4-expose-the-callback-address-and-state-of-each-.patch new file mode 100644 index 00000000000..a236980c482 --- /dev/null +++ b/queue-5.10/nfsd4-expose-the-callback-address-and-state-of-each-.patch @@ -0,0 +1,58 @@ +From 1f4ce8d0596ddeec7511e07fe422bc967f7e7a36 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 2 Jun 2021 13:51:39 -0400 +Subject: nfsd4: Expose the callback address and state of each NFS4 client + +From: Dave Wysochanski + +[ Upstream commit 3518c8666f15cdd5d38878005dab1d589add1c19 ] + +In addition to the client's address, display the callback channel +state and address in the 'info' file. + +Signed-off-by: Dave Wysochanski +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index 4e14a9f6dfd39..a20cdb1910048 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -2376,6 +2376,21 @@ static void seq_quote_mem(struct seq_file *m, char *data, int len) + seq_printf(m, "\""); + } + ++static const char *cb_state2str(int state) ++{ ++ switch (state) { ++ case NFSD4_CB_UP: ++ return "UP"; ++ case NFSD4_CB_UNKNOWN: ++ return "UNKNOWN"; ++ case NFSD4_CB_DOWN: ++ return "DOWN"; ++ case NFSD4_CB_FAULT: ++ return "FAULT"; ++ } ++ return "UNDEFINED"; ++} ++ + static int client_info_show(struct seq_file *m, void *v) + { + struct inode *inode = m->private; +@@ -2404,6 +2419,8 @@ static int client_info_show(struct seq_file *m, void *v) + seq_printf(m, "\nImplementation time: [%lld, %ld]\n", + clp->cl_nii_time.tv_sec, clp->cl_nii_time.tv_nsec); + } ++ seq_printf(m, "callback state: %s\n", cb_state2str(clp->cl_cb_state)); ++ seq_printf(m, "callback address: %pISpc\n", &clp->cl_cb_conn.cb_addr); + drop_client(clp); + + return 0; +-- +2.43.0 + diff --git a/queue-5.10/nfsd4-remove-obselete-comment.patch b/queue-5.10/nfsd4-remove-obselete-comment.patch new file mode 100644 index 00000000000..7689bbf4c78 --- /dev/null +++ b/queue-5.10/nfsd4-remove-obselete-comment.patch @@ -0,0 +1,37 @@ +From 9e534830d6e7713f44e659708d420beade82f038 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 26 Oct 2021 12:56:55 -0400 +Subject: nfsd4: remove obselete comment + +From: J. Bruce Fields + +[ Upstream commit 80479eb862102f9513e93fcf726c78cc0be2e3b2 ] + +Mandatory locking has been removed. And the rest of this comment is +redundant with the code. + +Reported-by: Jeff layton +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/vfs.c | 3 --- + 1 file changed, 3 deletions(-) + +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index 5b0abdf8de27e..deaf4a50550d5 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -751,9 +751,6 @@ __nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, + path.dentry = fhp->fh_dentry; + inode = d_inode(path.dentry); + +- /* Disallow write access to files with the append-only bit set +- * or any access when mandatory locking enabled +- */ + err = nfserr_perm; + if (IS_APPEND(inode) && (may_flags & NFSD_MAY_WRITE)) + goto out; +-- +2.43.0 + diff --git a/queue-5.10/nfsd4-simplify-process_lookup1.patch b/queue-5.10/nfsd4-simplify-process_lookup1.patch new file mode 100644 index 00000000000..df0797fd1f2 --- /dev/null +++ b/queue-5.10/nfsd4-simplify-process_lookup1.patch @@ -0,0 +1,38 @@ +From 2162ab22779a5d49fb59ddaddce4132862874dc4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 21 Jan 2021 17:57:37 -0500 +Subject: nfsd4: simplify process_lookup1 + +From: J. Bruce Fields + +[ Upstream commit 33311873adb0d55c287b164117b5b4bb7b1bdc40 ] + +This STALE_CLIENTID check is redundant with the one in +lookup_clientid(). + +There's a difference in behavior is in case of memory allocation +failure, which I think isn't a big deal. + +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4state.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c +index e7ec7593eaaa3..3f26047376368 100644 +--- a/fs/nfsd/nfs4state.c ++++ b/fs/nfsd/nfs4state.c +@@ -4722,8 +4722,6 @@ nfsd4_process_open1(struct nfsd4_compound_state *cstate, + struct nfs4_openowner *oo = NULL; + __be32 status; + +- if (STALE_CLIENTID(&open->op_clientid, nn)) +- return nfserr_stale_clientid; + /* + * In case we need it later, after we've already created the + * file and don't want to risk a further failure: +-- +2.43.0 + diff --git a/queue-5.10/nfsd_splice_actor-handle-compound-pages.patch b/queue-5.10/nfsd_splice_actor-handle-compound-pages.patch new file mode 100644 index 00000000000..5e08e2a0775 --- /dev/null +++ b/queue-5.10/nfsd_splice_actor-handle-compound-pages.patch @@ -0,0 +1,57 @@ +From c34305b052c2bb7a246929aaeed1eb3a1392fb53 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 10 Sep 2022 22:14:02 +0100 +Subject: nfsd_splice_actor(): handle compound pages +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Al Viro + +[ Upstream commit bfbfb6182ad1d7d184b16f25165faad879147f79 ] + +pipe_buffer might refer to a compound page (and contain more than a PAGE_SIZE +worth of data). Theoretically it had been possible since way back, but +nfsd_splice_actor() hadn't run into that until copy_page_to_iter() change. +Fortunately, the only thing that changes for compound pages is that we +need to stuff each relevant subpage in and convert the offset into offset +in the first subpage. + +Acked-by: Chuck Lever +Tested-by: Benjamin Coddington +Fixes: f0f6b614f83d "copy_page_to_iter(): don't split high-order page in case of ITER_PIPE" +Signed-off-by: Al Viro +[ cel: "‘for’ loop initial declarations are only allowed in C99 or C11 mode" ] +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/vfs.c | 13 +++++++++---- + 1 file changed, 9 insertions(+), 4 deletions(-) + +diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c +index 95f2e4549c034..bc377ee177171 100644 +--- a/fs/nfsd/vfs.c ++++ b/fs/nfsd/vfs.c +@@ -862,10 +862,15 @@ nfsd_splice_actor(struct pipe_inode_info *pipe, struct pipe_buffer *buf, + struct splice_desc *sd) + { + struct svc_rqst *rqstp = sd->u.data; +- +- svc_rqst_replace_page(rqstp, buf->page); +- if (rqstp->rq_res.page_len == 0) +- rqstp->rq_res.page_base = buf->offset; ++ struct page *page = buf->page; // may be a compound one ++ unsigned offset = buf->offset; ++ int i; ++ ++ page += offset / PAGE_SIZE; ++ for (i = sd->len; i > 0; i -= PAGE_SIZE) ++ svc_rqst_replace_page(rqstp, page++); ++ if (rqstp->rq_res.page_len == 0) // first call ++ rqstp->rq_res.page_base = offset % PAGE_SIZE; + rqstp->rq_res.page_len += sd->len; + return sd->len; + } +-- +2.43.0 + diff --git a/queue-5.10/nfsv4.2-remove-ifdef-config_nfsd-from-nfsv4.2-client.patch b/queue-5.10/nfsv4.2-remove-ifdef-config_nfsd-from-nfsv4.2-client.patch new file mode 100644 index 00000000000..1e7a6dba423 --- /dev/null +++ b/queue-5.10/nfsv4.2-remove-ifdef-config_nfsd-from-nfsv4.2-client.patch @@ -0,0 +1,99 @@ +From bfb4d3ce3f8aaca375d76fe46454e24300bf0b74 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 22 Apr 2021 03:37:49 -0400 +Subject: NFSv4.2: Remove ifdef CONFIG_NFSD from NFSv4.2 client SSC code. + +From: Dai Ngo + +[ Upstream commit d9092b4bb2109502eb8972021a3f74febc931a63 ] + +The client SSC code should not depend on any of the CONFIG_NFSD config. +This patch removes all CONFIG_NFSD from NFSv4.2 client SSC code and +simplifies the config of CONFIG_NFS_V4_2_SSC_HELPER, NFSD_V4_2_INTER_SSC. + +Signed-off-by: Dai Ngo +Signed-off-by: Trond Myklebust +Signed-off-by: Sasha Levin +--- + fs/Kconfig | 4 ++-- + fs/nfs/nfs4file.c | 4 ---- + fs/nfs/super.c | 4 ---- + fs/nfsd/Kconfig | 2 +- + 4 files changed, 3 insertions(+), 11 deletions(-) + +diff --git a/fs/Kconfig b/fs/Kconfig +index 462253ae483a3..eaff422877c39 100644 +--- a/fs/Kconfig ++++ b/fs/Kconfig +@@ -334,8 +334,8 @@ config NFS_COMMON + default y + + config NFS_V4_2_SSC_HELPER +- tristate +- default y if NFS_V4=y || NFS_FS=y ++ bool ++ default y if NFS_V4_2 + + source "net/sunrpc/Kconfig" + source "fs/ceph/Kconfig" +diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c +index 5ad57ad89fb1e..70cd0d764c447 100644 +--- a/fs/nfs/nfs4file.c ++++ b/fs/nfs/nfs4file.c +@@ -430,9 +430,7 @@ static const struct nfs4_ssc_client_ops nfs4_ssc_clnt_ops_tbl = { + */ + void nfs42_ssc_register_ops(void) + { +-#ifdef CONFIG_NFSD_V4 + nfs42_ssc_register(&nfs4_ssc_clnt_ops_tbl); +-#endif + } + + /** +@@ -443,9 +441,7 @@ void nfs42_ssc_register_ops(void) + */ + void nfs42_ssc_unregister_ops(void) + { +-#ifdef CONFIG_NFSD_V4 + nfs42_ssc_unregister(&nfs4_ssc_clnt_ops_tbl); +-#endif + } + #endif /* CONFIG_NFS_V4_2 */ + +diff --git a/fs/nfs/super.c b/fs/nfs/super.c +index 7179d59d73ca4..1ffce90760606 100644 +--- a/fs/nfs/super.c ++++ b/fs/nfs/super.c +@@ -116,16 +116,12 @@ static void unregister_nfs4_fs(void) + #ifdef CONFIG_NFS_V4_2 + static void nfs_ssc_register_ops(void) + { +-#ifdef CONFIG_NFSD_V4 + nfs_ssc_register(&nfs_ssc_clnt_ops_tbl); +-#endif + } + + static void nfs_ssc_unregister_ops(void) + { +-#ifdef CONFIG_NFSD_V4 + nfs_ssc_unregister(&nfs_ssc_clnt_ops_tbl); +-#endif + } + #endif /* CONFIG_NFS_V4_2 */ + +diff --git a/fs/nfsd/Kconfig b/fs/nfsd/Kconfig +index 5fa38ad9e7e3f..f229172652be0 100644 +--- a/fs/nfsd/Kconfig ++++ b/fs/nfsd/Kconfig +@@ -138,7 +138,7 @@ config NFSD_FLEXFILELAYOUT + + config NFSD_V4_2_INTER_SSC + bool "NFSv4.2 inter server to server COPY" +- depends on NFSD_V4 && NFS_V4_1 && NFS_V4_2 ++ depends on NFSD_V4 && NFS_V4_2 + help + This option enables support for NFSv4.2 inter server to + server copy where the destination server calls the NFSv4.2 +-- +2.43.0 + diff --git a/queue-5.10/nfsv4_2-ssc-helper-should-use-its-own-config.patch b/queue-5.10/nfsv4_2-ssc-helper-should-use-its-own-config.patch new file mode 100644 index 00000000000..708e5646fb2 --- /dev/null +++ b/queue-5.10/nfsv4_2-ssc-helper-should-use-its-own-config.patch @@ -0,0 +1,160 @@ +From 2e7600e096b4262ed0acce403c7245580443c610 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 28 Jan 2021 01:42:26 -0500 +Subject: NFSv4_2: SSC helper should use its own config. + +From: Dai Ngo + +[ Upstream commit 02591f9febd5f69bb4c266a4abf899c4cf21964f ] + +Currently NFSv4_2 SSC helper, nfs_ssc, incorrectly uses GRACE_PERIOD +as its config. Fix by adding new config NFS_V4_2_SSC_HELPER which +depends on NFS_V4_2 and is automatically selected when NFSD_V4 is +enabled. Also removed the file name from a comment in nfs_ssc.c. + +Signed-off-by: Dai Ngo +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/Kconfig | 4 ++++ + fs/nfs/nfs4file.c | 4 ++++ + fs/nfs/super.c | 12 ++++++++++++ + fs/nfs_common/Makefile | 2 +- + fs/nfs_common/nfs_ssc.c | 2 -- + fs/nfsd/Kconfig | 1 + + 6 files changed, 22 insertions(+), 3 deletions(-) + +diff --git a/fs/Kconfig b/fs/Kconfig +index da524c4d7b7e0..462253ae483a3 100644 +--- a/fs/Kconfig ++++ b/fs/Kconfig +@@ -333,6 +333,10 @@ config NFS_COMMON + depends on NFSD || NFS_FS || LOCKD + default y + ++config NFS_V4_2_SSC_HELPER ++ tristate ++ default y if NFS_V4=y || NFS_FS=y ++ + source "net/sunrpc/Kconfig" + source "fs/ceph/Kconfig" + source "fs/cifs/Kconfig" +diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c +index 70cd0d764c447..5ad57ad89fb1e 100644 +--- a/fs/nfs/nfs4file.c ++++ b/fs/nfs/nfs4file.c +@@ -430,7 +430,9 @@ static const struct nfs4_ssc_client_ops nfs4_ssc_clnt_ops_tbl = { + */ + void nfs42_ssc_register_ops(void) + { ++#ifdef CONFIG_NFSD_V4 + nfs42_ssc_register(&nfs4_ssc_clnt_ops_tbl); ++#endif + } + + /** +@@ -441,7 +443,9 @@ void nfs42_ssc_register_ops(void) + */ + void nfs42_ssc_unregister_ops(void) + { ++#ifdef CONFIG_NFSD_V4 + nfs42_ssc_unregister(&nfs4_ssc_clnt_ops_tbl); ++#endif + } + #endif /* CONFIG_NFS_V4_2 */ + +diff --git a/fs/nfs/super.c b/fs/nfs/super.c +index b3fcc27b95648..7179d59d73ca4 100644 +--- a/fs/nfs/super.c ++++ b/fs/nfs/super.c +@@ -86,9 +86,11 @@ const struct super_operations nfs_sops = { + }; + EXPORT_SYMBOL_GPL(nfs_sops); + ++#ifdef CONFIG_NFS_V4_2 + static const struct nfs_ssc_client_ops nfs_ssc_clnt_ops_tbl = { + .sco_sb_deactive = nfs_sb_deactive, + }; ++#endif + + #if IS_ENABLED(CONFIG_NFS_V4) + static int __init register_nfs4_fs(void) +@@ -111,15 +113,21 @@ static void unregister_nfs4_fs(void) + } + #endif + ++#ifdef CONFIG_NFS_V4_2 + static void nfs_ssc_register_ops(void) + { ++#ifdef CONFIG_NFSD_V4 + nfs_ssc_register(&nfs_ssc_clnt_ops_tbl); ++#endif + } + + static void nfs_ssc_unregister_ops(void) + { ++#ifdef CONFIG_NFSD_V4 + nfs_ssc_unregister(&nfs_ssc_clnt_ops_tbl); ++#endif + } ++#endif /* CONFIG_NFS_V4_2 */ + + static struct shrinker acl_shrinker = { + .count_objects = nfs_access_cache_count, +@@ -148,7 +156,9 @@ int __init register_nfs_fs(void) + ret = register_shrinker(&acl_shrinker); + if (ret < 0) + goto error_3; ++#ifdef CONFIG_NFS_V4_2 + nfs_ssc_register_ops(); ++#endif + return 0; + error_3: + nfs_unregister_sysctl(); +@@ -168,7 +178,9 @@ void __exit unregister_nfs_fs(void) + unregister_shrinker(&acl_shrinker); + nfs_unregister_sysctl(); + unregister_nfs4_fs(); ++#ifdef CONFIG_NFS_V4_2 + nfs_ssc_unregister_ops(); ++#endif + unregister_filesystem(&nfs_fs_type); + } + +diff --git a/fs/nfs_common/Makefile b/fs/nfs_common/Makefile +index fa82f5aaa6d95..119c75ab9fd08 100644 +--- a/fs/nfs_common/Makefile ++++ b/fs/nfs_common/Makefile +@@ -7,4 +7,4 @@ obj-$(CONFIG_NFS_ACL_SUPPORT) += nfs_acl.o + nfs_acl-objs := nfsacl.o + + obj-$(CONFIG_GRACE_PERIOD) += grace.o +-obj-$(CONFIG_GRACE_PERIOD) += nfs_ssc.o ++obj-$(CONFIG_NFS_V4_2_SSC_HELPER) += nfs_ssc.o +diff --git a/fs/nfs_common/nfs_ssc.c b/fs/nfs_common/nfs_ssc.c +index f43bbb3739134..7c1509e968c81 100644 +--- a/fs/nfs_common/nfs_ssc.c ++++ b/fs/nfs_common/nfs_ssc.c +@@ -1,7 +1,5 @@ + // SPDX-License-Identifier: GPL-2.0-only + /* +- * fs/nfs_common/nfs_ssc_comm.c +- * + * Helper for knfsd's SSC to access ops in NFS client modules + * + * Author: Dai Ngo +diff --git a/fs/nfsd/Kconfig b/fs/nfsd/Kconfig +index 248f1459c0399..d6cff5fbe705b 100644 +--- a/fs/nfsd/Kconfig ++++ b/fs/nfsd/Kconfig +@@ -77,6 +77,7 @@ config NFSD_V4 + select CRYPTO_MD5 + select CRYPTO_SHA256 + select GRACE_PERIOD ++ select NFS_V4_2_SSC_HELPER if NFS_V4_2 + help + This option enables support in your system's NFS server for + version 4 of the NFS protocol (RFC 3530). +-- +2.43.0 + diff --git a/queue-5.10/nlm-defend-against-file_lock-changes-after-vfs_test_.patch b/queue-5.10/nlm-defend-against-file_lock-changes-after-vfs_test_.patch new file mode 100644 index 00000000000..6945f009c16 --- /dev/null +++ b/queue-5.10/nlm-defend-against-file_lock-changes-after-vfs_test_.patch @@ -0,0 +1,144 @@ +From 877d7800645a18f7ee72a0a202cf5d940af224b7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 13 Jun 2022 09:40:06 -0400 +Subject: NLM: Defend against file_lock changes after vfs_test_lock() + +From: Benjamin Coddington + +[ Upstream commit 184cefbe62627730c30282df12bcff9aae4816ea ] + +Instead of trusting that struct file_lock returns completely unchanged +after vfs_test_lock() when there's no conflicting lock, stash away our +nlm_lockowner reference so we can properly release it for all cases. + +This defends against another file_lock implementation overwriting fl_owner +when the return type is F_UNLCK. + +Reported-by: Roberto Bergantinos Corpas +Tested-by: Roberto Bergantinos Corpas +Signed-off-by: Benjamin Coddington +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/svc4proc.c | 4 +++- + fs/lockd/svclock.c | 10 +--------- + fs/lockd/svcproc.c | 5 ++++- + include/linux/lockd/lockd.h | 1 + + 4 files changed, 9 insertions(+), 11 deletions(-) + +diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c +index 176b468a61c75..4f247ab8be611 100644 +--- a/fs/lockd/svc4proc.c ++++ b/fs/lockd/svc4proc.c +@@ -87,6 +87,7 @@ __nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_res *resp) + struct nlm_args *argp = rqstp->rq_argp; + struct nlm_host *host; + struct nlm_file *file; ++ struct nlm_lockowner *test_owner; + __be32 rc = rpc_success; + + dprintk("lockd: TEST4 called\n"); +@@ -96,6 +97,7 @@ __nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_res *resp) + if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file))) + return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; + ++ test_owner = argp->lock.fl.fl_owner; + /* Now check for conflicting locks */ + resp->status = nlmsvc_testlock(rqstp, file, host, &argp->lock, &resp->lock, &resp->cookie); + if (resp->status == nlm_drop_reply) +@@ -103,7 +105,7 @@ __nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_res *resp) + else + dprintk("lockd: TEST4 status %d\n", ntohl(resp->status)); + +- nlmsvc_release_lockowner(&argp->lock); ++ nlmsvc_put_lockowner(test_owner); + nlmsvc_release_host(host); + nlm_release_file(file); + return rc; +diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c +index cb3658ab9b7ae..9c1aa75441e1c 100644 +--- a/fs/lockd/svclock.c ++++ b/fs/lockd/svclock.c +@@ -340,7 +340,7 @@ nlmsvc_get_lockowner(struct nlm_lockowner *lockowner) + return lockowner; + } + +-static void nlmsvc_put_lockowner(struct nlm_lockowner *lockowner) ++void nlmsvc_put_lockowner(struct nlm_lockowner *lockowner) + { + if (!refcount_dec_and_lock(&lockowner->count, &lockowner->host->h_lock)) + return; +@@ -590,7 +590,6 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file, + int error; + int mode; + __be32 ret; +- struct nlm_lockowner *test_owner; + + dprintk("lockd: nlmsvc_testlock(%s/%ld, ty=%d, %Ld-%Ld)\n", + nlmsvc_file_inode(file)->i_sb->s_id, +@@ -604,9 +603,6 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file, + goto out; + } + +- /* If there's a conflicting lock, remember to clean up the test lock */ +- test_owner = (struct nlm_lockowner *)lock->fl.fl_owner; +- + mode = lock_to_openmode(&lock->fl); + error = vfs_test_lock(file->f_file[mode], &lock->fl); + if (error) { +@@ -635,10 +631,6 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file, + conflock->fl.fl_end = lock->fl.fl_end; + locks_release_private(&lock->fl); + +- /* Clean up the test lock */ +- lock->fl.fl_owner = NULL; +- nlmsvc_put_lockowner(test_owner); +- + ret = nlm_lck_denied; + out: + return ret; +diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c +index 4dc1b40a489a2..b09ca35b527cc 100644 +--- a/fs/lockd/svcproc.c ++++ b/fs/lockd/svcproc.c +@@ -116,6 +116,7 @@ __nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_res *resp) + struct nlm_args *argp = rqstp->rq_argp; + struct nlm_host *host; + struct nlm_file *file; ++ struct nlm_lockowner *test_owner; + __be32 rc = rpc_success; + + dprintk("lockd: TEST called\n"); +@@ -125,6 +126,8 @@ __nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_res *resp) + if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file))) + return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; + ++ test_owner = argp->lock.fl.fl_owner; ++ + /* Now check for conflicting locks */ + resp->status = cast_status(nlmsvc_testlock(rqstp, file, host, &argp->lock, &resp->lock, &resp->cookie)); + if (resp->status == nlm_drop_reply) +@@ -133,7 +136,7 @@ __nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_res *resp) + dprintk("lockd: TEST status %d vers %d\n", + ntohl(resp->status), rqstp->rq_vers); + +- nlmsvc_release_lockowner(&argp->lock); ++ nlmsvc_put_lockowner(test_owner); + nlmsvc_release_host(host); + nlm_release_file(file); + return rc; +diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h +index fcef192e5e45e..70ce419e27093 100644 +--- a/include/linux/lockd/lockd.h ++++ b/include/linux/lockd/lockd.h +@@ -292,6 +292,7 @@ void nlmsvc_locks_init_private(struct file_lock *, struct nlm_host *, pid_t); + __be32 nlm_lookup_file(struct svc_rqst *, struct nlm_file **, + struct nlm_lock *); + void nlm_release_file(struct nlm_file *); ++void nlmsvc_put_lockowner(struct nlm_lockowner *); + void nlmsvc_release_lockowner(struct nlm_lock *); + void nlmsvc_mark_resources(struct net *); + void nlmsvc_free_host_resources(struct nlm_host *); +-- +2.43.0 + diff --git a/queue-5.10/nlm-fix-svcxdr_encode_owner.patch b/queue-5.10/nlm-fix-svcxdr_encode_owner.patch new file mode 100644 index 00000000000..c74b12b9f51 --- /dev/null +++ b/queue-5.10/nlm-fix-svcxdr_encode_owner.patch @@ -0,0 +1,52 @@ +From eb46482aa9562c2681974f9c08fb460e6e5e6fe0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 16 Sep 2021 17:24:54 -0400 +Subject: NLM: Fix svcxdr_encode_owner() + +From: Chuck Lever + +[ Upstream commit 89c485c7a3ecbc2ebd568f9c9c2edf3a8cf7485b ] + +Dai Ngo reports that, since the XDR overhaul, the NLM server crashes +when the TEST procedure wants to return NLM_DENIED. There is a bug +in svcxdr_encode_owner() that none of our standard test cases found. + +Replace the open-coded function with a call to an appropriate +pre-fabricated XDR helper. + +Reported-by: Dai Ngo +Fixes: a6a63ca5652e ("lockd: Common NLM XDR helpers") +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/svcxdr.h | 13 ++----------- + 1 file changed, 2 insertions(+), 11 deletions(-) + +diff --git a/fs/lockd/svcxdr.h b/fs/lockd/svcxdr.h +index c69a0bb76c940..4f1a451da5ba2 100644 +--- a/fs/lockd/svcxdr.h ++++ b/fs/lockd/svcxdr.h +@@ -134,18 +134,9 @@ svcxdr_decode_owner(struct xdr_stream *xdr, struct xdr_netobj *obj) + static inline bool + svcxdr_encode_owner(struct xdr_stream *xdr, const struct xdr_netobj *obj) + { +- unsigned int quadlen = XDR_QUADLEN(obj->len); +- __be32 *p; +- +- if (xdr_stream_encode_u32(xdr, obj->len) < 0) +- return false; +- p = xdr_reserve_space(xdr, obj->len); +- if (!p) ++ if (obj->len > XDR_MAX_NETOBJ) + return false; +- p[quadlen - 1] = 0; /* XDR pad */ +- memcpy(p, obj->data, obj->len); +- +- return true; ++ return xdr_stream_encode_opaque(xdr, obj->data, obj->len) > 0; + } + + #endif /* _LOCKD_SVCXDR_H_ */ +-- +2.43.0 + diff --git a/queue-5.10/nlm-minor-nlm_lookup_file-argument-change.patch b/queue-5.10/nlm-minor-nlm_lookup_file-argument-change.patch new file mode 100644 index 00000000000..8737bf61e47 --- /dev/null +++ b/queue-5.10/nlm-minor-nlm_lookup_file-argument-change.patch @@ -0,0 +1,116 @@ +From 52f65d9bcb776180238ec926ce5837ba733f597e Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Aug 2021 12:01:18 -0400 +Subject: nlm: minor nlm_lookup_file argument change + +From: J. Bruce Fields + +[ Upstream commit 2dc6f19e4f438d4c14987cb17aee38aaf7304e7f ] + +It'll come in handy to get the whole nlm_lock. + +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/svc4proc.c | 3 ++- + fs/lockd/svcproc.c | 2 +- + fs/lockd/svcsubs.c | 15 ++++++++------- + include/linux/lockd/lockd.h | 2 +- + 4 files changed, 12 insertions(+), 10 deletions(-) + +diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c +index 4c10fb5138f10..bc496bbd696b8 100644 +--- a/fs/lockd/svc4proc.c ++++ b/fs/lockd/svc4proc.c +@@ -40,7 +40,8 @@ nlm4svc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp, + + /* Obtain file pointer. Not used by FREE_ALL call. */ + if (filp != NULL) { +- if ((error = nlm_lookup_file(rqstp, &file, &lock->fh)) != 0) ++ error = nlm_lookup_file(rqstp, &file, lock); ++ if (error) + goto no_locks; + *filp = file; + +diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c +index 4ae4b63b53925..f4e5e0eb30fd1 100644 +--- a/fs/lockd/svcproc.c ++++ b/fs/lockd/svcproc.c +@@ -69,7 +69,7 @@ nlmsvc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp, + + /* Obtain file pointer. Not used by FREE_ALL call. */ + if (filp != NULL) { +- error = cast_status(nlm_lookup_file(rqstp, &file, &lock->fh)); ++ error = cast_status(nlm_lookup_file(rqstp, &file, lock)); + if (error != 0) + goto no_locks; + *filp = file; +diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c +index 028fc152da22f..2d62633b39e51 100644 +--- a/fs/lockd/svcsubs.c ++++ b/fs/lockd/svcsubs.c +@@ -82,31 +82,31 @@ static inline unsigned int file_hash(struct nfs_fh *f) + */ + __be32 + nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result, +- struct nfs_fh *f) ++ struct nlm_lock *lock) + { + struct nlm_file *file; + unsigned int hash; + __be32 nfserr; + +- nlm_debug_print_fh("nlm_lookup_file", f); ++ nlm_debug_print_fh("nlm_lookup_file", &lock->fh); + +- hash = file_hash(f); ++ hash = file_hash(&lock->fh); + + /* Lock file table */ + mutex_lock(&nlm_file_mutex); + + hlist_for_each_entry(file, &nlm_files[hash], f_list) +- if (!nfs_compare_fh(&file->f_handle, f)) ++ if (!nfs_compare_fh(&file->f_handle, &lock->fh)) + goto found; + +- nlm_debug_print_fh("creating file for", f); ++ nlm_debug_print_fh("creating file for", &lock->fh); + + nfserr = nlm_lck_denied_nolocks; + file = kzalloc(sizeof(*file), GFP_KERNEL); + if (!file) + goto out_unlock; + +- memcpy(&file->f_handle, f, sizeof(struct nfs_fh)); ++ memcpy(&file->f_handle, &lock->fh, sizeof(struct nfs_fh)); + mutex_init(&file->f_mutex); + INIT_HLIST_NODE(&file->f_list); + INIT_LIST_HEAD(&file->f_blocks); +@@ -117,7 +117,8 @@ nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result, + * We have to make sure we have the right credential to open + * the file. + */ +- if ((nfserr = nlmsvc_ops->fopen(rqstp, f, &file->f_file)) != 0) { ++ nfserr = nlmsvc_ops->fopen(rqstp, &lock->fh, &file->f_file); ++ if (nfserr) { + dprintk("lockd: open failed (error %d)\n", nfserr); + goto out_free; + } +diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h +index 666f5f310a041..81b71ad2040ac 100644 +--- a/include/linux/lockd/lockd.h ++++ b/include/linux/lockd/lockd.h +@@ -286,7 +286,7 @@ void nlmsvc_locks_init_private(struct file_lock *, struct nlm_host *, pid_t); + * File handling for the server personality + */ + __be32 nlm_lookup_file(struct svc_rqst *, struct nlm_file **, +- struct nfs_fh *); ++ struct nlm_lock *); + void nlm_release_file(struct nlm_file *); + void nlmsvc_release_lockowner(struct nlm_lock *); + void nlmsvc_mark_resources(struct net *); +-- +2.43.0 + diff --git a/queue-5.10/nlm-minor-refactoring.patch b/queue-5.10/nlm-minor-refactoring.patch new file mode 100644 index 00000000000..32c93eaebd4 --- /dev/null +++ b/queue-5.10/nlm-minor-refactoring.patch @@ -0,0 +1,93 @@ +From 39fb28ced6800f7b41d457972fd5951d2e5bbdc8 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 23 Aug 2021 11:26:39 -0400 +Subject: nlm: minor refactoring + +From: J. Bruce Fields + +[ Upstream commit a81041b7d8f08c4e1014173c5483a0f18724a576 ] + +Make this lookup slightly more concise, and prepare for changing how we +look this up in a following patch. + +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/svclock.c | 16 ++++++++-------- + fs/lockd/svcsubs.c | 4 ++-- + 2 files changed, 10 insertions(+), 10 deletions(-) + +diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c +index 273a81971ed57..bcd180ba99576 100644 +--- a/fs/lockd/svclock.c ++++ b/fs/lockd/svclock.c +@@ -474,8 +474,8 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, + __be32 ret; + + dprintk("lockd: nlmsvc_lock(%s/%ld, ty=%d, pi=%d, %Ld-%Ld, bl=%d)\n", +- locks_inode(file->f_file)->i_sb->s_id, +- locks_inode(file->f_file)->i_ino, ++ nlmsvc_file_inode(file)->i_sb->s_id, ++ nlmsvc_file_inode(file)->i_ino, + lock->fl.fl_type, lock->fl.fl_pid, + (long long)lock->fl.fl_start, + (long long)lock->fl.fl_end, +@@ -581,8 +581,8 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file, + struct nlm_lockowner *test_owner; + + dprintk("lockd: nlmsvc_testlock(%s/%ld, ty=%d, %Ld-%Ld)\n", +- locks_inode(file->f_file)->i_sb->s_id, +- locks_inode(file->f_file)->i_ino, ++ nlmsvc_file_inode(file)->i_sb->s_id, ++ nlmsvc_file_inode(file)->i_ino, + lock->fl.fl_type, + (long long)lock->fl.fl_start, + (long long)lock->fl.fl_end); +@@ -644,8 +644,8 @@ nlmsvc_unlock(struct net *net, struct nlm_file *file, struct nlm_lock *lock) + int error; + + dprintk("lockd: nlmsvc_unlock(%s/%ld, pi=%d, %Ld-%Ld)\n", +- locks_inode(file->f_file)->i_sb->s_id, +- locks_inode(file->f_file)->i_ino, ++ nlmsvc_file_inode(file)->i_sb->s_id, ++ nlmsvc_file_inode(file)->i_ino, + lock->fl.fl_pid, + (long long)lock->fl.fl_start, + (long long)lock->fl.fl_end); +@@ -673,8 +673,8 @@ nlmsvc_cancel_blocked(struct net *net, struct nlm_file *file, struct nlm_lock *l + int status = 0; + + dprintk("lockd: nlmsvc_cancel(%s/%ld, pi=%d, %Ld-%Ld)\n", +- locks_inode(file->f_file)->i_sb->s_id, +- locks_inode(file->f_file)->i_ino, ++ nlmsvc_file_inode(file)->i_sb->s_id, ++ nlmsvc_file_inode(file)->i_ino, + lock->fl.fl_pid, + (long long)lock->fl.fl_start, + (long long)lock->fl.fl_end); +diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c +index 2d62633b39e51..e02951f8a28f5 100644 +--- a/fs/lockd/svcsubs.c ++++ b/fs/lockd/svcsubs.c +@@ -45,7 +45,7 @@ static inline void nlm_debug_print_fh(char *msg, struct nfs_fh *f) + + static inline void nlm_debug_print_file(char *msg, struct nlm_file *file) + { +- struct inode *inode = locks_inode(file->f_file); ++ struct inode *inode = nlmsvc_file_inode(file); + + dprintk("lockd: %s %s/%ld\n", + msg, inode->i_sb->s_id, inode->i_ino); +@@ -416,7 +416,7 @@ nlmsvc_match_sb(void *datap, struct nlm_file *file) + { + struct super_block *sb = datap; + +- return sb == locks_inode(file->f_file)->i_sb; ++ return sb == nlmsvc_file_inode(file)->i_sb; + } + + /** +-- +2.43.0 + diff --git a/queue-5.10/proc-fd-in-fdinfo-seq_show-don-t-use-get_files_struc.patch b/queue-5.10/proc-fd-in-fdinfo-seq_show-don-t-use-get_files_struc.patch new file mode 100644 index 00000000000..2b611b87c13 --- /dev/null +++ b/queue-5.10/proc-fd-in-fdinfo-seq_show-don-t-use-get_files_struc.patch @@ -0,0 +1,74 @@ +From 7a3d6b7d55c6b070141182197863ae30fc614048 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Nov 2020 17:14:34 -0600 +Subject: proc/fd: In fdinfo seq_show don't use get_files_struct + +From: Eric W. Biederman + +[ Upstream commit 775e0656b27210ae668e33af00bece858f44576f ] + +When discussing[1] exec and posix file locks it was realized that none +of the callers of get_files_struct fundamentally needed to call +get_files_struct, and that by switching them to helper functions +instead it will both simplify their code and remove unnecessary +increments of files_struct.count. Those unnecessary increments can +result in exec unnecessarily unsharing files_struct which breaking +posix locks, and it can result in fget_light having to fallback to +fget reducing system performance. + +Instead hold task_lock for the duration that task->files needs to be +stable in seq_show. The task_lock was already taken in +get_files_struct, and so skipping get_files_struct performs less work +overall, and avoids the problems with the files_struct reference +count. + +[1] https://lkml.kernel.org/r/20180915160423.GA31461@redhat.com +Suggested-by: Oleg Nesterov +Acked-by: Christian Brauner +v1: https://lkml.kernel.org/r/20200817220425.9389-12-ebiederm@xmission.com +Link: https://lkml.kernel.org/r/20201120231441.29911-17-ebiederm@xmission.com +Signed-off-by: Eric W. Biederman +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/proc/fd.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +diff --git a/fs/proc/fd.c b/fs/proc/fd.c +index 72c1525b4b3eb..cb51763ed554b 100644 +--- a/fs/proc/fd.c ++++ b/fs/proc/fd.c +@@ -28,9 +28,8 @@ static int seq_show(struct seq_file *m, void *v) + if (!task) + return -ENOENT; + +- files = get_files_struct(task); +- put_task_struct(task); +- ++ task_lock(task); ++ files = task->files; + if (files) { + unsigned int fd = proc_fd(m->private); + +@@ -47,8 +46,9 @@ static int seq_show(struct seq_file *m, void *v) + ret = 0; + } + spin_unlock(&files->file_lock); +- put_files_struct(files); + } ++ task_unlock(task); ++ put_task_struct(task); + + if (ret) + return ret; +@@ -57,6 +57,7 @@ static int seq_show(struct seq_file *m, void *v) + (long long)file->f_pos, f_flags, + real_mount(file->f_path.mnt)->mnt_id); + ++ /* show_fd_locks() never deferences files so a stale value is safe */ + show_fd_locks(m, file, files); + if (seq_has_overflowed(m)) + goto out; +-- +2.43.0 + diff --git a/queue-5.10/proc-fd-in-proc_fd_link-use-fget_task.patch b/queue-5.10/proc-fd-in-proc_fd_link-use-fget_task.patch new file mode 100644 index 00000000000..c906cebddfa --- /dev/null +++ b/queue-5.10/proc-fd-in-proc_fd_link-use-fget_task.patch @@ -0,0 +1,78 @@ +From b573a052cfc9ee1589d73d0db5e7a6d8934cd2f2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Nov 2020 17:14:23 -0600 +Subject: proc/fd: In proc_fd_link use fget_task + +From: Eric W. Biederman + +[ Upstream commit 439be32656035d3239fd56f9b83353ec06cb3b45 ] + +When discussing[1] exec and posix file locks it was realized that none +of the callers of get_files_struct fundamentally needed to call +get_files_struct, and that by switching them to helper functions +instead it will both simplify their code and remove unnecessary +increments of files_struct.count. Those unnecessary increments can +result in exec unnecessarily unsharing files_struct which breaking +posix locks, and it can result in fget_light having to fallback to +fget reducing system performance. + +Simplifying proc_fd_link is a little bit tricky. It is necessary to +know that there is a reference to fd_f ile while path_get is running. +This reference can either be guaranteed to exist either by locking the +fdtable as the code currently does or by taking a reference on the +file in question. + +Use fget_task to remove the need for get_files_struct and +to take a reference to file in question. + +[1] https://lkml.kernel.org/r/20180915160423.GA31461@redhat.com +Suggested-by: Oleg Nesterov +v1: https://lkml.kernel.org/r/20200817220425.9389-8-ebiederm@xmission.com +Link: https://lkml.kernel.org/r/20201120231441.29911-6-ebiederm@xmission.com +Signed-off-by: Eric W. Biederman +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/proc/fd.c | 13 +++---------- + 1 file changed, 3 insertions(+), 10 deletions(-) + +diff --git a/fs/proc/fd.c b/fs/proc/fd.c +index 81882a13212d3..d58960f6ee524 100644 +--- a/fs/proc/fd.c ++++ b/fs/proc/fd.c +@@ -146,29 +146,22 @@ static const struct dentry_operations tid_fd_dentry_operations = { + + static int proc_fd_link(struct dentry *dentry, struct path *path) + { +- struct files_struct *files = NULL; + struct task_struct *task; + int ret = -ENOENT; + + task = get_proc_task(d_inode(dentry)); + if (task) { +- files = get_files_struct(task); +- put_task_struct(task); +- } +- +- if (files) { + unsigned int fd = proc_fd(d_inode(dentry)); + struct file *fd_file; + +- spin_lock(&files->file_lock); +- fd_file = fcheck_files(files, fd); ++ fd_file = fget_task(task, fd); + if (fd_file) { + *path = fd_file->f_path; + path_get(&fd_file->f_path); + ret = 0; ++ fput(fd_file); + } +- spin_unlock(&files->file_lock); +- put_files_struct(files); ++ put_task_struct(task); + } + + return ret; +-- +2.43.0 + diff --git a/queue-5.10/proc-fd-in-proc_readfd_common-use-task_lookup_next_f.patch b/queue-5.10/proc-fd-in-proc_readfd_common-use-task_lookup_next_f.patch new file mode 100644 index 00000000000..a33e60914f5 --- /dev/null +++ b/queue-5.10/proc-fd-in-proc_readfd_common-use-task_lookup_next_f.patch @@ -0,0 +1,95 @@ +From cbce8f5d48529e76da9f7b339b014b1f7034c102 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Nov 2020 17:14:32 -0600 +Subject: proc/fd: In proc_readfd_common use task_lookup_next_fd_rcu + +From: Eric W. Biederman + +[ Upstream commit 5b17b61870e2f4b0a4fdc5c6039fbdb4ffb796df ] + +When discussing[1] exec and posix file locks it was realized that none +of the callers of get_files_struct fundamentally needed to call +get_files_struct, and that by switching them to helper functions +instead it will both simplify their code and remove unnecessary +increments of files_struct.count. Those unnecessary increments can +result in exec unnecessarily unsharing files_struct which breaking +posix locks, and it can result in fget_light having to fallback to +fget reducing system performance. + +Using task_lookup_next_fd_rcu simplifies proc_readfd_common, by moving +the checking for the maximum file descritor into the generic code, and +by remvoing the need for capturing and releasing a reference on +files_struct. + +As task_lookup_fd_rcu may update the fd ctx->pos has been changed +to be the fd +2 after task_lookup_fd_rcu returns. + +[1] https://lkml.kernel.org/r/20180915160423.GA31461@redhat.com +Suggested-by: Oleg Nesterov +Tested-by: Andy Lavr +v1: https://lkml.kernel.org/r/20200817220425.9389-10-ebiederm@xmission.com +Link: https://lkml.kernel.org/r/20201120231441.29911-15-ebiederm@xmission.com +Signed-off-by: Eric W. Biederman +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/proc/fd.c | 17 +++++------------ + 1 file changed, 5 insertions(+), 12 deletions(-) + +diff --git a/fs/proc/fd.c b/fs/proc/fd.c +index c1a984f3c4df7..72c1525b4b3eb 100644 +--- a/fs/proc/fd.c ++++ b/fs/proc/fd.c +@@ -217,7 +217,6 @@ static int proc_readfd_common(struct file *file, struct dir_context *ctx, + instantiate_t instantiate) + { + struct task_struct *p = get_proc_task(file_inode(file)); +- struct files_struct *files; + unsigned int fd; + + if (!p) +@@ -225,22 +224,18 @@ static int proc_readfd_common(struct file *file, struct dir_context *ctx, + + if (!dir_emit_dots(file, ctx)) + goto out; +- files = get_files_struct(p); +- if (!files) +- goto out; + + rcu_read_lock(); +- for (fd = ctx->pos - 2; +- fd < files_fdtable(files)->max_fds; +- fd++, ctx->pos++) { ++ for (fd = ctx->pos - 2;; fd++) { + struct file *f; + struct fd_data data; + char name[10 + 1]; + unsigned int len; + +- f = files_lookup_fd_rcu(files, fd); ++ f = task_lookup_next_fd_rcu(p, &fd); ++ ctx->pos = fd + 2LL; + if (!f) +- continue; ++ break; + data.mode = f->f_mode; + rcu_read_unlock(); + data.fd = fd; +@@ -249,13 +244,11 @@ static int proc_readfd_common(struct file *file, struct dir_context *ctx, + if (!proc_fill_cache(file, ctx, + name, len, instantiate, p, + &data)) +- goto out_fd_loop; ++ goto out; + cond_resched(); + rcu_read_lock(); + } + rcu_read_unlock(); +-out_fd_loop: +- put_files_struct(files); + out: + put_task_struct(p); + return 0; +-- +2.43.0 + diff --git a/queue-5.10/proc-fd-in-tid_fd_mode-use-task_lookup_fd_rcu.patch b/queue-5.10/proc-fd-in-tid_fd_mode-use-task_lookup_fd_rcu.patch new file mode 100644 index 00000000000..c71cf933855 --- /dev/null +++ b/queue-5.10/proc-fd-in-tid_fd_mode-use-task_lookup_fd_rcu.patch @@ -0,0 +1,62 @@ +From 27156237a0ae577259cc83bbbdf588ae3be3711c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 20 Nov 2020 17:14:29 -0600 +Subject: proc/fd: In tid_fd_mode use task_lookup_fd_rcu + +From: Eric W. Biederman + +[ Upstream commit 64eb661fda0269276b4c46965832938e3f268268 ] + +When discussing[1] exec and posix file locks it was realized that none +of the callers of get_files_struct fundamentally needed to call +get_files_struct, and that by switching them to helper functions +instead it will both simplify their code and remove unnecessary +increments of files_struct.count. Those unnecessary increments can +result in exec unnecessarily unsharing files_struct which breaking +posix locks, and it can result in fget_light having to fallback to +fget reducing system performance. + +Instead of manually coding finding the files struct for a task and +then calling files_lookup_fd_rcu, use the helper task_lookup_fd_rcu +that combines those to steps. Making the code simpler and removing +the need to get a reference on a files_struct. + +[1] https://lkml.kernel.org/r/20180915160423.GA31461@redhat.com +Suggested-by: Oleg Nesterov +Acked-by: Christian Brauner +v1: https://lkml.kernel.org/r/20200817220425.9389-7-ebiederm@xmission.com +Link: https://lkml.kernel.org/r/20201120231441.29911-12-ebiederm@xmission.com +Signed-off-by: Eric W. Biederman +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/proc/fd.c | 7 +------ + 1 file changed, 1 insertion(+), 6 deletions(-) + +diff --git a/fs/proc/fd.c b/fs/proc/fd.c +index 3dec44d7c5c5c..c1a984f3c4df7 100644 +--- a/fs/proc/fd.c ++++ b/fs/proc/fd.c +@@ -83,18 +83,13 @@ static const struct file_operations proc_fdinfo_file_operations = { + + static bool tid_fd_mode(struct task_struct *task, unsigned fd, fmode_t *mode) + { +- struct files_struct *files = get_files_struct(task); + struct file *file; + +- if (!files) +- return false; +- + rcu_read_lock(); +- file = files_lookup_fd_rcu(files, fd); ++ file = task_lookup_fd_rcu(task, fd); + if (file) + *mode = file->f_mode; + rcu_read_unlock(); +- put_files_struct(files); + return !!file; + } + +-- +2.43.0 + diff --git a/queue-5.10/revert-fanotify-limit-number-of-event-merge-attempts.patch b/queue-5.10/revert-fanotify-limit-number-of-event-merge-attempts.patch new file mode 100644 index 00000000000..ab556cb1bbb --- /dev/null +++ b/queue-5.10/revert-fanotify-limit-number-of-event-merge-attempts.patch @@ -0,0 +1,50 @@ +From f876d945cd6f8cfb878a6ae880b4dc24620de580 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 7 Mar 2024 09:22:43 -0500 +Subject: Revert "fanotify: limit number of event merge attempts" + +From: Chuck Lever + +Temporarily revert commit ad3ea16746cc ("fanotify: limit number of +event merge attempts") to enable subsequent upstream commits to +apply and build cleanly. + +Stable-dep-of: 8988f11abb82 ("fanotify: reduce event objectid to 29-bit hash") +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/notify/fanotify/fanotify.c | 6 ------ + 1 file changed, 6 deletions(-) + +diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c +index c3af99e94f1d1..1192c99536200 100644 +--- a/fs/notify/fanotify/fanotify.c ++++ b/fs/notify/fanotify/fanotify.c +@@ -129,15 +129,11 @@ static bool fanotify_should_merge(struct fsnotify_event *old_fsn, + return false; + } + +-/* Limit event merges to limit CPU overhead per event */ +-#define FANOTIFY_MAX_MERGE_EVENTS 128 +- + /* and the list better be locked by something too! */ + static int fanotify_merge(struct list_head *list, struct fsnotify_event *event) + { + struct fsnotify_event *test_event; + struct fanotify_event *new; +- int i = 0; + + pr_debug("%s: list=%p event=%p\n", __func__, list, event); + new = FANOTIFY_E(event); +@@ -151,8 +147,6 @@ static int fanotify_merge(struct list_head *list, struct fsnotify_event *event) + return 0; + + list_for_each_entry_reverse(test_event, list, list) { +- if (++i > FANOTIFY_MAX_MERGE_EVENTS) +- break; + if (fanotify_should_merge(test_event, event)) { + FANOTIFY_E(test_event)->mask |= new->mask; + return 1; +-- +2.43.0 + diff --git a/queue-5.10/revert-fget-clarify-and-improve-__fget_files-impleme.patch b/queue-5.10/revert-fget-clarify-and-improve-__fget_files-impleme.patch new file mode 100644 index 00000000000..07237f0827d --- /dev/null +++ b/queue-5.10/revert-fget-clarify-and-improve-__fget_files-impleme.patch @@ -0,0 +1,110 @@ +From e7593c2535bdbb634b5108f38521a35e35fac48d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 29 Feb 2024 18:19:36 -0500 +Subject: Revert "fget: clarify and improve __fget_files() implementation" + +From: Chuck Lever + +Temporarily revert commit 0849f83e4782 ("fget: clarify and improve +__fget_files() implementation") to enable subsequent upstream +commits to apply and build cleanly. + +Stable-dep-of: bebf684bf330 ("file: Rename __fcheck_files to files_lookup_fd_raw") +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/file.c | 72 +++++++++++++------------------------------------------ + 1 file changed, 16 insertions(+), 56 deletions(-) + +diff --git a/fs/file.c b/fs/file.c +index 5065252bb474e..fea693acc065e 100644 +--- a/fs/file.c ++++ b/fs/file.c +@@ -849,68 +849,28 @@ void do_close_on_exec(struct files_struct *files) + spin_unlock(&files->file_lock); + } + +-static inline struct file *__fget_files_rcu(struct files_struct *files, +- unsigned int fd, fmode_t mask, unsigned int refs) +-{ +- for (;;) { +- struct file *file; +- struct fdtable *fdt = rcu_dereference_raw(files->fdt); +- struct file __rcu **fdentry; +- +- if (unlikely(fd >= fdt->max_fds)) +- return NULL; +- +- fdentry = fdt->fd + array_index_nospec(fd, fdt->max_fds); +- file = rcu_dereference_raw(*fdentry); +- if (unlikely(!file)) +- return NULL; +- +- if (unlikely(file->f_mode & mask)) +- return NULL; +- +- /* +- * Ok, we have a file pointer. However, because we do +- * this all locklessly under RCU, we may be racing with +- * that file being closed. +- * +- * Such a race can take two forms: +- * +- * (a) the file ref already went down to zero, +- * and get_file_rcu_many() fails. Just try +- * again: +- */ +- if (unlikely(!get_file_rcu_many(file, refs))) +- continue; +- +- /* +- * (b) the file table entry has changed under us. +- * Note that we don't need to re-check the 'fdt->fd' +- * pointer having changed, because it always goes +- * hand-in-hand with 'fdt'. +- * +- * If so, we need to put our refs and try again. +- */ +- if (unlikely(rcu_dereference_raw(files->fdt) != fdt) || +- unlikely(rcu_dereference_raw(*fdentry) != file)) { +- fput_many(file, refs); +- continue; +- } +- +- /* +- * Ok, we have a ref to the file, and checked that it +- * still exists. +- */ +- return file; +- } +-} +- + static struct file *__fget_files(struct files_struct *files, unsigned int fd, + fmode_t mask, unsigned int refs) + { + struct file *file; + + rcu_read_lock(); +- file = __fget_files_rcu(files, fd, mask, refs); ++loop: ++ file = fcheck_files(files, fd); ++ if (file) { ++ /* File object ref couldn't be taken. ++ * dup2() atomicity guarantee is the reason ++ * we loop to catch the new file (or NULL pointer) ++ */ ++ if (file->f_mode & mask) ++ file = NULL; ++ else if (!get_file_rcu_many(file, refs)) ++ goto loop; ++ else if (__fcheck_files(files, fd) != file) { ++ fput_many(file, refs); ++ goto loop; ++ } ++ } + rcu_read_unlock(); + + return file; +-- +2.43.0 + diff --git a/queue-5.10/revert-nfsd-skip-some-unnecessary-stats-in-the-v4-ca.patch b/queue-5.10/revert-nfsd-skip-some-unnecessary-stats-in-the-v4-ca.patch new file mode 100644 index 00000000000..552182ee297 --- /dev/null +++ b/queue-5.10/revert-nfsd-skip-some-unnecessary-stats-in-the-v4-ca.patch @@ -0,0 +1,141 @@ +From e55aa271cc61d2d595617f2a99a13d03c70a9de0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Dec 2021 14:22:28 -0500 +Subject: Revert "nfsd: skip some unnecessary stats in the v4 case" + +From: Chuck Lever + +[ Upstream commit 58f258f65267542959487dbe8b5641754411843d ] + +On the wire, I observed NFSv4 OPEN(CREATE) operations sometimes +returning a reasonable-looking value in the cinfo.before field and +zero in the cinfo.after field. + +RFC 8881 Section 10.8.1 says: +> When a client is making changes to a given directory, it needs to +> determine whether there have been changes made to the directory by +> other clients. It does this by using the change attribute as +> reported before and after the directory operation in the associated +> change_info4 value returned for the operation. + +and + +> ... The post-operation change +> value needs to be saved as the basis for future change_info4 +> comparisons. + +A good quality client implementation therefore saves the zero +cinfo.after value. During a subsequent OPEN operation, it will +receive a different non-zero value in the cinfo.before field for +that directory, and it will incorrectly believe the directory has +changed, triggering an undesirable directory cache invalidation. + +There are filesystem types where fs_supports_change_attribute() +returns false, tmpfs being one. On NFSv4 mounts, this means the +fh_getattr() call site in fill_pre_wcc() and fill_post_wcc() is +never invoked. Subsequently, nfsd4_change_attribute() is invoked +with an uninitialized @stat argument. + +In fill_pre_wcc(), @stat contains stale stack garbage, which is +then placed on the wire. In fill_post_wcc(), ->fh_post_wc is all +zeroes, so zero is placed on the wire. Both of these values are +meaningless. + +This fix can be applied immediately to stable kernels. Once there +are more regression tests in this area, this optimization can be +attempted again. + +Fixes: 428a23d2bf0c ("nfsd: skip some unnecessary stats in the v4 case") +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs3xdr.c | 44 +++++++++++++++++--------------------------- + 1 file changed, 17 insertions(+), 27 deletions(-) + +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index c3ac1b6aa3aaa..84088581bbe09 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -487,11 +487,6 @@ svcxdr_encode_wcc_data(struct svc_rqst *rqstp, struct xdr_stream *xdr, + return true; + } + +-static bool fs_supports_change_attribute(struct super_block *sb) +-{ +- return sb->s_flags & SB_I_VERSION || sb->s_export_op->fetch_iversion; +-} +- + /* + * Fill in the pre_op attr for the wcc data + */ +@@ -500,26 +495,24 @@ void fill_pre_wcc(struct svc_fh *fhp) + struct inode *inode; + struct kstat stat; + bool v4 = (fhp->fh_maxsize == NFS4_FHSIZE); ++ __be32 err; + + if (fhp->fh_no_wcc || fhp->fh_pre_saved) + return; + inode = d_inode(fhp->fh_dentry); +- if (fs_supports_change_attribute(inode->i_sb) || !v4) { +- __be32 err = fh_getattr(fhp, &stat); +- +- if (err) { +- /* Grab the times from inode anyway */ +- stat.mtime = inode->i_mtime; +- stat.ctime = inode->i_ctime; +- stat.size = inode->i_size; +- } +- fhp->fh_pre_mtime = stat.mtime; +- fhp->fh_pre_ctime = stat.ctime; +- fhp->fh_pre_size = stat.size; ++ err = fh_getattr(fhp, &stat); ++ if (err) { ++ /* Grab the times from inode anyway */ ++ stat.mtime = inode->i_mtime; ++ stat.ctime = inode->i_ctime; ++ stat.size = inode->i_size; + } + if (v4) + fhp->fh_pre_change = nfsd4_change_attribute(&stat, inode); + ++ fhp->fh_pre_mtime = stat.mtime; ++ fhp->fh_pre_ctime = stat.ctime; ++ fhp->fh_pre_size = stat.size; + fhp->fh_pre_saved = true; + } + +@@ -530,6 +523,7 @@ void fill_post_wcc(struct svc_fh *fhp) + { + bool v4 = (fhp->fh_maxsize == NFS4_FHSIZE); + struct inode *inode = d_inode(fhp->fh_dentry); ++ __be32 err; + + if (fhp->fh_no_wcc) + return; +@@ -537,16 +531,12 @@ void fill_post_wcc(struct svc_fh *fhp) + if (fhp->fh_post_saved) + printk("nfsd: inode locked twice during operation.\n"); + +- fhp->fh_post_saved = true; +- +- if (fs_supports_change_attribute(inode->i_sb) || !v4) { +- __be32 err = fh_getattr(fhp, &fhp->fh_post_attr); +- +- if (err) { +- fhp->fh_post_saved = false; +- fhp->fh_post_attr.ctime = inode->i_ctime; +- } +- } ++ err = fh_getattr(fhp, &fhp->fh_post_attr); ++ if (err) { ++ fhp->fh_post_saved = false; ++ fhp->fh_post_attr.ctime = inode->i_ctime; ++ } else ++ fhp->fh_post_saved = true; + if (v4) + fhp->fh_post_change = + nfsd4_change_attribute(&fhp->fh_post_attr, inode); +-- +2.43.0 + diff --git a/queue-5.10/revert-nfsd4-support-change_attr_type-attribute.patch b/queue-5.10/revert-nfsd4-support-change_attr_type-attribute.patch new file mode 100644 index 00000000000..aa0a1bc2bcd --- /dev/null +++ b/queue-5.10/revert-nfsd4-support-change_attr_type-attribute.patch @@ -0,0 +1,91 @@ +From 40ce5f4d98f4e42c443b820a58de43da855f7db0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 30 Nov 2020 17:46:18 -0500 +Subject: Revert "nfsd4: support change_attr_type attribute" + +From: J. Bruce Fields + +This reverts commit a85857633b04d57f4524cca0a2bfaf87b2543f9f. + +We're still factoring ctime into our change attribute even in the +IS_I_VERSION case. If someone sets the system time backwards, a client +could see the change attribute go backwards. Maybe we can just say +"well, don't do that", but there's some question whether that's good +enough, or whether we need a better guarantee. + +Also, the client still isn't actually using the attribute. + +While we're still figuring this out, let's just stop returning this +attribute. + +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 10 ---------- + fs/nfsd/nfsd.h | 1 - + include/linux/nfs4.h | 8 -------- + 3 files changed, 19 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 4df6c75d0eb7f..bb037e8eb8304 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -3311,16 +3311,6 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, + goto out; + } + +- if (bmval2 & FATTR4_WORD2_CHANGE_ATTR_TYPE) { +- p = xdr_reserve_space(xdr, 4); +- if (!p) +- goto out_resource; +- if (IS_I_VERSION(d_inode(dentry))) +- *p++ = cpu_to_be32(NFS4_CHANGE_TYPE_IS_MONOTONIC_INCR); +- else +- *p++ = cpu_to_be32(NFS4_CHANGE_TYPE_IS_TIME_METADATA); +- } +- + #ifdef CONFIG_NFSD_V4_SECURITY_LABEL + if (bmval2 & FATTR4_WORD2_SECURITY_LABEL) { + status = nfsd4_encode_security_label(xdr, rqstp, context, +diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h +index 3eaa81e001f9c..2326428e2c5bf 100644 +--- a/fs/nfsd/nfsd.h ++++ b/fs/nfsd/nfsd.h +@@ -394,7 +394,6 @@ void nfsd_lockd_shutdown(void); + + #define NFSD4_2_SUPPORTED_ATTRS_WORD2 \ + (NFSD4_1_SUPPORTED_ATTRS_WORD2 | \ +- FATTR4_WORD2_CHANGE_ATTR_TYPE | \ + FATTR4_WORD2_MODE_UMASK | \ + NFSD4_2_SECURITY_ATTRS | \ + FATTR4_WORD2_XATTR_SUPPORT) +diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h +index 9dc7eeac924f0..5b4c67c91f56a 100644 +--- a/include/linux/nfs4.h ++++ b/include/linux/nfs4.h +@@ -385,13 +385,6 @@ enum lock_type4 { + NFS4_WRITEW_LT = 4 + }; + +-enum change_attr_type4 { +- NFS4_CHANGE_TYPE_IS_MONOTONIC_INCR = 0, +- NFS4_CHANGE_TYPE_IS_VERSION_COUNTER = 1, +- NFS4_CHANGE_TYPE_IS_VERSION_COUNTER_NOPNFS = 2, +- NFS4_CHANGE_TYPE_IS_TIME_METADATA = 3, +- NFS4_CHANGE_TYPE_IS_UNDEFINED = 4 +-}; + + /* Mandatory Attributes */ + #define FATTR4_WORD0_SUPPORTED_ATTRS (1UL << 0) +@@ -459,7 +452,6 @@ enum change_attr_type4 { + #define FATTR4_WORD2_LAYOUT_BLKSIZE (1UL << 1) + #define FATTR4_WORD2_MDSTHRESHOLD (1UL << 4) + #define FATTR4_WORD2_CLONE_BLKSIZE (1UL << 13) +-#define FATTR4_WORD2_CHANGE_ATTR_TYPE (1UL << 15) + #define FATTR4_WORD2_SECURITY_LABEL (1UL << 16) + #define FATTR4_WORD2_MODE_UMASK (1UL << 17) + #define FATTR4_WORD2_XATTR_SUPPORT (1UL << 18) +-- +2.43.0 + diff --git a/queue-5.10/revert-sunrpc-use-rmw-bitops-in-single-threaded-hot-.patch b/queue-5.10/revert-sunrpc-use-rmw-bitops-in-single-threaded-hot-.patch new file mode 100644 index 00000000000..514f9a08a73 --- /dev/null +++ b/queue-5.10/revert-sunrpc-use-rmw-bitops-in-single-threaded-hot-.patch @@ -0,0 +1,176 @@ +From 361540383da6208081273f6cf41a8394b14ce57d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 6 Jan 2023 12:43:37 -0500 +Subject: Revert "SUNRPC: Use RMW bitops in single-threaded hot paths" + +From: Chuck Lever + +[ Upstream commit 7827c81f0248e3c2f40d438b020f3d222f002171 ] + +The premise that "Once an svc thread is scheduled and executing an +RPC, no other processes will touch svc_rqst::rq_flags" is false. +svc_xprt_enqueue() examines the RQ_BUSY flag in scheduled nfsd +threads when determining which thread to wake up next. + +Found via KCSAN. + +Fixes: 28df0988815f ("SUNRPC: Use RMW bitops in single-threaded hot paths") +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 7 +++---- + fs/nfsd/nfs4xdr.c | 2 +- + net/sunrpc/auth_gss/svcauth_gss.c | 4 ++-- + net/sunrpc/svc.c | 6 +++--- + net/sunrpc/svc_xprt.c | 2 +- + net/sunrpc/svcsock.c | 8 ++++---- + net/sunrpc/xprtrdma/svc_rdma_transport.c | 2 +- + 7 files changed, 15 insertions(+), 16 deletions(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index cf558d951ec68..a89f98fa3a9d0 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -937,7 +937,7 @@ nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + * the client wants us to do more in this compound: + */ + if (!nfsd4_last_compound_op(rqstp)) +- __clear_bit(RQ_SPLICE_OK, &rqstp->rq_flags); ++ clear_bit(RQ_SPLICE_OK, &rqstp->rq_flags); + + /* check stateid */ + status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh, +@@ -2609,12 +2609,11 @@ nfsd4_proc_compound(struct svc_rqst *rqstp) + cstate->minorversion = args->minorversion; + fh_init(current_fh, NFS4_FHSIZE); + fh_init(save_fh, NFS4_FHSIZE); +- + /* + * Don't use the deferral mechanism for NFSv4; compounds make it + * too hard to avoid non-idempotency problems. + */ +- __clear_bit(RQ_USEDEFERRAL, &rqstp->rq_flags); ++ clear_bit(RQ_USEDEFERRAL, &rqstp->rq_flags); + + /* + * According to RFC3010, this takes precedence over all other errors. +@@ -2736,7 +2735,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp) + out: + cstate->status = status; + /* Reset deferral mechanism for RPC deferrals */ +- __set_bit(RQ_USEDEFERRAL, &rqstp->rq_flags); ++ set_bit(RQ_USEDEFERRAL, &rqstp->rq_flags); + return rpc_success; + } + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 8bbf85da1de05..d0b9fbf189ac6 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -2523,7 +2523,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) + argp->rqstp->rq_cachetype = cachethis ? RC_REPLBUFF : RC_NOCACHE; + + if (readcount > 1 || max_reply > PAGE_SIZE - auth_slack) +- __clear_bit(RQ_SPLICE_OK, &argp->rqstp->rq_flags); ++ clear_bit(RQ_SPLICE_OK, &argp->rqstp->rq_flags); + + return true; + } +diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c +index abaa952ae7518..329eac782cc5e 100644 +--- a/net/sunrpc/auth_gss/svcauth_gss.c ++++ b/net/sunrpc/auth_gss/svcauth_gss.c +@@ -898,7 +898,7 @@ unwrap_integ_data(struct svc_rqst *rqstp, struct xdr_buf *buf, u32 seq, struct g + * rejecting the server-computed MIC in this somewhat rare case, + * do not use splice with the GSS integrity service. + */ +- __clear_bit(RQ_SPLICE_OK, &rqstp->rq_flags); ++ clear_bit(RQ_SPLICE_OK, &rqstp->rq_flags); + + /* Did we already verify the signature on the original pass through? */ + if (rqstp->rq_deferred) +@@ -970,7 +970,7 @@ unwrap_priv_data(struct svc_rqst *rqstp, struct xdr_buf *buf, u32 seq, struct gs + int pad, remaining_len, offset; + u32 rseqno; + +- __clear_bit(RQ_SPLICE_OK, &rqstp->rq_flags); ++ clear_bit(RQ_SPLICE_OK, &rqstp->rq_flags); + + priv_len = svc_getnl(&buf->head[0]); + if (rqstp->rq_deferred) { +diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c +index 8c29181796492..26d972c54a593 100644 +--- a/net/sunrpc/svc.c ++++ b/net/sunrpc/svc.c +@@ -1276,10 +1276,10 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv) + goto err_short_len; + + /* Will be turned off by GSS integrity and privacy services */ +- __set_bit(RQ_SPLICE_OK, &rqstp->rq_flags); ++ set_bit(RQ_SPLICE_OK, &rqstp->rq_flags); + /* Will be turned off only when NFSv4 Sessions are used */ +- __set_bit(RQ_USEDEFERRAL, &rqstp->rq_flags); +- __clear_bit(RQ_DROPME, &rqstp->rq_flags); ++ set_bit(RQ_USEDEFERRAL, &rqstp->rq_flags); ++ clear_bit(RQ_DROPME, &rqstp->rq_flags); + + svc_putu32(resv, rqstp->rq_xid); + +diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c +index ea65036dc5068..000b737784bd9 100644 +--- a/net/sunrpc/svc_xprt.c ++++ b/net/sunrpc/svc_xprt.c +@@ -1228,7 +1228,7 @@ static struct cache_deferred_req *svc_defer(struct cache_req *req) + trace_svc_defer(rqstp); + svc_xprt_get(rqstp->rq_xprt); + dr->xprt = rqstp->rq_xprt; +- __set_bit(RQ_DROPME, &rqstp->rq_flags); ++ set_bit(RQ_DROPME, &rqstp->rq_flags); + + dr->handle.revisit = svc_revisit; + return &dr->handle; +diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c +index ff8dcebbdfc4e..90f6231d6ed67 100644 +--- a/net/sunrpc/svcsock.c ++++ b/net/sunrpc/svcsock.c +@@ -309,9 +309,9 @@ static void svc_sock_setbufsize(struct svc_sock *svsk, unsigned int nreqs) + static void svc_sock_secure_port(struct svc_rqst *rqstp) + { + if (svc_port_is_privileged(svc_addr(rqstp))) +- __set_bit(RQ_SECURE, &rqstp->rq_flags); ++ set_bit(RQ_SECURE, &rqstp->rq_flags); + else +- __clear_bit(RQ_SECURE, &rqstp->rq_flags); ++ clear_bit(RQ_SECURE, &rqstp->rq_flags); + } + + /* +@@ -1014,9 +1014,9 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) + rqstp->rq_xprt_ctxt = NULL; + rqstp->rq_prot = IPPROTO_TCP; + if (test_bit(XPT_LOCAL, &svsk->sk_xprt.xpt_flags)) +- __set_bit(RQ_LOCAL, &rqstp->rq_flags); ++ set_bit(RQ_LOCAL, &rqstp->rq_flags); + else +- __clear_bit(RQ_LOCAL, &rqstp->rq_flags); ++ clear_bit(RQ_LOCAL, &rqstp->rq_flags); + + p = (__be32 *)rqstp->rq_arg.head[0].iov_base; + calldir = p[1]; +diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c +index e72e36989985f..c895f80df659c 100644 +--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c ++++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c +@@ -606,7 +606,7 @@ static int svc_rdma_has_wspace(struct svc_xprt *xprt) + + static void svc_rdma_secure_port(struct svc_rqst *rqstp) + { +- __set_bit(RQ_SECURE, &rqstp->rq_flags); ++ set_bit(RQ_SECURE, &rqstp->rq_flags); + } + + static void svc_rdma_kill_temp_xprt(struct svc_xprt *xprt) +-- +2.43.0 + diff --git a/queue-5.10/series b/queue-5.10/series index e69de29bb2d..5a93e76a534 100644 --- a/queue-5.10/series +++ b/queue-5.10/series @@ -0,0 +1,770 @@ +sunrpc-rename-svc_encode_read_payload.patch +nfsd-invoke-svc_encode_result_payload-in-read-nfsd-e.patch +nfsd-a-semicolon-is-not-needed-after-a-switch-statem.patch +nfsd-nfs3-remove-unused-macro-nfsd3_fhandleres.patch +nfsd-clean-up-the-show_nf_may-macro.patch +nfsd-remove-extra-0x-in-tracepoint-format-specifier.patch +nfsd-add-spdx-header-for-fs-nfsd-trace.c.patch +nfsd-fix-error-return-code-in-nfsd_file_cache_init.patch +sunrpc-add-xdr_set_scratch_page-and-xdr_reset_scratc.patch +sunrpc-prepare-for-xdr_stream-style-decoding-on-the-.patch +nfsd-add-common-helpers-to-decode-void-args-and-enco.patch +nfsd-add-tracepoints-in-nfsd_dispatch.patch +nfsd-add-tracepoints-in-nfsd4_decode-encode_compound.patch +nfsd-replace-the-internals-of-the-read_buf-macro.patch +nfsd-replace-read-macros-in-nfsd4_decode_access.patch +nfsd-replace-read-macros-in-nfsd4_decode_close.patch +nfsd-replace-read-macros-in-nfsd4_decode_commit.patch +nfsd-change-the-way-the-expected-length-of-a-fattr4-.patch +nfsd-replace-read-macros-that-decode-the-fattr4-size.patch +nfsd-replace-read-macros-that-decode-the-fattr4-acl-.patch +nfsd-replace-read-macros-that-decode-the-fattr4-mode.patch +nfsd-replace-read-macros-that-decode-the-fattr4-owne.patch +nfsd-replace-read-macros-that-decode-the-fattr4-owne.patch-23903 +nfsd-replace-read-macros-that-decode-the-fattr4-time.patch +nfsd-replace-read-macros-that-decode-the-fattr4-secu.patch +nfsd-replace-read-macros-that-decode-the-fattr4-umas.patch +nfsd-replace-read-macros-in-nfsd4_decode_fattr.patch +nfsd-replace-read-macros-in-nfsd4_decode_create.patch +nfsd-replace-read-macros-in-nfsd4_decode_delegreturn.patch +nfsd-replace-read-macros-in-nfsd4_decode_getattr.patch +nfsd-replace-read-macros-in-nfsd4_decode_link.patch +nfsd-relocate-nfsd4_decode_opaque.patch +nfsd-add-helpers-to-decode-a-clientid4-and-an-nfsv4-.patch +nfsd-add-helper-for-decoding-locker4.patch +nfsd-replace-read-macros-in-nfsd4_decode_lock.patch +nfsd-replace-read-macros-in-nfsd4_decode_lockt.patch +nfsd-replace-read-macros-in-nfsd4_decode_locku.patch +nfsd-replace-read-macros-in-nfsd4_decode_lookup.patch +nfsd-add-helper-to-decode-nfsv4-verifiers.patch +nfsd-add-helper-to-decode-open-s-createhow4-argument.patch +nfsd-add-helper-to-decode-open-s-openflag4-argument.patch +nfsd-replace-read-macros-in-nfsd4_decode_share_acces.patch +nfsd-replace-read-macros-in-nfsd4_decode_share_deny.patch +nfsd-add-helper-to-decode-open-s-open_claim4-argumen.patch +nfsd-replace-read-macros-in-nfsd4_decode_open.patch +nfsd-replace-read-macros-in-nfsd4_decode_open_confir.patch +nfsd-replace-read-macros-in-nfsd4_decode_open_downgr.patch +nfsd-replace-read-macros-in-nfsd4_decode_putfh.patch +nfsd-replace-read-macros-in-nfsd4_decode_read.patch +nfsd-replace-read-macros-in-nfsd4_decode_readdir.patch +nfsd-replace-read-macros-in-nfsd4_decode_remove.patch +nfsd-replace-read-macros-in-nfsd4_decode_rename.patch +nfsd-replace-read-macros-in-nfsd4_decode_renew.patch +nfsd-replace-read-macros-in-nfsd4_decode_secinfo.patch +nfsd-replace-read-macros-in-nfsd4_decode_setattr.patch +nfsd-replace-read-macros-in-nfsd4_decode_setclientid.patch +nfsd-replace-read-macros-in-nfsd4_decode_setclientid.patch-10977 +nfsd-replace-read-macros-in-nfsd4_decode_verify.patch +nfsd-replace-read-macros-in-nfsd4_decode_write.patch +nfsd-replace-read-macros-in-nfsd4_decode_release_loc.patch +nfsd-replace-read-macros-in-nfsd4_decode_cb_sec.patch +nfsd-replace-read-macros-in-nfsd4_decode_backchannel.patch +nfsd-replace-read-macros-in-nfsd4_decode_bind_conn_t.patch +nfsd-add-a-separate-decoder-to-handle-state_protect_.patch +nfsd-add-a-separate-decoder-for-ssv_sp_parms.patch +nfsd-add-a-helper-to-decode-state_protect4_a.patch +nfsd-add-a-helper-to-decode-nfs_impl_id4.patch +nfsd-add-a-helper-to-decode-channel_attrs4.patch +nfsd-replace-read-macros-in-nfsd4_decode_create_sess.patch +nfsd-replace-read-macros-in-nfsd4_decode_destroy_ses.patch +nfsd-replace-read-macros-in-nfsd4_decode_free_statei.patch +nfsd-replace-read-macros-in-nfsd4_decode_getdevicein.patch +nfsd-replace-read-macros-in-nfsd4_decode_layoutcommi.patch +nfsd-replace-read-macros-in-nfsd4_decode_layoutget.patch +nfsd-replace-read-macros-in-nfsd4_decode_layoutretur.patch +nfsd-replace-read-macros-in-nfsd4_decode_secinfo_no_.patch +nfsd-replace-read-macros-in-nfsd4_decode_sequence.patch +nfsd-replace-read-macros-in-nfsd4_decode_test_statei.patch +nfsd-replace-read-macros-in-nfsd4_decode_destroy_cli.patch +nfsd-replace-read-macros-in-nfsd4_decode_reclaim_com.patch +nfsd-replace-read-macros-in-nfsd4_decode_fallocate.patch +nfsd-replace-read-macros-in-nfsd4_decode_nl4_server.patch +nfsd-replace-read-macros-in-nfsd4_decode_copy.patch +nfsd-replace-read-macros-in-nfsd4_decode_copy_notify.patch +nfsd-replace-read-macros-in-nfsd4_decode_offload_sta.patch +nfsd-replace-read-macros-in-nfsd4_decode_seek.patch +nfsd-replace-read-macros-in-nfsd4_decode_clone.patch +nfsd-replace-read-macros-in-nfsd4_decode_xattr_name.patch +nfsd-replace-read-macros-in-nfsd4_decode_setxattr.patch +nfsd-replace-read-macros-in-nfsd4_decode_listxattrs.patch +nfsd-make-nfsd4_ops-opnum-a-u32.patch +nfsd-replace-read-macros-in-nfsd4_decode_compound.patch +nfsd-remove-macros-that-are-no-longer-used.patch +nfsd-only-call-inode_query_iversion-in-the-i_version.patch +nfsd-simplify-nfsd4_change_info.patch +nfsd-minor-nfsd4_change_attribute-cleanup.patch +nfsd4-don-t-query-change-attribute-in-v2-v3-case.patch +revert-nfsd4-support-change_attr_type-attribute.patch +nfsd-add-a-new-export_op_nowcc-flag-to-struct-export.patch +nfsd-allow-filesystems-to-opt-out-of-subtree-checkin.patch +nfsd-close-cached-files-prior-to-a-remove-or-rename-.patch +exportfs-add-a-function-to-return-the-raw-output-fro.patch +nfsd-fix-up-nfsd-to-ensure-that-timeout-errors-don-t.patch +nfsd-set-pf_local_throttle-on-local-filesystems-only.patch +nfsd-record-nfsv4-pre-post-op-attributes-as-non-atom.patch +exec-don-t-open-code-get_close_on_exec.patch +exec-move-unshare_files-to-fix-posix-file-locking-du.patch +exec-simplify-unshare_files.patch +exec-remove-reset_files_struct.patch +kcmp-in-kcmp_epoll_target-use-fget_task.patch +bpf-in-bpf_task_fd_query-use-fget_task.patch +proc-fd-in-proc_fd_link-use-fget_task.patch +revert-fget-clarify-and-improve-__fget_files-impleme.patch +file-rename-__fcheck_files-to-files_lookup_fd_raw.patch +file-factor-files_lookup_fd_locked-out-of-fcheck_fil.patch +file-replace-fcheck_files-with-files_lookup_fd_rcu.patch +file-rename-fcheck-lookup_fd_rcu.patch +file-implement-task_lookup_fd_rcu.patch +proc-fd-in-tid_fd_mode-use-task_lookup_fd_rcu.patch +kcmp-in-get_file_raw_ptr-use-task_lookup_fd_rcu.patch +file-implement-task_lookup_next_fd_rcu.patch +proc-fd-in-proc_readfd_common-use-task_lookup_next_f.patch +proc-fd-in-fdinfo-seq_show-don-t-use-get_files_struc.patch +file-merge-__fd_install-into-fd_install.patch +file-in-f_dupfd-read-rlimit_nofile-once.patch +file-merge-__alloc_fd-into-alloc_fd.patch +file-rename-__close_fd-to-close_fd-and-remove-the-fi.patch +file-replace-ksys_close-with-close_fd.patch +inotify-increase-default-inotify.max_user_watches-li.patch +fs-lockd-convert-comma-to-semicolon.patch +nfsd-fix-sparse-warning-in-nfssvc.c.patch +nfsd-restore-nfsv4-decoding-s-savemem-functionality.patch +sunrpc-make-trace_svc_process-display-the-rpc-proced.patch +sunrpc-display-rpc-procedure-names-instead-of-proc-n.patch +sunrpc-move-definition-of-xdr_unit.patch +nfsd-update-getattr3args-decoder-to-use-struct-xdr_s.patch +nfsd-update-access3arg-decoder-to-use-struct-xdr_str.patch +nfsd-update-read3arg-decoder-to-use-struct-xdr_strea.patch +nfsd-update-write3arg-decoder-to-use-struct-xdr_stre.patch +nfsd-update-readlink3arg-decoder-to-use-struct-xdr_s.patch +nfsd-fix-returned-readdir-offset-cookie.patch +nfsd-add-helper-to-set-up-the-pages-where-the-dirlis.patch +nfsd-update-readdir3args-decoders-to-use-struct-xdr_.patch +nfsd-update-commit3arg-decoder-to-use-struct-xdr_str.patch +nfsd-update-the-nfsv3-diropargs-decoder-to-use-struc.patch +nfsd-update-the-rename3args-decoder-to-use-struct-xd.patch +nfsd-update-the-link3args-decoder-to-use-struct-xdr_.patch +nfsd-update-the-setattr3args-decoder-to-use-struct-x.patch +nfsd-update-the-create3args-decoder-to-use-struct-xd.patch +nfsd-update-the-mkdir3args-decoder-to-use-struct-xdr.patch +nfsd-update-the-symlink3args-decoder-to-use-struct-x.patch +nfsd-update-the-mknod3args-decoder-to-use-struct-xdr.patch +nfsd-update-the-nfsv2-getattr-argument-decoder-to-us.patch +nfsd-update-the-nfsv2-read-argument-decoder-to-use-s.patch +nfsd-update-the-nfsv2-write-argument-decoder-to-use-.patch +nfsd-update-the-nfsv2-readlink-argument-decoder-to-u.patch +nfsd-add-helper-to-set-up-the-pages-where-the-dirlis.patch-28629 +nfsd-update-the-nfsv2-readdir-argument-decoder-to-us.patch +nfsd-update-nfsv2-diropargs-decoding-to-use-struct-x.patch +nfsd-update-the-nfsv2-rename-argument-decoder-to-use.patch +nfsd-update-the-nfsv2-link-argument-decoder-to-use-s.patch +nfsd-update-the-nfsv2-setattr-argument-decoder-to-us.patch +nfsd-update-the-nfsv2-create-argument-decoder-to-use.patch +nfsd-update-the-nfsv2-symlink-argument-decoder-to-us.patch +nfsd-remove-argument-length-checking-in-nfsd_dispatc.patch +nfsd-update-the-nfsv2-getacl-argument-decoder-to-use.patch +nfsd-add-an-xdr_stream-based-decoder-for-nfsv2-3-acl.patch +nfsd-update-the-nfsv2-setacl-argument-decoder-to-use.patch +nfsd-update-the-nfsv2-acl-getattr-argument-decoder-t.patch +nfsd-update-the-nfsv2-acl-access-argument-decoder-to.patch +nfsd-clean-up-after-updating-nfsv2-acl-decoders.patch +nfsd-update-the-nfsv3-getacl-argument-decoder-to-use.patch +nfsd-update-the-nfsv2-setacl-argument-decoder-to-use.patch-31348 +nfsd-clean-up-after-updating-nfsv3-acl-decoders.patch +nfsd-remove-unused-stats-counters.patch +nfsd-protect-concurrent-access-to-nfsd-stats-counter.patch +nfsd-report-per-export-stats.patch +nfsd4-simplify-process_lookup1.patch +nfsd-simplify-process_lock.patch +nfsd-simplify-nfsd_renew.patch +nfsd-rename-lookup_clientid-set_client.patch +nfsd-refactor-set_client.patch +nfsd-find_cpntf_state-cleanup.patch +nfsd-remove-unused-set_client-argument.patch +nfsd-simplify-nfsd4_check_open_reclaim.patch +nfsd-cstate-session-se_client-cstate-clp.patch +nfsv4_2-ssc-helper-should-use-its-own-config.patch +nfs-use-change-attribute-for-nfs-re-exports.patch +nfsd-skip-some-unnecessary-stats-in-the-v4-case.patch +inotify-memcg-account-inotify-instances-to-kmemcg.patch +module-unexport-find_module-and-module_mutex.patch +module-use-rcu-to-synchronize-find_module.patch +kallsyms-refactor-module_-kallsyms_on_each_symbol.patch +kallsyms-only-build-module_-kallsyms_on_each_symbol-.patch +fs-add-file-and-path-permissions-helpers.patch +namei-introduce-struct-renamedata.patch +nfsd-extract-the-svcxdr_init_encode-helper.patch +nfsd-update-the-getattr3res-encoder-to-use-struct-xd.patch +nfsd-update-the-nfsv3-access3res-encoder-to-use-stru.patch +nfsd-update-the-nfsv3-lookup3res-encoder-to-use-stru.patch +nfsd-update-the-nfsv3-wccstat-result-encoder-to-use-.patch +nfsd-update-the-nfsv3-readlink3res-encoder-to-use-st.patch +nfsd-update-the-nfsv3-read3res-encode-to-use-struct-.patch +nfsd-update-the-nfsv3-write3res-encoder-to-use-struc.patch +nfsd-update-the-nfsv3-create-family-of-encoders-to-u.patch +nfsd-update-the-nfsv3-renamev3res-encoder-to-use-str.patch +nfsd-update-the-nfsv3-link3res-encoder-to-use-struct.patch +nfsd-update-the-nfsv3-fsstat3res-encoder-to-use-stru.patch +nfsd-update-the-nfsv3-fsinfo3res-encoder-to-use-stru.patch +nfsd-update-the-nfsv3-pathconf3res-encoder-to-use-st.patch +nfsd-update-the-nfsv3-commit3res-encoder-to-use-stru.patch +nfsd-add-a-helper-that-encodes-nfsv3-directory-offse.patch +nfsd-count-bytes-instead-of-pages-in-the-nfsv3-readd.patch +nfsd-update-the-nfsv3-readdir3res-encoder-to-use-str.patch +nfsd-update-nfsv3-readdir-entry-encoders-to-use-stru.patch +nfsd-remove-unused-nfsv3-directory-entry-encoders.patch +nfsd-reduce-svc_rqst-rq_pages-churn-during-readdir-o.patch +nfsd-update-the-nfsv2-stat-encoder-to-use-struct-xdr.patch +nfsd-update-the-nfsv2-attrstat-encoder-to-use-struct.patch +nfsd-update-the-nfsv2-diropres-encoder-to-use-struct.patch +nfsd-update-the-nfsv2-readlink-result-encoder-to-use.patch +nfsd-update-the-nfsv2-read-result-encoder-to-use-str.patch +nfsd-update-the-nfsv2-statfs-result-encoder-to-use-s.patch +nfsd-add-a-helper-that-encodes-nfsv3-directory-offse.patch-18644 +nfsd-count-bytes-instead-of-pages-in-the-nfsv2-readd.patch +nfsd-update-the-nfsv2-readdir-result-encoder-to-use-.patch +nfsd-update-the-nfsv2-readdir-entry-encoder-to-use-s.patch +nfsd-remove-unused-nfsv2-directory-entry-encoders.patch +nfsd-add-an-xdr_stream-based-encoder-for-nfsv2-3-acl.patch +nfsd-update-the-nfsv2-getacl-result-encoder-to-use-s.patch +nfsd-update-the-nfsv2-setacl-result-encoder-to-use-s.patch +nfsd-update-the-nfsv2-acl-getattr-result-encoder-to-.patch +nfsd-update-the-nfsv2-acl-access-result-encoder-to-u.patch +nfsd-clean-up-after-updating-nfsv2-acl-encoders.patch +nfsd-update-the-nfsv3-getacl-result-encoder-to-use-s.patch +nfsd-update-the-nfsv3-setacl-result-encoder-to-use-s.patch +nfsd-clean-up-after-updating-nfsv3-acl-encoders.patch +nfsd-add-a-tracepoint-to-record-directory-entry-enco.patch +nfsd-clean-up-nfsddbg_facility-macro.patch +nfsd-helper-for-laundromat-expiry-calculations.patch +nfsd-log-client-tracking-type-log-message-as-info-in.patch +nfsd-fix-typo-accesible.patch +nfsd-copy-with-length-0-should-copy-to-end-of-file.patch +nfsd-don-t-ignore-high-bits-of-copy-count.patch +nfsd-report-client-confirmation-status-in-info-file.patch +sunrpc-export-svc_xprt_received.patch +uapi-nfsfh.h-replace-one-element-array-with-flexible.patch +nfsd-use-define_spinlock-for-spinlock.patch +fsnotify-allow-fsnotify_-peek-remove-_first_event-wi.patch +revert-fanotify-limit-number-of-event-merge-attempts.patch +fanotify-reduce-event-objectid-to-29-bit-hash.patch +fanotify-mix-event-info-and-pid-into-merge-key-hash.patch +fsnotify-use-hash-table-for-faster-events-merge.patch +fanotify-limit-number-of-event-merge-attempts.patch-30929 +fanotify-configurable-limits-via-sysfs.patch +fanotify-support-limited-functionality-for-unprivile.patch +fanotify_user-use-upper_32_bits-to-verify-mask.patch +nfsd-remove-unused-function.patch +nfsd-removed-unused-argument-in-nfsd_startup_generic.patch +nfsd-hash-nfs4_files-by-inode-number.patch +nfsd-track-filehandle-aliasing-in-nfs4_files.patch +nfsd-reshuffle-some-code.patch +nfsd-grant-read-delegations-to-clients-holding-write.patch +nfsd-fix-fall-through-warnings-for-clang.patch +nfsv4.2-remove-ifdef-config_nfsd-from-nfsv4.2-client.patch +nfs-fix-nfs_fetch_iversion.patch +fanotify-fix-permission-model-of-unprivileged-group.patch +nfsd-add-an-rpc-authflavor-tracepoint-display-helper.patch +nfsd-add-nfsd_clid_cred_mismatch-tracepoint.patch +nfsd-add-nfsd_clid_verf_mismatch-tracepoint.patch +nfsd-remove-trace_nfsd_clid_inuse_err.patch +nfsd-add-nfsd_clid_confirmed-tracepoint.patch +nfsd-add-nfsd_clid_reclaim_complete-tracepoint.patch +nfsd-add-nfsd_clid_destroyed-tracepoint.patch +nfsd-add-a-couple-more-nfsd_clid_expired-call-sites.patch +nfsd-add-tracepoints-for-setclientid-edge-cases.patch +nfsd-add-tracepoints-for-exchangeid-edge-cases.patch +nfsd-constify-fh-argument-of-knfsd_fh_hash.patch +nfsd-capture-every-cb-state-transition.patch +nfsd-drop-trace_define_enum-for-nfsd4_cb_-state-macr.patch +nfsd-add-cb_lost-tracepoint.patch +nfsd-adjust-cb_shutdown-tracepoint.patch +nfsd-enhance-the-nfsd_cb_setup-tracepoint.patch +nfsd-add-an-nfsd_cb_lm_notify-tracepoint.patch +nfsd-add-an-nfsd_cb_offload-tracepoint.patch +nfsd-replace-the-nfsd_deleg_break-tracepoint.patch +nfsd-add-an-nfsd_cb_probe-tracepoint.patch +nfsd-remove-the-nfsd_cb_work-and-nfsd_cb_done-tracep.patch +nfsd-update-nfsd_cb_args-tracepoint.patch +nfsd-prevent-truncation-of-an-unlinked-inode-from-bl.patch +nfsd-move-some-commit_metadata-s-outside-the-inode-l.patch +nfsd-add-vfs_fsync-after-async-copy-is-done.patch +nfsd-delay-unmount-source-s-export-after-inter-serve.patch +nfsd-move-fsnotify-on-client-creation-outside-spinlo.patch +nfsd4-expose-the-callback-address-and-state-of-each-.patch +nfsd-fix-kernel-test-robot-warning-in-ssc-code.patch +nfsd-fix-error-return-code-in-nfsd4_interssc_connect.patch +nfsd-rpc_peeraddr2str-needs-rcu-lock.patch +lockd-remove-stale-comments.patch +lockd-create-a-simplified-.vs_dispatch-method-for-nl.patch +lockd-common-nlm-xdr-helpers.patch +lockd-update-the-nlmv1-void-argument-decoder-to-use-.patch +lockd-update-the-nlmv1-test-arguments-decoder-to-use.patch +lockd-update-the-nlmv1-lock-arguments-decoder-to-use.patch +lockd-update-the-nlmv1-cancel-arguments-decoder-to-u.patch +lockd-update-the-nlmv1-unlock-arguments-decoder-to-u.patch +lockd-update-the-nlmv1-nlm_res-arguments-decoder-to-.patch +lockd-update-the-nlmv1-sm_notify-arguments-decoder-t.patch +lockd-update-the-nlmv1-share-arguments-decoder-to-us.patch +lockd-update-the-nlmv1-free_all-arguments-decoder-to.patch +lockd-update-the-nlmv1-void-results-encoder-to-use-s.patch +lockd-update-the-nlmv1-test-results-encoder-to-use-s.patch +lockd-update-the-nlmv1-nlm_res-results-encoder-to-us.patch +lockd-update-the-nlmv1-share-results-encoder-to-use-.patch +lockd-update-the-nlmv4-void-arguments-decoder-to-use.patch +lockd-update-the-nlmv4-test-arguments-decoder-to-use.patch +lockd-update-the-nlmv4-lock-arguments-decoder-to-use.patch +lockd-update-the-nlmv4-cancel-arguments-decoder-to-u.patch +lockd-update-the-nlmv4-unlock-arguments-decoder-to-u.patch +lockd-update-the-nlmv4-nlm_res-arguments-decoder-to-.patch +lockd-update-the-nlmv4-sm_notify-arguments-decoder-t.patch +lockd-update-the-nlmv4-share-arguments-decoder-to-us.patch +lockd-update-the-nlmv4-free_all-arguments-decoder-to.patch +lockd-update-the-nlmv4-void-results-encoder-to-use-s.patch +lockd-update-the-nlmv4-test-results-encoder-to-use-s.patch +lockd-update-the-nlmv4-nlm_res-results-encoder-to-us.patch +lockd-update-the-nlmv4-share-results-encoder-to-use-.patch +nfsd-remove-redundant-assignment-to-pointer-this.patch +nfsd-prevent-a-possible-oops-in-the-nfs_dirent-trace.patch +nfsd-fix-null-dereference-in-nfs3svc_encode_getaclre.patch +kernel-pid.c-remove-static-qualifier-from-pidfd_crea.patch +kernel-pid.c-implement-additional-checks-upon-pidfd_.patch +fanotify-minor-cosmetic-adjustments-to-fid-labels.patch +fanotify-introduce-a-generic-info-record-copying-hel.patch +fanotify-add-pidfd-support-to-the-fanotify-api.patch +fsnotify-replace-igrab-with-ihold-on-attach-connecto.patch +fsnotify-count-s_fsnotify_inode_refs-for-attached-co.patch +fsnotify-count-all-objects-with-attached-connectors.patch +fsnotify-optimize-the-case-of-no-marks-of-any-type.patch +nfsd-clean-up-splice-actor.patch +sunrpc-add-svc_rqst_replace_page-api.patch +nfsd-batch-release-pages-during-splice-read.patch +nfsd-remove-vanity-comments.patch +sysctl-introduce-new-proc-handler-proc_dobool.patch +lockd-change-the-proc_handler-for-nsm_use_hostnames.patch +nlm-minor-nlm_lookup_file-argument-change.patch +nlm-minor-refactoring.patch +lockd-update-nlm_lookup_file-reexport-comment.patch +keep-read-and-write-fds-with-each-nlm_file.patch +nfs-don-t-atempt-blocking-locks-on-nfs-reexports.patch +lockd-don-t-attempt-blocking-locks-on-nfs-reexports.patch +nfs-don-t-allow-reexport-reclaims.patch +sunrpc-add-svc_rqst-rq_auth_stat.patch +sunrpc-set-rq_auth_stat-in-the-pg_authenticate-callo.patch +sunrpc-eliminate-the-rq_autherr-flag.patch +nfs-add-a-private-local-dispatcher-for-nfsv4-callbac.patch +nfs-remove-unused-callback-void-decoder.patch +fsnotify-fix-sb_connectors-leak.patch +nlm-fix-svcxdr_encode_owner.patch +nfsd-fix-a-warning-for-nfsd_file_close_inode.patch +fsnotify-pass-data_type-to-fsnotify_name.patch +fsnotify-pass-dentry-instead-of-inode-data.patch +fsnotify-clarify-contract-for-create-event-hooks.patch +fsnotify-don-t-insert-unmergeable-events-in-hashtabl.patch +fanotify-fold-event-size-calculation-to-its-own-func.patch +fanotify-split-fsid-check-from-other-fid-mode-checks.patch +inotify-don-t-force-fs_in_ignored.patch +fsnotify-add-helper-to-detect-overflow_event.patch +fsnotify-add-wrapper-around-fsnotify_add_event.patch +fsnotify-retrieve-super-block-from-the-data-field.patch +fsnotify-protect-fsnotify_handle_inode_event-from-no.patch +fsnotify-pass-group-argument-to-free_event.patch +fanotify-support-null-inode-event-in-fanotify_dfid_i.patch +fanotify-allow-file-handle-encoding-for-unhashed-eve.patch +fanotify-encode-empty-file-handle-when-no-inode-is-p.patch +fanotify-require-fid_mode-for-any-non-fd-event.patch +fsnotify-support-fs_error-event-type.patch +fanotify-reserve-uapi-bits-for-fan_fs_error.patch +fanotify-pre-allocate-pool-of-error-events.patch +fanotify-support-enqueueing-of-error-events.patch +fanotify-support-merging-of-error-events.patch +fanotify-wrap-object_fh-inline-space-in-a-creator-ma.patch +fanotify-add-helpers-to-decide-whether-to-report-fid.patch +fanotify-warn_on-against-too-large-file-handles.patch +fanotify-report-fid-info-for-file-related-file-syste.patch +fanotify-emit-generic-error-info-for-error-event.patch +fanotify-allow-users-to-request-fan_fs_error-events.patch +sunrpc-trace-calls-to-.rpc_call_done.patch +nfsd-optimize-drc-bucket-pruning.patch +nfsd-move-filehandle-format-declarations-out-of-uapi.patch +nfsd-drop-support-for-ancient-filehandles.patch +nfsd-simplify-struct-nfsfh.patch +nfsd-initialize-pointer-ni-with-null-and-not-plain-i.patch +nfsd-have-legacy-nfsd-write-decoders-use-xdr_stream_.patch +sunrpc-replace-the-__be32-p-parameter-to-.pc_decode.patch +sunrpc-change-return-value-type-of-.pc_decode.patch +nfsd-save-location-of-nfsv4-compound-status.patch +sunrpc-replace-the-__be32-p-parameter-to-.pc_encode.patch +sunrpc-change-return-value-type-of-.pc_encode.patch +nfsd-update-create-verifier-comment.patch +nfsd-fix-boolreturn.cocci-warning.patch +nfsd4-remove-obselete-comment.patch +nfsd-fix-exposure-in-nfsd4_decode_bitmap.patch +nfsd-fix-readdir-buffer-overflow.patch +fsnotify-clarify-object-type-argument.patch +fsnotify-separate-mark-iterator-type-from-object-typ.patch +fanotify-introduce-group-flag-fan_report_target_fid.patch +fsnotify-generate-fs_rename-event-with-rich-informat.patch +fanotify-use-macros-to-get-the-offset-to-fanotify_in.patch +fanotify-use-helpers-to-parcel-fanotify_info-buffer.patch +fanotify-support-secondary-dir-fh-and-name-in-fanoti.patch +fanotify-record-old-and-new-parent-and-name-in-fan_r.patch +fanotify-record-either-old-name-new-name-or-both-for.patch +fanotify-report-old-and-or-new-parent-name-in-fan_re.patch +fanotify-wire-up-fan_rename-event.patch +exit-implement-kthread_exit.patch +exit-rename-module_put_and_exit-to-module_put_and_kt.patch +nfsd-fix-sparse-warning.patch +nfsd-handle-errors-better-in-write_ports_addfd.patch +sunrpc-change-svc_get-to-return-the-svc.patch +sunrpc-nfsd-clean-up-get-put-functions.patch +sunrpc-stop-using-sv_nrthreads-as-a-refcount.patch +nfsd-make-nfsd_stats.th_cnt-atomic_t.patch +sunrpc-use-sv_lock-to-protect-updates-to-sv_nrthread.patch +nfsd-narrow-nfsd_mutex-protection-in-nfsd-thread.patch +nfsd-make-it-possible-to-use-svc_set_num_threads_syn.patch +sunrpc-discard-svo_setup-and-rename-svc_set_num_thre.patch +nfsd-simplify-locking-for-network-notifier.patch +lockd-introduce-nlmsvc_serv.patch +lockd-simplify-management-of-network-status-notifier.patch +lockd-move-lockd_start_svc-call-into-lockd_create_sv.patch +lockd-move-svc_exit_thread-into-the-thread.patch +lockd-introduce-lockd_put.patch +lockd-rename-lockd_create_svc-to-lockd_get.patch +sunrpc-move-the-pool_map-definitions-back-into-svc.c.patch +sunrpc-always-treat-sv_nrpools-1-as-not-pooled.patch +lockd-use-svc_set_num_threads-for-thread-start-and-s.patch +nfs-switch-the-callback-service-back-to-non-pooled.patch +nfsd-remove-be32_to_cpu-from-drc-hash-function.patch +nfsd-fix-inconsistent-indenting.patch +nfsd-simplify-per-net-file-cache-management.patch +nfsd-combine-xdr-error-tracepoints.patch +nfsd-improve-stateid-access-bitmask-documentation.patch +nfsd-de-duplicate-nfsd4_decode_bitmap4.patch +nfs-block-notification-on-fs-with-its-own-lock.patch +nfsd4-add-refcount-for-nfsd4_blocked_lock.patch +nfsd-fix-zero-length-nfsv3-writes.patch +nfsd-map-ebadf.patch +nfsd-add-errno-mapping-for-eremoteio.patch +nfsd-retry-once-in-nfsd_open-on-an-eopenstale-return.patch +nfsd-clean-up-nfsd_vfs_write.patch +nfsd-de-duplicate-net_generic-svc_net-rqstp-nfsd_net.patch +nfsd-de-duplicate-net_generic-nf-nf_net-nfsd_net_id.patch +nfsd-add-a-tracepoint-for-errors-in-nfsd4_clone_file.patch +nfsd-write-verifier-might-go-backwards.patch +nfsd-clean-up-the-nfsd_net-nfssvc_boot-field.patch +nfsd-rename-boot-verifier-functions.patch +nfsd-trace-boot-verifier-resets.patch +revert-nfsd-skip-some-unnecessary-stats-in-the-v4-ca.patch +nfsd-move-fill_pre_wcc-and-fill_post_wcc.patch +nfsd-fix-crash-on-copy_notify-with-special-stateid.patch +fanotify-remove-variable-set-but-not-used.patch +lockd-fix-server-crash-on-reboot-of-client-holding-l.patch +lockd-fix-failure-to-cleanup-client-locks.patch +nfsd-fix-the-behavior-of-read-near-offset_max.patch +nfsd-fix-ia_size-underflow.patch +nfsd-fix-nfsv3-setattr-create-s-handling-of-large-fi.patch +nfsd-commit-operations-must-not-return-nfs-err_inval.patch +nfsd-deprecate-nfs_offset_max.patch +nfsd-add-support-for-the-birth-time-attribute.patch +nfsd-de-duplicate-hash-bucket-indexing.patch +nfsd-skip-extra-computation-for-rc_nocache-case.patch +nfsd-streamline-the-rare-found-case.patch +sunrpc-remove-the-.svo_enqueue_xprt-method.patch +sunrpc-merge-svc_do_enqueue_xprt-into-svc_enqueue_xp.patch +sunrpc-remove-svo_shutdown-method.patch +sunrpc-rename-svc_create_xprt.patch +sunrpc-rename-svc_close_xprt.patch +sunrpc-remove-svc_shutdown_net.patch +nfsd-remove-svc_serv_ops-svo_module.patch +nfsd-move-svc_serv_ops-svo_function-into-struct-svc_.patch +nfsd-remove-config_nfsd_v3.patch +nfsd-clean-up-_lm_-operation-names.patch +nfsd-fix-using-the-correct-variable-for-sizeof.patch +fsnotify-fix-merge-with-parent-s-ignored-mask.patch +fsnotify-optimize-fs_modify-events-with-no-ignored-m.patch +fsnotify-remove-redundant-parameter-judgment.patch +sunrpc-return-true-false-not-1-0-from-bool-functions.patch +nfsd-fix-a-write-performance-regression.patch +nfsd-clean-up-nfsd_file_put.patch +fanotify-do-not-allow-setting-dirent-events-in-mask-.patch +fs-lock-documentation-cleanup.-replace-inode-i_lock-.patch +inotify-move-control-flags-from-mask-to-mark-flags.patch +fsnotify-pass-flags-argument-to-fsnotify_alloc_group.patch +fsnotify-make-allow_dups-a-property-of-the-group.patch +fsnotify-create-helpers-for-group-mark_mutex-lock.patch +inotify-use-fsnotify-group-lock-helpers.patch +nfsd-use-fsnotify-group-lock-helpers.patch +dnotify-use-fsnotify-group-lock-helpers.patch +fsnotify-allow-adding-an-inode-mark-without-pinning-.patch +fanotify-create-helper-fanotify_mark_user_flags.patch +fanotify-factor-out-helper-fanotify_mark_update_flag.patch +fanotify-implement-evictable-inode-marks.patch +fanotify-use-fsnotify-group-lock-helpers.patch +fanotify-enable-evictable-inode-marks.patch +fsnotify-introduce-mark-type-iterator.patch +fsnotify-consistent-behavior-for-parent-not-watching.patch +fanotify-fix-incorrect-fmode_t-casts.patch +nfsd-clean-up-nfsd_splice_actor.patch +nfsd-add-courteous-server-support-for-thread-with-on.patch +nfsd-add-support-for-share-reservation-conflict-to-c.patch +nfsd-move-create-destroy-of-laundry_wq-to-init_nfsd-.patch +fs-lock-add-helper-locks_owner_has_blockers-to-check.patch +fs-lock-add-2-callbacks-to-lock_manager_operations-t.patch +nfsd-add-support-for-lock-conflict-to-courteous-serv.patch +nfsd-show-state-of-courtesy-client-in-client-info.patch +nfsd-clean-up-nfsd3_proc_create.patch +nfsd-avoid-calling-fh_drop_write-twice-in-do_nfsd_cr.patch +nfsd-refactor-nfsd_create_setattr.patch +nfsd-refactor-nfsv3-create.patch +nfsd-refactor-nfsv4-open-create.patch +nfsd-remove-do_nfsd_create.patch +nfsd-clean-up-nfsd_open_verified.patch +nfsd-instantiate-a-struct-file-when-creating-a-regul.patch +nfsd-remove-dprintk-call-sites-from-tail-of-nfsd4_op.patch +nfsd-fix-whitespace.patch +nfsd-move-documenting-comment-for-nfsd4_process_open.patch +nfsd-trace-filecache-opens.patch +nfsd-clean-up-the-show_nf_flags-macro.patch +sunrpc-use-rmw-bitops-in-single-threaded-hot-paths.patch +nfsd-unregister-the-cld-notifier-when-laundry_wq-cre.patch +nfsd-fix-null-ptr-deref-in-nfsd_fill_super.patch +nfsd-destroy-percpu-stats-counters-after-reply-cache.patch +nfsd-modernize-nfsd4_release_lockowner.patch +nfsd-add-documenting-comment-for-nfsd4_release_locko.patch +nfsd-nfsd_file_put-can-sleep.patch +nfsd-fix-potential-use-after-free-in-nfsd_file_put.patch +sunrpc-optimize-xdr_reserve_space.patch +fanotify-refine-the-validation-checks-on-non-dir-ino.patch +nfs-restore-module-put-when-manager-exits.patch +nfsd-decode-nfsv4-birth-time-attribute.patch +lockd-set-fl_owner-when-unlocking-files.patch +lockd-fix-nlm_close_files.patch +fs-inotify-fix-typo-in-inotify-comment.patch +fanotify-prepare-for-setting-event-flags-in-ignore-m.patch +fanotify-cleanups-for-fanotify_mark-input-validation.patch +fanotify-introduce-fan_mark_ignore.patch +fsnotify-fix-comment-typo.patch +nfsd-eliminate-the-nfsd_file_break_-flags.patch +sunrpc-fix-xdr_encode_bool.patch +nlm-defend-against-file_lock-changes-after-vfs_test_.patch +nfsd-fix-space-and-spelling-mistake.patch +nfsd-remove-redundant-assignment-to-variable-len.patch +nfsd-demote-a-warn-to-a-pr_warn.patch +nfsd-report-filecache-lru-size.patch +nfsd-report-count-of-calls-to-nfsd_file_acquire.patch +nfsd-report-count-of-freed-filecache-items.patch +nfsd-report-average-age-of-filecache-items.patch +nfsd-add-nfsd_file_lru_dispose_list-helper.patch +nfsd-refactor-nfsd_file_gc.patch +nfsd-refactor-nfsd_file_lru_scan.patch +nfsd-report-the-number-of-items-evicted-by-the-lru-w.patch +nfsd-record-number-of-flush-calls.patch +nfsd-zero-counters-when-the-filecache-is-re-initiali.patch +nfsd-hook-up-the-filecache-stat-file.patch +nfsd-warn-when-freeing-an-item-still-linked-via-nf_l.patch +nfsd-trace-filecache-lru-activity.patch +nfsd-leave-open-files-out-of-the-filecache-lru.patch +nfsd-fix-the-filecache-lru-shrinker.patch +nfsd-never-call-nfsd_file_gc-in-foreground-paths.patch +nfsd-no-longer-record-nf_hashval-in-the-trace-log.patch +nfsd-remove-lockdep-assertion-from-unhash_and_releas.patch +nfsd-nfsd_file_unhash-can-compute-hashval-from-nf-nf.patch +nfsd-refactor-__nfsd_file_close_inode.patch +nfsd-nfsd_file_hash_remove-can-compute-hashval.patch +nfsd-remove-nfsd_file-nf_hashval.patch +nfsd-replace-the-init-once-mechanism.patch +nfsd-set-up-an-rhashtable-for-the-filecache.patch +nfsd-convert-the-filecache-to-use-rhashtable.patch +nfsd-clean-up-unused-code-after-rhashtable-conversio.patch +nfsd-separate-tracepoints-for-acquire-and-create.patch +nfsd-move-nfsd_file_trace_alloc-tracepoint.patch +nfsd-nfsv4-close-should-release-an-nfsd_file-immedia.patch +nfsd-ensure-nf_inode-is-never-dereferenced.patch +nfsd-refactoring-v4-specific-code-to-a-helper-in-nfs.patch +nfsd-keep-track-of-the-number-of-v4-clients-in-the-s.patch +nfsd-limit-the-number-of-v4-clients-to-1024-per-1gb-.patch +nfsd-silence-extraneous-printk-on-nfsd.ko-insertion.patch +nfsd-optimize-nfsd4_encode_operation.patch +nfsd-optimize-nfsd4_encode_fattr.patch +nfsd-clean-up-splice_ok-in-nfsd4_encode_read.patch +nfsd-add-an-nfsd4_read-rd_eof-field.patch +nfsd-optimize-nfsd4_encode_readv.patch +nfsd-simplify-starting_len.patch +nfsd-use-xdr_pad_size.patch +nfsd-clean-up-nfsd4_encode_readlink.patch +nfsd-fix-strncpy-fortify-warning.patch +nfsd-nfserrno-enomem-is-nfserr_jukebox.patch +nfsd-shrink-size-of-struct-nfsd4_copy_notify.patch +nfsd-shrink-size-of-struct-nfsd4_copy.patch +nfsd-reorder-the-fields-in-struct-nfsd4_op.patch +nfsd-make-nfs4_put_copy-static.patch +nfsd-replace-boolean-fields-in-struct-nfsd4_copy.patch +nfsd-refactor-nfsd4_cleanup_inter_ssc-1-2.patch +nfsd-refactor-nfsd4_cleanup_inter_ssc-2-2.patch +nfsd-refactor-nfsd4_do_copy.patch +nfsd-remove-kmalloc-from-nfsd4_do_async_copy.patch +nfsd-add-nfsd4_send_cb_offload.patch +nfsd-move-copy-offload-callback-arguments-into-a-sep.patch +nfsd-drop-fh-argument-from-alloc_init_deleg.patch +nfsd-verify-the-opened-dentry-after-setting-a-delega.patch +nfsd-introduce-struct-nfsd_attrs.patch +nfsd-set-attributes-when-creating-symlinks.patch +nfsd-add-security-label-to-struct-nfsd_attrs.patch +nfsd-add-posix-acls-to-struct-nfsd_attrs.patch +nfsd-change-nfsd_create-nfsd_symlink-to-unlock-direc.patch +nfsd-always-drop-directory-lock-in-nfsd_unlink.patch +nfsd-only-call-fh_unlock-once-in-nfsd_link.patch +nfsd-reduce-locking-in-nfsd_lookup.patch +nfsd-use-explicit-lock-unlock-for-directory-ops.patch +nfsd-use-un-lock_inode-instead-of-fh_-un-lock-for-fi.patch +nfsd-discard-fh_locked-flag-and-fh_lock-fh_unlock.patch +lockd-detect-and-reject-lock-arguments-that-overflow.patch +nfsd-fix-regression-with-setting-acls.patch +nfsd_splice_actor-handle-compound-pages.patch +nfsd-move-from-strlcpy-with-unused-retval-to-strscpy.patch +lockd-move-from-strlcpy-with-unused-retval-to-strscp.patch +nfsd-enforce-filehandle-check-for-source-file-in-cop.patch +nfsd-remove-redundant-variable-status.patch +nfsd-avoid-some-useless-tests.patch +nfsd-propagate-some-error-code-returned-by-memdup_us.patch +nfsd-increase-nfsd_max_ops_per_compound.patch +nfsd-protect-against-send-buffer-overflow-in-nfsv2-r.patch +nfsd-protect-against-send-buffer-overflow-in-nfsv3-r.patch +nfsd-protect-against-send-buffer-overflow-in-nfsv2-r.patch-22138 +nfsd-protect-against-send-buffer-overflow-in-nfsv3-r.patch-26809 +nfsd-drop-fname-and-flen-args-from-nfsd_create_locke.patch +nfsd-fix-handling-of-oversized-nfsv4-compound-reques.patch +nfsd-clean-up-mounted_on_fileid-handling.patch +nfsd-remove-nfsd4_prepare_cb_recall-declaration.patch +nfsd-add-tracepoints-to-report-nfsv4-callback-comple.patch +nfsd-add-a-mechanism-to-wait-for-a-delegreturn.patch +nfsd-refactor-nfsd_setattr.patch +nfsd-make-nfsd4_setattr-wait-before-returning-nfs4er.patch +nfsd-make-nfsd4_rename-wait-before-returning-nfs4err.patch +nfsd-make-nfsd4_remove-wait-before-returning-nfs4err.patch +nfsd-keep-track-of-the-number-of-courtesy-clients-in.patch +nfsd-add-shrinker-to-reap-courtesy-clients-on-low-me.patch +sunrpc-parametrize-how-much-of-argsize-should-be-zer.patch +nfsd-reduce-amount-of-struct-nfsd4_compoundargs-that.patch +nfsd-refactor-common-code-out-of-dirlist-helpers.patch +nfsd-use-xdr_inline_decode-to-decode-nfsv3-symlinks.patch +nfsd-clean-up-write-arg-decoders.patch +nfsd-clean-up-nfs4svc_encode_compoundres.patch +nfsd-remove-inline-directives-on-op_rsize_bop-helper.patch +nfsd-remove-unused-nfsd4_compoundargs-cachetype-fiel.patch +nfsd-pack-struct-nfsd4_compoundres.patch +nfsd-use-define_proc_show_attribute-to-define-nfsd_p.patch +nfsd-use-define_show_attribute-to-define-export_feat.patch +nfsd-use-define_show_attribute-to-define-client_info.patch +nfsd-use-define_show_attribute-to-define-nfsd_reply_.patch +nfsd-use-define_show_attribute-to-define-nfsd_file_c.patch +nfsd-rename-the-fields-in-copy_stateid_t.patch +nfsd-cap-rsize_bop-result-based-on-send-buffer-size.patch +nfsd-only-fill-out-return-pointer-on-success-in-nfsd.patch +nfsd-fix-comments-about-spinlock-handling-with-deleg.patch +nfsd-make-nfsd4_run_cb-a-bool-return-function.patch +nfsd-extra-checks-when-freeing-delegation-stateids.patch +fs-notify-constify-path.patch +fsnotify-remove-unused-declaration.patch +fanotify-remove-obsoleted-fanotify_event_has_path.patch +nfsd-fix-nfsd_file_unhash_and_dispose.patch +nfsd-rework-hashtable-handling-in-nfsd_do_file_acqui.patch +nfsd-unregister-shrinker-when-nfsd_init_net-fails.patch +nfsd-fix-net-namespace-logic-in-__nfsd_file_cache_pu.patch +nfsd-fix-use-after-free-in-nfsd_file_do_acquire-trac.patch +nfsd-put-the-export-reference-in-nfsd4_verify_deleg_.patch +nfsd-fix-reads-with-a-non-zero-offset-that-don-t-end.patch +filelock-add-a-new-locks_inode_context-accessor-func.patch +lockd-use-locks_inode_context-helper.patch +nfsd-use-locks_inode_context-helper.patch +nfsd-simplify-read_plus.patch +nfsd-remove-redundant-assignment-to-variable-host_er.patch +nfsd-finish-converting-the-nfsv2-getacl-result-encod.patch +nfsd-finish-converting-the-nfsv3-getacl-result-encod.patch +nfsd-ignore-requests-to-disable-unsupported-versions.patch +nfsd-move-nfserrno-to-vfs.c.patch +nfsd-allow-disabling-nfsv2-at-compile-time.patch +exportfs-use-pr_debug-for-unreachable-debug-statemen.patch +nfsd-pass-the-target-nfsd_file-to-nfsd_commit.patch +nfsd-revert-nfsd-nfsv4-close-should-release-an-nfsd_.patch +nfsd-add-an-nfsd_file_gc-flag-to-enable-nfsd_file-ga.patch +nfsd-flesh-out-a-documenting-comment-for-filecache.c.patch +nfsd-clean-up-nfs4_preprocess_stateid_op-call-sites.patch +nfsd-trace-stateids-returned-via-delegreturn.patch +nfsd-trace-delegation-revocations.patch +nfsd-use-const-pointers-as-parameters-to-fh_-helpers.patch +nfsd-update-file_hashtbl-helpers.patch +nfsd-clean-up-nfsd4_init_file.patch +nfsd-add-a-nfsd4_file_hash_remove-helper.patch +nfsd-clean-up-find_or_add_file.patch +nfsd-refactor-find_file.patch +nfsd-use-rhashtable-for-managing-nfs4_file-objects.patch +nfsd-fix-licensing-header-in-filecache.c.patch +nfsd-remove-the-pages_flushed-statistic-from-filecac.patch +nfsd-reorganize-filecache.c.patch +nfsd-fix-up-the-filecache-laundrette-scheduling.patch +nfsd-add-an-nfsd_file_fsync-tracepoint.patch +lockd-set-other-missing-fields-when-unlocking-files.patch +nfsd-return-error-if-nfs4_setacl-fails.patch +nfsd-use-struct_size-helper-in-alloc_session.patch +lockd-set-missing-fl_flags-field-when-retrieving-arg.patch +lockd-ensure-we-use-the-correct-file-descriptor-when.patch +lockd-fix-file-selection-in-nlmsvc_cancel_blocked.patch +nfsd-pass-range-end-to-vfs_fsync_range-instead-of-co.patch +nfsd-refactoring-courtesy_client_reaper-to-a-generic.patch +nfsd-add-support-for-sending-cb_recall_any.patch +nfsd-add-delegation-reaper-to-react-to-low-memory-co.patch +nfsd-use-only-rq_dropme-to-signal-the-need-to-drop-a.patch +nfsd-avoid-clashing-function-prototypes.patch +nfsd-rework-refcounting-in-filecache.patch +nfsd-fix-handling-of-cached-open-files-in-nfsd4_open.patch +revert-sunrpc-use-rmw-bitops-in-single-threaded-hot-.patch +nfsd-use-set_bit-rq_dropme.patch +nfsd-fix-use-after-free-in-nfsd4_ssc_setup_dul.patch +nfsd-register-unregister-of-nfsd-client-shrinker-at-.patch +nfsd-replace-delayed_work-with-work_struct-for-nfsd_.patch +nfsd-don-t-free-files-unconditionally-in-__nfsd_file.patch +nfsd-don-t-destroy-global-nfs4_file-table-in-per-net.patch +nfsd-enhance-inter-server-copy-cleanup.patch +nfsd-allow-nfsd_file_get-to-sanely-handle-a-null-poi.patch +nfsd-clean-up-potential-nfsd_file-refcount-leaks-in-.patch +nfsd-fix-leaked-reference-count-of-nfsd4_ssc_umount_.patch +nfsd-don-t-hand-out-delegation-on-setuid-files-being.patch +nfsd-fix-problems-with-cleanup-on-errors-in-nfsd4_co.patch +nfsd-fix-courtesy-client-with-deny-mode-handling-in-.patch +nfsd-don-t-fsync-nfsd_files-on-last-close.patch +nfsd-copy-the-whole-verifier-in-nfsd_copy_write_veri.patch +nfsd-protect-against-filesystem-freezing.patch +lockd-set-file_lock-start-and-end-when-decoding-nlm4.patch +nfsd-don-t-replace-page-in-rq_pages-if-it-s-a-contin.patch +nfsd-avoid-calling-opdesc-with-ops-opnum-op_illegal.patch +nfsd-call-op_release-even-when-op_func-returns-an-er.patch +nfsd-don-t-open-code-clear_and_wake_up_bit.patch +nfsd-nfsd_file_key_inode-only-needs-to-find-gc-ed-en.patch +nfsd-simplify-test_bit-return-in-nfsd_file_key_full-.patch +nfsd-don-t-kill-nfsd_files-because-of-lease-break-er.patch +nfsd-add-some-comments-to-nfsd_file_do_acquire.patch +nfsd-don-t-take-put-an-extra-reference-when-putting-.patch +nfsd-update-comment-over-__nfsd_file_cache_purge.patch +nfsd-allow-reaping-files-still-under-writeback.patch +nfsd-convert-filecache-to-rhltable.patch +nfsd-simplify-the-delayed-disposal-list-code.patch +nfsd-fix-problem-of-commit-and-nfs4err_delay-in-infi.patch +nfsd-make-a-copy-of-struct-iattr-before-calling-noti.patch +nfsd-fix-double-fget-bug-in-__write_ports_addfd.patch +lockd-drop-inappropriate-svc_get-from-locked_get.patch +nfsd-add-an-nfsd4_encode_nfstime4-helper.patch +nfsd-fix-creation-time-serialization-order.patch +nfsd-don-t-allow-nfsd-threads-to-be-signalled.patch +nfsd-simplify-code-around-svc_exit_thread-call-in-nf.patch +nfsd-separate-nfsd_last_thread-from-nfsd_put.patch +documentation-add-missing-documentation-for-export_o.patch +nfsd-fix-possible-oops-when-nfsd-pool_stats-is-close.patch +nfsd-call-nfsd_last_thread-before-final-nfsd_put.patch +nfsd-drop-the-nfsd_put-helper.patch +nfsd-fix-release_lockowner.patch +nfsd-don-t-take-fi_lock-in-nfsd_break_deleg_cb.patch +nfsd-don-t-call-locks_release_private-twice-concurre.patch +nfsd-fix-a-regression-in-nfsd_setattr.patch diff --git a/queue-5.10/sunrpc-add-svc_rqst-rq_auth_stat.patch b/queue-5.10/sunrpc-add-svc_rqst-rq_auth_stat.patch new file mode 100644 index 00000000000..c3a7cbda714 --- /dev/null +++ b/queue-5.10/sunrpc-add-svc_rqst-rq_auth_stat.patch @@ -0,0 +1,421 @@ +From a9e87e5500db183263b556cad57ae9a4ae5191e2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jul 2021 15:52:06 -0400 +Subject: SUNRPC: Add svc_rqst::rq_auth_stat + +From: Chuck Lever + +[ Upstream commit 438623a06bacd69c40c4af633bb09a3bbb9dfc78 ] + +I'd like to take commit 4532608d71c8 ("SUNRPC: Clean up generic +dispatcher code") even further by using only private local SVC +dispatchers for all kernel RPC services. This change would enable +the removal of the logic that switches between +svc_generic_dispatch() and a service's private dispatcher, and +simplify the invocation of the service's pc_release method +so that humans can visually verify that it is always invoked +properly. + +All that will come later. + +First, let's provide a better way to return authentication errors +from SVC dispatcher functions. Instead of overloading the dispatch +method's *statp argument, add a field to struct svc_rqst that can +hold an error value. + +Signed-off-by: Chuck Lever +Signed-off-by: Anna Schumaker +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + include/linux/sunrpc/svc.h | 1 + + include/linux/sunrpc/svcauth.h | 4 +-- + include/trace/events/sunrpc.h | 6 ++--- + net/sunrpc/auth_gss/svcauth_gss.c | 43 +++++++++++++++---------------- + net/sunrpc/svc.c | 17 ++++++------ + net/sunrpc/svcauth.c | 8 +++--- + net/sunrpc/svcauth_unix.c | 12 ++++----- + 7 files changed, 46 insertions(+), 45 deletions(-) + +diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h +index ab9afbf0a0d8b..7b7bd8a0a6fbd 100644 +--- a/include/linux/sunrpc/svc.h ++++ b/include/linux/sunrpc/svc.h +@@ -284,6 +284,7 @@ struct svc_rqst { + void * rq_argp; /* decoded arguments */ + void * rq_resp; /* xdr'd results */ + void * rq_auth_data; /* flavor-specific data */ ++ __be32 rq_auth_stat; /* authentication status */ + int rq_auth_slack; /* extra space xdr code + * should leave in head + * for krb5i, krb5p. +diff --git a/include/linux/sunrpc/svcauth.h b/include/linux/sunrpc/svcauth.h +index b0003866a2497..6d9cc9080aca7 100644 +--- a/include/linux/sunrpc/svcauth.h ++++ b/include/linux/sunrpc/svcauth.h +@@ -127,7 +127,7 @@ struct auth_ops { + char * name; + struct module *owner; + int flavour; +- int (*accept)(struct svc_rqst *rq, __be32 *authp); ++ int (*accept)(struct svc_rqst *rq); + int (*release)(struct svc_rqst *rq); + void (*domain_release)(struct auth_domain *); + int (*set_client)(struct svc_rqst *rq); +@@ -149,7 +149,7 @@ struct auth_ops { + + struct svc_xprt; + +-extern int svc_authenticate(struct svc_rqst *rqstp, __be32 *authp); ++extern int svc_authenticate(struct svc_rqst *rqstp); + extern int svc_authorise(struct svc_rqst *rqstp); + extern int svc_set_client(struct svc_rqst *rqstp); + extern int svc_auth_register(rpc_authflavor_t flavor, struct auth_ops *aops); +diff --git a/include/trace/events/sunrpc.h b/include/trace/events/sunrpc.h +index 657138ab1f91f..0cb9e182a1b1e 100644 +--- a/include/trace/events/sunrpc.h ++++ b/include/trace/events/sunrpc.h +@@ -1547,9 +1547,9 @@ TRACE_DEFINE_ENUM(SVC_COMPLETE); + { SVC_COMPLETE, "SVC_COMPLETE" }) + + TRACE_EVENT(svc_authenticate, +- TP_PROTO(const struct svc_rqst *rqst, int auth_res, __be32 auth_stat), ++ TP_PROTO(const struct svc_rqst *rqst, int auth_res), + +- TP_ARGS(rqst, auth_res, auth_stat), ++ TP_ARGS(rqst, auth_res), + + TP_STRUCT__entry( + __field(u32, xid) +@@ -1560,7 +1560,7 @@ TRACE_EVENT(svc_authenticate, + TP_fast_assign( + __entry->xid = be32_to_cpu(rqst->rq_xid); + __entry->svc_status = auth_res; +- __entry->auth_stat = be32_to_cpu(auth_stat); ++ __entry->auth_stat = be32_to_cpu(rqst->rq_auth_stat); + ), + + TP_printk("xid=0x%08x auth_res=%s auth_stat=%s", +diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c +index 784c8b24f1640..54303b7efde76 100644 +--- a/net/sunrpc/auth_gss/svcauth_gss.c ++++ b/net/sunrpc/auth_gss/svcauth_gss.c +@@ -707,11 +707,11 @@ svc_safe_putnetobj(struct kvec *resv, struct xdr_netobj *o) + /* + * Verify the checksum on the header and return SVC_OK on success. + * Otherwise, return SVC_DROP (in the case of a bad sequence number) +- * or return SVC_DENIED and indicate error in authp. ++ * or return SVC_DENIED and indicate error in rqstp->rq_auth_stat. + */ + static int + gss_verify_header(struct svc_rqst *rqstp, struct rsc *rsci, +- __be32 *rpcstart, struct rpc_gss_wire_cred *gc, __be32 *authp) ++ __be32 *rpcstart, struct rpc_gss_wire_cred *gc) + { + struct gss_ctx *ctx_id = rsci->mechctx; + struct xdr_buf rpchdr; +@@ -725,7 +725,7 @@ gss_verify_header(struct svc_rqst *rqstp, struct rsc *rsci, + iov.iov_len = (u8 *)argv->iov_base - (u8 *)rpcstart; + xdr_buf_from_iov(&iov, &rpchdr); + +- *authp = rpc_autherr_badverf; ++ rqstp->rq_auth_stat = rpc_autherr_badverf; + if (argv->iov_len < 4) + return SVC_DENIED; + flavor = svc_getnl(argv); +@@ -737,13 +737,13 @@ gss_verify_header(struct svc_rqst *rqstp, struct rsc *rsci, + if (rqstp->rq_deferred) /* skip verification of revisited request */ + return SVC_OK; + if (gss_verify_mic(ctx_id, &rpchdr, &checksum) != GSS_S_COMPLETE) { +- *authp = rpcsec_gsserr_credproblem; ++ rqstp->rq_auth_stat = rpcsec_gsserr_credproblem; + return SVC_DENIED; + } + + if (gc->gc_seq > MAXSEQ) { + trace_rpcgss_svc_seqno_large(rqstp, gc->gc_seq); +- *authp = rpcsec_gsserr_ctxproblem; ++ rqstp->rq_auth_stat = rpcsec_gsserr_ctxproblem; + return SVC_DENIED; + } + if (!gss_check_seq_num(rqstp, rsci, gc->gc_seq)) +@@ -1136,7 +1136,7 @@ static void gss_free_in_token_pages(struct gssp_in_token *in_token) + } + + static int gss_read_proxy_verf(struct svc_rqst *rqstp, +- struct rpc_gss_wire_cred *gc, __be32 *authp, ++ struct rpc_gss_wire_cred *gc, + struct xdr_netobj *in_handle, + struct gssp_in_token *in_token) + { +@@ -1145,7 +1145,7 @@ static int gss_read_proxy_verf(struct svc_rqst *rqstp, + int pages, i, res, pgto, pgfrom; + size_t inlen, to_offs, from_offs; + +- res = gss_read_common_verf(gc, argv, authp, in_handle); ++ res = gss_read_common_verf(gc, argv, &rqstp->rq_auth_stat, in_handle); + if (res) + return res; + +@@ -1226,7 +1226,7 @@ gss_write_resv(struct kvec *resv, size_t size_limit, + * Otherwise, drop the request pending an answer to the upcall. + */ + static int svcauth_gss_legacy_init(struct svc_rqst *rqstp, +- struct rpc_gss_wire_cred *gc, __be32 *authp) ++ struct rpc_gss_wire_cred *gc) + { + struct kvec *argv = &rqstp->rq_arg.head[0]; + struct kvec *resv = &rqstp->rq_res.head[0]; +@@ -1235,7 +1235,7 @@ static int svcauth_gss_legacy_init(struct svc_rqst *rqstp, + struct sunrpc_net *sn = net_generic(SVC_NET(rqstp), sunrpc_net_id); + + memset(&rsikey, 0, sizeof(rsikey)); +- ret = gss_read_verf(gc, argv, authp, ++ ret = gss_read_verf(gc, argv, &rqstp->rq_auth_stat, + &rsikey.in_handle, &rsikey.in_token); + if (ret) + return ret; +@@ -1338,7 +1338,7 @@ static int gss_proxy_save_rsc(struct cache_detail *cd, + } + + static int svcauth_gss_proxy_init(struct svc_rqst *rqstp, +- struct rpc_gss_wire_cred *gc, __be32 *authp) ++ struct rpc_gss_wire_cred *gc) + { + struct kvec *resv = &rqstp->rq_res.head[0]; + struct xdr_netobj cli_handle; +@@ -1350,8 +1350,7 @@ static int svcauth_gss_proxy_init(struct svc_rqst *rqstp, + struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); + + memset(&ud, 0, sizeof(ud)); +- ret = gss_read_proxy_verf(rqstp, gc, authp, +- &ud.in_handle, &ud.in_token); ++ ret = gss_read_proxy_verf(rqstp, gc, &ud.in_handle, &ud.in_token); + if (ret) + return ret; + +@@ -1524,7 +1523,7 @@ static void destroy_use_gss_proxy_proc_entry(struct net *net) {} + * response here and return SVC_COMPLETE. + */ + static int +-svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp) ++svcauth_gss_accept(struct svc_rqst *rqstp) + { + struct kvec *argv = &rqstp->rq_arg.head[0]; + struct kvec *resv = &rqstp->rq_res.head[0]; +@@ -1537,7 +1536,7 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp) + int ret; + struct sunrpc_net *sn = net_generic(SVC_NET(rqstp), sunrpc_net_id); + +- *authp = rpc_autherr_badcred; ++ rqstp->rq_auth_stat = rpc_autherr_badcred; + if (!svcdata) + svcdata = kmalloc(sizeof(*svcdata), GFP_KERNEL); + if (!svcdata) +@@ -1574,22 +1573,22 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp) + if ((gc->gc_proc != RPC_GSS_PROC_DATA) && (rqstp->rq_proc != 0)) + goto auth_err; + +- *authp = rpc_autherr_badverf; ++ rqstp->rq_auth_stat = rpc_autherr_badverf; + switch (gc->gc_proc) { + case RPC_GSS_PROC_INIT: + case RPC_GSS_PROC_CONTINUE_INIT: + if (use_gss_proxy(SVC_NET(rqstp))) +- return svcauth_gss_proxy_init(rqstp, gc, authp); ++ return svcauth_gss_proxy_init(rqstp, gc); + else +- return svcauth_gss_legacy_init(rqstp, gc, authp); ++ return svcauth_gss_legacy_init(rqstp, gc); + case RPC_GSS_PROC_DATA: + case RPC_GSS_PROC_DESTROY: + /* Look up the context, and check the verifier: */ +- *authp = rpcsec_gsserr_credproblem; ++ rqstp->rq_auth_stat = rpcsec_gsserr_credproblem; + rsci = gss_svc_searchbyctx(sn->rsc_cache, &gc->gc_ctx); + if (!rsci) + goto auth_err; +- switch (gss_verify_header(rqstp, rsci, rpcstart, gc, authp)) { ++ switch (gss_verify_header(rqstp, rsci, rpcstart, gc)) { + case SVC_OK: + break; + case SVC_DENIED: +@@ -1599,7 +1598,7 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp) + } + break; + default: +- *authp = rpc_autherr_rejectedcred; ++ rqstp->rq_auth_stat = rpc_autherr_rejectedcred; + goto auth_err; + } + +@@ -1615,13 +1614,13 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp) + svc_putnl(resv, RPC_SUCCESS); + goto complete; + case RPC_GSS_PROC_DATA: +- *authp = rpcsec_gsserr_ctxproblem; ++ rqstp->rq_auth_stat = rpcsec_gsserr_ctxproblem; + svcdata->verf_start = resv->iov_base + resv->iov_len; + if (gss_write_verf(rqstp, rsci->mechctx, gc->gc_seq)) + goto auth_err; + rqstp->rq_cred = rsci->cred; + get_group_info(rsci->cred.cr_group_info); +- *authp = rpc_autherr_badcred; ++ rqstp->rq_auth_stat = rpc_autherr_badcred; + switch (gc->gc_svc) { + case RPC_GSS_SVC_NONE: + break; +diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c +index 27f98756d1751..cbcc951639ad5 100644 +--- a/net/sunrpc/svc.c ++++ b/net/sunrpc/svc.c +@@ -1305,7 +1305,7 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv) + struct svc_process_info process; + __be32 *statp; + u32 prog, vers; +- __be32 auth_stat, rpc_stat; ++ __be32 rpc_stat; + int auth_res; + __be32 *reply_statp; + +@@ -1348,14 +1348,14 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv) + * We do this before anything else in order to get a decent + * auth verifier. + */ +- auth_res = svc_authenticate(rqstp, &auth_stat); ++ auth_res = svc_authenticate(rqstp); + /* Also give the program a chance to reject this call: */ + if (auth_res == SVC_OK && progp) { +- auth_stat = rpc_autherr_badcred; ++ rqstp->rq_auth_stat = rpc_autherr_badcred; + auth_res = progp->pg_authenticate(rqstp); + } + if (auth_res != SVC_OK) +- trace_svc_authenticate(rqstp, auth_res, auth_stat); ++ trace_svc_authenticate(rqstp, auth_res); + switch (auth_res) { + case SVC_OK: + break; +@@ -1414,8 +1414,8 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv) + goto release_dropit; + if (*statp == rpc_garbage_args) + goto err_garbage; +- auth_stat = svc_get_autherr(rqstp, statp); +- if (auth_stat != rpc_auth_ok) ++ rqstp->rq_auth_stat = svc_get_autherr(rqstp, statp); ++ if (rqstp->rq_auth_stat != rpc_auth_ok) + goto err_release_bad_auth; + } else { + dprintk("svc: calling dispatcher\n"); +@@ -1472,13 +1472,14 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv) + if (procp->pc_release) + procp->pc_release(rqstp); + err_bad_auth: +- dprintk("svc: authentication failed (%d)\n", ntohl(auth_stat)); ++ dprintk("svc: authentication failed (%d)\n", ++ be32_to_cpu(rqstp->rq_auth_stat)); + serv->sv_stats->rpcbadauth++; + /* Restore write pointer to location of accept status: */ + xdr_ressize_check(rqstp, reply_statp); + svc_putnl(resv, 1); /* REJECT */ + svc_putnl(resv, 1); /* AUTH_ERROR */ +- svc_putnl(resv, ntohl(auth_stat)); /* status */ ++ svc_putu32(resv, rqstp->rq_auth_stat); /* status */ + goto sendit; + + err_bad_prog: +diff --git a/net/sunrpc/svcauth.c b/net/sunrpc/svcauth.c +index 998b196b61767..5a8b8e03fdd42 100644 +--- a/net/sunrpc/svcauth.c ++++ b/net/sunrpc/svcauth.c +@@ -59,12 +59,12 @@ svc_put_auth_ops(struct auth_ops *aops) + } + + int +-svc_authenticate(struct svc_rqst *rqstp, __be32 *authp) ++svc_authenticate(struct svc_rqst *rqstp) + { + rpc_authflavor_t flavor; + struct auth_ops *aops; + +- *authp = rpc_auth_ok; ++ rqstp->rq_auth_stat = rpc_auth_ok; + + flavor = svc_getnl(&rqstp->rq_arg.head[0]); + +@@ -72,7 +72,7 @@ svc_authenticate(struct svc_rqst *rqstp, __be32 *authp) + + aops = svc_get_auth_ops(flavor); + if (aops == NULL) { +- *authp = rpc_autherr_badcred; ++ rqstp->rq_auth_stat = rpc_autherr_badcred; + return SVC_DENIED; + } + +@@ -80,7 +80,7 @@ svc_authenticate(struct svc_rqst *rqstp, __be32 *authp) + init_svc_cred(&rqstp->rq_cred); + + rqstp->rq_authop = aops; +- return aops->accept(rqstp, authp); ++ return aops->accept(rqstp); + } + EXPORT_SYMBOL_GPL(svc_authenticate); + +diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c +index 60754a292589b..c20c63d651a9c 100644 +--- a/net/sunrpc/svcauth_unix.c ++++ b/net/sunrpc/svcauth_unix.c +@@ -743,7 +743,7 @@ svcauth_unix_set_client(struct svc_rqst *rqstp) + EXPORT_SYMBOL_GPL(svcauth_unix_set_client); + + static int +-svcauth_null_accept(struct svc_rqst *rqstp, __be32 *authp) ++svcauth_null_accept(struct svc_rqst *rqstp) + { + struct kvec *argv = &rqstp->rq_arg.head[0]; + struct kvec *resv = &rqstp->rq_res.head[0]; +@@ -754,12 +754,12 @@ svcauth_null_accept(struct svc_rqst *rqstp, __be32 *authp) + + if (svc_getu32(argv) != 0) { + dprintk("svc: bad null cred\n"); +- *authp = rpc_autherr_badcred; ++ rqstp->rq_auth_stat = rpc_autherr_badcred; + return SVC_DENIED; + } + if (svc_getu32(argv) != htonl(RPC_AUTH_NULL) || svc_getu32(argv) != 0) { + dprintk("svc: bad null verf\n"); +- *authp = rpc_autherr_badverf; ++ rqstp->rq_auth_stat = rpc_autherr_badverf; + return SVC_DENIED; + } + +@@ -803,7 +803,7 @@ struct auth_ops svcauth_null = { + + + static int +-svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp) ++svcauth_unix_accept(struct svc_rqst *rqstp) + { + struct kvec *argv = &rqstp->rq_arg.head[0]; + struct kvec *resv = &rqstp->rq_res.head[0]; +@@ -845,7 +845,7 @@ svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp) + } + groups_sort(cred->cr_group_info); + if (svc_getu32(argv) != htonl(RPC_AUTH_NULL) || svc_getu32(argv) != 0) { +- *authp = rpc_autherr_badverf; ++ rqstp->rq_auth_stat = rpc_autherr_badverf; + return SVC_DENIED; + } + +@@ -857,7 +857,7 @@ svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp) + return SVC_OK; + + badcred: +- *authp = rpc_autherr_badcred; ++ rqstp->rq_auth_stat = rpc_autherr_badcred; + return SVC_DENIED; + } + +-- +2.43.0 + diff --git a/queue-5.10/sunrpc-add-svc_rqst_replace_page-api.patch b/queue-5.10/sunrpc-add-svc_rqst_replace_page-api.patch new file mode 100644 index 00000000000..d75aaed6a8d --- /dev/null +++ b/queue-5.10/sunrpc-add-svc_rqst_replace_page-api.patch @@ -0,0 +1,112 @@ +From 6b682b75ddffbeb5c11a1aa670d53d368b970d1f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 1 Jul 2021 10:03:10 -0400 +Subject: SUNRPC: Add svc_rqst_replace_page() API + +From: Chuck Lever + +[ Upstream commit 2f0f88f42f2eab0421ed37d7494de9124fdf0d34 ] + +Replacing a page in rq_pages[] requires a get_page(), which is a +bus-locked operation, and a put_page(), which can be even more +costly. + +To reduce the cost of replacing a page in rq_pages[], batch the +put_page() operations by collecting "freed" pages in a pagevec, +and then release those pages when the pagevec is full. This +pagevec is also emptied when each RPC completes. + +[ cel: adjusted to apply without f6e70aab9dfe ] +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + include/linux/sunrpc/svc.h | 4 ++++ + net/sunrpc/svc.c | 21 +++++++++++++++++++++ + net/sunrpc/svc_xprt.c | 3 +++ + 3 files changed, 28 insertions(+) + +diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h +index e91d51ea028bb..ab9afbf0a0d8b 100644 +--- a/include/linux/sunrpc/svc.h ++++ b/include/linux/sunrpc/svc.h +@@ -19,6 +19,7 @@ + #include + #include + #include ++#include + + /* statistics for svc_pool structures */ + struct svc_pool_stats { +@@ -256,6 +257,7 @@ struct svc_rqst { + struct page * *rq_next_page; /* next reply page to use */ + struct page * *rq_page_end; /* one past the last page */ + ++ struct pagevec rq_pvec; + struct kvec rq_vec[RPCSVC_MAXPAGES]; /* generally useful.. */ + struct bio_vec rq_bvec[RPCSVC_MAXPAGES]; + +@@ -502,6 +504,8 @@ struct svc_rqst *svc_rqst_alloc(struct svc_serv *serv, + struct svc_pool *pool, int node); + struct svc_rqst *svc_prepare_thread(struct svc_serv *serv, + struct svc_pool *pool, int node); ++void svc_rqst_replace_page(struct svc_rqst *rqstp, ++ struct page *page); + void svc_rqst_free(struct svc_rqst *); + void svc_exit_thread(struct svc_rqst *); + unsigned int svc_pool_map_get(void); +diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c +index 73e02ba4ed53a..27f98756d1751 100644 +--- a/net/sunrpc/svc.c ++++ b/net/sunrpc/svc.c +@@ -842,6 +842,27 @@ svc_set_num_threads_sync(struct svc_serv *serv, struct svc_pool *pool, int nrser + } + EXPORT_SYMBOL_GPL(svc_set_num_threads_sync); + ++/** ++ * svc_rqst_replace_page - Replace one page in rq_pages[] ++ * @rqstp: svc_rqst with pages to replace ++ * @page: replacement page ++ * ++ * When replacing a page in rq_pages, batch the release of the ++ * replaced pages to avoid hammering the page allocator. ++ */ ++void svc_rqst_replace_page(struct svc_rqst *rqstp, struct page *page) ++{ ++ if (*rqstp->rq_next_page) { ++ if (!pagevec_space(&rqstp->rq_pvec)) ++ __pagevec_release(&rqstp->rq_pvec); ++ pagevec_add(&rqstp->rq_pvec, *rqstp->rq_next_page); ++ } ++ ++ get_page(page); ++ *(rqstp->rq_next_page++) = page; ++} ++EXPORT_SYMBOL_GPL(svc_rqst_replace_page); ++ + /* + * Called from a server thread as it's exiting. Caller must hold the "service + * mutex" for the service. +diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c +index d150e25b4d45e..570b092165d73 100644 +--- a/net/sunrpc/svc_xprt.c ++++ b/net/sunrpc/svc_xprt.c +@@ -525,6 +525,7 @@ static void svc_xprt_release(struct svc_rqst *rqstp) + kfree(rqstp->rq_deferred); + rqstp->rq_deferred = NULL; + ++ pagevec_release(&rqstp->rq_pvec); + svc_free_res_pages(rqstp); + rqstp->rq_res.page_len = 0; + rqstp->rq_res.page_base = 0; +@@ -651,6 +652,8 @@ static int svc_alloc_arg(struct svc_rqst *rqstp) + int pages; + int i; + ++ pagevec_init(&rqstp->rq_pvec); ++ + /* now allocate needed pages. If we get a failure, sleep briefly */ + pages = (serv->sv_max_mesg + 2 * PAGE_SIZE) >> PAGE_SHIFT; + if (pages > RPCSVC_MAXPAGES) { +-- +2.43.0 + diff --git a/queue-5.10/sunrpc-add-xdr_set_scratch_page-and-xdr_reset_scratc.patch b/queue-5.10/sunrpc-add-xdr_set_scratch_page-and-xdr_reset_scratc.patch new file mode 100644 index 00000000000..7d34638354c --- /dev/null +++ b/queue-5.10/sunrpc-add-xdr_set_scratch_page-and-xdr_reset_scratc.patch @@ -0,0 +1,308 @@ +From 549c0260f087bfd57b9256492bbe1205c6c82087 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 11 Nov 2020 15:52:47 -0500 +Subject: SUNRPC: Add xdr_set_scratch_page() and xdr_reset_scratch_buffer() + +From: Chuck Lever + +[ Upstream commit 0ae4c3e8a64ace1b8d7de033b0751afe43024416 ] + +Clean up: De-duplicate some frequently-used code. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfs/blocklayout/blocklayout.c | 2 +- + fs/nfs/blocklayout/dev.c | 2 +- + fs/nfs/dir.c | 2 +- + fs/nfs/filelayout/filelayout.c | 2 +- + fs/nfs/filelayout/filelayoutdev.c | 2 +- + fs/nfs/flexfilelayout/flexfilelayout.c | 2 +- + fs/nfs/flexfilelayout/flexfilelayoutdev.c | 2 +- + fs/nfs/nfs42xdr.c | 2 +- + fs/nfs/nfs4xdr.c | 6 ++-- + fs/nfsd/nfs4proc.c | 2 +- + include/linux/sunrpc/xdr.h | 44 ++++++++++++++++++++++- + net/sunrpc/auth_gss/gss_rpc_xdr.c | 2 +- + net/sunrpc/xdr.c | 28 +++------------ + 13 files changed, 59 insertions(+), 39 deletions(-) + +diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c +index 73000aa2d220b..a9e563145e0c2 100644 +--- a/fs/nfs/blocklayout/blocklayout.c ++++ b/fs/nfs/blocklayout/blocklayout.c +@@ -699,7 +699,7 @@ bl_alloc_lseg(struct pnfs_layout_hdr *lo, struct nfs4_layoutget_res *lgr, + + xdr_init_decode_pages(&xdr, &buf, + lgr->layoutp->pages, lgr->layoutp->len); +- xdr_set_scratch_buffer(&xdr, page_address(scratch), PAGE_SIZE); ++ xdr_set_scratch_page(&xdr, scratch); + + status = -EIO; + p = xdr_inline_decode(&xdr, 4); +diff --git a/fs/nfs/blocklayout/dev.c b/fs/nfs/blocklayout/dev.c +index 6e3a14fdff9c8..16412d6636e86 100644 +--- a/fs/nfs/blocklayout/dev.c ++++ b/fs/nfs/blocklayout/dev.c +@@ -510,7 +510,7 @@ bl_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev, + goto out; + + xdr_init_decode_pages(&xdr, &buf, pdev->pages, pdev->pglen); +- xdr_set_scratch_buffer(&xdr, page_address(scratch), PAGE_SIZE); ++ xdr_set_scratch_page(&xdr, scratch); + + p = xdr_inline_decode(&xdr, sizeof(__be32)); + if (!p) +diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c +index 9f88ca7b20015..935029632d5f6 100644 +--- a/fs/nfs/dir.c ++++ b/fs/nfs/dir.c +@@ -576,7 +576,7 @@ int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *en + goto out_nopages; + + xdr_init_decode_pages(&stream, &buf, xdr_pages, buflen); +- xdr_set_scratch_buffer(&stream, page_address(scratch), PAGE_SIZE); ++ xdr_set_scratch_page(&stream, scratch); + + do { + if (entry->label) +diff --git a/fs/nfs/filelayout/filelayout.c b/fs/nfs/filelayout/filelayout.c +index deecfb50dd7e3..45eec08ec904f 100644 +--- a/fs/nfs/filelayout/filelayout.c ++++ b/fs/nfs/filelayout/filelayout.c +@@ -666,7 +666,7 @@ filelayout_decode_layout(struct pnfs_layout_hdr *flo, + return -ENOMEM; + + xdr_init_decode_pages(&stream, &buf, lgr->layoutp->pages, lgr->layoutp->len); +- xdr_set_scratch_buffer(&stream, page_address(scratch), PAGE_SIZE); ++ xdr_set_scratch_page(&stream, scratch); + + /* 20 = ufl_util (4), first_stripe_index (4), pattern_offset (8), + * num_fh (4) */ +diff --git a/fs/nfs/filelayout/filelayoutdev.c b/fs/nfs/filelayout/filelayoutdev.c +index d913e818858f3..86c3f7e69ec42 100644 +--- a/fs/nfs/filelayout/filelayoutdev.c ++++ b/fs/nfs/filelayout/filelayoutdev.c +@@ -82,7 +82,7 @@ nfs4_fl_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev, + goto out_err; + + xdr_init_decode_pages(&stream, &buf, pdev->pages, pdev->pglen); +- xdr_set_scratch_buffer(&stream, page_address(scratch), PAGE_SIZE); ++ xdr_set_scratch_page(&stream, scratch); + + /* Get the stripe count (number of stripe index) */ + p = xdr_inline_decode(&stream, 4); +diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c +index e4f2820ba5a59..f2ae271fe7ec7 100644 +--- a/fs/nfs/flexfilelayout/flexfilelayout.c ++++ b/fs/nfs/flexfilelayout/flexfilelayout.c +@@ -378,7 +378,7 @@ ff_layout_alloc_lseg(struct pnfs_layout_hdr *lh, + + xdr_init_decode_pages(&stream, &buf, lgr->layoutp->pages, + lgr->layoutp->len); +- xdr_set_scratch_buffer(&stream, page_address(scratch), PAGE_SIZE); ++ xdr_set_scratch_page(&stream, scratch); + + /* stripe unit and mirror_array_cnt */ + rc = -EIO; +diff --git a/fs/nfs/flexfilelayout/flexfilelayoutdev.c b/fs/nfs/flexfilelayout/flexfilelayoutdev.c +index 1f12297109b41..bfa7202ca7be1 100644 +--- a/fs/nfs/flexfilelayout/flexfilelayoutdev.c ++++ b/fs/nfs/flexfilelayout/flexfilelayoutdev.c +@@ -69,7 +69,7 @@ nfs4_ff_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev, + INIT_LIST_HEAD(&dsaddrs); + + xdr_init_decode_pages(&stream, &buf, pdev->pages, pdev->pglen); +- xdr_set_scratch_buffer(&stream, page_address(scratch), PAGE_SIZE); ++ xdr_set_scratch_page(&stream, scratch); + + /* multipath count */ + p = xdr_inline_decode(&stream, 4); +diff --git a/fs/nfs/nfs42xdr.c b/fs/nfs/nfs42xdr.c +index f2248d9d4db51..df5bee2f505c4 100644 +--- a/fs/nfs/nfs42xdr.c ++++ b/fs/nfs/nfs42xdr.c +@@ -1536,7 +1536,7 @@ static int nfs4_xdr_dec_listxattrs(struct rpc_rqst *rqstp, + struct compound_hdr hdr; + int status; + +- xdr_set_scratch_buffer(xdr, page_address(res->scratch), PAGE_SIZE); ++ xdr_set_scratch_page(xdr, res->scratch); + + status = decode_compound_hdr(xdr, &hdr); + if (status) +diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c +index f1e599553f2be..4e5c6cb770ad5 100644 +--- a/fs/nfs/nfs4xdr.c ++++ b/fs/nfs/nfs4xdr.c +@@ -6404,10 +6404,8 @@ nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, struct xdr_stream *xdr, + struct compound_hdr hdr; + int status; + +- if (res->acl_scratch != NULL) { +- void *p = page_address(res->acl_scratch); +- xdr_set_scratch_buffer(xdr, p, PAGE_SIZE); +- } ++ if (res->acl_scratch != NULL) ++ xdr_set_scratch_page(xdr, res->acl_scratch); + status = decode_compound_hdr(xdr, &hdr); + if (status) + goto out; +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index e84996c3867c7..c01b6f7462fcb 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -2266,7 +2266,7 @@ static void svcxdr_init_encode(struct svc_rqst *rqstp, + xdr->end = head->iov_base + PAGE_SIZE - rqstp->rq_auth_slack; + /* Tail and page_len should be zero at this point: */ + buf->len = buf->head[0].iov_len; +- xdr->scratch.iov_len = 0; ++ xdr_reset_scratch_buffer(xdr); + xdr->page_ptr = buf->pages - 1; + buf->buflen = PAGE_SIZE * (1 + rqstp->rq_page_end - buf->pages) + - rqstp->rq_auth_slack; +diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h +index 6d9d1520612b8..0c8cab6210b3b 100644 +--- a/include/linux/sunrpc/xdr.h ++++ b/include/linux/sunrpc/xdr.h +@@ -246,7 +246,6 @@ extern void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, + __be32 *p, struct rpc_rqst *rqst); + extern void xdr_init_decode_pages(struct xdr_stream *xdr, struct xdr_buf *buf, + struct page **pages, unsigned int len); +-extern void xdr_set_scratch_buffer(struct xdr_stream *xdr, void *buf, size_t buflen); + extern __be32 *xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes); + extern unsigned int xdr_read_pages(struct xdr_stream *xdr, unsigned int len); + extern void xdr_enter_page(struct xdr_stream *xdr, unsigned int len); +@@ -254,6 +253,49 @@ extern int xdr_process_buf(struct xdr_buf *buf, unsigned int offset, unsigned in + extern uint64_t xdr_align_data(struct xdr_stream *, uint64_t, uint32_t); + extern uint64_t xdr_expand_hole(struct xdr_stream *, uint64_t, uint64_t); + ++/** ++ * xdr_set_scratch_buffer - Attach a scratch buffer for decoding data. ++ * @xdr: pointer to xdr_stream struct ++ * @buf: pointer to an empty buffer ++ * @buflen: size of 'buf' ++ * ++ * The scratch buffer is used when decoding from an array of pages. ++ * If an xdr_inline_decode() call spans across page boundaries, then ++ * we copy the data into the scratch buffer in order to allow linear ++ * access. ++ */ ++static inline void ++xdr_set_scratch_buffer(struct xdr_stream *xdr, void *buf, size_t buflen) ++{ ++ xdr->scratch.iov_base = buf; ++ xdr->scratch.iov_len = buflen; ++} ++ ++/** ++ * xdr_set_scratch_page - Attach a scratch buffer for decoding data ++ * @xdr: pointer to xdr_stream struct ++ * @page: an anonymous page ++ * ++ * See xdr_set_scratch_buffer(). ++ */ ++static inline void ++xdr_set_scratch_page(struct xdr_stream *xdr, struct page *page) ++{ ++ xdr_set_scratch_buffer(xdr, page_address(page), PAGE_SIZE); ++} ++ ++/** ++ * xdr_reset_scratch_buffer - Clear scratch buffer information ++ * @xdr: pointer to xdr_stream struct ++ * ++ * See xdr_set_scratch_buffer(). ++ */ ++static inline void ++xdr_reset_scratch_buffer(struct xdr_stream *xdr) ++{ ++ xdr_set_scratch_buffer(xdr, NULL, 0); ++} ++ + /** + * xdr_stream_remaining - Return the number of bytes remaining in the stream + * @xdr: pointer to struct xdr_stream +diff --git a/net/sunrpc/auth_gss/gss_rpc_xdr.c b/net/sunrpc/auth_gss/gss_rpc_xdr.c +index e265b8d38aa14..a857fc99431ce 100644 +--- a/net/sunrpc/auth_gss/gss_rpc_xdr.c ++++ b/net/sunrpc/auth_gss/gss_rpc_xdr.c +@@ -800,7 +800,7 @@ int gssx_dec_accept_sec_context(struct rpc_rqst *rqstp, + scratch = alloc_page(GFP_KERNEL); + if (!scratch) + return -ENOMEM; +- xdr_set_scratch_buffer(xdr, page_address(scratch), PAGE_SIZE); ++ xdr_set_scratch_page(xdr, scratch); + + /* res->status */ + err = gssx_dec_status(xdr, &res->status); +diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c +index d84bb5037bb5b..02adc5c7f034d 100644 +--- a/net/sunrpc/xdr.c ++++ b/net/sunrpc/xdr.c +@@ -669,7 +669,7 @@ void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p, + struct kvec *iov = buf->head; + int scratch_len = buf->buflen - buf->page_len - buf->tail[0].iov_len; + +- xdr_set_scratch_buffer(xdr, NULL, 0); ++ xdr_reset_scratch_buffer(xdr); + BUG_ON(scratch_len < 0); + xdr->buf = buf; + xdr->iov = iov; +@@ -713,7 +713,7 @@ inline void xdr_commit_encode(struct xdr_stream *xdr) + page = page_address(*xdr->page_ptr); + memcpy(xdr->scratch.iov_base, page, shift); + memmove(page, page + shift, (void *)xdr->p - page); +- xdr->scratch.iov_len = 0; ++ xdr_reset_scratch_buffer(xdr); + } + EXPORT_SYMBOL_GPL(xdr_commit_encode); + +@@ -743,8 +743,7 @@ static __be32 *xdr_get_next_encode_buffer(struct xdr_stream *xdr, + * the "scratch" iov to track any temporarily unused fragment of + * space at the end of the previous buffer: + */ +- xdr->scratch.iov_base = xdr->p; +- xdr->scratch.iov_len = frag1bytes; ++ xdr_set_scratch_buffer(xdr, xdr->p, frag1bytes); + p = page_address(*xdr->page_ptr); + /* + * Note this is where the next encode will start after we've +@@ -1056,8 +1055,7 @@ void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p, + struct rpc_rqst *rqst) + { + xdr->buf = buf; +- xdr->scratch.iov_base = NULL; +- xdr->scratch.iov_len = 0; ++ xdr_reset_scratch_buffer(xdr); + xdr->nwords = XDR_QUADLEN(buf->len); + if (buf->head[0].iov_len != 0) + xdr_set_iov(xdr, buf->head, buf->len); +@@ -1105,24 +1103,6 @@ static __be32 * __xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes) + return p; + } + +-/** +- * xdr_set_scratch_buffer - Attach a scratch buffer for decoding data. +- * @xdr: pointer to xdr_stream struct +- * @buf: pointer to an empty buffer +- * @buflen: size of 'buf' +- * +- * The scratch buffer is used when decoding from an array of pages. +- * If an xdr_inline_decode() call spans across page boundaries, then +- * we copy the data into the scratch buffer in order to allow linear +- * access. +- */ +-void xdr_set_scratch_buffer(struct xdr_stream *xdr, void *buf, size_t buflen) +-{ +- xdr->scratch.iov_base = buf; +- xdr->scratch.iov_len = buflen; +-} +-EXPORT_SYMBOL_GPL(xdr_set_scratch_buffer); +- + static __be32 *xdr_copy_to_scratch(struct xdr_stream *xdr, size_t nbytes) + { + __be32 *p; +-- +2.43.0 + diff --git a/queue-5.10/sunrpc-always-treat-sv_nrpools-1-as-not-pooled.patch b/queue-5.10/sunrpc-always-treat-sv_nrpools-1-as-not-pooled.patch new file mode 100644 index 00000000000..d9a8ee2da99 --- /dev/null +++ b/queue-5.10/sunrpc-always-treat-sv_nrpools-1-as-not-pooled.patch @@ -0,0 +1,164 @@ +From 9e6a59ef833175cf1138349b250348bbb9f8131c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Nov 2021 15:51:25 +1100 +Subject: SUNRPC: always treat sv_nrpools==1 as "not pooled" + +From: NeilBrown + +[ Upstream commit 93aa619eb0b42eec2f3a9b4d9db41f5095390aec ] + +Currently 'pooled' services hold a reference on the pool_map, and +'unpooled' services do not. +svc_destroy() uses the presence of ->svo_function (via +svc_serv_is_pooled()) to determine if the reference should be dropped. +There is no direct correlation between being pooled and the use of +svo_function, though in practice, lockd is the only non-pooled service, +and the only one not to use svo_function. + +This is untidy and would cause problems if we changed lockd to use +svc_set_num_threads(), which requires the use of ->svo_function. + +So change the test for "is the service pooled" to "is sv_nrpools > 1". + +This means that when svc_pool_map_get() returns 1, it must NOT take a +reference to the pool. + +We discard svc_serv_is_pooled(), and test sv_nrpools directly. + +Signed-off-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + net/sunrpc/svc.c | 54 ++++++++++++++++++++++++++---------------------- + 1 file changed, 29 insertions(+), 25 deletions(-) + +diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c +index c681ac1c9d569..ceccd4ae5f797 100644 +--- a/net/sunrpc/svc.c ++++ b/net/sunrpc/svc.c +@@ -35,8 +35,6 @@ + + static void svc_unregister(const struct svc_serv *serv, struct net *net); + +-#define svc_serv_is_pooled(serv) ((serv)->sv_ops->svo_function) +- + #define SVC_POOL_DEFAULT SVC_POOL_GLOBAL + + /* +@@ -238,8 +236,10 @@ svc_pool_map_init_pernode(struct svc_pool_map *m) + + /* + * Add a reference to the global map of cpus to pools (and +- * vice versa). Initialise the map if we're the first user. +- * Returns the number of pools. ++ * vice versa) if pools are in use. ++ * Initialise the map if we're the first user. ++ * Returns the number of pools. If this is '1', no reference ++ * was taken. + */ + static unsigned int + svc_pool_map_get(void) +@@ -251,6 +251,7 @@ svc_pool_map_get(void) + + if (m->count++) { + mutex_unlock(&svc_pool_map_mutex); ++ WARN_ON_ONCE(m->npools <= 1); + return m->npools; + } + +@@ -266,29 +267,36 @@ svc_pool_map_get(void) + break; + } + +- if (npools < 0) { ++ if (npools <= 0) { + /* default, or memory allocation failure */ + npools = 1; + m->mode = SVC_POOL_GLOBAL; + } + m->npools = npools; + ++ if (npools == 1) ++ /* service is unpooled, so doesn't hold a reference */ ++ m->count--; ++ + mutex_unlock(&svc_pool_map_mutex); +- return m->npools; ++ return npools; + } + + /* +- * Drop a reference to the global map of cpus to pools. ++ * Drop a reference to the global map of cpus to pools, if ++ * pools were in use, i.e. if npools > 1. + * When the last reference is dropped, the map data is + * freed; this allows the sysadmin to change the pool + * mode using the pool_mode module option without + * rebooting or re-loading sunrpc.ko. + */ + static void +-svc_pool_map_put(void) ++svc_pool_map_put(int npools) + { + struct svc_pool_map *m = &svc_pool_map; + ++ if (npools <= 1) ++ return; + mutex_lock(&svc_pool_map_mutex); + + if (!--m->count) { +@@ -357,21 +365,18 @@ svc_pool_for_cpu(struct svc_serv *serv, int cpu) + struct svc_pool_map *m = &svc_pool_map; + unsigned int pidx = 0; + +- /* +- * An uninitialised map happens in a pure client when +- * lockd is brought up, so silently treat it the +- * same as SVC_POOL_GLOBAL. +- */ +- if (svc_serv_is_pooled(serv)) { +- switch (m->mode) { +- case SVC_POOL_PERCPU: +- pidx = m->to_pool[cpu]; +- break; +- case SVC_POOL_PERNODE: +- pidx = m->to_pool[cpu_to_node(cpu)]; +- break; +- } ++ if (serv->sv_nrpools <= 1) ++ return serv->sv_pools; ++ ++ switch (m->mode) { ++ case SVC_POOL_PERCPU: ++ pidx = m->to_pool[cpu]; ++ break; ++ case SVC_POOL_PERNODE: ++ pidx = m->to_pool[cpu_to_node(cpu)]; ++ break; + } ++ + return &serv->sv_pools[pidx % serv->sv_nrpools]; + } + +@@ -524,7 +529,7 @@ svc_create_pooled(struct svc_program *prog, unsigned int bufsize, + goto out_err; + return serv; + out_err: +- svc_pool_map_put(); ++ svc_pool_map_put(npools); + return NULL; + } + EXPORT_SYMBOL_GPL(svc_create_pooled); +@@ -559,8 +564,7 @@ svc_destroy(struct kref *ref) + + cache_clean_deferred(serv); + +- if (svc_serv_is_pooled(serv)) +- svc_pool_map_put(); ++ svc_pool_map_put(serv->sv_nrpools); + + kfree(serv->sv_pools); + kfree(serv); +-- +2.43.0 + diff --git a/queue-5.10/sunrpc-change-return-value-type-of-.pc_decode.patch b/queue-5.10/sunrpc-change-return-value-type-of-.pc_decode.patch new file mode 100644 index 00000000000..18954a466f9 --- /dev/null +++ b/queue-5.10/sunrpc-change-return-value-type-of-.pc_decode.patch @@ -0,0 +1,1350 @@ +From d88f88054803db9f2a97544073b28348a0cd5c38 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 Oct 2021 11:57:28 -0400 +Subject: SUNRPC: Change return value type of .pc_decode + +From: Chuck Lever + +[ Upstream commit c44b31c263798ec34614dd394c31ef1a2e7e716e ] + +Returning an undecorated integer is an age-old trope, but it's +not clear (even to previous experts in this code) that the only +valid return values are 1 and 0. These functions do not return +a negative errno, rpc_stat value, or a positive length. + +Document there are only two valid return values by having +.pc_decode return only true or false. + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/xdr.c | 96 +++++++++++++++--------------- + fs/lockd/xdr4.c | 97 +++++++++++++++--------------- + fs/nfsd/nfs2acl.c | 30 +++++----- + fs/nfsd/nfs3acl.c | 22 +++---- + fs/nfsd/nfs3xdr.c | 118 ++++++++++++++++++------------------- + fs/nfsd/nfs4xdr.c | 24 ++++---- + fs/nfsd/nfsd.h | 2 +- + fs/nfsd/nfssvc.c | 6 +- + fs/nfsd/nfsxdr.c | 62 +++++++++---------- + fs/nfsd/xdr.h | 20 +++---- + fs/nfsd/xdr3.h | 30 +++++----- + fs/nfsd/xdr4.h | 2 +- + include/linux/lockd/xdr.h | 18 +++--- + include/linux/lockd/xdr4.h | 18 +++--- + include/linux/sunrpc/svc.h | 2 +- + 15 files changed, 274 insertions(+), 273 deletions(-) + +diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c +index 895f152221048..622c2ca37dbfd 100644 +--- a/fs/lockd/xdr.c ++++ b/fs/lockd/xdr.c +@@ -145,103 +145,103 @@ svcxdr_encode_testrply(struct xdr_stream *xdr, const struct nlm_res *resp) + * Decode Call arguments + */ + +-int ++bool + nlmsvc_decode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- return 1; ++ return true; + } + +-int ++bool + nlmsvc_decode_testargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nlm_args *argp = rqstp->rq_argp; + u32 exclusive; + + if (!svcxdr_decode_cookie(xdr, &argp->cookie)) +- return 0; ++ return false; + if (xdr_stream_decode_bool(xdr, &exclusive) < 0) +- return 0; ++ return false; + if (!svcxdr_decode_lock(xdr, &argp->lock)) +- return 0; ++ return false; + if (exclusive) + argp->lock.fl.fl_type = F_WRLCK; + +- return 1; ++ return true; + } + +-int ++bool + nlmsvc_decode_lockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nlm_args *argp = rqstp->rq_argp; + u32 exclusive; + + if (!svcxdr_decode_cookie(xdr, &argp->cookie)) +- return 0; ++ return false; + if (xdr_stream_decode_bool(xdr, &argp->block) < 0) +- return 0; ++ return false; + if (xdr_stream_decode_bool(xdr, &exclusive) < 0) +- return 0; ++ return false; + if (!svcxdr_decode_lock(xdr, &argp->lock)) +- return 0; ++ return false; + if (exclusive) + argp->lock.fl.fl_type = F_WRLCK; + if (xdr_stream_decode_bool(xdr, &argp->reclaim) < 0) +- return 0; ++ return false; + if (xdr_stream_decode_u32(xdr, &argp->state) < 0) +- return 0; ++ return false; + argp->monitor = 1; /* monitor client by default */ + +- return 1; ++ return true; + } + +-int ++bool + nlmsvc_decode_cancargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nlm_args *argp = rqstp->rq_argp; + u32 exclusive; + + if (!svcxdr_decode_cookie(xdr, &argp->cookie)) +- return 0; ++ return false; + if (xdr_stream_decode_bool(xdr, &argp->block) < 0) +- return 0; ++ return false; + if (xdr_stream_decode_bool(xdr, &exclusive) < 0) +- return 0; ++ return false; + if (!svcxdr_decode_lock(xdr, &argp->lock)) +- return 0; ++ return false; + if (exclusive) + argp->lock.fl.fl_type = F_WRLCK; + +- return 1; ++ return true; + } + +-int ++bool + nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nlm_args *argp = rqstp->rq_argp; + + if (!svcxdr_decode_cookie(xdr, &argp->cookie)) +- return 0; ++ return false; + if (!svcxdr_decode_lock(xdr, &argp->lock)) +- return 0; ++ return false; + argp->lock.fl.fl_type = F_UNLCK; + +- return 1; ++ return true; + } + +-int ++bool + nlmsvc_decode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nlm_res *resp = rqstp->rq_argp; + + if (!svcxdr_decode_cookie(xdr, &resp->cookie)) +- return 0; ++ return false; + if (!svcxdr_decode_stats(xdr, &resp->status)) +- return 0; ++ return false; + +- return 1; ++ return true; + } + +-int ++bool + nlmsvc_decode_reboot(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nlm_reboot *argp = rqstp->rq_argp; +@@ -249,25 +249,25 @@ nlmsvc_decode_reboot(struct svc_rqst *rqstp, struct xdr_stream *xdr) + u32 len; + + if (xdr_stream_decode_u32(xdr, &len) < 0) +- return 0; ++ return false; + if (len > SM_MAXSTRLEN) +- return 0; ++ return false; + p = xdr_inline_decode(xdr, len); + if (!p) +- return 0; ++ return false; + argp->len = len; + argp->mon = (char *)p; + if (xdr_stream_decode_u32(xdr, &argp->state) < 0) +- return 0; ++ return false; + p = xdr_inline_decode(xdr, SM_PRIV_SIZE); + if (!p) +- return 0; ++ return false; + memcpy(&argp->priv.data, p, sizeof(argp->priv.data)); + +- return 1; ++ return true; + } + +-int ++bool + nlmsvc_decode_shareargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nlm_args *argp = rqstp->rq_argp; +@@ -278,34 +278,34 @@ nlmsvc_decode_shareargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + lock->svid = ~(u32)0; + + if (!svcxdr_decode_cookie(xdr, &argp->cookie)) +- return 0; ++ return false; + if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len)) +- return 0; ++ return false; + if (!svcxdr_decode_fhandle(xdr, &lock->fh)) +- return 0; ++ return false; + if (!svcxdr_decode_owner(xdr, &lock->oh)) +- return 0; ++ return false; + /* XXX: Range checks are missing in the original code */ + if (xdr_stream_decode_u32(xdr, &argp->fsm_mode) < 0) +- return 0; ++ return false; + if (xdr_stream_decode_u32(xdr, &argp->fsm_access) < 0) +- return 0; ++ return false; + +- return 1; ++ return true; + } + +-int ++bool + nlmsvc_decode_notify(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nlm_args *argp = rqstp->rq_argp; + struct nlm_lock *lock = &argp->lock; + + if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len)) +- return 0; ++ return false; + if (xdr_stream_decode_u32(xdr, &argp->state) < 0) +- return 0; ++ return false; + +- return 1; ++ return true; + } + + +diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c +index 573c7d580a5e6..45551dee26b41 100644 +--- a/fs/lockd/xdr4.c ++++ b/fs/lockd/xdr4.c +@@ -144,102 +144,103 @@ svcxdr_encode_testrply(struct xdr_stream *xdr, const struct nlm_res *resp) + * Decode Call arguments + */ + +-int ++bool + nlm4svc_decode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- return 1; ++ return true; + } + +-int ++bool + nlm4svc_decode_testargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nlm_args *argp = rqstp->rq_argp; + u32 exclusive; + + if (!svcxdr_decode_cookie(xdr, &argp->cookie)) +- return 0; ++ return false; + if (xdr_stream_decode_bool(xdr, &exclusive) < 0) +- return 0; ++ return false; + if (!svcxdr_decode_lock(xdr, &argp->lock)) +- return 0; ++ return false; + if (exclusive) + argp->lock.fl.fl_type = F_WRLCK; + +- return 1; ++ return true; + } + +-int ++bool + nlm4svc_decode_lockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nlm_args *argp = rqstp->rq_argp; + u32 exclusive; + + if (!svcxdr_decode_cookie(xdr, &argp->cookie)) +- return 0; ++ return false; + if (xdr_stream_decode_bool(xdr, &argp->block) < 0) +- return 0; ++ return false; + if (xdr_stream_decode_bool(xdr, &exclusive) < 0) +- return 0; ++ return false; + if (!svcxdr_decode_lock(xdr, &argp->lock)) +- return 0; ++ return false; + if (exclusive) + argp->lock.fl.fl_type = F_WRLCK; + if (xdr_stream_decode_bool(xdr, &argp->reclaim) < 0) +- return 0; ++ return false; + if (xdr_stream_decode_u32(xdr, &argp->state) < 0) +- return 0; ++ return false; + argp->monitor = 1; /* monitor client by default */ + +- return 1; ++ return true; + } + +-int ++bool + nlm4svc_decode_cancargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nlm_args *argp = rqstp->rq_argp; + u32 exclusive; + + if (!svcxdr_decode_cookie(xdr, &argp->cookie)) +- return 0; ++ return false; + if (xdr_stream_decode_bool(xdr, &argp->block) < 0) +- return 0; ++ return false; + if (xdr_stream_decode_bool(xdr, &exclusive) < 0) +- return 0; ++ return false; + if (!svcxdr_decode_lock(xdr, &argp->lock)) +- return 0; ++ return false; + if (exclusive) + argp->lock.fl.fl_type = F_WRLCK; +- return 1; ++ ++ return true; + } + +-int ++bool + nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nlm_args *argp = rqstp->rq_argp; + + if (!svcxdr_decode_cookie(xdr, &argp->cookie)) +- return 0; ++ return false; + if (!svcxdr_decode_lock(xdr, &argp->lock)) +- return 0; ++ return false; + argp->lock.fl.fl_type = F_UNLCK; + +- return 1; ++ return true; + } + +-int ++bool + nlm4svc_decode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nlm_res *resp = rqstp->rq_argp; + + if (!svcxdr_decode_cookie(xdr, &resp->cookie)) +- return 0; ++ return false; + if (!svcxdr_decode_stats(xdr, &resp->status)) +- return 0; ++ return false; + +- return 1; ++ return true; + } + +-int ++bool + nlm4svc_decode_reboot(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nlm_reboot *argp = rqstp->rq_argp; +@@ -247,25 +248,25 @@ nlm4svc_decode_reboot(struct svc_rqst *rqstp, struct xdr_stream *xdr) + u32 len; + + if (xdr_stream_decode_u32(xdr, &len) < 0) +- return 0; ++ return false; + if (len > SM_MAXSTRLEN) +- return 0; ++ return false; + p = xdr_inline_decode(xdr, len); + if (!p) +- return 0; ++ return false; + argp->len = len; + argp->mon = (char *)p; + if (xdr_stream_decode_u32(xdr, &argp->state) < 0) +- return 0; ++ return false; + p = xdr_inline_decode(xdr, SM_PRIV_SIZE); + if (!p) +- return 0; ++ return false; + memcpy(&argp->priv.data, p, sizeof(argp->priv.data)); + +- return 1; ++ return true; + } + +-int ++bool + nlm4svc_decode_shareargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nlm_args *argp = rqstp->rq_argp; +@@ -276,34 +277,34 @@ nlm4svc_decode_shareargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + lock->svid = ~(u32)0; + + if (!svcxdr_decode_cookie(xdr, &argp->cookie)) +- return 0; ++ return false; + if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len)) +- return 0; ++ return false; + if (!svcxdr_decode_fhandle(xdr, &lock->fh)) +- return 0; ++ return false; + if (!svcxdr_decode_owner(xdr, &lock->oh)) +- return 0; ++ return false; + /* XXX: Range checks are missing in the original code */ + if (xdr_stream_decode_u32(xdr, &argp->fsm_mode) < 0) +- return 0; ++ return false; + if (xdr_stream_decode_u32(xdr, &argp->fsm_access) < 0) +- return 0; ++ return false; + +- return 1; ++ return true; + } + +-int ++bool + nlm4svc_decode_notify(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nlm_args *argp = rqstp->rq_argp; + struct nlm_lock *lock = &argp->lock; + + if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len)) +- return 0; ++ return false; + if (xdr_stream_decode_u32(xdr, &argp->state) < 0) +- return 0; ++ return false; + +- return 1; ++ return true; + } + + +diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c +index 53f793c3606d6..eb6a89baf675f 100644 +--- a/fs/nfsd/nfs2acl.c ++++ b/fs/nfsd/nfs2acl.c +@@ -186,51 +186,51 @@ static __be32 nfsacld_proc_access(struct svc_rqst *rqstp) + * XDR decode functions + */ + +-static int ++static bool + nfsaclsvc_decode_getaclargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd3_getaclargs *argp = rqstp->rq_argp; + + if (!svcxdr_decode_fhandle(xdr, &argp->fh)) +- return 0; ++ return false; + if (xdr_stream_decode_u32(xdr, &argp->mask) < 0) +- return 0; ++ return false; + +- return 1; ++ return true; + } + +-static int ++static bool + nfsaclsvc_decode_setaclargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd3_setaclargs *argp = rqstp->rq_argp; + + if (!svcxdr_decode_fhandle(xdr, &argp->fh)) +- return 0; ++ return false; + if (xdr_stream_decode_u32(xdr, &argp->mask) < 0) +- return 0; ++ return false; + if (argp->mask & ~NFS_ACL_MASK) +- return 0; ++ return false; + if (!nfs_stream_decode_acl(xdr, NULL, (argp->mask & NFS_ACL) ? + &argp->acl_access : NULL)) +- return 0; ++ return false; + if (!nfs_stream_decode_acl(xdr, NULL, (argp->mask & NFS_DFACL) ? + &argp->acl_default : NULL)) +- return 0; ++ return false; + +- return 1; ++ return true; + } + +-static int ++static bool + nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd3_accessargs *args = rqstp->rq_argp; + + if (!svcxdr_decode_fhandle(xdr, &args->fh)) +- return 0; ++ return false; + if (xdr_stream_decode_u32(xdr, &args->access) < 0) +- return 0; ++ return false; + +- return 1; ++ return true; + } + + /* +diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c +index 37c8fb184ca4d..f60b072ce9ecc 100644 +--- a/fs/nfsd/nfs3acl.c ++++ b/fs/nfsd/nfs3acl.c +@@ -125,38 +125,38 @@ static __be32 nfsd3_proc_setacl(struct svc_rqst *rqstp) + * XDR decode functions + */ + +-static int ++static bool + nfs3svc_decode_getaclargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd3_getaclargs *args = rqstp->rq_argp; + + if (!svcxdr_decode_nfs_fh3(xdr, &args->fh)) +- return 0; ++ return false; + if (xdr_stream_decode_u32(xdr, &args->mask) < 0) +- return 0; ++ return false; + +- return 1; ++ return true; + } + +-static int ++static bool + nfs3svc_decode_setaclargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd3_setaclargs *argp = rqstp->rq_argp; + + if (!svcxdr_decode_nfs_fh3(xdr, &argp->fh)) +- return 0; ++ return false; + if (xdr_stream_decode_u32(xdr, &argp->mask) < 0) +- return 0; ++ return false; + if (argp->mask & ~NFS_ACL_MASK) +- return 0; ++ return false; + if (!nfs_stream_decode_acl(xdr, NULL, (argp->mask & NFS_ACL) ? + &argp->acl_access : NULL)) +- return 0; ++ return false; + if (!nfs_stream_decode_acl(xdr, NULL, (argp->mask & NFS_DFACL) ? + &argp->acl_default : NULL)) +- return 0; ++ return false; + +- return 1; ++ return true; + } + + /* +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index 5f744f03cda7c..1f3de46d24d46 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -556,7 +556,7 @@ void fill_post_wcc(struct svc_fh *fhp) + * XDR decode functions + */ + +-int ++bool + nfs3svc_decode_fhandleargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd_fhandle *args = rqstp->rq_argp; +@@ -564,7 +564,7 @@ nfs3svc_decode_fhandleargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + return svcxdr_decode_nfs_fh3(xdr, &args->fh); + } + +-int ++bool + nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd3_sattrargs *args = rqstp->rq_argp; +@@ -574,7 +574,7 @@ nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + svcxdr_decode_sattrguard3(xdr, args); + } + +-int ++bool + nfs3svc_decode_diropargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd3_diropargs *args = rqstp->rq_argp; +@@ -582,75 +582,75 @@ nfs3svc_decode_diropargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + return svcxdr_decode_diropargs3(xdr, &args->fh, &args->name, &args->len); + } + +-int ++bool + nfs3svc_decode_accessargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd3_accessargs *args = rqstp->rq_argp; + + if (!svcxdr_decode_nfs_fh3(xdr, &args->fh)) +- return 0; ++ return false; + if (xdr_stream_decode_u32(xdr, &args->access) < 0) +- return 0; ++ return false; + +- return 1; ++ return true; + } + +-int ++bool + nfs3svc_decode_readargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd3_readargs *args = rqstp->rq_argp; + + if (!svcxdr_decode_nfs_fh3(xdr, &args->fh)) +- return 0; ++ return false; + if (xdr_stream_decode_u64(xdr, &args->offset) < 0) +- return 0; ++ return false; + if (xdr_stream_decode_u32(xdr, &args->count) < 0) +- return 0; ++ return false; + +- return 1; ++ return true; + } + +-int ++bool + nfs3svc_decode_writeargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd3_writeargs *args = rqstp->rq_argp; + u32 max_blocksize = svc_max_payload(rqstp); + + if (!svcxdr_decode_nfs_fh3(xdr, &args->fh)) +- return 0; ++ return false; + if (xdr_stream_decode_u64(xdr, &args->offset) < 0) +- return 0; ++ return false; + if (xdr_stream_decode_u32(xdr, &args->count) < 0) +- return 0; ++ return false; + if (xdr_stream_decode_u32(xdr, &args->stable) < 0) +- return 0; ++ return false; + + /* opaque data */ + if (xdr_stream_decode_u32(xdr, &args->len) < 0) +- return 0; ++ return false; + + /* request sanity */ + if (args->count != args->len) +- return 0; ++ return false; + if (args->count > max_blocksize) { + args->count = max_blocksize; + args->len = max_blocksize; + } + if (!xdr_stream_subsegment(xdr, &args->payload, args->count)) +- return 0; ++ return false; + +- return 1; ++ return true; + } + +-int ++bool + nfs3svc_decode_createargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd3_createargs *args = rqstp->rq_argp; + + if (!svcxdr_decode_diropargs3(xdr, &args->fh, &args->name, &args->len)) +- return 0; ++ return false; + if (xdr_stream_decode_u32(xdr, &args->createmode) < 0) +- return 0; ++ return false; + switch (args->createmode) { + case NFS3_CREATE_UNCHECKED: + case NFS3_CREATE_GUARDED: +@@ -658,15 +658,15 @@ nfs3svc_decode_createargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + case NFS3_CREATE_EXCLUSIVE: + args->verf = xdr_inline_decode(xdr, NFS3_CREATEVERFSIZE); + if (!args->verf) +- return 0; ++ return false; + break; + default: +- return 0; ++ return false; + } +- return 1; ++ return true; + } + +-int ++bool + nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd3_createargs *args = rqstp->rq_argp; +@@ -676,7 +676,7 @@ nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + svcxdr_decode_sattr3(rqstp, xdr, &args->attrs); + } + +-int ++bool + nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd3_symlinkargs *args = rqstp->rq_argp; +@@ -685,33 +685,33 @@ nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + size_t remaining; + + if (!svcxdr_decode_diropargs3(xdr, &args->ffh, &args->fname, &args->flen)) +- return 0; ++ return false; + if (!svcxdr_decode_sattr3(rqstp, xdr, &args->attrs)) +- return 0; ++ return false; + if (xdr_stream_decode_u32(xdr, &args->tlen) < 0) +- return 0; ++ return false; + + /* request sanity */ + remaining = head->iov_len + rqstp->rq_arg.page_len + tail->iov_len; + remaining -= xdr_stream_pos(xdr); + if (remaining < xdr_align_size(args->tlen)) +- return 0; ++ return false; + + args->first.iov_base = xdr->p; + args->first.iov_len = head->iov_len - xdr_stream_pos(xdr); + +- return 1; ++ return true; + } + +-int ++bool + nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd3_mknodargs *args = rqstp->rq_argp; + + if (!svcxdr_decode_diropargs3(xdr, &args->fh, &args->name, &args->len)) +- return 0; ++ return false; + if (xdr_stream_decode_u32(xdr, &args->ftype) < 0) +- return 0; ++ return false; + switch (args->ftype) { + case NF3CHR: + case NF3BLK: +@@ -725,13 +725,13 @@ nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + /* Valid XDR but illegal file types */ + break; + default: +- return 0; ++ return false; + } + +- return 1; ++ return true; + } + +-int ++bool + nfs3svc_decode_renameargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd3_renameargs *args = rqstp->rq_argp; +@@ -742,7 +742,7 @@ nfs3svc_decode_renameargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + &args->tname, &args->tlen); + } + +-int ++bool + nfs3svc_decode_linkargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd3_linkargs *args = rqstp->rq_argp; +@@ -752,59 +752,59 @@ nfs3svc_decode_linkargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + &args->tname, &args->tlen); + } + +-int ++bool + nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd3_readdirargs *args = rqstp->rq_argp; + + if (!svcxdr_decode_nfs_fh3(xdr, &args->fh)) +- return 0; ++ return false; + if (xdr_stream_decode_u64(xdr, &args->cookie) < 0) +- return 0; ++ return false; + args->verf = xdr_inline_decode(xdr, NFS3_COOKIEVERFSIZE); + if (!args->verf) +- return 0; ++ return false; + if (xdr_stream_decode_u32(xdr, &args->count) < 0) +- return 0; ++ return false; + +- return 1; ++ return true; + } + +-int ++bool + nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd3_readdirargs *args = rqstp->rq_argp; + u32 dircount; + + if (!svcxdr_decode_nfs_fh3(xdr, &args->fh)) +- return 0; ++ return false; + if (xdr_stream_decode_u64(xdr, &args->cookie) < 0) +- return 0; ++ return false; + args->verf = xdr_inline_decode(xdr, NFS3_COOKIEVERFSIZE); + if (!args->verf) +- return 0; ++ return false; + /* dircount is ignored */ + if (xdr_stream_decode_u32(xdr, &dircount) < 0) +- return 0; ++ return false; + if (xdr_stream_decode_u32(xdr, &args->count) < 0) +- return 0; ++ return false; + +- return 1; ++ return true; + } + +-int ++bool + nfs3svc_decode_commitargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd3_commitargs *args = rqstp->rq_argp; + + if (!svcxdr_decode_nfs_fh3(xdr, &args->fh)) +- return 0; ++ return false; + if (xdr_stream_decode_u64(xdr, &args->offset) < 0) +- return 0; ++ return false; + if (xdr_stream_decode_u32(xdr, &args->count) < 0) +- return 0; ++ return false; + +- return 1; ++ return true; + } + + /* +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 5ee5081c56637..1b33c1c93e883 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -2322,7 +2322,7 @@ nfsd4_opnum_in_range(struct nfsd4_compoundargs *argp, struct nfsd4_op *op) + return true; + } + +-static int ++static bool + nfsd4_decode_compound(struct nfsd4_compoundargs *argp) + { + struct nfsd4_op *op; +@@ -2335,25 +2335,25 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) + int i; + + if (xdr_stream_decode_u32(argp->xdr, &argp->taglen) < 0) +- return 0; ++ return false; + max_reply += XDR_UNIT; + argp->tag = NULL; + if (unlikely(argp->taglen)) { + if (argp->taglen > NFSD4_MAX_TAGLEN) +- return 0; ++ return false; + p = xdr_inline_decode(argp->xdr, argp->taglen); + if (!p) +- return 0; ++ return false; + argp->tag = svcxdr_savemem(argp, p, argp->taglen); + if (!argp->tag) +- return 0; ++ return false; + max_reply += xdr_align_size(argp->taglen); + } + + if (xdr_stream_decode_u32(argp->xdr, &argp->minorversion) < 0) +- return 0; ++ return false; + if (xdr_stream_decode_u32(argp->xdr, &argp->opcnt) < 0) +- return 0; ++ return false; + + /* + * NFS4ERR_RESOURCE is a more helpful error than GARBAGE_ARGS +@@ -2361,14 +2361,14 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) + * nfsd4_proc can handle this is an NFS-level error. + */ + if (argp->opcnt > NFSD_MAX_OPS_PER_COMPOUND) +- return 1; ++ return true; + + if (argp->opcnt > ARRAY_SIZE(argp->iops)) { + argp->ops = kzalloc(argp->opcnt * sizeof(*argp->ops), GFP_KERNEL); + if (!argp->ops) { + argp->ops = argp->iops; + dprintk("nfsd: couldn't allocate room for COMPOUND\n"); +- return 0; ++ return false; + } + } + +@@ -2380,7 +2380,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) + op->replay = NULL; + + if (xdr_stream_decode_u32(argp->xdr, &op->opnum) < 0) +- return 0; ++ return false; + if (nfsd4_opnum_in_range(argp, op)) { + op->status = nfsd4_dec_ops[op->opnum](argp, &op->u); + if (op->status != nfs_ok) +@@ -2427,7 +2427,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) + if (readcount > 1 || max_reply > PAGE_SIZE - auth_slack) + clear_bit(RQ_SPLICE_OK, &argp->rqstp->rq_flags); + +- return 1; ++ return true; + } + + static __be32 *encode_change(__be32 *p, struct kstat *stat, struct inode *inode, +@@ -5422,7 +5422,7 @@ void nfsd4_release_compoundargs(struct svc_rqst *rqstp) + } + } + +-int ++bool + nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd4_compoundargs *args = rqstp->rq_argp; +diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h +index 6e8ad5f9757c8..bfcddd4c75345 100644 +--- a/fs/nfsd/nfsd.h ++++ b/fs/nfsd/nfsd.h +@@ -78,7 +78,7 @@ extern const struct seq_operations nfs_exports_op; + */ + struct nfsd_voidargs { }; + struct nfsd_voidres { }; +-int nfssvc_decode_voidarg(struct svc_rqst *rqstp, ++bool nfssvc_decode_voidarg(struct svc_rqst *rqstp, + struct xdr_stream *xdr); + int nfssvc_encode_voidres(struct svc_rqst *rqstp, __be32 *p); + +diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c +index be1d656548cfe..00aadc2635032 100644 +--- a/fs/nfsd/nfssvc.c ++++ b/fs/nfsd/nfssvc.c +@@ -1067,10 +1067,10 @@ int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) + * @xdr: XDR stream positioned at arguments to decode + * + * Return values: +- * %0: Arguments were not valid +- * %1: Decoding was successful ++ * %false: Arguments were not valid ++ * %true: Decoding was successful + */ +-int nfssvc_decode_voidarg(struct svc_rqst *rqstp, struct xdr_stream *xdr) ++bool nfssvc_decode_voidarg(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + return 1; + } +diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c +index 08e899180ee43..b5817a41b3de6 100644 +--- a/fs/nfsd/nfsxdr.c ++++ b/fs/nfsd/nfsxdr.c +@@ -272,7 +272,7 @@ svcxdr_encode_fattr(struct svc_rqst *rqstp, struct xdr_stream *xdr, + * XDR decode functions + */ + +-int ++bool + nfssvc_decode_fhandleargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd_fhandle *args = rqstp->rq_argp; +@@ -280,7 +280,7 @@ nfssvc_decode_fhandleargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + return svcxdr_decode_fhandle(xdr, &args->fh); + } + +-int ++bool + nfssvc_decode_sattrargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd_sattrargs *args = rqstp->rq_argp; +@@ -289,7 +289,7 @@ nfssvc_decode_sattrargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + svcxdr_decode_sattr(rqstp, xdr, &args->attrs); + } + +-int ++bool + nfssvc_decode_diropargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd_diropargs *args = rqstp->rq_argp; +@@ -297,54 +297,54 @@ nfssvc_decode_diropargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + return svcxdr_decode_diropargs(xdr, &args->fh, &args->name, &args->len); + } + +-int ++bool + nfssvc_decode_readargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd_readargs *args = rqstp->rq_argp; + u32 totalcount; + + if (!svcxdr_decode_fhandle(xdr, &args->fh)) +- return 0; ++ return false; + if (xdr_stream_decode_u32(xdr, &args->offset) < 0) +- return 0; ++ return false; + if (xdr_stream_decode_u32(xdr, &args->count) < 0) +- return 0; ++ return false; + /* totalcount is ignored */ + if (xdr_stream_decode_u32(xdr, &totalcount) < 0) +- return 0; ++ return false; + +- return 1; ++ return true; + } + +-int ++bool + nfssvc_decode_writeargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd_writeargs *args = rqstp->rq_argp; + u32 beginoffset, totalcount; + + if (!svcxdr_decode_fhandle(xdr, &args->fh)) +- return 0; ++ return false; + /* beginoffset is ignored */ + if (xdr_stream_decode_u32(xdr, &beginoffset) < 0) +- return 0; ++ return false; + if (xdr_stream_decode_u32(xdr, &args->offset) < 0) +- return 0; ++ return false; + /* totalcount is ignored */ + if (xdr_stream_decode_u32(xdr, &totalcount) < 0) +- return 0; ++ return false; + + /* opaque data */ + if (xdr_stream_decode_u32(xdr, &args->len) < 0) +- return 0; ++ return false; + if (args->len > NFSSVC_MAXBLKSIZE_V2) +- return 0; ++ return false; + if (!xdr_stream_subsegment(xdr, &args->payload, args->len)) +- return 0; ++ return false; + +- return 1; ++ return true; + } + +-int ++bool + nfssvc_decode_createargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd_createargs *args = rqstp->rq_argp; +@@ -354,7 +354,7 @@ nfssvc_decode_createargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + svcxdr_decode_sattr(rqstp, xdr, &args->attrs); + } + +-int ++bool + nfssvc_decode_renameargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd_renameargs *args = rqstp->rq_argp; +@@ -365,7 +365,7 @@ nfssvc_decode_renameargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + &args->tname, &args->tlen); + } + +-int ++bool + nfssvc_decode_linkargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd_linkargs *args = rqstp->rq_argp; +@@ -375,39 +375,39 @@ nfssvc_decode_linkargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + &args->tname, &args->tlen); + } + +-int ++bool + nfssvc_decode_symlinkargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd_symlinkargs *args = rqstp->rq_argp; + struct kvec *head = rqstp->rq_arg.head; + + if (!svcxdr_decode_diropargs(xdr, &args->ffh, &args->fname, &args->flen)) +- return 0; ++ return false; + if (xdr_stream_decode_u32(xdr, &args->tlen) < 0) +- return 0; ++ return false; + if (args->tlen == 0) +- return 0; ++ return false; + + args->first.iov_len = head->iov_len - xdr_stream_pos(xdr); + args->first.iov_base = xdr_inline_decode(xdr, args->tlen); + if (!args->first.iov_base) +- return 0; ++ return false; + return svcxdr_decode_sattr(rqstp, xdr, &args->attrs); + } + +-int ++bool + nfssvc_decode_readdirargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd_readdirargs *args = rqstp->rq_argp; + + if (!svcxdr_decode_fhandle(xdr, &args->fh)) +- return 0; ++ return false; + if (xdr_stream_decode_u32(xdr, &args->cookie) < 0) +- return 0; ++ return false; + if (xdr_stream_decode_u32(xdr, &args->count) < 0) +- return 0; ++ return false; + +- return 1; ++ return true; + } + + /* +diff --git a/fs/nfsd/xdr.h b/fs/nfsd/xdr.h +index 19e281382bb98..d897c198c9126 100644 +--- a/fs/nfsd/xdr.h ++++ b/fs/nfsd/xdr.h +@@ -141,16 +141,16 @@ union nfsd_xdrstore { + #define NFS2_SVC_XDRSIZE sizeof(union nfsd_xdrstore) + + +-int nfssvc_decode_fhandleargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nfssvc_decode_sattrargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nfssvc_decode_diropargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nfssvc_decode_readargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nfssvc_decode_writeargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nfssvc_decode_createargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nfssvc_decode_renameargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nfssvc_decode_linkargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nfssvc_decode_symlinkargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nfssvc_decode_readdirargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfssvc_decode_fhandleargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfssvc_decode_sattrargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfssvc_decode_diropargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfssvc_decode_readargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfssvc_decode_writeargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfssvc_decode_createargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfssvc_decode_renameargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfssvc_decode_linkargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfssvc_decode_symlinkargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfssvc_decode_readdirargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); + + int nfssvc_encode_statres(struct svc_rqst *, __be32 *); + int nfssvc_encode_attrstatres(struct svc_rqst *, __be32 *); +diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h +index 60a8909205e5a..ef72bc4868da6 100644 +--- a/fs/nfsd/xdr3.h ++++ b/fs/nfsd/xdr3.h +@@ -265,21 +265,21 @@ union nfsd3_xdrstore { + + #define NFS3_SVC_XDRSIZE sizeof(union nfsd3_xdrstore) + +-int nfs3svc_decode_fhandleargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nfs3svc_decode_diropargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nfs3svc_decode_accessargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nfs3svc_decode_readargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nfs3svc_decode_writeargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nfs3svc_decode_createargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nfs3svc_decode_renameargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nfs3svc_decode_linkargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nfs3svc_decode_commitargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfs3svc_decode_fhandleargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfs3svc_decode_diropargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfs3svc_decode_accessargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfs3svc_decode_readargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfs3svc_decode_writeargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfs3svc_decode_createargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfs3svc_decode_renameargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfs3svc_decode_linkargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfs3svc_decode_commitargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); + + int nfs3svc_encode_getattrres(struct svc_rqst *, __be32 *); + int nfs3svc_encode_wccstat(struct svc_rqst *, __be32 *); +diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h +index c3e18efcd23b6..8f349640d2e97 100644 +--- a/fs/nfsd/xdr4.h ++++ b/fs/nfsd/xdr4.h +@@ -756,7 +756,7 @@ set_change_info(struct nfsd4_change_info *cinfo, struct svc_fh *fhp) + + + bool nfsd4_mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp); +-int nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); + int nfs4svc_encode_compoundres(struct svc_rqst *, __be32 *); + __be32 nfsd4_check_resp_size(struct nfsd4_compoundres *, u32); + void nfsd4_encode_operation(struct nfsd4_compoundres *, struct nfsd4_op *); +diff --git a/include/linux/lockd/xdr.h b/include/linux/lockd/xdr.h +index 170ad6f5596a0..e1362244f909b 100644 +--- a/include/linux/lockd/xdr.h ++++ b/include/linux/lockd/xdr.h +@@ -96,15 +96,15 @@ struct nlm_reboot { + */ + #define NLMSVC_XDRSIZE sizeof(struct nlm_args) + +-int nlmsvc_decode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nlmsvc_decode_testargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nlmsvc_decode_lockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nlmsvc_decode_cancargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nlmsvc_decode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nlmsvc_decode_reboot(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nlmsvc_decode_shareargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nlmsvc_decode_notify(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nlmsvc_decode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nlmsvc_decode_testargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nlmsvc_decode_lockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nlmsvc_decode_cancargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nlmsvc_decode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nlmsvc_decode_reboot(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nlmsvc_decode_shareargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nlmsvc_decode_notify(struct svc_rqst *rqstp, struct xdr_stream *xdr); + + int nlmsvc_encode_testres(struct svc_rqst *, __be32 *); + int nlmsvc_encode_res(struct svc_rqst *, __be32 *); +diff --git a/include/linux/lockd/xdr4.h b/include/linux/lockd/xdr4.h +index 68e14e0f2b1fb..376b8f6a3763a 100644 +--- a/include/linux/lockd/xdr4.h ++++ b/include/linux/lockd/xdr4.h +@@ -22,15 +22,15 @@ + #define nlm4_fbig cpu_to_be32(NLM_FBIG) + #define nlm4_failed cpu_to_be32(NLM_FAILED) + +-int nlm4svc_decode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nlm4svc_decode_testargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nlm4svc_decode_lockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nlm4svc_decode_cancargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nlm4svc_decode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nlm4svc_decode_reboot(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nlm4svc_decode_shareargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nlm4svc_decode_notify(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nlm4svc_decode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nlm4svc_decode_testargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nlm4svc_decode_lockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nlm4svc_decode_cancargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nlm4svc_decode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nlm4svc_decode_reboot(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nlm4svc_decode_shareargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nlm4svc_decode_notify(struct svc_rqst *rqstp, struct xdr_stream *xdr); + + int nlm4svc_encode_testres(struct svc_rqst *, __be32 *); + int nlm4svc_encode_res(struct svc_rqst *, __be32 *); +diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h +index 77e3a9b398275..85a9884b10743 100644 +--- a/include/linux/sunrpc/svc.h ++++ b/include/linux/sunrpc/svc.h +@@ -457,7 +457,7 @@ struct svc_procedure { + /* process the request: */ + __be32 (*pc_func)(struct svc_rqst *); + /* XDR decode args: */ +- int (*pc_decode)(struct svc_rqst *rqstp, ++ bool (*pc_decode)(struct svc_rqst *rqstp, + struct xdr_stream *xdr); + /* XDR encode result: */ + int (*pc_encode)(struct svc_rqst *, __be32 *data); +-- +2.43.0 + diff --git a/queue-5.10/sunrpc-change-return-value-type-of-.pc_encode.patch b/queue-5.10/sunrpc-change-return-value-type-of-.pc_encode.patch new file mode 100644 index 00000000000..bf034ffb7a9 --- /dev/null +++ b/queue-5.10/sunrpc-change-return-value-type-of-.pc_encode.patch @@ -0,0 +1,1038 @@ +From 538972df6b86b436b10619e3fa6270aa00f15c2f Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 13 Oct 2021 10:41:13 -0400 +Subject: SUNRPC: Change return value type of .pc_encode + +From: Chuck Lever + +[ Upstream commit 130e2054d4a652a2bd79fb1557ddcd19c053cb37 ] + +Returning an undecorated integer is an age-old trope, but it's +not clear (even to previous experts in this code) that the only +valid return values are 1 and 0. These functions do not return +a negative errno, rpc_stat value, or a positive length. + +Document there are only two valid return values by having +.pc_encode return only true or false. + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/xdr.c | 18 ++-- + fs/lockd/xdr4.c | 18 ++-- + fs/nfs/callback_xdr.c | 4 +- + fs/nfsd/nfs2acl.c | 4 +- + fs/nfsd/nfs3acl.c | 18 ++-- + fs/nfsd/nfs3xdr.c | 166 ++++++++++++++++++------------------- + fs/nfsd/nfs4xdr.c | 4 +- + fs/nfsd/nfsd.h | 2 +- + fs/nfsd/nfssvc.c | 8 +- + fs/nfsd/nfsxdr.c | 60 +++++++------- + fs/nfsd/xdr.h | 14 ++-- + fs/nfsd/xdr3.h | 30 +++---- + fs/nfsd/xdr4.h | 2 +- + include/linux/lockd/xdr.h | 8 +- + include/linux/lockd/xdr4.h | 8 +- + include/linux/sunrpc/svc.h | 2 +- + 16 files changed, 183 insertions(+), 183 deletions(-) + +diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c +index 2595b4d14cd44..2fb5748dae0c8 100644 +--- a/fs/lockd/xdr.c ++++ b/fs/lockd/xdr.c +@@ -313,13 +313,13 @@ nlmsvc_decode_notify(struct svc_rqst *rqstp, struct xdr_stream *xdr) + * Encode Reply results + */ + +-int ++bool + nlmsvc_encode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- return 1; ++ return true; + } + +-int ++bool + nlmsvc_encode_testres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nlm_res *resp = rqstp->rq_resp; +@@ -328,7 +328,7 @@ nlmsvc_encode_testres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + svcxdr_encode_testrply(xdr, resp); + } + +-int ++bool + nlmsvc_encode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nlm_res *resp = rqstp->rq_resp; +@@ -337,18 +337,18 @@ nlmsvc_encode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr) + svcxdr_encode_stats(xdr, resp->status); + } + +-int ++bool + nlmsvc_encode_shareres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nlm_res *resp = rqstp->rq_resp; + + if (!svcxdr_encode_cookie(xdr, &resp->cookie)) +- return 0; ++ return false; + if (!svcxdr_encode_stats(xdr, resp->status)) +- return 0; ++ return false; + /* sequence */ + if (xdr_stream_encode_u32(xdr, 0) < 0) +- return 0; ++ return false; + +- return 1; ++ return true; + } +diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c +index 32231c21c22dd..856267c0864bd 100644 +--- a/fs/lockd/xdr4.c ++++ b/fs/lockd/xdr4.c +@@ -312,13 +312,13 @@ nlm4svc_decode_notify(struct svc_rqst *rqstp, struct xdr_stream *xdr) + * Encode Reply results + */ + +-int ++bool + nlm4svc_encode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- return 1; ++ return true; + } + +-int ++bool + nlm4svc_encode_testres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nlm_res *resp = rqstp->rq_resp; +@@ -327,7 +327,7 @@ nlm4svc_encode_testres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + svcxdr_encode_testrply(xdr, resp); + } + +-int ++bool + nlm4svc_encode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nlm_res *resp = rqstp->rq_resp; +@@ -336,18 +336,18 @@ nlm4svc_encode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr) + svcxdr_encode_stats(xdr, resp->status); + } + +-int ++bool + nlm4svc_encode_shareres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nlm_res *resp = rqstp->rq_resp; + + if (!svcxdr_encode_cookie(xdr, &resp->cookie)) +- return 0; ++ return false; + if (!svcxdr_encode_stats(xdr, resp->status)) +- return 0; ++ return false; + /* sequence */ + if (xdr_stream_encode_u32(xdr, 0) < 0) +- return 0; ++ return false; + +- return 1; ++ return true; + } +diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c +index c58b3b60bc2c0..1b21f88a9808c 100644 +--- a/fs/nfs/callback_xdr.c ++++ b/fs/nfs/callback_xdr.c +@@ -67,9 +67,9 @@ static __be32 nfs4_callback_null(struct svc_rqst *rqstp) + * svc_process_common() looks for an XDR encoder to know when + * not to drop a Reply. + */ +-static int nfs4_encode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr) ++static bool nfs4_encode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- return 1; ++ return true; + } + + static __be32 decode_string(struct xdr_stream *xdr, unsigned int *len, +diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c +index 23e4c3eb2c381..96733dff354d3 100644 +--- a/fs/nfsd/nfs2acl.c ++++ b/fs/nfsd/nfs2acl.c +@@ -238,7 +238,7 @@ nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + */ + + /* GETACL */ +-static int ++static bool + nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd3_getaclres *resp = rqstp->rq_resp; +@@ -278,7 +278,7 @@ nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + } + + /* ACCESS */ +-static int ++static bool + nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd3_accessres *resp = rqstp->rq_resp; +diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c +index 21aacba88ea3e..350fae92ae045 100644 +--- a/fs/nfsd/nfs3acl.c ++++ b/fs/nfsd/nfs3acl.c +@@ -164,7 +164,7 @@ nfs3svc_decode_setaclargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + */ + + /* GETACL */ +-static int ++static bool + nfs3svc_encode_getaclres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd3_getaclres *resp = rqstp->rq_resp; +@@ -176,14 +176,14 @@ nfs3svc_encode_getaclres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + int w; + + if (!svcxdr_encode_nfsstat3(xdr, resp->status)) +- return 0; ++ return false; + switch (resp->status) { + case nfs_ok: + inode = d_inode(dentry); + if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) +- return 0; ++ return false; + if (xdr_stream_encode_u32(xdr, resp->mask) < 0) +- return 0; ++ return false; + + base = (char *)xdr->p - (char *)head->iov_base; + +@@ -192,7 +192,7 @@ nfs3svc_encode_getaclres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + (resp->mask & NFS_DFACL) ? resp->acl_default : NULL); + while (w > 0) { + if (!*(rqstp->rq_next_page++)) +- return 0; ++ return false; + w -= PAGE_SIZE; + } + +@@ -205,18 +205,18 @@ nfs3svc_encode_getaclres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + resp->mask & NFS_DFACL, + NFS_ACL_DEFAULT); + if (n <= 0) +- return 0; ++ return false; + break; + default: + if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) +- return 0; ++ return false; + } + +- return 1; ++ return true; + } + + /* SETACL */ +-static int ++static bool + nfs3svc_encode_setaclres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd3_attrstat *resp = rqstp->rq_resp; +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index 63f0be4e44f70..c3ac1b6aa3aaa 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -812,26 +812,26 @@ nfs3svc_decode_commitargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + */ + + /* GETATTR */ +-int ++bool + nfs3svc_encode_getattrres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd3_attrstat *resp = rqstp->rq_resp; + + if (!svcxdr_encode_nfsstat3(xdr, resp->status)) +- return 0; ++ return false; + switch (resp->status) { + case nfs_ok: + lease_get_mtime(d_inode(resp->fh.fh_dentry), &resp->stat.mtime); + if (!svcxdr_encode_fattr3(rqstp, xdr, &resp->fh, &resp->stat)) +- return 0; ++ return false; + break; + } + +- return 1; ++ return true; + } + + /* SETATTR, REMOVE, RMDIR */ +-int ++bool + nfs3svc_encode_wccstat(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd3_attrstat *resp = rqstp->rq_resp; +@@ -841,166 +841,166 @@ nfs3svc_encode_wccstat(struct svc_rqst *rqstp, struct xdr_stream *xdr) + } + + /* LOOKUP */ +-int ++bool + nfs3svc_encode_lookupres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd3_diropres *resp = rqstp->rq_resp; + + if (!svcxdr_encode_nfsstat3(xdr, resp->status)) +- return 0; ++ return false; + switch (resp->status) { + case nfs_ok: + if (!svcxdr_encode_nfs_fh3(xdr, &resp->fh)) +- return 0; ++ return false; + if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) +- return 0; ++ return false; + if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->dirfh)) +- return 0; ++ return false; + break; + default: + if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->dirfh)) +- return 0; ++ return false; + } + +- return 1; ++ return true; + } + + /* ACCESS */ +-int ++bool + nfs3svc_encode_accessres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd3_accessres *resp = rqstp->rq_resp; + + if (!svcxdr_encode_nfsstat3(xdr, resp->status)) +- return 0; ++ return false; + switch (resp->status) { + case nfs_ok: + if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) +- return 0; ++ return false; + if (xdr_stream_encode_u32(xdr, resp->access) < 0) +- return 0; ++ return false; + break; + default: + if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) +- return 0; ++ return false; + } + +- return 1; ++ return true; + } + + /* READLINK */ +-int ++bool + nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd3_readlinkres *resp = rqstp->rq_resp; + struct kvec *head = rqstp->rq_res.head; + + if (!svcxdr_encode_nfsstat3(xdr, resp->status)) +- return 0; ++ return false; + switch (resp->status) { + case nfs_ok: + if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) +- return 0; ++ return false; + if (xdr_stream_encode_u32(xdr, resp->len) < 0) +- return 0; ++ return false; + xdr_write_pages(xdr, resp->pages, 0, resp->len); + if (svc_encode_result_payload(rqstp, head->iov_len, resp->len) < 0) +- return 0; ++ return false; + break; + default: + if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) +- return 0; ++ return false; + } + +- return 1; ++ return true; + } + + /* READ */ +-int ++bool + nfs3svc_encode_readres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd3_readres *resp = rqstp->rq_resp; + struct kvec *head = rqstp->rq_res.head; + + if (!svcxdr_encode_nfsstat3(xdr, resp->status)) +- return 0; ++ return false; + switch (resp->status) { + case nfs_ok: + if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) +- return 0; ++ return false; + if (xdr_stream_encode_u32(xdr, resp->count) < 0) +- return 0; ++ return false; + if (xdr_stream_encode_bool(xdr, resp->eof) < 0) +- return 0; ++ return false; + if (xdr_stream_encode_u32(xdr, resp->count) < 0) +- return 0; ++ return false; + xdr_write_pages(xdr, resp->pages, rqstp->rq_res.page_base, + resp->count); + if (svc_encode_result_payload(rqstp, head->iov_len, resp->count) < 0) +- return 0; ++ return false; + break; + default: + if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) +- return 0; ++ return false; + } + +- return 1; ++ return true; + } + + /* WRITE */ +-int ++bool + nfs3svc_encode_writeres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd3_writeres *resp = rqstp->rq_resp; + + if (!svcxdr_encode_nfsstat3(xdr, resp->status)) +- return 0; ++ return false; + switch (resp->status) { + case nfs_ok: + if (!svcxdr_encode_wcc_data(rqstp, xdr, &resp->fh)) +- return 0; ++ return false; + if (xdr_stream_encode_u32(xdr, resp->count) < 0) +- return 0; ++ return false; + if (xdr_stream_encode_u32(xdr, resp->committed) < 0) +- return 0; ++ return false; + if (!svcxdr_encode_writeverf3(xdr, resp->verf)) +- return 0; ++ return false; + break; + default: + if (!svcxdr_encode_wcc_data(rqstp, xdr, &resp->fh)) +- return 0; ++ return false; + } + +- return 1; ++ return true; + } + + /* CREATE, MKDIR, SYMLINK, MKNOD */ +-int ++bool + nfs3svc_encode_createres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd3_diropres *resp = rqstp->rq_resp; + + if (!svcxdr_encode_nfsstat3(xdr, resp->status)) +- return 0; ++ return false; + switch (resp->status) { + case nfs_ok: + if (!svcxdr_encode_post_op_fh3(xdr, &resp->fh)) +- return 0; ++ return false; + if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) +- return 0; ++ return false; + if (!svcxdr_encode_wcc_data(rqstp, xdr, &resp->dirfh)) +- return 0; ++ return false; + break; + default: + if (!svcxdr_encode_wcc_data(rqstp, xdr, &resp->dirfh)) +- return 0; ++ return false; + } + +- return 1; ++ return true; + } + + /* RENAME */ +-int ++bool + nfs3svc_encode_renameres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd3_renameres *resp = rqstp->rq_resp; +@@ -1011,7 +1011,7 @@ nfs3svc_encode_renameres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + } + + /* LINK */ +-int ++bool + nfs3svc_encode_linkres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd3_linkres *resp = rqstp->rq_resp; +@@ -1022,33 +1022,33 @@ nfs3svc_encode_linkres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + } + + /* READDIR */ +-int ++bool + nfs3svc_encode_readdirres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd3_readdirres *resp = rqstp->rq_resp; + struct xdr_buf *dirlist = &resp->dirlist; + + if (!svcxdr_encode_nfsstat3(xdr, resp->status)) +- return 0; ++ return false; + switch (resp->status) { + case nfs_ok: + if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) +- return 0; ++ return false; + if (!svcxdr_encode_cookieverf3(xdr, resp->verf)) +- return 0; ++ return false; + xdr_write_pages(xdr, dirlist->pages, 0, dirlist->len); + /* no more entries */ + if (xdr_stream_encode_item_absent(xdr) < 0) +- return 0; ++ return false; + if (xdr_stream_encode_bool(xdr, resp->common.err == nfserr_eof) < 0) +- return 0; ++ return false; + break; + default: + if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh)) +- return 0; ++ return false; + } + +- return 1; ++ return true; + } + + static __be32 +@@ -1275,26 +1275,26 @@ svcxdr_encode_fsstat3resok(struct xdr_stream *xdr, + } + + /* FSSTAT */ +-int ++bool + nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd3_fsstatres *resp = rqstp->rq_resp; + + if (!svcxdr_encode_nfsstat3(xdr, resp->status)) +- return 0; ++ return false; + switch (resp->status) { + case nfs_ok: + if (!svcxdr_encode_post_op_attr(rqstp, xdr, &nfs3svc_null_fh)) +- return 0; ++ return false; + if (!svcxdr_encode_fsstat3resok(xdr, resp)) +- return 0; ++ return false; + break; + default: + if (!svcxdr_encode_post_op_attr(rqstp, xdr, &nfs3svc_null_fh)) +- return 0; ++ return false; + } + +- return 1; ++ return true; + } + + static bool +@@ -1321,26 +1321,26 @@ svcxdr_encode_fsinfo3resok(struct xdr_stream *xdr, + } + + /* FSINFO */ +-int ++bool + nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd3_fsinfores *resp = rqstp->rq_resp; + + if (!svcxdr_encode_nfsstat3(xdr, resp->status)) +- return 0; ++ return false; + switch (resp->status) { + case nfs_ok: + if (!svcxdr_encode_post_op_attr(rqstp, xdr, &nfs3svc_null_fh)) +- return 0; ++ return false; + if (!svcxdr_encode_fsinfo3resok(xdr, resp)) +- return 0; ++ return false; + break; + default: + if (!svcxdr_encode_post_op_attr(rqstp, xdr, &nfs3svc_null_fh)) +- return 0; ++ return false; + } + +- return 1; ++ return true; + } + + static bool +@@ -1363,49 +1363,49 @@ svcxdr_encode_pathconf3resok(struct xdr_stream *xdr, + } + + /* PATHCONF */ +-int ++bool + nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd3_pathconfres *resp = rqstp->rq_resp; + + if (!svcxdr_encode_nfsstat3(xdr, resp->status)) +- return 0; ++ return false; + switch (resp->status) { + case nfs_ok: + if (!svcxdr_encode_post_op_attr(rqstp, xdr, &nfs3svc_null_fh)) +- return 0; ++ return false; + if (!svcxdr_encode_pathconf3resok(xdr, resp)) +- return 0; ++ return false; + break; + default: + if (!svcxdr_encode_post_op_attr(rqstp, xdr, &nfs3svc_null_fh)) +- return 0; ++ return false; + } + +- return 1; ++ return true; + } + + /* COMMIT */ +-int ++bool + nfs3svc_encode_commitres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd3_commitres *resp = rqstp->rq_resp; + + if (!svcxdr_encode_nfsstat3(xdr, resp->status)) +- return 0; ++ return false; + switch (resp->status) { + case nfs_ok: + if (!svcxdr_encode_wcc_data(rqstp, xdr, &resp->fh)) +- return 0; ++ return false; + if (!svcxdr_encode_writeverf3(xdr, resp->verf)) +- return 0; ++ return false; + break; + default: + if (!svcxdr_encode_wcc_data(rqstp, xdr, &resp->fh)) +- return 0; ++ return false; + } + +- return 1; ++ return true; + } + + /* +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 697d61819a59d..ba2ed12df2060 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -5437,7 +5437,7 @@ nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + return nfsd4_decode_compound(args); + } + +-int ++bool + nfs4svc_encode_compoundres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd4_compoundres *resp = rqstp->rq_resp; +@@ -5463,7 +5463,7 @@ nfs4svc_encode_compoundres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + *p++ = htonl(resp->opcnt); + + nfsd4_sequence_done(resp); +- return 1; ++ return true; + } + + /* +diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h +index 345f8247d5da9..498e5a4898260 100644 +--- a/fs/nfsd/nfsd.h ++++ b/fs/nfsd/nfsd.h +@@ -80,7 +80,7 @@ struct nfsd_voidargs { }; + struct nfsd_voidres { }; + bool nfssvc_decode_voidarg(struct svc_rqst *rqstp, + struct xdr_stream *xdr); +-int nfssvc_encode_voidres(struct svc_rqst *rqstp, ++bool nfssvc_encode_voidres(struct svc_rqst *rqstp, + struct xdr_stream *xdr); + + /* +diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c +index 195f2bcc65384..7df1505425edc 100644 +--- a/fs/nfsd/nfssvc.c ++++ b/fs/nfsd/nfssvc.c +@@ -1078,12 +1078,12 @@ bool nfssvc_decode_voidarg(struct svc_rqst *rqstp, struct xdr_stream *xdr) + * @xdr: XDR stream into which to encode results + * + * Return values: +- * %0: Local error while encoding +- * %1: Encoding was successful ++ * %false: Local error while encoding ++ * %true: Encoding was successful + */ +-int nfssvc_encode_voidres(struct svc_rqst *rqstp, struct xdr_stream *xdr) ++bool nfssvc_encode_voidres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- return 1; ++ return true; + } + + int nfsd_pool_stats_open(struct inode *inode, struct file *file) +diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c +index 6aa8138ae2f7d..aba8520b4b8b6 100644 +--- a/fs/nfsd/nfsxdr.c ++++ b/fs/nfsd/nfsxdr.c +@@ -414,7 +414,7 @@ nfssvc_decode_readdirargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + * XDR encode functions + */ + +-int ++bool + nfssvc_encode_statres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd_stat *resp = rqstp->rq_resp; +@@ -422,110 +422,110 @@ nfssvc_encode_statres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + return svcxdr_encode_stat(xdr, resp->status); + } + +-int ++bool + nfssvc_encode_attrstatres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd_attrstat *resp = rqstp->rq_resp; + + if (!svcxdr_encode_stat(xdr, resp->status)) +- return 0; ++ return false; + switch (resp->status) { + case nfs_ok: + if (!svcxdr_encode_fattr(rqstp, xdr, &resp->fh, &resp->stat)) +- return 0; ++ return false; + break; + } + +- return 1; ++ return true; + } + +-int ++bool + nfssvc_encode_diropres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd_diropres *resp = rqstp->rq_resp; + + if (!svcxdr_encode_stat(xdr, resp->status)) +- return 0; ++ return false; + switch (resp->status) { + case nfs_ok: + if (!svcxdr_encode_fhandle(xdr, &resp->fh)) +- return 0; ++ return false; + if (!svcxdr_encode_fattr(rqstp, xdr, &resp->fh, &resp->stat)) +- return 0; ++ return false; + break; + } + +- return 1; ++ return true; + } + +-int ++bool + nfssvc_encode_readlinkres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd_readlinkres *resp = rqstp->rq_resp; + struct kvec *head = rqstp->rq_res.head; + + if (!svcxdr_encode_stat(xdr, resp->status)) +- return 0; ++ return false; + switch (resp->status) { + case nfs_ok: + if (xdr_stream_encode_u32(xdr, resp->len) < 0) +- return 0; ++ return false; + xdr_write_pages(xdr, &resp->page, 0, resp->len); + if (svc_encode_result_payload(rqstp, head->iov_len, resp->len) < 0) +- return 0; ++ return false; + break; + } + +- return 1; ++ return true; + } + +-int ++bool + nfssvc_encode_readres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd_readres *resp = rqstp->rq_resp; + struct kvec *head = rqstp->rq_res.head; + + if (!svcxdr_encode_stat(xdr, resp->status)) +- return 0; ++ return false; + switch (resp->status) { + case nfs_ok: + if (!svcxdr_encode_fattr(rqstp, xdr, &resp->fh, &resp->stat)) +- return 0; ++ return false; + if (xdr_stream_encode_u32(xdr, resp->count) < 0) +- return 0; ++ return false; + xdr_write_pages(xdr, resp->pages, rqstp->rq_res.page_base, + resp->count); + if (svc_encode_result_payload(rqstp, head->iov_len, resp->count) < 0) +- return 0; ++ return false; + break; + } + +- return 1; ++ return true; + } + +-int ++bool + nfssvc_encode_readdirres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd_readdirres *resp = rqstp->rq_resp; + struct xdr_buf *dirlist = &resp->dirlist; + + if (!svcxdr_encode_stat(xdr, resp->status)) +- return 0; ++ return false; + switch (resp->status) { + case nfs_ok: + xdr_write_pages(xdr, dirlist->pages, 0, dirlist->len); + /* no more entries */ + if (xdr_stream_encode_item_absent(xdr) < 0) +- return 0; ++ return false; + if (xdr_stream_encode_bool(xdr, resp->common.err == nfserr_eof) < 0) +- return 0; ++ return false; + break; + } + +- return 1; ++ return true; + } + +-int ++bool + nfssvc_encode_statfsres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd_statfsres *resp = rqstp->rq_resp; +@@ -533,12 +533,12 @@ nfssvc_encode_statfsres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + __be32 *p; + + if (!svcxdr_encode_stat(xdr, resp->status)) +- return 0; ++ return false; + switch (resp->status) { + case nfs_ok: + p = xdr_reserve_space(xdr, XDR_UNIT * 5); + if (!p) +- return 0; ++ return false; + *p++ = cpu_to_be32(NFSSVC_MAXBLKSIZE_V2); + *p++ = cpu_to_be32(stat->f_bsize); + *p++ = cpu_to_be32(stat->f_blocks); +@@ -547,7 +547,7 @@ nfssvc_encode_statfsres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + break; + } + +- return 1; ++ return true; + } + + /** +diff --git a/fs/nfsd/xdr.h b/fs/nfsd/xdr.h +index bff7258041fc4..852f71580bd06 100644 +--- a/fs/nfsd/xdr.h ++++ b/fs/nfsd/xdr.h +@@ -152,13 +152,13 @@ bool nfssvc_decode_linkargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); + bool nfssvc_decode_symlinkargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); + bool nfssvc_decode_readdirargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); + +-int nfssvc_encode_statres(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nfssvc_encode_attrstatres(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nfssvc_encode_diropres(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nfssvc_encode_readlinkres(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nfssvc_encode_readres(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nfssvc_encode_statfsres(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nfssvc_encode_readdirres(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfssvc_encode_statres(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfssvc_encode_attrstatres(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfssvc_encode_diropres(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfssvc_encode_readlinkres(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfssvc_encode_readres(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfssvc_encode_statfsres(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfssvc_encode_readdirres(struct svc_rqst *rqstp, struct xdr_stream *xdr); + + void nfssvc_encode_nfscookie(struct nfsd_readdirres *resp, u32 offset); + int nfssvc_encode_entry(void *data, const char *name, int namlen, +diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h +index bb017fc7cba19..03fe4e21306cb 100644 +--- a/fs/nfsd/xdr3.h ++++ b/fs/nfsd/xdr3.h +@@ -281,21 +281,21 @@ bool nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); + bool nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); + bool nfs3svc_decode_commitargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); + +-int nfs3svc_encode_getattrres(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nfs3svc_encode_wccstat(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nfs3svc_encode_lookupres(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nfs3svc_encode_accessres(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nfs3svc_encode_readres(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nfs3svc_encode_writeres(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nfs3svc_encode_createres(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nfs3svc_encode_renameres(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nfs3svc_encode_linkres(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nfs3svc_encode_readdirres(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nfs3svc_encode_commitres(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfs3svc_encode_getattrres(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfs3svc_encode_wccstat(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfs3svc_encode_lookupres(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfs3svc_encode_accessres(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfs3svc_encode_readres(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfs3svc_encode_writeres(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfs3svc_encode_createres(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfs3svc_encode_renameres(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfs3svc_encode_linkres(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfs3svc_encode_readdirres(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfs3svc_encode_commitres(struct svc_rqst *rqstp, struct xdr_stream *xdr); + + void nfs3svc_release_fhandle(struct svc_rqst *); + void nfs3svc_release_fhandle2(struct svc_rqst *); +diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h +index 5b343d0c6963a..4a298ac5515df 100644 +--- a/fs/nfsd/xdr4.h ++++ b/fs/nfsd/xdr4.h +@@ -758,7 +758,7 @@ set_change_info(struct nfsd4_change_info *cinfo, struct svc_fh *fhp) + + bool nfsd4_mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp); + bool nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nfs4svc_encode_compoundres(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nfs4svc_encode_compoundres(struct svc_rqst *rqstp, struct xdr_stream *xdr); + __be32 nfsd4_check_resp_size(struct nfsd4_compoundres *, u32); + void nfsd4_encode_operation(struct nfsd4_compoundres *, struct nfsd4_op *); + void nfsd4_encode_replay(struct xdr_stream *xdr, struct nfsd4_op *op); +diff --git a/include/linux/lockd/xdr.h b/include/linux/lockd/xdr.h +index d8bd26a5525ef..398f70093cd35 100644 +--- a/include/linux/lockd/xdr.h ++++ b/include/linux/lockd/xdr.h +@@ -106,9 +106,9 @@ bool nlmsvc_decode_reboot(struct svc_rqst *rqstp, struct xdr_stream *xdr); + bool nlmsvc_decode_shareargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); + bool nlmsvc_decode_notify(struct svc_rqst *rqstp, struct xdr_stream *xdr); + +-int nlmsvc_encode_testres(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nlmsvc_encode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nlmsvc_encode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nlmsvc_encode_shareres(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nlmsvc_encode_testres(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nlmsvc_encode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nlmsvc_encode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nlmsvc_encode_shareres(struct svc_rqst *rqstp, struct xdr_stream *xdr); + + #endif /* LOCKD_XDR_H */ +diff --git a/include/linux/lockd/xdr4.h b/include/linux/lockd/xdr4.h +index 50677be3557dc..9a6b55da8fd64 100644 +--- a/include/linux/lockd/xdr4.h ++++ b/include/linux/lockd/xdr4.h +@@ -32,10 +32,10 @@ bool nlm4svc_decode_reboot(struct svc_rqst *rqstp, struct xdr_stream *xdr); + bool nlm4svc_decode_shareargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); + bool nlm4svc_decode_notify(struct svc_rqst *rqstp, struct xdr_stream *xdr); + +-int nlm4svc_encode_testres(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nlm4svc_encode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nlm4svc_encode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nlm4svc_encode_shareres(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nlm4svc_encode_testres(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nlm4svc_encode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nlm4svc_encode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++bool nlm4svc_encode_shareres(struct svc_rqst *rqstp, struct xdr_stream *xdr); + + extern const struct rpc_version nlm_version4; + +diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h +index c6a0b4364f4a2..15ecd5b1abacf 100644 +--- a/include/linux/sunrpc/svc.h ++++ b/include/linux/sunrpc/svc.h +@@ -460,7 +460,7 @@ struct svc_procedure { + bool (*pc_decode)(struct svc_rqst *rqstp, + struct xdr_stream *xdr); + /* XDR encode result: */ +- int (*pc_encode)(struct svc_rqst *rqstp, ++ bool (*pc_encode)(struct svc_rqst *rqstp, + struct xdr_stream *xdr); + /* XDR free result: */ + void (*pc_release)(struct svc_rqst *); +-- +2.43.0 + diff --git a/queue-5.10/sunrpc-change-svc_get-to-return-the-svc.patch b/queue-5.10/sunrpc-change-svc_get-to-return-the-svc.patch new file mode 100644 index 00000000000..b058fa1c72c --- /dev/null +++ b/queue-5.10/sunrpc-change-svc_get-to-return-the-svc.patch @@ -0,0 +1,85 @@ +From 892d7885f1d9b5676f5e97f9bf7a081fa755cd53 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Nov 2021 15:51:25 +1100 +Subject: SUNRPC: change svc_get() to return the svc. + +From: NeilBrown + +[ Upstream commit df5e49c880ea0776806b8a9f8ab95e035272cf6f ] + +It is common for 'get' functions to return the object that was 'got', +and there are a couple of places where users of svc_get() would be a +little simpler if svc_get() did that. + +Make it so. + +Signed-off-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/svc.c | 6 ++---- + fs/nfs/callback.c | 6 ++---- + include/linux/sunrpc/svc.h | 3 ++- + 3 files changed, 6 insertions(+), 9 deletions(-) + +diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c +index b220e1b917268..2f50d5b2a8a42 100644 +--- a/fs/lockd/svc.c ++++ b/fs/lockd/svc.c +@@ -430,14 +430,12 @@ static struct svc_serv *lockd_create_svc(void) + /* + * Check whether we're already up and running. + */ +- if (nlmsvc_rqst) { ++ if (nlmsvc_rqst) + /* + * Note: increase service usage, because later in case of error + * svc_destroy() will be called. + */ +- svc_get(nlmsvc_rqst->rq_server); +- return nlmsvc_rqst->rq_server; +- } ++ return svc_get(nlmsvc_rqst->rq_server); + + /* + * Sanity check: if there's no pid, +diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c +index 3c86a559a321a..674198e0eb5e1 100644 +--- a/fs/nfs/callback.c ++++ b/fs/nfs/callback.c +@@ -266,14 +266,12 @@ static struct svc_serv *nfs_callback_create_svc(int minorversion) + /* + * Check whether we're already up and running. + */ +- if (cb_info->serv) { ++ if (cb_info->serv) + /* + * Note: increase service usage, because later in case of error + * svc_destroy() will be called. + */ +- svc_get(cb_info->serv); +- return cb_info->serv; +- } ++ return svc_get(cb_info->serv); + + switch (minorversion) { + case 0: +diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h +index 15ecd5b1abacf..e2580f6a05c21 100644 +--- a/include/linux/sunrpc/svc.h ++++ b/include/linux/sunrpc/svc.h +@@ -120,9 +120,10 @@ struct svc_serv { + * change the number of threads. Horrible, but there it is. + * Should be called with the "service mutex" held. + */ +-static inline void svc_get(struct svc_serv *serv) ++static inline struct svc_serv *svc_get(struct svc_serv *serv) + { + serv->sv_nrthreads++; ++ return serv; + } + + /* +-- +2.43.0 + diff --git a/queue-5.10/sunrpc-discard-svo_setup-and-rename-svc_set_num_thre.patch b/queue-5.10/sunrpc-discard-svo_setup-and-rename-svc_set_num_thre.patch new file mode 100644 index 00000000000..14f727c4b10 --- /dev/null +++ b/queue-5.10/sunrpc-discard-svo_setup-and-rename-svc_set_num_thre.patch @@ -0,0 +1,215 @@ +From 18eaea9f9fd4720e4e1ca853b50c53f36b88d26c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Nov 2021 15:51:25 +1100 +Subject: SUNRPC: discard svo_setup and rename svc_set_num_threads_sync() + +From: NeilBrown + +[ Upstream commit 3ebdbe5203a874614819700d3f470724cb803709 ] + +The ->svo_setup callback serves no purpose. It is always called from +within the same module that chooses which callback is needed. So +discard it and call the relevant function directly. + +Now that svc_set_num_threads() is no longer used remove it and rename +svc_set_num_threads_sync() to remove the "_sync" suffix. + +Signed-off-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfs/callback.c | 8 +++---- + fs/nfsd/nfssvc.c | 11 ++++----- + include/linux/sunrpc/svc.h | 4 ---- + net/sunrpc/svc.c | 49 ++------------------------------------ + 4 files changed, 10 insertions(+), 62 deletions(-) + +diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c +index 09ec60b99f65e..422055a1092f0 100644 +--- a/fs/nfs/callback.c ++++ b/fs/nfs/callback.c +@@ -172,9 +172,9 @@ static int nfs_callback_start_svc(int minorversion, struct rpc_xprt *xprt, + if (serv->sv_nrthreads == nrservs) + return 0; + +- ret = serv->sv_ops->svo_setup(serv, NULL, nrservs); ++ ret = svc_set_num_threads(serv, NULL, nrservs); + if (ret) { +- serv->sv_ops->svo_setup(serv, NULL, 0); ++ svc_set_num_threads(serv, NULL, 0); + return ret; + } + dprintk("nfs_callback_up: service started\n"); +@@ -235,14 +235,12 @@ static int nfs_callback_up_net(int minorversion, struct svc_serv *serv, + static const struct svc_serv_ops nfs40_cb_sv_ops = { + .svo_function = nfs4_callback_svc, + .svo_enqueue_xprt = svc_xprt_do_enqueue, +- .svo_setup = svc_set_num_threads_sync, + .svo_module = THIS_MODULE, + }; + #if defined(CONFIG_NFS_V4_1) + static const struct svc_serv_ops nfs41_cb_sv_ops = { + .svo_function = nfs41_callback_svc, + .svo_enqueue_xprt = svc_xprt_do_enqueue, +- .svo_setup = svc_set_num_threads_sync, + .svo_module = THIS_MODULE, + }; + +@@ -357,7 +355,7 @@ void nfs_callback_down(int minorversion, struct net *net) + cb_info->users--; + if (cb_info->users == 0) { + svc_get(serv); +- serv->sv_ops->svo_setup(serv, NULL, 0); ++ svc_set_num_threads(serv, NULL, 0); + svc_put(serv); + dprintk("nfs_callback_down: service destroyed\n"); + cb_info->serv = NULL; +diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c +index 6b10415e4006b..8d49dfbe03f85 100644 +--- a/fs/nfsd/nfssvc.c ++++ b/fs/nfsd/nfssvc.c +@@ -593,7 +593,6 @@ static const struct svc_serv_ops nfsd_thread_sv_ops = { + .svo_shutdown = nfsd_last_thread, + .svo_function = nfsd, + .svo_enqueue_xprt = svc_xprt_do_enqueue, +- .svo_setup = svc_set_num_threads_sync, + .svo_module = THIS_MODULE, + }; + +@@ -611,7 +610,7 @@ void nfsd_shutdown_threads(struct net *net) + + svc_get(serv); + /* Kill outstanding nfsd threads */ +- serv->sv_ops->svo_setup(serv, NULL, 0); ++ svc_set_num_threads(serv, NULL, 0); + nfsd_put(net); + mutex_unlock(&nfsd_mutex); + } +@@ -750,8 +749,9 @@ int nfsd_set_nrthreads(int n, int *nthreads, struct net *net) + /* apply the new numbers */ + svc_get(nn->nfsd_serv); + for (i = 0; i < n; i++) { +- err = nn->nfsd_serv->sv_ops->svo_setup(nn->nfsd_serv, +- &nn->nfsd_serv->sv_pools[i], nthreads[i]); ++ err = svc_set_num_threads(nn->nfsd_serv, ++ &nn->nfsd_serv->sv_pools[i], ++ nthreads[i]); + if (err) + break; + } +@@ -793,8 +793,7 @@ nfsd_svc(int nrservs, struct net *net, const struct cred *cred) + error = nfsd_startup_net(net, cred); + if (error) + goto out_put; +- error = nn->nfsd_serv->sv_ops->svo_setup(nn->nfsd_serv, +- NULL, nrservs); ++ error = svc_set_num_threads(nn->nfsd_serv, NULL, nrservs); + if (error) + goto out_shutdown; + error = nn->nfsd_serv->sv_nrthreads; +diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h +index 2768d61b8aed5..165719a6229ab 100644 +--- a/include/linux/sunrpc/svc.h ++++ b/include/linux/sunrpc/svc.h +@@ -64,9 +64,6 @@ struct svc_serv_ops { + /* queue up a transport for servicing */ + void (*svo_enqueue_xprt)(struct svc_xprt *); + +- /* set up thread (or whatever) execution context */ +- int (*svo_setup)(struct svc_serv *, struct svc_pool *, int); +- + /* optional module to count when adding threads (pooled svcs only) */ + struct module *svo_module; + }; +@@ -544,7 +541,6 @@ void svc_pool_map_put(void); + struct svc_serv * svc_create_pooled(struct svc_program *, unsigned int, + const struct svc_serv_ops *); + int svc_set_num_threads(struct svc_serv *, struct svc_pool *, int); +-int svc_set_num_threads_sync(struct svc_serv *, struct svc_pool *, int); + int svc_pool_stats_open(struct svc_serv *serv, struct file *file); + void svc_shutdown_net(struct svc_serv *, struct net *); + int svc_process(struct svc_rqst *); +diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c +index 283088f3215e6..da5f008b8d27c 100644 +--- a/net/sunrpc/svc.c ++++ b/net/sunrpc/svc.c +@@ -741,58 +741,13 @@ svc_start_kthreads(struct svc_serv *serv, struct svc_pool *pool, int nrservs) + return 0; + } + +- +-/* destroy old threads */ +-static int +-svc_signal_kthreads(struct svc_serv *serv, struct svc_pool *pool, int nrservs) +-{ +- struct task_struct *task; +- unsigned int state = serv->sv_nrthreads-1; +- +- /* destroy old threads */ +- do { +- task = choose_victim(serv, pool, &state); +- if (task == NULL) +- break; +- send_sig(SIGINT, task, 1); +- nrservs++; +- } while (nrservs < 0); +- +- return 0; +-} +- + /* + * Create or destroy enough new threads to make the number + * of threads the given number. If `pool' is non-NULL, applies + * only to threads in that pool, otherwise round-robins between + * all pools. Caller must ensure that mutual exclusion between this and + * server startup or shutdown. +- * +- * Destroying threads relies on the service threads filling in +- * rqstp->rq_task, which only the nfs ones do. Assumes the serv +- * has been created using svc_create_pooled(). +- * +- * Based on code that used to be in nfsd_svc() but tweaked +- * to be pool-aware. + */ +-int +-svc_set_num_threads(struct svc_serv *serv, struct svc_pool *pool, int nrservs) +-{ +- if (pool == NULL) { +- nrservs -= serv->sv_nrthreads; +- } else { +- spin_lock_bh(&pool->sp_lock); +- nrservs -= pool->sp_nrthreads; +- spin_unlock_bh(&pool->sp_lock); +- } +- +- if (nrservs > 0) +- return svc_start_kthreads(serv, pool, nrservs); +- if (nrservs < 0) +- return svc_signal_kthreads(serv, pool, nrservs); +- return 0; +-} +-EXPORT_SYMBOL_GPL(svc_set_num_threads); + + /* destroy old threads */ + static int +@@ -817,7 +772,7 @@ svc_stop_kthreads(struct svc_serv *serv, struct svc_pool *pool, int nrservs) + } + + int +-svc_set_num_threads_sync(struct svc_serv *serv, struct svc_pool *pool, int nrservs) ++svc_set_num_threads(struct svc_serv *serv, struct svc_pool *pool, int nrservs) + { + if (pool == NULL) { + nrservs -= serv->sv_nrthreads; +@@ -833,7 +788,7 @@ svc_set_num_threads_sync(struct svc_serv *serv, struct svc_pool *pool, int nrser + return svc_stop_kthreads(serv, pool, nrservs); + return 0; + } +-EXPORT_SYMBOL_GPL(svc_set_num_threads_sync); ++EXPORT_SYMBOL_GPL(svc_set_num_threads); + + /** + * svc_rqst_replace_page - Replace one page in rq_pages[] +-- +2.43.0 + diff --git a/queue-5.10/sunrpc-display-rpc-procedure-names-instead-of-proc-n.patch b/queue-5.10/sunrpc-display-rpc-procedure-names-instead-of-proc-n.patch new file mode 100644 index 00000000000..d4a809fe2e2 --- /dev/null +++ b/queue-5.10/sunrpc-display-rpc-procedure-names-instead-of-proc-n.patch @@ -0,0 +1,75 @@ +From eb4621541b55e8fcc4ca580ac207eeba8a59f4c0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 3 Dec 2020 10:22:09 -0500 +Subject: SUNRPC: Display RPC procedure names instead of proc numbers + +From: Chuck Lever + +[ Upstream commit 89ff87494c6e4b32ea7960d0c644efdbb2fe6ef5 ] + +Make the sunrpc trace subsystem trace events easier to use. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + include/trace/events/sunrpc.h | 15 +++++++++++---- + 1 file changed, 11 insertions(+), 4 deletions(-) + +diff --git a/include/trace/events/sunrpc.h b/include/trace/events/sunrpc.h +index 8220369ee6105..200978b94a0b9 100644 +--- a/include/trace/events/sunrpc.h ++++ b/include/trace/events/sunrpc.h +@@ -1578,6 +1578,7 @@ TRACE_EVENT(svc_process, + __field(u32, vers) + __field(u32, proc) + __string(service, name) ++ __string(procedure, rqst->rq_procinfo->pc_name) + __string(addr, rqst->rq_xprt ? + rqst->rq_xprt->xpt_remotebuf : "(null)") + ), +@@ -1587,13 +1588,16 @@ TRACE_EVENT(svc_process, + __entry->vers = rqst->rq_vers; + __entry->proc = rqst->rq_proc; + __assign_str(service, name); ++ __assign_str(procedure, rqst->rq_procinfo->pc_name); + __assign_str(addr, rqst->rq_xprt ? + rqst->rq_xprt->xpt_remotebuf : "(null)"); + ), + +- TP_printk("addr=%s xid=0x%08x service=%s vers=%u proc=%u", ++ TP_printk("addr=%s xid=0x%08x service=%s vers=%u proc=%s", + __get_str(addr), __entry->xid, +- __get_str(service), __entry->vers, __entry->proc) ++ __get_str(service), __entry->vers, ++ __get_str(procedure) ++ ) + ); + + DECLARE_EVENT_CLASS(svc_rqst_event, +@@ -1849,6 +1853,7 @@ TRACE_EVENT(svc_stats_latency, + TP_STRUCT__entry( + __field(u32, xid) + __field(unsigned long, execute) ++ __string(procedure, rqst->rq_procinfo->pc_name) + __string(addr, rqst->rq_xprt->xpt_remotebuf) + ), + +@@ -1856,11 +1861,13 @@ TRACE_EVENT(svc_stats_latency, + __entry->xid = be32_to_cpu(rqst->rq_xid); + __entry->execute = ktime_to_us(ktime_sub(ktime_get(), + rqst->rq_stime)); ++ __assign_str(procedure, rqst->rq_procinfo->pc_name); + __assign_str(addr, rqst->rq_xprt->xpt_remotebuf); + ), + +- TP_printk("addr=%s xid=0x%08x execute-us=%lu", +- __get_str(addr), __entry->xid, __entry->execute) ++ TP_printk("addr=%s xid=0x%08x proc=%s execute-us=%lu", ++ __get_str(addr), __entry->xid, __get_str(procedure), ++ __entry->execute) + ); + + DECLARE_EVENT_CLASS(svc_deferred_event, +-- +2.43.0 + diff --git a/queue-5.10/sunrpc-eliminate-the-rq_autherr-flag.patch b/queue-5.10/sunrpc-eliminate-the-rq_autherr-flag.patch new file mode 100644 index 00000000000..2d12a7492f8 --- /dev/null +++ b/queue-5.10/sunrpc-eliminate-the-rq_autherr-flag.patch @@ -0,0 +1,129 @@ +From 6f5e5f61ae354469091c43ee86ee3f7ff035172b Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jul 2021 15:52:19 -0400 +Subject: SUNRPC: Eliminate the RQ_AUTHERR flag + +From: Chuck Lever + +[ Upstream commit 9082e1d914f8b27114352b1940bbcc7522f682e7 ] + +Now that there is an alternate method for returning an auth_stat +value, replace the RQ_AUTHERR flag with use of that new method. + +Signed-off-by: Chuck Lever +Signed-off-by: Anna Schumaker +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfs/callback_xdr.c | 3 ++- + include/linux/sunrpc/svc.h | 2 -- + include/trace/events/sunrpc.h | 3 +-- + net/sunrpc/svc.c | 24 ++++-------------------- + 4 files changed, 7 insertions(+), 25 deletions(-) + +diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c +index f9dfd4e712a30..0559e8b6a8ec4 100644 +--- a/fs/nfs/callback_xdr.c ++++ b/fs/nfs/callback_xdr.c +@@ -984,7 +984,8 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp) + + out_invalidcred: + pr_warn_ratelimited("NFS: NFSv4 callback contains invalid cred\n"); +- return svc_return_autherr(rqstp, rpc_autherr_badcred); ++ rqstp->rq_auth_stat = rpc_autherr_badcred; ++ return rpc_success; + } + + /* +diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h +index 7b7bd8a0a6fbd..dd3daadbc0e5c 100644 +--- a/include/linux/sunrpc/svc.h ++++ b/include/linux/sunrpc/svc.h +@@ -277,7 +277,6 @@ struct svc_rqst { + #define RQ_VICTIM (5) /* about to be shut down */ + #define RQ_BUSY (6) /* request is busy */ + #define RQ_DATA (7) /* request has data */ +-#define RQ_AUTHERR (8) /* Request status is auth error */ + unsigned long rq_flags; /* flags field */ + ktime_t rq_qtime; /* enqueue time */ + +@@ -537,7 +536,6 @@ unsigned int svc_fill_write_vector(struct svc_rqst *rqstp, + char *svc_fill_symlink_pathname(struct svc_rqst *rqstp, + struct kvec *first, void *p, + size_t total); +-__be32 svc_return_autherr(struct svc_rqst *rqstp, __be32 auth_err); + __be32 svc_generic_init_request(struct svc_rqst *rqstp, + const struct svc_program *progp, + struct svc_process_info *procinfo); +diff --git a/include/trace/events/sunrpc.h b/include/trace/events/sunrpc.h +index 0cb9e182a1b1e..fce071f39f51f 100644 +--- a/include/trace/events/sunrpc.h ++++ b/include/trace/events/sunrpc.h +@@ -1480,8 +1480,7 @@ DEFINE_SVCXDRBUF_EVENT(sendto); + svc_rqst_flag(SPLICE_OK) \ + svc_rqst_flag(VICTIM) \ + svc_rqst_flag(BUSY) \ +- svc_rqst_flag(DATA) \ +- svc_rqst_flag_end(AUTHERR) ++ svc_rqst_flag_end(DATA) + + #undef svc_rqst_flag + #undef svc_rqst_flag_end +diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c +index f036507275338..0d3c3ca2830a8 100644 +--- a/net/sunrpc/svc.c ++++ b/net/sunrpc/svc.c +@@ -1187,22 +1187,6 @@ void svc_printk(struct svc_rqst *rqstp, const char *fmt, ...) + static __printf(2,3) void svc_printk(struct svc_rqst *rqstp, const char *fmt, ...) {} + #endif + +-__be32 +-svc_return_autherr(struct svc_rqst *rqstp, __be32 auth_err) +-{ +- set_bit(RQ_AUTHERR, &rqstp->rq_flags); +- return auth_err; +-} +-EXPORT_SYMBOL_GPL(svc_return_autherr); +- +-static __be32 +-svc_get_autherr(struct svc_rqst *rqstp, __be32 *statp) +-{ +- if (test_and_clear_bit(RQ_AUTHERR, &rqstp->rq_flags)) +- return *statp; +- return rpc_auth_ok; +-} +- + static int + svc_generic_dispatch(struct svc_rqst *rqstp, __be32 *statp) + { +@@ -1226,7 +1210,7 @@ svc_generic_dispatch(struct svc_rqst *rqstp, __be32 *statp) + test_bit(RQ_DROPME, &rqstp->rq_flags)) + return 0; + +- if (test_bit(RQ_AUTHERR, &rqstp->rq_flags)) ++ if (rqstp->rq_auth_stat != rpc_auth_ok) + return 1; + + if (*statp != rpc_success) +@@ -1412,15 +1396,15 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv) + goto release_dropit; + if (*statp == rpc_garbage_args) + goto err_garbage; +- rqstp->rq_auth_stat = svc_get_autherr(rqstp, statp); +- if (rqstp->rq_auth_stat != rpc_auth_ok) +- goto err_release_bad_auth; + } else { + dprintk("svc: calling dispatcher\n"); + if (!process.dispatch(rqstp, statp)) + goto release_dropit; /* Release reply info */ + } + ++ if (rqstp->rq_auth_stat != rpc_auth_ok) ++ goto err_release_bad_auth; ++ + /* Check RPC status result */ + if (*statp != rpc_success) + resv->iov_len = ((void*)statp) - resv->iov_base + 4; +-- +2.43.0 + diff --git a/queue-5.10/sunrpc-export-svc_xprt_received.patch b/queue-5.10/sunrpc-export-svc_xprt_received.patch new file mode 100644 index 00000000000..8140ca906e5 --- /dev/null +++ b/queue-5.10/sunrpc-export-svc_xprt_received.patch @@ -0,0 +1,89 @@ +From 0af1404b223c837da46e897ac7db98619230b9f4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 Jan 2021 13:04:04 -0500 +Subject: SUNRPC: Export svc_xprt_received() + +From: Chuck Lever + +[ Upstream commit 7dcfbd86adc45f6d6b37278efd22530cf80ab474 ] + +Prepare svc_xprt_received() to be called from transport code instead +of from generic RPC server code. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + include/linux/sunrpc/svc_xprt.h | 1 + + include/trace/events/sunrpc.h | 1 + + net/sunrpc/svc_xprt.c | 13 +++++++++---- + 3 files changed, 11 insertions(+), 4 deletions(-) + +diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h +index 92455e0d52445..c5278871f9e40 100644 +--- a/include/linux/sunrpc/svc_xprt.h ++++ b/include/linux/sunrpc/svc_xprt.h +@@ -130,6 +130,7 @@ void svc_xprt_init(struct net *, struct svc_xprt_class *, struct svc_xprt *, + int svc_create_xprt(struct svc_serv *, const char *, struct net *, + const int, const unsigned short, int, + const struct cred *); ++void svc_xprt_received(struct svc_xprt *xprt); + void svc_xprt_do_enqueue(struct svc_xprt *xprt); + void svc_xprt_enqueue(struct svc_xprt *xprt); + void svc_xprt_put(struct svc_xprt *xprt); +diff --git a/include/trace/events/sunrpc.h b/include/trace/events/sunrpc.h +index 200978b94a0b9..657138ab1f91f 100644 +--- a/include/trace/events/sunrpc.h ++++ b/include/trace/events/sunrpc.h +@@ -1756,6 +1756,7 @@ DECLARE_EVENT_CLASS(svc_xprt_event, + ), \ + TP_ARGS(xprt)) + ++DEFINE_SVC_XPRT_EVENT(received); + DEFINE_SVC_XPRT_EVENT(no_write_space); + DEFINE_SVC_XPRT_EVENT(close); + DEFINE_SVC_XPRT_EVENT(detach); +diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c +index 06e503466c32c..d150e25b4d45e 100644 +--- a/net/sunrpc/svc_xprt.c ++++ b/net/sunrpc/svc_xprt.c +@@ -233,21 +233,25 @@ static struct svc_xprt *__svc_xpo_create(struct svc_xprt_class *xcl, + return xprt; + } + +-/* +- * svc_xprt_received conditionally queues the transport for processing +- * by another thread. The caller must hold the XPT_BUSY bit and must ++/** ++ * svc_xprt_received - start next receiver thread ++ * @xprt: controlling transport ++ * ++ * The caller must hold the XPT_BUSY bit and must + * not thereafter touch transport data. + * + * Note: XPT_DATA only gets cleared when a read-attempt finds no (or + * insufficient) data. + */ +-static void svc_xprt_received(struct svc_xprt *xprt) ++void svc_xprt_received(struct svc_xprt *xprt) + { + if (!test_bit(XPT_BUSY, &xprt->xpt_flags)) { + WARN_ONCE(1, "xprt=0x%p already busy!", xprt); + return; + } + ++ trace_svc_xprt_received(xprt); ++ + /* As soon as we clear busy, the xprt could be closed and + * 'put', so we need a reference to call svc_enqueue_xprt with: + */ +@@ -257,6 +261,7 @@ static void svc_xprt_received(struct svc_xprt *xprt) + xprt->xpt_server->sv_ops->svo_enqueue_xprt(xprt); + svc_xprt_put(xprt); + } ++EXPORT_SYMBOL_GPL(svc_xprt_received); + + void svc_add_new_perm_xprt(struct svc_serv *serv, struct svc_xprt *new) + { +-- +2.43.0 + diff --git a/queue-5.10/sunrpc-fix-xdr_encode_bool.patch b/queue-5.10/sunrpc-fix-xdr_encode_bool.patch new file mode 100644 index 00000000000..542a28d6f76 --- /dev/null +++ b/queue-5.10/sunrpc-fix-xdr_encode_bool.patch @@ -0,0 +1,44 @@ +From 3cae461a445d2bdd4955b1431b6f4191bdab77b6 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 19 Jul 2022 09:18:35 -0400 +Subject: SUNRPC: Fix xdr_encode_bool() + +From: Chuck Lever + +[ Upstream commit c770f31d8f580ed4b965c64f924ec1cc50e41734 ] + +I discovered that xdr_encode_bool() was returning the same address +that was passed in the @p parameter. The documenting comment states +that the intent is to return the address of the next buffer +location, just like the other "xdr_encode_*" helpers. + +The result was the encoded results of NFSv3 PATHCONF operations were +not formed correctly. + +Fixes: ded04a587f6c ("NFSD: Update the NFSv3 PATHCONF3res encoder to use struct xdr_stream") +Signed-off-by: Chuck Lever +Reviewed-by: Jeff Layton +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + include/linux/sunrpc/xdr.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h +index b8fb866e1fd32..59d99ff31c1a9 100644 +--- a/include/linux/sunrpc/xdr.h ++++ b/include/linux/sunrpc/xdr.h +@@ -418,8 +418,8 @@ static inline int xdr_stream_encode_item_absent(struct xdr_stream *xdr) + */ + static inline __be32 *xdr_encode_bool(__be32 *p, u32 n) + { +- *p = n ? xdr_one : xdr_zero; +- return p++; ++ *p++ = n ? xdr_one : xdr_zero; ++ return p; + } + + /** +-- +2.43.0 + diff --git a/queue-5.10/sunrpc-make-trace_svc_process-display-the-rpc-proced.patch b/queue-5.10/sunrpc-make-trace_svc_process-display-the-rpc-proced.patch new file mode 100644 index 00000000000..8152a510b58 --- /dev/null +++ b/queue-5.10/sunrpc-make-trace_svc_process-display-the-rpc-proced.patch @@ -0,0 +1,873 @@ +From e18fd4582f06000a382b03cbbb8b14e196c61b39 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 17 Sep 2020 17:22:49 -0400 +Subject: SUNRPC: Make trace_svc_process() display the RPC procedure + symbolically + +From: Chuck Lever + +[ Upstream commit 2289e87b5951f97783f07fc895e6c5e804b53668 ] + +The next few patches will employ these strings to help make server- +side trace logs more human-readable. A similar technique is already +in use in kernel RPC client code. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/svc4proc.c | 24 ++++++++++++++++++++++++ + fs/lockd/svcproc.c | 24 ++++++++++++++++++++++++ + fs/nfs/callback_xdr.c | 2 ++ + fs/nfsd/nfs2acl.c | 5 +++++ + fs/nfsd/nfs3acl.c | 3 +++ + fs/nfsd/nfs3proc.c | 22 ++++++++++++++++++++++ + fs/nfsd/nfs4proc.c | 2 ++ + fs/nfsd/nfsproc.c | 18 ++++++++++++++++++ + include/linux/sunrpc/svc.h | 1 + + 9 files changed, 101 insertions(+) + +diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c +index fa41dda399259..4c10fb5138f10 100644 +--- a/fs/lockd/svc4proc.c ++++ b/fs/lockd/svc4proc.c +@@ -512,6 +512,7 @@ const struct svc_procedure nlmsvc_procedures4[24] = { + .pc_argsize = sizeof(struct nlm_void), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, ++ .pc_name = "NULL", + }, + [NLMPROC_TEST] = { + .pc_func = nlm4svc_proc_test, +@@ -520,6 +521,7 @@ const struct svc_procedure nlmsvc_procedures4[24] = { + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St+2+No+Rg, ++ .pc_name = "TEST", + }, + [NLMPROC_LOCK] = { + .pc_func = nlm4svc_proc_lock, +@@ -528,6 +530,7 @@ const struct svc_procedure nlmsvc_procedures4[24] = { + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St, ++ .pc_name = "LOCK", + }, + [NLMPROC_CANCEL] = { + .pc_func = nlm4svc_proc_cancel, +@@ -536,6 +539,7 @@ const struct svc_procedure nlmsvc_procedures4[24] = { + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St, ++ .pc_name = "CANCEL", + }, + [NLMPROC_UNLOCK] = { + .pc_func = nlm4svc_proc_unlock, +@@ -544,6 +548,7 @@ const struct svc_procedure nlmsvc_procedures4[24] = { + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St, ++ .pc_name = "UNLOCK", + }, + [NLMPROC_GRANTED] = { + .pc_func = nlm4svc_proc_granted, +@@ -552,6 +557,7 @@ const struct svc_procedure nlmsvc_procedures4[24] = { + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St, ++ .pc_name = "GRANTED", + }, + [NLMPROC_TEST_MSG] = { + .pc_func = nlm4svc_proc_test_msg, +@@ -560,6 +566,7 @@ const struct svc_procedure nlmsvc_procedures4[24] = { + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, ++ .pc_name = "TEST_MSG", + }, + [NLMPROC_LOCK_MSG] = { + .pc_func = nlm4svc_proc_lock_msg, +@@ -568,6 +575,7 @@ const struct svc_procedure nlmsvc_procedures4[24] = { + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, ++ .pc_name = "LOCK_MSG", + }, + [NLMPROC_CANCEL_MSG] = { + .pc_func = nlm4svc_proc_cancel_msg, +@@ -576,6 +584,7 @@ const struct svc_procedure nlmsvc_procedures4[24] = { + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, ++ .pc_name = "CANCEL_MSG", + }, + [NLMPROC_UNLOCK_MSG] = { + .pc_func = nlm4svc_proc_unlock_msg, +@@ -584,6 +593,7 @@ const struct svc_procedure nlmsvc_procedures4[24] = { + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, ++ .pc_name = "UNLOCK_MSG", + }, + [NLMPROC_GRANTED_MSG] = { + .pc_func = nlm4svc_proc_granted_msg, +@@ -592,6 +602,7 @@ const struct svc_procedure nlmsvc_procedures4[24] = { + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, ++ .pc_name = "GRANTED_MSG", + }, + [NLMPROC_TEST_RES] = { + .pc_func = nlm4svc_proc_null, +@@ -600,6 +611,7 @@ const struct svc_procedure nlmsvc_procedures4[24] = { + .pc_argsize = sizeof(struct nlm_res), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, ++ .pc_name = "TEST_RES", + }, + [NLMPROC_LOCK_RES] = { + .pc_func = nlm4svc_proc_null, +@@ -608,6 +620,7 @@ const struct svc_procedure nlmsvc_procedures4[24] = { + .pc_argsize = sizeof(struct nlm_res), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, ++ .pc_name = "LOCK_RES", + }, + [NLMPROC_CANCEL_RES] = { + .pc_func = nlm4svc_proc_null, +@@ -616,6 +629,7 @@ const struct svc_procedure nlmsvc_procedures4[24] = { + .pc_argsize = sizeof(struct nlm_res), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, ++ .pc_name = "CANCEL_RES", + }, + [NLMPROC_UNLOCK_RES] = { + .pc_func = nlm4svc_proc_null, +@@ -624,6 +638,7 @@ const struct svc_procedure nlmsvc_procedures4[24] = { + .pc_argsize = sizeof(struct nlm_res), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, ++ .pc_name = "UNLOCK_RES", + }, + [NLMPROC_GRANTED_RES] = { + .pc_func = nlm4svc_proc_granted_res, +@@ -632,6 +647,7 @@ const struct svc_procedure nlmsvc_procedures4[24] = { + .pc_argsize = sizeof(struct nlm_res), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, ++ .pc_name = "GRANTED_RES", + }, + [NLMPROC_NSM_NOTIFY] = { + .pc_func = nlm4svc_proc_sm_notify, +@@ -640,6 +656,7 @@ const struct svc_procedure nlmsvc_procedures4[24] = { + .pc_argsize = sizeof(struct nlm_reboot), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, ++ .pc_name = "SM_NOTIFY", + }, + [17] = { + .pc_func = nlm4svc_proc_unused, +@@ -648,6 +665,7 @@ const struct svc_procedure nlmsvc_procedures4[24] = { + .pc_argsize = sizeof(struct nlm_void), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = 0, ++ .pc_name = "UNUSED", + }, + [18] = { + .pc_func = nlm4svc_proc_unused, +@@ -656,6 +674,7 @@ const struct svc_procedure nlmsvc_procedures4[24] = { + .pc_argsize = sizeof(struct nlm_void), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = 0, ++ .pc_name = "UNUSED", + }, + [19] = { + .pc_func = nlm4svc_proc_unused, +@@ -664,6 +683,7 @@ const struct svc_procedure nlmsvc_procedures4[24] = { + .pc_argsize = sizeof(struct nlm_void), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = 0, ++ .pc_name = "UNUSED", + }, + [NLMPROC_SHARE] = { + .pc_func = nlm4svc_proc_share, +@@ -672,6 +692,7 @@ const struct svc_procedure nlmsvc_procedures4[24] = { + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St+1, ++ .pc_name = "SHARE", + }, + [NLMPROC_UNSHARE] = { + .pc_func = nlm4svc_proc_unshare, +@@ -680,6 +701,7 @@ const struct svc_procedure nlmsvc_procedures4[24] = { + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St+1, ++ .pc_name = "UNSHARE", + }, + [NLMPROC_NM_LOCK] = { + .pc_func = nlm4svc_proc_nm_lock, +@@ -688,6 +710,7 @@ const struct svc_procedure nlmsvc_procedures4[24] = { + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St, ++ .pc_name = "NM_LOCK", + }, + [NLMPROC_FREE_ALL] = { + .pc_func = nlm4svc_proc_free_all, +@@ -696,5 +719,6 @@ const struct svc_procedure nlmsvc_procedures4[24] = { + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, ++ .pc_name = "FREE_ALL", + }, + }; +diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c +index 50855f2c1f4b8..4ae4b63b53925 100644 +--- a/fs/lockd/svcproc.c ++++ b/fs/lockd/svcproc.c +@@ -554,6 +554,7 @@ const struct svc_procedure nlmsvc_procedures[24] = { + .pc_argsize = sizeof(struct nlm_void), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, ++ .pc_name = "NULL", + }, + [NLMPROC_TEST] = { + .pc_func = nlmsvc_proc_test, +@@ -562,6 +563,7 @@ const struct svc_procedure nlmsvc_procedures[24] = { + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St+2+No+Rg, ++ .pc_name = "TEST", + }, + [NLMPROC_LOCK] = { + .pc_func = nlmsvc_proc_lock, +@@ -570,6 +572,7 @@ const struct svc_procedure nlmsvc_procedures[24] = { + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St, ++ .pc_name = "LOCK", + }, + [NLMPROC_CANCEL] = { + .pc_func = nlmsvc_proc_cancel, +@@ -578,6 +581,7 @@ const struct svc_procedure nlmsvc_procedures[24] = { + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St, ++ .pc_name = "CANCEL", + }, + [NLMPROC_UNLOCK] = { + .pc_func = nlmsvc_proc_unlock, +@@ -586,6 +590,7 @@ const struct svc_procedure nlmsvc_procedures[24] = { + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St, ++ .pc_name = "UNLOCK", + }, + [NLMPROC_GRANTED] = { + .pc_func = nlmsvc_proc_granted, +@@ -594,6 +599,7 @@ const struct svc_procedure nlmsvc_procedures[24] = { + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St, ++ .pc_name = "GRANTED", + }, + [NLMPROC_TEST_MSG] = { + .pc_func = nlmsvc_proc_test_msg, +@@ -602,6 +608,7 @@ const struct svc_procedure nlmsvc_procedures[24] = { + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, ++ .pc_name = "TEST_MSG", + }, + [NLMPROC_LOCK_MSG] = { + .pc_func = nlmsvc_proc_lock_msg, +@@ -610,6 +617,7 @@ const struct svc_procedure nlmsvc_procedures[24] = { + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, ++ .pc_name = "LOCK_MSG", + }, + [NLMPROC_CANCEL_MSG] = { + .pc_func = nlmsvc_proc_cancel_msg, +@@ -618,6 +626,7 @@ const struct svc_procedure nlmsvc_procedures[24] = { + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, ++ .pc_name = "CANCEL_MSG", + }, + [NLMPROC_UNLOCK_MSG] = { + .pc_func = nlmsvc_proc_unlock_msg, +@@ -626,6 +635,7 @@ const struct svc_procedure nlmsvc_procedures[24] = { + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, ++ .pc_name = "UNLOCK_MSG", + }, + [NLMPROC_GRANTED_MSG] = { + .pc_func = nlmsvc_proc_granted_msg, +@@ -634,6 +644,7 @@ const struct svc_procedure nlmsvc_procedures[24] = { + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, ++ .pc_name = "GRANTED_MSG", + }, + [NLMPROC_TEST_RES] = { + .pc_func = nlmsvc_proc_null, +@@ -642,6 +653,7 @@ const struct svc_procedure nlmsvc_procedures[24] = { + .pc_argsize = sizeof(struct nlm_res), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, ++ .pc_name = "TEST_RES", + }, + [NLMPROC_LOCK_RES] = { + .pc_func = nlmsvc_proc_null, +@@ -650,6 +662,7 @@ const struct svc_procedure nlmsvc_procedures[24] = { + .pc_argsize = sizeof(struct nlm_res), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, ++ .pc_name = "LOCK_RES", + }, + [NLMPROC_CANCEL_RES] = { + .pc_func = nlmsvc_proc_null, +@@ -658,6 +671,7 @@ const struct svc_procedure nlmsvc_procedures[24] = { + .pc_argsize = sizeof(struct nlm_res), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, ++ .pc_name = "CANCEL_RES", + }, + [NLMPROC_UNLOCK_RES] = { + .pc_func = nlmsvc_proc_null, +@@ -666,6 +680,7 @@ const struct svc_procedure nlmsvc_procedures[24] = { + .pc_argsize = sizeof(struct nlm_res), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, ++ .pc_name = "UNLOCK_RES", + }, + [NLMPROC_GRANTED_RES] = { + .pc_func = nlmsvc_proc_granted_res, +@@ -674,6 +689,7 @@ const struct svc_procedure nlmsvc_procedures[24] = { + .pc_argsize = sizeof(struct nlm_res), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, ++ .pc_name = "GRANTED_RES", + }, + [NLMPROC_NSM_NOTIFY] = { + .pc_func = nlmsvc_proc_sm_notify, +@@ -682,6 +698,7 @@ const struct svc_procedure nlmsvc_procedures[24] = { + .pc_argsize = sizeof(struct nlm_reboot), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, ++ .pc_name = "SM_NOTIFY", + }, + [17] = { + .pc_func = nlmsvc_proc_unused, +@@ -690,6 +707,7 @@ const struct svc_procedure nlmsvc_procedures[24] = { + .pc_argsize = sizeof(struct nlm_void), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, ++ .pc_name = "UNUSED", + }, + [18] = { + .pc_func = nlmsvc_proc_unused, +@@ -698,6 +716,7 @@ const struct svc_procedure nlmsvc_procedures[24] = { + .pc_argsize = sizeof(struct nlm_void), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, ++ .pc_name = "UNUSED", + }, + [19] = { + .pc_func = nlmsvc_proc_unused, +@@ -706,6 +725,7 @@ const struct svc_procedure nlmsvc_procedures[24] = { + .pc_argsize = sizeof(struct nlm_void), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, ++ .pc_name = "UNUSED", + }, + [NLMPROC_SHARE] = { + .pc_func = nlmsvc_proc_share, +@@ -714,6 +734,7 @@ const struct svc_procedure nlmsvc_procedures[24] = { + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St+1, ++ .pc_name = "SHARE", + }, + [NLMPROC_UNSHARE] = { + .pc_func = nlmsvc_proc_unshare, +@@ -722,6 +743,7 @@ const struct svc_procedure nlmsvc_procedures[24] = { + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St+1, ++ .pc_name = "UNSHARE", + }, + [NLMPROC_NM_LOCK] = { + .pc_func = nlmsvc_proc_nm_lock, +@@ -730,6 +752,7 @@ const struct svc_procedure nlmsvc_procedures[24] = { + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St, ++ .pc_name = "NM_LOCK", + }, + [NLMPROC_FREE_ALL] = { + .pc_func = nlmsvc_proc_free_all, +@@ -738,5 +761,6 @@ const struct svc_procedure nlmsvc_procedures[24] = { + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = 0, ++ .pc_name = "FREE_ALL", + }, + }; +diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c +index ca8a4aa351dc9..f9dfd4e712a30 100644 +--- a/fs/nfs/callback_xdr.c ++++ b/fs/nfs/callback_xdr.c +@@ -1056,6 +1056,7 @@ static const struct svc_procedure nfs4_callback_procedures1[] = { + .pc_decode = nfs4_decode_void, + .pc_encode = nfs4_encode_void, + .pc_xdrressize = 1, ++ .pc_name = "NULL", + }, + [CB_COMPOUND] = { + .pc_func = nfs4_callback_compound, +@@ -1063,6 +1064,7 @@ static const struct svc_procedure nfs4_callback_procedures1[] = { + .pc_argsize = 256, + .pc_ressize = 256, + .pc_xdrressize = NFS4_CALLBACK_BUFSIZE, ++ .pc_name = "COMPOUND", + } + }; + +diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c +index b0f66604532a5..899762da23c92 100644 +--- a/fs/nfsd/nfs2acl.c ++++ b/fs/nfsd/nfs2acl.c +@@ -371,6 +371,7 @@ static const struct svc_procedure nfsd_acl_procedures2[5] = { + .pc_ressize = sizeof(struct nfsd_voidres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST, ++ .pc_name = "NULL", + }, + [ACLPROC2_GETACL] = { + .pc_func = nfsacld_proc_getacl, +@@ -381,6 +382,7 @@ static const struct svc_procedure nfsd_acl_procedures2[5] = { + .pc_ressize = sizeof(struct nfsd3_getaclres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+1+2*(1+ACL), ++ .pc_name = "GETACL", + }, + [ACLPROC2_SETACL] = { + .pc_func = nfsacld_proc_setacl, +@@ -391,6 +393,7 @@ static const struct svc_procedure nfsd_acl_procedures2[5] = { + .pc_ressize = sizeof(struct nfsd_attrstat), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+AT, ++ .pc_name = "SETACL", + }, + [ACLPROC2_GETATTR] = { + .pc_func = nfsacld_proc_getattr, +@@ -401,6 +404,7 @@ static const struct svc_procedure nfsd_acl_procedures2[5] = { + .pc_ressize = sizeof(struct nfsd_attrstat), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+AT, ++ .pc_name = "GETATTR", + }, + [ACLPROC2_ACCESS] = { + .pc_func = nfsacld_proc_access, +@@ -411,6 +415,7 @@ static const struct svc_procedure nfsd_acl_procedures2[5] = { + .pc_ressize = sizeof(struct nfsd3_accessres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+AT+1, ++ .pc_name = "SETATTR", + }, + }; + +diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c +index 7c30876a31a1b..9e1a92fb97712 100644 +--- a/fs/nfsd/nfs3acl.c ++++ b/fs/nfsd/nfs3acl.c +@@ -251,6 +251,7 @@ static const struct svc_procedure nfsd_acl_procedures3[3] = { + .pc_ressize = sizeof(struct nfsd_voidres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST, ++ .pc_name = "NULL", + }, + [ACLPROC3_GETACL] = { + .pc_func = nfsd3_proc_getacl, +@@ -261,6 +262,7 @@ static const struct svc_procedure nfsd_acl_procedures3[3] = { + .pc_ressize = sizeof(struct nfsd3_getaclres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+1+2*(1+ACL), ++ .pc_name = "GETACL", + }, + [ACLPROC3_SETACL] = { + .pc_func = nfsd3_proc_setacl, +@@ -271,6 +273,7 @@ static const struct svc_procedure nfsd_acl_procedures3[3] = { + .pc_ressize = sizeof(struct nfsd3_attrstat), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+pAT, ++ .pc_name = "SETACL", + }, + }; + +diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c +index 3257233d1a655..0f79e007c620f 100644 +--- a/fs/nfsd/nfs3proc.c ++++ b/fs/nfsd/nfs3proc.c +@@ -713,6 +713,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { + .pc_ressize = sizeof(struct nfsd_voidres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST, ++ .pc_name = "NULL", + }, + [NFS3PROC_GETATTR] = { + .pc_func = nfsd3_proc_getattr, +@@ -723,6 +724,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { + .pc_ressize = sizeof(struct nfsd3_attrstatres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+AT, ++ .pc_name = "GETATTR", + }, + [NFS3PROC_SETATTR] = { + .pc_func = nfsd3_proc_setattr, +@@ -733,6 +735,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { + .pc_ressize = sizeof(struct nfsd3_wccstatres), + .pc_cachetype = RC_REPLBUFF, + .pc_xdrressize = ST+WC, ++ .pc_name = "SETATTR", + }, + [NFS3PROC_LOOKUP] = { + .pc_func = nfsd3_proc_lookup, +@@ -743,6 +746,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { + .pc_ressize = sizeof(struct nfsd3_diropres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+FH+pAT+pAT, ++ .pc_name = "LOOKUP", + }, + [NFS3PROC_ACCESS] = { + .pc_func = nfsd3_proc_access, +@@ -753,6 +757,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { + .pc_ressize = sizeof(struct nfsd3_accessres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+pAT+1, ++ .pc_name = "ACCESS", + }, + [NFS3PROC_READLINK] = { + .pc_func = nfsd3_proc_readlink, +@@ -763,6 +768,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { + .pc_ressize = sizeof(struct nfsd3_readlinkres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+pAT+1+NFS3_MAXPATHLEN/4, ++ .pc_name = "READLINK", + }, + [NFS3PROC_READ] = { + .pc_func = nfsd3_proc_read, +@@ -773,6 +779,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { + .pc_ressize = sizeof(struct nfsd3_readres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+pAT+4+NFSSVC_MAXBLKSIZE/4, ++ .pc_name = "READ", + }, + [NFS3PROC_WRITE] = { + .pc_func = nfsd3_proc_write, +@@ -783,6 +790,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { + .pc_ressize = sizeof(struct nfsd3_writeres), + .pc_cachetype = RC_REPLBUFF, + .pc_xdrressize = ST+WC+4, ++ .pc_name = "WRITE", + }, + [NFS3PROC_CREATE] = { + .pc_func = nfsd3_proc_create, +@@ -793,6 +801,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { + .pc_ressize = sizeof(struct nfsd3_createres), + .pc_cachetype = RC_REPLBUFF, + .pc_xdrressize = ST+(1+FH+pAT)+WC, ++ .pc_name = "CREATE", + }, + [NFS3PROC_MKDIR] = { + .pc_func = nfsd3_proc_mkdir, +@@ -803,6 +812,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { + .pc_ressize = sizeof(struct nfsd3_createres), + .pc_cachetype = RC_REPLBUFF, + .pc_xdrressize = ST+(1+FH+pAT)+WC, ++ .pc_name = "MKDIR", + }, + [NFS3PROC_SYMLINK] = { + .pc_func = nfsd3_proc_symlink, +@@ -813,6 +823,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { + .pc_ressize = sizeof(struct nfsd3_createres), + .pc_cachetype = RC_REPLBUFF, + .pc_xdrressize = ST+(1+FH+pAT)+WC, ++ .pc_name = "SYMLINK", + }, + [NFS3PROC_MKNOD] = { + .pc_func = nfsd3_proc_mknod, +@@ -823,6 +834,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { + .pc_ressize = sizeof(struct nfsd3_createres), + .pc_cachetype = RC_REPLBUFF, + .pc_xdrressize = ST+(1+FH+pAT)+WC, ++ .pc_name = "MKNOD", + }, + [NFS3PROC_REMOVE] = { + .pc_func = nfsd3_proc_remove, +@@ -833,6 +845,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { + .pc_ressize = sizeof(struct nfsd3_wccstatres), + .pc_cachetype = RC_REPLBUFF, + .pc_xdrressize = ST+WC, ++ .pc_name = "REMOVE", + }, + [NFS3PROC_RMDIR] = { + .pc_func = nfsd3_proc_rmdir, +@@ -843,6 +856,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { + .pc_ressize = sizeof(struct nfsd3_wccstatres), + .pc_cachetype = RC_REPLBUFF, + .pc_xdrressize = ST+WC, ++ .pc_name = "RMDIR", + }, + [NFS3PROC_RENAME] = { + .pc_func = nfsd3_proc_rename, +@@ -853,6 +867,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { + .pc_ressize = sizeof(struct nfsd3_renameres), + .pc_cachetype = RC_REPLBUFF, + .pc_xdrressize = ST+WC+WC, ++ .pc_name = "RENAME", + }, + [NFS3PROC_LINK] = { + .pc_func = nfsd3_proc_link, +@@ -863,6 +878,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { + .pc_ressize = sizeof(struct nfsd3_linkres), + .pc_cachetype = RC_REPLBUFF, + .pc_xdrressize = ST+pAT+WC, ++ .pc_name = "LINK", + }, + [NFS3PROC_READDIR] = { + .pc_func = nfsd3_proc_readdir, +@@ -872,6 +888,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { + .pc_argsize = sizeof(struct nfsd3_readdirargs), + .pc_ressize = sizeof(struct nfsd3_readdirres), + .pc_cachetype = RC_NOCACHE, ++ .pc_name = "READDIR", + }, + [NFS3PROC_READDIRPLUS] = { + .pc_func = nfsd3_proc_readdirplus, +@@ -881,6 +898,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { + .pc_argsize = sizeof(struct nfsd3_readdirplusargs), + .pc_ressize = sizeof(struct nfsd3_readdirres), + .pc_cachetype = RC_NOCACHE, ++ .pc_name = "READDIRPLUS", + }, + [NFS3PROC_FSSTAT] = { + .pc_func = nfsd3_proc_fsstat, +@@ -890,6 +908,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { + .pc_ressize = sizeof(struct nfsd3_fsstatres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+pAT+2*6+1, ++ .pc_name = "FSSTAT", + }, + [NFS3PROC_FSINFO] = { + .pc_func = nfsd3_proc_fsinfo, +@@ -899,6 +918,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { + .pc_ressize = sizeof(struct nfsd3_fsinfores), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+pAT+12, ++ .pc_name = "FSINFO", + }, + [NFS3PROC_PATHCONF] = { + .pc_func = nfsd3_proc_pathconf, +@@ -908,6 +928,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { + .pc_ressize = sizeof(struct nfsd3_pathconfres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+pAT+6, ++ .pc_name = "PATHCONF", + }, + [NFS3PROC_COMMIT] = { + .pc_func = nfsd3_proc_commit, +@@ -918,6 +939,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { + .pc_ressize = sizeof(struct nfsd3_commitres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+WC+2, ++ .pc_name = "COMMIT", + }, + }; + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 1ef98398362a5..a5e1f5c1a4d64 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -3299,6 +3299,7 @@ static const struct svc_procedure nfsd_procedures4[2] = { + .pc_ressize = sizeof(struct nfsd_voidres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = 1, ++ .pc_name = "NULL", + }, + [NFSPROC4_COMPOUND] = { + .pc_func = nfsd4_proc_compound, +@@ -3309,6 +3310,7 @@ static const struct svc_procedure nfsd_procedures4[2] = { + .pc_release = nfsd4_release_compoundargs, + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = NFSD_BUFSIZE/4, ++ .pc_name = "COMPOUND", + }, + }; + +diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c +index dbd8d36046539..f22f70f63b53e 100644 +--- a/fs/nfsd/nfsproc.c ++++ b/fs/nfsd/nfsproc.c +@@ -623,6 +623,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { + .pc_ressize = sizeof(struct nfsd_voidres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = 0, ++ .pc_name = "NULL", + }, + [NFSPROC_GETATTR] = { + .pc_func = nfsd_proc_getattr, +@@ -633,6 +634,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { + .pc_ressize = sizeof(struct nfsd_attrstat), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+AT, ++ .pc_name = "GETATTR", + }, + [NFSPROC_SETATTR] = { + .pc_func = nfsd_proc_setattr, +@@ -643,6 +645,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { + .pc_ressize = sizeof(struct nfsd_attrstat), + .pc_cachetype = RC_REPLBUFF, + .pc_xdrressize = ST+AT, ++ .pc_name = "SETATTR", + }, + [NFSPROC_ROOT] = { + .pc_func = nfsd_proc_root, +@@ -652,6 +655,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { + .pc_ressize = sizeof(struct nfsd_voidres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = 0, ++ .pc_name = "ROOT", + }, + [NFSPROC_LOOKUP] = { + .pc_func = nfsd_proc_lookup, +@@ -662,6 +666,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { + .pc_ressize = sizeof(struct nfsd_diropres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+FH+AT, ++ .pc_name = "LOOKUP", + }, + [NFSPROC_READLINK] = { + .pc_func = nfsd_proc_readlink, +@@ -671,6 +676,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { + .pc_ressize = sizeof(struct nfsd_readlinkres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+1+NFS_MAXPATHLEN/4, ++ .pc_name = "READLINK", + }, + [NFSPROC_READ] = { + .pc_func = nfsd_proc_read, +@@ -681,6 +687,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { + .pc_ressize = sizeof(struct nfsd_readres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+AT+1+NFSSVC_MAXBLKSIZE_V2/4, ++ .pc_name = "READ", + }, + [NFSPROC_WRITECACHE] = { + .pc_func = nfsd_proc_writecache, +@@ -690,6 +697,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { + .pc_ressize = sizeof(struct nfsd_voidres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = 0, ++ .pc_name = "WRITECACHE", + }, + [NFSPROC_WRITE] = { + .pc_func = nfsd_proc_write, +@@ -700,6 +708,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { + .pc_ressize = sizeof(struct nfsd_attrstat), + .pc_cachetype = RC_REPLBUFF, + .pc_xdrressize = ST+AT, ++ .pc_name = "WRITE", + }, + [NFSPROC_CREATE] = { + .pc_func = nfsd_proc_create, +@@ -710,6 +719,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { + .pc_ressize = sizeof(struct nfsd_diropres), + .pc_cachetype = RC_REPLBUFF, + .pc_xdrressize = ST+FH+AT, ++ .pc_name = "CREATE", + }, + [NFSPROC_REMOVE] = { + .pc_func = nfsd_proc_remove, +@@ -719,6 +729,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { + .pc_ressize = sizeof(struct nfsd_stat), + .pc_cachetype = RC_REPLSTAT, + .pc_xdrressize = ST, ++ .pc_name = "REMOVE", + }, + [NFSPROC_RENAME] = { + .pc_func = nfsd_proc_rename, +@@ -728,6 +739,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { + .pc_ressize = sizeof(struct nfsd_stat), + .pc_cachetype = RC_REPLSTAT, + .pc_xdrressize = ST, ++ .pc_name = "RENAME", + }, + [NFSPROC_LINK] = { + .pc_func = nfsd_proc_link, +@@ -737,6 +749,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { + .pc_ressize = sizeof(struct nfsd_stat), + .pc_cachetype = RC_REPLSTAT, + .pc_xdrressize = ST, ++ .pc_name = "LINK", + }, + [NFSPROC_SYMLINK] = { + .pc_func = nfsd_proc_symlink, +@@ -746,6 +759,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { + .pc_ressize = sizeof(struct nfsd_stat), + .pc_cachetype = RC_REPLSTAT, + .pc_xdrressize = ST, ++ .pc_name = "SYMLINK", + }, + [NFSPROC_MKDIR] = { + .pc_func = nfsd_proc_mkdir, +@@ -756,6 +770,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { + .pc_ressize = sizeof(struct nfsd_diropres), + .pc_cachetype = RC_REPLBUFF, + .pc_xdrressize = ST+FH+AT, ++ .pc_name = "MKDIR", + }, + [NFSPROC_RMDIR] = { + .pc_func = nfsd_proc_rmdir, +@@ -765,6 +780,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { + .pc_ressize = sizeof(struct nfsd_stat), + .pc_cachetype = RC_REPLSTAT, + .pc_xdrressize = ST, ++ .pc_name = "RMDIR", + }, + [NFSPROC_READDIR] = { + .pc_func = nfsd_proc_readdir, +@@ -773,6 +789,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { + .pc_argsize = sizeof(struct nfsd_readdirargs), + .pc_ressize = sizeof(struct nfsd_readdirres), + .pc_cachetype = RC_NOCACHE, ++ .pc_name = "READDIR", + }, + [NFSPROC_STATFS] = { + .pc_func = nfsd_proc_statfs, +@@ -782,6 +799,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { + .pc_ressize = sizeof(struct nfsd_statfsres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+5, ++ .pc_name = "STATFS", + }, + }; + +diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h +index 34c2a69820e93..31ee3b6047c30 100644 +--- a/include/linux/sunrpc/svc.h ++++ b/include/linux/sunrpc/svc.h +@@ -463,6 +463,7 @@ struct svc_procedure { + unsigned int pc_ressize; /* result struct size */ + unsigned int pc_cachetype; /* cache info (NFS) */ + unsigned int pc_xdrressize; /* maximum size of XDR reply */ ++ const char * pc_name; /* for display */ + }; + + /* +-- +2.43.0 + diff --git a/queue-5.10/sunrpc-merge-svc_do_enqueue_xprt-into-svc_enqueue_xp.patch b/queue-5.10/sunrpc-merge-svc_do_enqueue_xprt-into-svc_enqueue_xp.patch new file mode 100644 index 00000000000..ed869d1eee8 --- /dev/null +++ b/queue-5.10/sunrpc-merge-svc_do_enqueue_xprt-into-svc_enqueue_xp.patch @@ -0,0 +1,99 @@ +From b31c202ade468b7b562152ea56af000f2deb1e22 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 25 Jan 2022 17:57:23 -0500 +Subject: SUNRPC: Merge svc_do_enqueue_xprt() into svc_enqueue_xprt() + +From: Chuck Lever + +[ Upstream commit c0219c499799c1e92bd570c15a47e6257a27bb15 ] + +Neil says: +"These functions were separated in commit 0971374e2818 ("SUNRPC: +Reduce contention in svc_xprt_enqueue()") so that the XPT_BUSY check +happened before taking any spinlocks. + +We have since moved or removed the spinlocks so the extra test is +fairly pointless." + +I've made this a separate patch in case the XPT_BUSY change has +unexpected consequences and needs to be reverted. + +Suggested-by: Neil Brown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + net/sunrpc/svc_xprt.c | 26 ++++++++++---------------- + 1 file changed, 10 insertions(+), 16 deletions(-) + +diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c +index 833952db23192..b5e80817b02f5 100644 +--- a/net/sunrpc/svc_xprt.c ++++ b/net/sunrpc/svc_xprt.c +@@ -31,7 +31,6 @@ static int svc_deferred_recv(struct svc_rqst *rqstp); + static struct cache_deferred_req *svc_defer(struct cache_req *req); + static void svc_age_temp_xprts(struct timer_list *t); + static void svc_delete_xprt(struct svc_xprt *xprt); +-static void svc_xprt_do_enqueue(struct svc_xprt *xprt); + + /* apparently the "standard" is that clients close + * idle connections after 5 minutes, servers after +@@ -254,12 +253,12 @@ void svc_xprt_received(struct svc_xprt *xprt) + trace_svc_xprt_received(xprt); + + /* As soon as we clear busy, the xprt could be closed and +- * 'put', so we need a reference to call svc_xprt_do_enqueue with: ++ * 'put', so we need a reference to call svc_xprt_enqueue with: + */ + svc_xprt_get(xprt); + smp_mb__before_atomic(); + clear_bit(XPT_BUSY, &xprt->xpt_flags); +- svc_xprt_do_enqueue(xprt); ++ svc_xprt_enqueue(xprt); + svc_xprt_put(xprt); + } + EXPORT_SYMBOL_GPL(svc_xprt_received); +@@ -399,6 +398,8 @@ static bool svc_xprt_ready(struct svc_xprt *xprt) + smp_rmb(); + xpt_flags = READ_ONCE(xprt->xpt_flags); + ++ if (xpt_flags & BIT(XPT_BUSY)) ++ return false; + if (xpt_flags & (BIT(XPT_CONN) | BIT(XPT_CLOSE))) + return true; + if (xpt_flags & (BIT(XPT_DATA) | BIT(XPT_DEFERRED))) { +@@ -411,7 +412,12 @@ static bool svc_xprt_ready(struct svc_xprt *xprt) + return false; + } + +-static void svc_xprt_do_enqueue(struct svc_xprt *xprt) ++/** ++ * svc_xprt_enqueue - Queue a transport on an idle nfsd thread ++ * @xprt: transport with data pending ++ * ++ */ ++void svc_xprt_enqueue(struct svc_xprt *xprt) + { + struct svc_pool *pool; + struct svc_rqst *rqstp = NULL; +@@ -455,18 +461,6 @@ static void svc_xprt_do_enqueue(struct svc_xprt *xprt) + put_cpu(); + trace_svc_xprt_do_enqueue(xprt, rqstp); + } +- +-/* +- * Queue up a transport with data pending. If there are idle nfsd +- * processes, wake 'em up. +- * +- */ +-void svc_xprt_enqueue(struct svc_xprt *xprt) +-{ +- if (test_bit(XPT_BUSY, &xprt->xpt_flags)) +- return; +- svc_xprt_do_enqueue(xprt); +-} + EXPORT_SYMBOL_GPL(svc_xprt_enqueue); + + /* +-- +2.43.0 + diff --git a/queue-5.10/sunrpc-move-definition-of-xdr_unit.patch b/queue-5.10/sunrpc-move-definition-of-xdr_unit.patch new file mode 100644 index 00000000000..383ae119a3d --- /dev/null +++ b/queue-5.10/sunrpc-move-definition-of-xdr_unit.patch @@ -0,0 +1,82 @@ +From 68be125f67521a1d76ba6dcf20701616cfd1f945 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 27 Nov 2020 17:37:02 -0500 +Subject: SUNRPC: Move definition of XDR_UNIT + +From: Chuck Lever + +[ Upstream commit 81d217474326b25d7f14274b02fe3da1e85ad934 ] + +Clean up: The unit of XDR alignment is defined by RFC 4506, +not as part of the RPC message header. Thus it belongs in +include/linux/sunrpc/xdr.h. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + include/linux/sunrpc/msg_prot.h | 3 --- + include/linux/sunrpc/xdr.h | 13 ++++++++++--- + 2 files changed, 10 insertions(+), 6 deletions(-) + +diff --git a/include/linux/sunrpc/msg_prot.h b/include/linux/sunrpc/msg_prot.h +index 43f854487539b..938c2bf29db88 100644 +--- a/include/linux/sunrpc/msg_prot.h ++++ b/include/linux/sunrpc/msg_prot.h +@@ -10,9 +10,6 @@ + + #define RPC_VERSION 2 + +-/* size of an XDR encoding unit in bytes, i.e. 32bit */ +-#define XDR_UNIT (4) +- + /* spec defines authentication flavor as an unsigned 32 bit integer */ + typedef u32 rpc_authflavor_t; + +diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h +index f6569b620beab..eba6204330b3c 100644 +--- a/include/linux/sunrpc/xdr.h ++++ b/include/linux/sunrpc/xdr.h +@@ -19,6 +19,13 @@ + struct bio_vec; + struct rpc_rqst; + ++/* ++ * Size of an XDR encoding unit in bytes, i.e. 32 bits, ++ * as defined in Section 3 of RFC 4506. All encoded ++ * XDR data items are aligned on a boundary of 32 bits. ++ */ ++#define XDR_UNIT sizeof(__be32) ++ + /* + * Buffer adjustment + */ +@@ -329,7 +336,7 @@ ssize_t xdr_stream_decode_string_dup(struct xdr_stream *xdr, char **str, + static inline size_t + xdr_align_size(size_t n) + { +- const size_t mask = sizeof(__u32) - 1; ++ const size_t mask = XDR_UNIT - 1; + + return (n + mask) & ~mask; + } +@@ -359,7 +366,7 @@ static inline size_t xdr_pad_size(size_t n) + */ + static inline ssize_t xdr_stream_encode_item_present(struct xdr_stream *xdr) + { +- const size_t len = sizeof(__be32); ++ const size_t len = XDR_UNIT; + __be32 *p = xdr_reserve_space(xdr, len); + + if (unlikely(!p)) +@@ -378,7 +385,7 @@ static inline ssize_t xdr_stream_encode_item_present(struct xdr_stream *xdr) + */ + static inline int xdr_stream_encode_item_absent(struct xdr_stream *xdr) + { +- const size_t len = sizeof(__be32); ++ const size_t len = XDR_UNIT; + __be32 *p = xdr_reserve_space(xdr, len); + + if (unlikely(!p)) +-- +2.43.0 + diff --git a/queue-5.10/sunrpc-move-the-pool_map-definitions-back-into-svc.c.patch b/queue-5.10/sunrpc-move-the-pool_map-definitions-back-into-svc.c.patch new file mode 100644 index 00000000000..b5c61d92c32 --- /dev/null +++ b/queue-5.10/sunrpc-move-the-pool_map-definitions-back-into-svc.c.patch @@ -0,0 +1,143 @@ +From 0ac9bdf0dc976cb612fadf3079da62914dc102e5 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Nov 2021 15:51:25 +1100 +Subject: SUNRPC: move the pool_map definitions (back) into svc.c + +From: NeilBrown + +[ Upstream commit cf0e124e0a489944d08fcc3c694d2b234d2cc658 ] + +These definitions are not used outside of svc.c, and there is no +evidence that they ever have been. So move them into svc.c +and make the declarations 'static'. + +Signed-off-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + include/linux/sunrpc/svc.h | 25 ------------------------- + net/sunrpc/svc.c | 31 +++++++++++++++++++++++++------ + 2 files changed, 25 insertions(+), 31 deletions(-) + +diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h +index 165719a6229ab..89e9d00af601b 100644 +--- a/include/linux/sunrpc/svc.h ++++ b/include/linux/sunrpc/svc.h +@@ -497,29 +497,6 @@ struct svc_procedure { + const char * pc_name; /* for display */ + }; + +-/* +- * Mode for mapping cpus to pools. +- */ +-enum { +- SVC_POOL_AUTO = -1, /* choose one of the others */ +- SVC_POOL_GLOBAL, /* no mapping, just a single global pool +- * (legacy & UP mode) */ +- SVC_POOL_PERCPU, /* one pool per cpu */ +- SVC_POOL_PERNODE /* one pool per numa node */ +-}; +- +-struct svc_pool_map { +- int count; /* How many svc_servs use us */ +- int mode; /* Note: int not enum to avoid +- * warnings about "enumeration value +- * not handled in switch" */ +- unsigned int npools; +- unsigned int *pool_to; /* maps pool id to cpu or node */ +- unsigned int *to_pool; /* maps cpu or node to pool id */ +-}; +- +-extern struct svc_pool_map svc_pool_map; +- + /* + * Function prototypes. + */ +@@ -536,8 +513,6 @@ void svc_rqst_replace_page(struct svc_rqst *rqstp, + struct page *page); + void svc_rqst_free(struct svc_rqst *); + void svc_exit_thread(struct svc_rqst *); +-unsigned int svc_pool_map_get(void); +-void svc_pool_map_put(void); + struct svc_serv * svc_create_pooled(struct svc_program *, unsigned int, + const struct svc_serv_ops *); + int svc_set_num_threads(struct svc_serv *, struct svc_pool *, int); +diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c +index da5f008b8d27c..c681ac1c9d569 100644 +--- a/net/sunrpc/svc.c ++++ b/net/sunrpc/svc.c +@@ -39,14 +39,35 @@ static void svc_unregister(const struct svc_serv *serv, struct net *net); + + #define SVC_POOL_DEFAULT SVC_POOL_GLOBAL + ++/* ++ * Mode for mapping cpus to pools. ++ */ ++enum { ++ SVC_POOL_AUTO = -1, /* choose one of the others */ ++ SVC_POOL_GLOBAL, /* no mapping, just a single global pool ++ * (legacy & UP mode) */ ++ SVC_POOL_PERCPU, /* one pool per cpu */ ++ SVC_POOL_PERNODE /* one pool per numa node */ ++}; ++ + /* + * Structure for mapping cpus to pools and vice versa. + * Setup once during sunrpc initialisation. + */ +-struct svc_pool_map svc_pool_map = { ++ ++struct svc_pool_map { ++ int count; /* How many svc_servs use us */ ++ int mode; /* Note: int not enum to avoid ++ * warnings about "enumeration value ++ * not handled in switch" */ ++ unsigned int npools; ++ unsigned int *pool_to; /* maps pool id to cpu or node */ ++ unsigned int *to_pool; /* maps cpu or node to pool id */ ++}; ++ ++static struct svc_pool_map svc_pool_map = { + .mode = SVC_POOL_DEFAULT + }; +-EXPORT_SYMBOL_GPL(svc_pool_map); + + static DEFINE_MUTEX(svc_pool_map_mutex);/* protects svc_pool_map.count only */ + +@@ -220,7 +241,7 @@ svc_pool_map_init_pernode(struct svc_pool_map *m) + * vice versa). Initialise the map if we're the first user. + * Returns the number of pools. + */ +-unsigned int ++static unsigned int + svc_pool_map_get(void) + { + struct svc_pool_map *m = &svc_pool_map; +@@ -255,7 +276,6 @@ svc_pool_map_get(void) + mutex_unlock(&svc_pool_map_mutex); + return m->npools; + } +-EXPORT_SYMBOL_GPL(svc_pool_map_get); + + /* + * Drop a reference to the global map of cpus to pools. +@@ -264,7 +284,7 @@ EXPORT_SYMBOL_GPL(svc_pool_map_get); + * mode using the pool_mode module option without + * rebooting or re-loading sunrpc.ko. + */ +-void ++static void + svc_pool_map_put(void) + { + struct svc_pool_map *m = &svc_pool_map; +@@ -281,7 +301,6 @@ svc_pool_map_put(void) + + mutex_unlock(&svc_pool_map_mutex); + } +-EXPORT_SYMBOL_GPL(svc_pool_map_put); + + static int svc_pool_map_get_node(unsigned int pidx) + { +-- +2.43.0 + diff --git a/queue-5.10/sunrpc-nfsd-clean-up-get-put-functions.patch b/queue-5.10/sunrpc-nfsd-clean-up-get-put-functions.patch new file mode 100644 index 00000000000..07b79626d82 --- /dev/null +++ b/queue-5.10/sunrpc-nfsd-clean-up-get-put-functions.patch @@ -0,0 +1,331 @@ +From f9fd53b8b604ba928cd2912794b329ac56ffdfc2 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Nov 2021 15:51:25 +1100 +Subject: SUNRPC/NFSD: clean up get/put functions. + +From: NeilBrown + +[ Upstream commit 8c62d12740a1450d2e8456d5747f440e10db281a ] + +svc_destroy() is poorly named - it doesn't necessarily destroy the svc, +it might just reduce the ref count. +nfsd_destroy() is poorly named for the same reason. + +This patch: + - removes the refcount functionality from svc_destroy(), moving it to + a new svc_put(). Almost all previous callers of svc_destroy() now + call svc_put(). + - renames nfsd_destroy() to nfsd_put() and improves the code, using + the new svc_destroy() rather than svc_put() + - removes a few comments that explain the important for balanced + get/put calls. This should be obvious. + +The only non-trivial part of this is that svc_destroy() would call +svc_sock_update() on a non-final decrement. It can no longer do that, +and svc_put() isn't really a good place of it. This call is now made +from svc_exit_thread() which seems like a good place. This makes the +call *before* sv_nrthreads is decremented rather than after. This +is not particularly important as the call just sets a flag which +causes sv_nrthreads set be checked later. A subsequent patch will +improve the ordering. + +Signed-off-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/svc.c | 6 +----- + fs/nfs/callback.c | 14 ++------------ + fs/nfsd/nfsctl.c | 4 ++-- + fs/nfsd/nfsd.h | 2 +- + fs/nfsd/nfssvc.c | 30 ++++++++++++++++-------------- + include/linux/sunrpc/svc.h | 26 +++++++++++++++++++++++--- + net/sunrpc/svc.c | 19 +++++-------------- + 7 files changed, 50 insertions(+), 51 deletions(-) + +diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c +index 2f50d5b2a8a42..135bd86ed3adb 100644 +--- a/fs/lockd/svc.c ++++ b/fs/lockd/svc.c +@@ -431,10 +431,6 @@ static struct svc_serv *lockd_create_svc(void) + * Check whether we're already up and running. + */ + if (nlmsvc_rqst) +- /* +- * Note: increase service usage, because later in case of error +- * svc_destroy() will be called. +- */ + return svc_get(nlmsvc_rqst->rq_server); + + /* +@@ -495,7 +491,7 @@ int lockd_up(struct net *net, const struct cred *cred) + * so we exit through here on both success and failure. + */ + err_put: +- svc_destroy(serv); ++ svc_put(serv); + err_create: + mutex_unlock(&nlmsvc_mutex); + return error; +diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c +index 674198e0eb5e1..dddd66749a881 100644 +--- a/fs/nfs/callback.c ++++ b/fs/nfs/callback.c +@@ -267,10 +267,6 @@ static struct svc_serv *nfs_callback_create_svc(int minorversion) + * Check whether we're already up and running. + */ + if (cb_info->serv) +- /* +- * Note: increase service usage, because later in case of error +- * svc_destroy() will be called. +- */ + return svc_get(cb_info->serv); + + switch (minorversion) { +@@ -333,16 +329,10 @@ int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt) + goto err_start; + + cb_info->users++; +- /* +- * svc_create creates the svc_serv with sv_nrthreads == 1, and then +- * svc_prepare_thread increments that. So we need to call svc_destroy +- * on both success and failure so that the refcount is 1 when the +- * thread exits. +- */ + err_net: + if (!cb_info->users) + cb_info->serv = NULL; +- svc_destroy(serv); ++ svc_put(serv); + err_create: + mutex_unlock(&nfs_callback_mutex); + return ret; +@@ -368,7 +358,7 @@ void nfs_callback_down(int minorversion, struct net *net) + if (cb_info->users == 0) { + svc_get(serv); + serv->sv_ops->svo_setup(serv, NULL, 0); +- svc_destroy(serv); ++ svc_put(serv); + dprintk("nfs_callback_down: service destroyed\n"); + cb_info->serv = NULL; + } +diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c +index 162866cfe83a2..5c8d985acf5fb 100644 +--- a/fs/nfsd/nfsctl.c ++++ b/fs/nfsd/nfsctl.c +@@ -743,7 +743,7 @@ static ssize_t __write_ports_addfd(char *buf, struct net *net, const struct cred + + err = svc_addsock(nn->nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT, cred); + if (err < 0 && list_empty(&nn->nfsd_serv->sv_permsocks)) { +- nfsd_destroy(net); ++ nfsd_put(net); + return err; + } + +@@ -796,7 +796,7 @@ static ssize_t __write_ports_addxprt(char *buf, struct net *net, const struct cr + if (!list_empty(&nn->nfsd_serv->sv_permsocks)) + nn->nfsd_serv->sv_nrthreads--; + else +- nfsd_destroy(net); ++ nfsd_put(net); + return err; + } + +diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h +index 498e5a4898260..3e5008b475ff0 100644 +--- a/fs/nfsd/nfsd.h ++++ b/fs/nfsd/nfsd.h +@@ -97,7 +97,7 @@ int nfsd_pool_stats_open(struct inode *, struct file *); + int nfsd_pool_stats_release(struct inode *, struct file *); + void nfsd_shutdown_threads(struct net *net); + +-void nfsd_destroy(struct net *net); ++void nfsd_put(struct net *net); + + bool i_am_nfsd(void); + +diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c +index 0f84151011088..4aee1cfe0d1bb 100644 +--- a/fs/nfsd/nfssvc.c ++++ b/fs/nfsd/nfssvc.c +@@ -623,7 +623,7 @@ void nfsd_shutdown_threads(struct net *net) + svc_get(serv); + /* Kill outstanding nfsd threads */ + serv->sv_ops->svo_setup(serv, NULL, 0); +- nfsd_destroy(net); ++ nfsd_put(net); + mutex_unlock(&nfsd_mutex); + /* Wait for shutdown of nfsd_serv to complete */ + wait_for_completion(&nn->nfsd_shutdown_complete); +@@ -656,7 +656,10 @@ int nfsd_create_serv(struct net *net) + nn->nfsd_serv->sv_maxconn = nn->max_connections; + error = svc_bind(nn->nfsd_serv, net); + if (error < 0) { +- svc_destroy(nn->nfsd_serv); ++ /* NOT nfsd_put() as notifiers (see below) haven't ++ * been set up yet. ++ */ ++ svc_put(nn->nfsd_serv); + nfsd_complete_shutdown(net); + return error; + } +@@ -697,16 +700,16 @@ int nfsd_get_nrthreads(int n, int *nthreads, struct net *net) + return 0; + } + +-void nfsd_destroy(struct net *net) ++void nfsd_put(struct net *net) + { + struct nfsd_net *nn = net_generic(net, nfsd_net_id); +- int destroy = (nn->nfsd_serv->sv_nrthreads == 1); + +- if (destroy) ++ nn->nfsd_serv->sv_nrthreads -= 1; ++ if (nn->nfsd_serv->sv_nrthreads == 0) { + svc_shutdown_net(nn->nfsd_serv, net); +- svc_destroy(nn->nfsd_serv); +- if (destroy) ++ svc_destroy(nn->nfsd_serv); + nfsd_complete_shutdown(net); ++ } + } + + int nfsd_set_nrthreads(int n, int *nthreads, struct net *net) +@@ -758,7 +761,7 @@ int nfsd_set_nrthreads(int n, int *nthreads, struct net *net) + if (err) + break; + } +- nfsd_destroy(net); ++ nfsd_put(net); + return err; + } + +@@ -795,7 +798,7 @@ nfsd_svc(int nrservs, struct net *net, const struct cred *cred) + + error = nfsd_startup_net(net, cred); + if (error) +- goto out_destroy; ++ goto out_put; + error = nn->nfsd_serv->sv_ops->svo_setup(nn->nfsd_serv, + NULL, nrservs); + if (error) +@@ -808,8 +811,8 @@ nfsd_svc(int nrservs, struct net *net, const struct cred *cred) + out_shutdown: + if (error < 0 && !nfsd_up_before) + nfsd_shutdown_net(net); +-out_destroy: +- nfsd_destroy(net); /* Release server */ ++out_put: ++ nfsd_put(net); + out: + mutex_unlock(&nfsd_mutex); + return error; +@@ -982,7 +985,7 @@ nfsd(void *vrqstp) + /* Release the thread */ + svc_exit_thread(rqstp); + +- nfsd_destroy(net); ++ nfsd_put(net); + + /* Release module */ + mutex_unlock(&nfsd_mutex); +@@ -1109,8 +1112,7 @@ int nfsd_pool_stats_release(struct inode *inode, struct file *file) + struct net *net = inode->i_sb->s_fs_info; + + mutex_lock(&nfsd_mutex); +- /* this function really, really should have been called svc_put() */ +- nfsd_destroy(net); ++ nfsd_put(net); + mutex_unlock(&nfsd_mutex); + return ret; + } +diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h +index e2580f6a05c21..f7b582d3a65ac 100644 +--- a/include/linux/sunrpc/svc.h ++++ b/include/linux/sunrpc/svc.h +@@ -114,8 +114,13 @@ struct svc_serv { + #endif /* CONFIG_SUNRPC_BACKCHANNEL */ + }; + +-/* +- * We use sv_nrthreads as a reference count. svc_destroy() drops ++/** ++ * svc_get() - increment reference count on a SUNRPC serv ++ * @serv: the svc_serv to have count incremented ++ * ++ * Returns: the svc_serv that was passed in. ++ * ++ * We use sv_nrthreads as a reference count. svc_put() drops + * this refcount, so we need to bump it up around operations that + * change the number of threads. Horrible, but there it is. + * Should be called with the "service mutex" held. +@@ -126,6 +131,22 @@ static inline struct svc_serv *svc_get(struct svc_serv *serv) + return serv; + } + ++void svc_destroy(struct svc_serv *serv); ++ ++/** ++ * svc_put - decrement reference count on a SUNRPC serv ++ * @serv: the svc_serv to have count decremented ++ * ++ * When the reference count reaches zero, svc_destroy() ++ * is called to clean up and free the serv. ++ */ ++static inline void svc_put(struct svc_serv *serv) ++{ ++ serv->sv_nrthreads -= 1; ++ if (serv->sv_nrthreads == 0) ++ svc_destroy(serv); ++} ++ + /* + * Maximum payload size supported by a kernel RPC server. + * This is use to determine the max number of pages nfsd is +@@ -518,7 +539,6 @@ struct svc_serv * svc_create_pooled(struct svc_program *, unsigned int, + int svc_set_num_threads(struct svc_serv *, struct svc_pool *, int); + int svc_set_num_threads_sync(struct svc_serv *, struct svc_pool *, int); + int svc_pool_stats_open(struct svc_serv *serv, struct file *file); +-void svc_destroy(struct svc_serv *); + void svc_shutdown_net(struct svc_serv *, struct net *); + int svc_process(struct svc_rqst *); + int bc_svc_process(struct svc_serv *, struct rpc_rqst *, +diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c +index 54f66f66beb59..00d464f6dbe60 100644 +--- a/net/sunrpc/svc.c ++++ b/net/sunrpc/svc.c +@@ -526,17 +526,7 @@ EXPORT_SYMBOL_GPL(svc_shutdown_net); + void + svc_destroy(struct svc_serv *serv) + { +- dprintk("svc: svc_destroy(%s, %d)\n", +- serv->sv_program->pg_name, +- serv->sv_nrthreads); +- +- if (serv->sv_nrthreads) { +- if (--(serv->sv_nrthreads) != 0) { +- svc_sock_update_bufs(serv); +- return; +- } +- } else +- printk("svc_destroy: no threads for serv=%p!\n", serv); ++ dprintk("svc: svc_destroy(%s)\n", serv->sv_program->pg_name); + + del_timer_sync(&serv->sv_temptimer); + +@@ -893,9 +883,10 @@ svc_exit_thread(struct svc_rqst *rqstp) + + svc_rqst_free(rqstp); + +- /* Release the server */ +- if (serv) +- svc_destroy(serv); ++ if (!serv) ++ return; ++ svc_sock_update_bufs(serv); ++ svc_destroy(serv); + } + EXPORT_SYMBOL_GPL(svc_exit_thread); + +-- +2.43.0 + diff --git a/queue-5.10/sunrpc-optimize-xdr_reserve_space.patch b/queue-5.10/sunrpc-optimize-xdr_reserve_space.patch new file mode 100644 index 00000000000..4311d01d98d --- /dev/null +++ b/queue-5.10/sunrpc-optimize-xdr_reserve_space.patch @@ -0,0 +1,109 @@ +From 2780155a71abd75d22195eee76024e42e3120e21 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 7 Jun 2022 16:47:58 -0400 +Subject: SUNRPC: Optimize xdr_reserve_space() + +From: Chuck Lever + +[ Upstream commit 62ed448cc53b654036f7d7f3c99f299d79ad14c3 ] + +Transitioning between encode buffers is quite infrequent. It happens +about 1 time in 400 calls to xdr_reserve_space(), measured on NFSD +with a typical build/test workload. + +Force the compiler to remove that code from xdr_reserve_space(), +which is a hot path on both the server and the client. This change +reduces the size of xdr_reserve_space() from 10 cache lines to 2 +when compiled with -Os. + +Signed-off-by: Chuck Lever +Reviewed-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + include/linux/sunrpc/xdr.h | 16 +++++++++++++++- + net/sunrpc/xdr.c | 17 ++++++++++------- + 2 files changed, 25 insertions(+), 8 deletions(-) + +diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h +index 927f1458bcab9..b8fb866e1fd32 100644 +--- a/include/linux/sunrpc/xdr.h ++++ b/include/linux/sunrpc/xdr.h +@@ -242,7 +242,7 @@ extern void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, + extern __be32 *xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes); + extern int xdr_reserve_space_vec(struct xdr_stream *xdr, struct kvec *vec, + size_t nbytes); +-extern void xdr_commit_encode(struct xdr_stream *xdr); ++extern void __xdr_commit_encode(struct xdr_stream *xdr); + extern void xdr_truncate_encode(struct xdr_stream *xdr, size_t len); + extern int xdr_restrict_buflen(struct xdr_stream *xdr, int newbuflen); + extern void xdr_write_pages(struct xdr_stream *xdr, struct page **pages, +@@ -305,6 +305,20 @@ xdr_reset_scratch_buffer(struct xdr_stream *xdr) + xdr_set_scratch_buffer(xdr, NULL, 0); + } + ++/** ++ * xdr_commit_encode - Ensure all data is written to xdr->buf ++ * @xdr: pointer to xdr_stream ++ * ++ * Handle encoding across page boundaries by giving the caller a ++ * temporary location to write to, then later copying the data into ++ * place. __xdr_commit_encode() does that copying. ++ */ ++static inline void xdr_commit_encode(struct xdr_stream *xdr) ++{ ++ if (unlikely(xdr->scratch.iov_len)) ++ __xdr_commit_encode(xdr); ++} ++ + /** + * xdr_stream_remaining - Return the number of bytes remaining in the stream + * @xdr: pointer to struct xdr_stream +diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c +index 722586696fade..f66e2de7cd279 100644 +--- a/net/sunrpc/xdr.c ++++ b/net/sunrpc/xdr.c +@@ -691,7 +691,7 @@ void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p, + EXPORT_SYMBOL_GPL(xdr_init_encode); + + /** +- * xdr_commit_encode - Ensure all data is written to buffer ++ * __xdr_commit_encode - Ensure all data is written to buffer + * @xdr: pointer to xdr_stream + * + * We handle encoding across page boundaries by giving the caller a +@@ -703,22 +703,25 @@ EXPORT_SYMBOL_GPL(xdr_init_encode); + * required at the end of encoding, or any other time when the xdr_buf + * data might be read. + */ +-inline void xdr_commit_encode(struct xdr_stream *xdr) ++void __xdr_commit_encode(struct xdr_stream *xdr) + { + int shift = xdr->scratch.iov_len; + void *page; + +- if (shift == 0) +- return; + page = page_address(*xdr->page_ptr); + memcpy(xdr->scratch.iov_base, page, shift); + memmove(page, page + shift, (void *)xdr->p - page); + xdr_reset_scratch_buffer(xdr); + } +-EXPORT_SYMBOL_GPL(xdr_commit_encode); ++EXPORT_SYMBOL_GPL(__xdr_commit_encode); + +-static __be32 *xdr_get_next_encode_buffer(struct xdr_stream *xdr, +- size_t nbytes) ++/* ++ * The buffer space to be reserved crosses the boundary between ++ * xdr->buf->head and xdr->buf->pages, or between two pages ++ * in xdr->buf->pages. ++ */ ++static noinline __be32 *xdr_get_next_encode_buffer(struct xdr_stream *xdr, ++ size_t nbytes) + { + __be32 *p; + int space_left; +-- +2.43.0 + diff --git a/queue-5.10/sunrpc-parametrize-how-much-of-argsize-should-be-zer.patch b/queue-5.10/sunrpc-parametrize-how-much-of-argsize-should-be-zer.patch new file mode 100644 index 00000000000..5e43e614706 --- /dev/null +++ b/queue-5.10/sunrpc-parametrize-how-much-of-argsize-should-be-zer.patch @@ -0,0 +1,887 @@ +From ca00d07c4d466c74916c47389459c954728dfb5a Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 12 Sep 2022 17:22:38 -0400 +Subject: SUNRPC: Parametrize how much of argsize should be zeroed + +From: Chuck Lever + +[ Upstream commit 103cc1fafee48adb91fca0e19deb869fd23e46ab ] + +Currently, SUNRPC clears the whole of .pc_argsize before processing +each incoming RPC transaction. Add an extra parameter to struct +svc_procedure to enable upper layers to reduce the amount of each +operation's argument structure that is zeroed by SUNRPC. + +The size of struct nfsd4_compoundargs, in particular, is a lot to +clear on each incoming RPC Call. A subsequent patch will cut this +down to something closer to what NFSv2 and NFSv3 uses. + +This patch should cause no behavior changes. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/svc4proc.c | 24 ++++++++++++++++++++++++ + fs/lockd/svcproc.c | 24 ++++++++++++++++++++++++ + fs/nfs/callback_xdr.c | 1 + + fs/nfsd/nfs2acl.c | 5 +++++ + fs/nfsd/nfs3acl.c | 3 +++ + fs/nfsd/nfs3proc.c | 22 ++++++++++++++++++++++ + fs/nfsd/nfs4proc.c | 2 ++ + fs/nfsd/nfsproc.c | 18 ++++++++++++++++++ + include/linux/sunrpc/svc.h | 1 + + net/sunrpc/svc.c | 2 +- + 10 files changed, 101 insertions(+), 1 deletion(-) + +diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c +index bf274f23969b3..284b019cb6529 100644 +--- a/fs/lockd/svc4proc.c ++++ b/fs/lockd/svc4proc.c +@@ -521,6 +521,7 @@ const struct svc_procedure nlmsvc_procedures4[24] = { + .pc_decode = nlm4svc_decode_void, + .pc_encode = nlm4svc_encode_void, + .pc_argsize = sizeof(struct nlm_void), ++ .pc_argzero = sizeof(struct nlm_void), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "NULL", +@@ -530,6 +531,7 @@ const struct svc_procedure nlmsvc_procedures4[24] = { + .pc_decode = nlm4svc_decode_testargs, + .pc_encode = nlm4svc_encode_testres, + .pc_argsize = sizeof(struct nlm_args), ++ .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St+2+No+Rg, + .pc_name = "TEST", +@@ -539,6 +541,7 @@ const struct svc_procedure nlmsvc_procedures4[24] = { + .pc_decode = nlm4svc_decode_lockargs, + .pc_encode = nlm4svc_encode_res, + .pc_argsize = sizeof(struct nlm_args), ++ .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St, + .pc_name = "LOCK", +@@ -548,6 +551,7 @@ const struct svc_procedure nlmsvc_procedures4[24] = { + .pc_decode = nlm4svc_decode_cancargs, + .pc_encode = nlm4svc_encode_res, + .pc_argsize = sizeof(struct nlm_args), ++ .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St, + .pc_name = "CANCEL", +@@ -557,6 +561,7 @@ const struct svc_procedure nlmsvc_procedures4[24] = { + .pc_decode = nlm4svc_decode_unlockargs, + .pc_encode = nlm4svc_encode_res, + .pc_argsize = sizeof(struct nlm_args), ++ .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St, + .pc_name = "UNLOCK", +@@ -566,6 +571,7 @@ const struct svc_procedure nlmsvc_procedures4[24] = { + .pc_decode = nlm4svc_decode_testargs, + .pc_encode = nlm4svc_encode_res, + .pc_argsize = sizeof(struct nlm_args), ++ .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St, + .pc_name = "GRANTED", +@@ -575,6 +581,7 @@ const struct svc_procedure nlmsvc_procedures4[24] = { + .pc_decode = nlm4svc_decode_testargs, + .pc_encode = nlm4svc_encode_void, + .pc_argsize = sizeof(struct nlm_args), ++ .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "TEST_MSG", +@@ -584,6 +591,7 @@ const struct svc_procedure nlmsvc_procedures4[24] = { + .pc_decode = nlm4svc_decode_lockargs, + .pc_encode = nlm4svc_encode_void, + .pc_argsize = sizeof(struct nlm_args), ++ .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "LOCK_MSG", +@@ -593,6 +601,7 @@ const struct svc_procedure nlmsvc_procedures4[24] = { + .pc_decode = nlm4svc_decode_cancargs, + .pc_encode = nlm4svc_encode_void, + .pc_argsize = sizeof(struct nlm_args), ++ .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "CANCEL_MSG", +@@ -602,6 +611,7 @@ const struct svc_procedure nlmsvc_procedures4[24] = { + .pc_decode = nlm4svc_decode_unlockargs, + .pc_encode = nlm4svc_encode_void, + .pc_argsize = sizeof(struct nlm_args), ++ .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "UNLOCK_MSG", +@@ -611,6 +621,7 @@ const struct svc_procedure nlmsvc_procedures4[24] = { + .pc_decode = nlm4svc_decode_testargs, + .pc_encode = nlm4svc_encode_void, + .pc_argsize = sizeof(struct nlm_args), ++ .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "GRANTED_MSG", +@@ -620,6 +631,7 @@ const struct svc_procedure nlmsvc_procedures4[24] = { + .pc_decode = nlm4svc_decode_void, + .pc_encode = nlm4svc_encode_void, + .pc_argsize = sizeof(struct nlm_res), ++ .pc_argzero = sizeof(struct nlm_res), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "TEST_RES", +@@ -629,6 +641,7 @@ const struct svc_procedure nlmsvc_procedures4[24] = { + .pc_decode = nlm4svc_decode_void, + .pc_encode = nlm4svc_encode_void, + .pc_argsize = sizeof(struct nlm_res), ++ .pc_argzero = sizeof(struct nlm_res), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "LOCK_RES", +@@ -638,6 +651,7 @@ const struct svc_procedure nlmsvc_procedures4[24] = { + .pc_decode = nlm4svc_decode_void, + .pc_encode = nlm4svc_encode_void, + .pc_argsize = sizeof(struct nlm_res), ++ .pc_argzero = sizeof(struct nlm_res), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "CANCEL_RES", +@@ -647,6 +661,7 @@ const struct svc_procedure nlmsvc_procedures4[24] = { + .pc_decode = nlm4svc_decode_void, + .pc_encode = nlm4svc_encode_void, + .pc_argsize = sizeof(struct nlm_res), ++ .pc_argzero = sizeof(struct nlm_res), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "UNLOCK_RES", +@@ -656,6 +671,7 @@ const struct svc_procedure nlmsvc_procedures4[24] = { + .pc_decode = nlm4svc_decode_res, + .pc_encode = nlm4svc_encode_void, + .pc_argsize = sizeof(struct nlm_res), ++ .pc_argzero = sizeof(struct nlm_res), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "GRANTED_RES", +@@ -665,6 +681,7 @@ const struct svc_procedure nlmsvc_procedures4[24] = { + .pc_decode = nlm4svc_decode_reboot, + .pc_encode = nlm4svc_encode_void, + .pc_argsize = sizeof(struct nlm_reboot), ++ .pc_argzero = sizeof(struct nlm_reboot), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "SM_NOTIFY", +@@ -674,6 +691,7 @@ const struct svc_procedure nlmsvc_procedures4[24] = { + .pc_decode = nlm4svc_decode_void, + .pc_encode = nlm4svc_encode_void, + .pc_argsize = sizeof(struct nlm_void), ++ .pc_argzero = sizeof(struct nlm_void), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = 0, + .pc_name = "UNUSED", +@@ -683,6 +701,7 @@ const struct svc_procedure nlmsvc_procedures4[24] = { + .pc_decode = nlm4svc_decode_void, + .pc_encode = nlm4svc_encode_void, + .pc_argsize = sizeof(struct nlm_void), ++ .pc_argzero = sizeof(struct nlm_void), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = 0, + .pc_name = "UNUSED", +@@ -692,6 +711,7 @@ const struct svc_procedure nlmsvc_procedures4[24] = { + .pc_decode = nlm4svc_decode_void, + .pc_encode = nlm4svc_encode_void, + .pc_argsize = sizeof(struct nlm_void), ++ .pc_argzero = sizeof(struct nlm_void), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = 0, + .pc_name = "UNUSED", +@@ -701,6 +721,7 @@ const struct svc_procedure nlmsvc_procedures4[24] = { + .pc_decode = nlm4svc_decode_shareargs, + .pc_encode = nlm4svc_encode_shareres, + .pc_argsize = sizeof(struct nlm_args), ++ .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St+1, + .pc_name = "SHARE", +@@ -710,6 +731,7 @@ const struct svc_procedure nlmsvc_procedures4[24] = { + .pc_decode = nlm4svc_decode_shareargs, + .pc_encode = nlm4svc_encode_shareres, + .pc_argsize = sizeof(struct nlm_args), ++ .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St+1, + .pc_name = "UNSHARE", +@@ -719,6 +741,7 @@ const struct svc_procedure nlmsvc_procedures4[24] = { + .pc_decode = nlm4svc_decode_lockargs, + .pc_encode = nlm4svc_encode_res, + .pc_argsize = sizeof(struct nlm_args), ++ .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St, + .pc_name = "NM_LOCK", +@@ -728,6 +751,7 @@ const struct svc_procedure nlmsvc_procedures4[24] = { + .pc_decode = nlm4svc_decode_notify, + .pc_encode = nlm4svc_encode_void, + .pc_argsize = sizeof(struct nlm_args), ++ .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "FREE_ALL", +diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c +index b09ca35b527cc..e35c05e278061 100644 +--- a/fs/lockd/svcproc.c ++++ b/fs/lockd/svcproc.c +@@ -555,6 +555,7 @@ const struct svc_procedure nlmsvc_procedures[24] = { + .pc_decode = nlmsvc_decode_void, + .pc_encode = nlmsvc_encode_void, + .pc_argsize = sizeof(struct nlm_void), ++ .pc_argzero = sizeof(struct nlm_void), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "NULL", +@@ -564,6 +565,7 @@ const struct svc_procedure nlmsvc_procedures[24] = { + .pc_decode = nlmsvc_decode_testargs, + .pc_encode = nlmsvc_encode_testres, + .pc_argsize = sizeof(struct nlm_args), ++ .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St+2+No+Rg, + .pc_name = "TEST", +@@ -573,6 +575,7 @@ const struct svc_procedure nlmsvc_procedures[24] = { + .pc_decode = nlmsvc_decode_lockargs, + .pc_encode = nlmsvc_encode_res, + .pc_argsize = sizeof(struct nlm_args), ++ .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St, + .pc_name = "LOCK", +@@ -582,6 +585,7 @@ const struct svc_procedure nlmsvc_procedures[24] = { + .pc_decode = nlmsvc_decode_cancargs, + .pc_encode = nlmsvc_encode_res, + .pc_argsize = sizeof(struct nlm_args), ++ .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St, + .pc_name = "CANCEL", +@@ -591,6 +595,7 @@ const struct svc_procedure nlmsvc_procedures[24] = { + .pc_decode = nlmsvc_decode_unlockargs, + .pc_encode = nlmsvc_encode_res, + .pc_argsize = sizeof(struct nlm_args), ++ .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St, + .pc_name = "UNLOCK", +@@ -600,6 +605,7 @@ const struct svc_procedure nlmsvc_procedures[24] = { + .pc_decode = nlmsvc_decode_testargs, + .pc_encode = nlmsvc_encode_res, + .pc_argsize = sizeof(struct nlm_args), ++ .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St, + .pc_name = "GRANTED", +@@ -609,6 +615,7 @@ const struct svc_procedure nlmsvc_procedures[24] = { + .pc_decode = nlmsvc_decode_testargs, + .pc_encode = nlmsvc_encode_void, + .pc_argsize = sizeof(struct nlm_args), ++ .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "TEST_MSG", +@@ -618,6 +625,7 @@ const struct svc_procedure nlmsvc_procedures[24] = { + .pc_decode = nlmsvc_decode_lockargs, + .pc_encode = nlmsvc_encode_void, + .pc_argsize = sizeof(struct nlm_args), ++ .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "LOCK_MSG", +@@ -627,6 +635,7 @@ const struct svc_procedure nlmsvc_procedures[24] = { + .pc_decode = nlmsvc_decode_cancargs, + .pc_encode = nlmsvc_encode_void, + .pc_argsize = sizeof(struct nlm_args), ++ .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "CANCEL_MSG", +@@ -636,6 +645,7 @@ const struct svc_procedure nlmsvc_procedures[24] = { + .pc_decode = nlmsvc_decode_unlockargs, + .pc_encode = nlmsvc_encode_void, + .pc_argsize = sizeof(struct nlm_args), ++ .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "UNLOCK_MSG", +@@ -645,6 +655,7 @@ const struct svc_procedure nlmsvc_procedures[24] = { + .pc_decode = nlmsvc_decode_testargs, + .pc_encode = nlmsvc_encode_void, + .pc_argsize = sizeof(struct nlm_args), ++ .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "GRANTED_MSG", +@@ -654,6 +665,7 @@ const struct svc_procedure nlmsvc_procedures[24] = { + .pc_decode = nlmsvc_decode_void, + .pc_encode = nlmsvc_encode_void, + .pc_argsize = sizeof(struct nlm_res), ++ .pc_argzero = sizeof(struct nlm_res), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "TEST_RES", +@@ -663,6 +675,7 @@ const struct svc_procedure nlmsvc_procedures[24] = { + .pc_decode = nlmsvc_decode_void, + .pc_encode = nlmsvc_encode_void, + .pc_argsize = sizeof(struct nlm_res), ++ .pc_argzero = sizeof(struct nlm_res), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "LOCK_RES", +@@ -672,6 +685,7 @@ const struct svc_procedure nlmsvc_procedures[24] = { + .pc_decode = nlmsvc_decode_void, + .pc_encode = nlmsvc_encode_void, + .pc_argsize = sizeof(struct nlm_res), ++ .pc_argzero = sizeof(struct nlm_res), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "CANCEL_RES", +@@ -681,6 +695,7 @@ const struct svc_procedure nlmsvc_procedures[24] = { + .pc_decode = nlmsvc_decode_void, + .pc_encode = nlmsvc_encode_void, + .pc_argsize = sizeof(struct nlm_res), ++ .pc_argzero = sizeof(struct nlm_res), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "UNLOCK_RES", +@@ -690,6 +705,7 @@ const struct svc_procedure nlmsvc_procedures[24] = { + .pc_decode = nlmsvc_decode_res, + .pc_encode = nlmsvc_encode_void, + .pc_argsize = sizeof(struct nlm_res), ++ .pc_argzero = sizeof(struct nlm_res), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "GRANTED_RES", +@@ -699,6 +715,7 @@ const struct svc_procedure nlmsvc_procedures[24] = { + .pc_decode = nlmsvc_decode_reboot, + .pc_encode = nlmsvc_encode_void, + .pc_argsize = sizeof(struct nlm_reboot), ++ .pc_argzero = sizeof(struct nlm_reboot), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "SM_NOTIFY", +@@ -708,6 +725,7 @@ const struct svc_procedure nlmsvc_procedures[24] = { + .pc_decode = nlmsvc_decode_void, + .pc_encode = nlmsvc_encode_void, + .pc_argsize = sizeof(struct nlm_void), ++ .pc_argzero = sizeof(struct nlm_void), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "UNUSED", +@@ -717,6 +735,7 @@ const struct svc_procedure nlmsvc_procedures[24] = { + .pc_decode = nlmsvc_decode_void, + .pc_encode = nlmsvc_encode_void, + .pc_argsize = sizeof(struct nlm_void), ++ .pc_argzero = sizeof(struct nlm_void), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "UNUSED", +@@ -726,6 +745,7 @@ const struct svc_procedure nlmsvc_procedures[24] = { + .pc_decode = nlmsvc_decode_void, + .pc_encode = nlmsvc_encode_void, + .pc_argsize = sizeof(struct nlm_void), ++ .pc_argzero = sizeof(struct nlm_void), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + .pc_name = "UNUSED", +@@ -735,6 +755,7 @@ const struct svc_procedure nlmsvc_procedures[24] = { + .pc_decode = nlmsvc_decode_shareargs, + .pc_encode = nlmsvc_encode_shareres, + .pc_argsize = sizeof(struct nlm_args), ++ .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St+1, + .pc_name = "SHARE", +@@ -744,6 +765,7 @@ const struct svc_procedure nlmsvc_procedures[24] = { + .pc_decode = nlmsvc_decode_shareargs, + .pc_encode = nlmsvc_encode_shareres, + .pc_argsize = sizeof(struct nlm_args), ++ .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St+1, + .pc_name = "UNSHARE", +@@ -753,6 +775,7 @@ const struct svc_procedure nlmsvc_procedures[24] = { + .pc_decode = nlmsvc_decode_lockargs, + .pc_encode = nlmsvc_encode_res, + .pc_argsize = sizeof(struct nlm_args), ++ .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St, + .pc_name = "NM_LOCK", +@@ -762,6 +785,7 @@ const struct svc_procedure nlmsvc_procedures[24] = { + .pc_decode = nlmsvc_decode_notify, + .pc_encode = nlmsvc_encode_void, + .pc_argsize = sizeof(struct nlm_args), ++ .pc_argzero = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = 0, + .pc_name = "FREE_ALL", +diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c +index 1b21f88a9808c..db69fc267c9a0 100644 +--- a/fs/nfs/callback_xdr.c ++++ b/fs/nfs/callback_xdr.c +@@ -1070,6 +1070,7 @@ static const struct svc_procedure nfs4_callback_procedures1[] = { + .pc_func = nfs4_callback_compound, + .pc_encode = nfs4_encode_void, + .pc_argsize = 256, ++ .pc_argzero = 256, + .pc_ressize = 256, + .pc_xdrressize = NFS4_CALLBACK_BUFSIZE, + .pc_name = "COMPOUND", +diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c +index f7d166f056afa..f8179fc8c9bdf 100644 +--- a/fs/nfsd/nfs2acl.c ++++ b/fs/nfsd/nfs2acl.c +@@ -329,6 +329,7 @@ static const struct svc_procedure nfsd_acl_procedures2[5] = { + .pc_decode = nfssvc_decode_voidarg, + .pc_encode = nfssvc_encode_voidres, + .pc_argsize = sizeof(struct nfsd_voidargs), ++ .pc_argzero = sizeof(struct nfsd_voidargs), + .pc_ressize = sizeof(struct nfsd_voidres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST, +@@ -340,6 +341,7 @@ static const struct svc_procedure nfsd_acl_procedures2[5] = { + .pc_encode = nfsaclsvc_encode_getaclres, + .pc_release = nfsaclsvc_release_getacl, + .pc_argsize = sizeof(struct nfsd3_getaclargs), ++ .pc_argzero = sizeof(struct nfsd3_getaclargs), + .pc_ressize = sizeof(struct nfsd3_getaclres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+1+2*(1+ACL), +@@ -351,6 +353,7 @@ static const struct svc_procedure nfsd_acl_procedures2[5] = { + .pc_encode = nfssvc_encode_attrstatres, + .pc_release = nfssvc_release_attrstat, + .pc_argsize = sizeof(struct nfsd3_setaclargs), ++ .pc_argzero = sizeof(struct nfsd3_setaclargs), + .pc_ressize = sizeof(struct nfsd_attrstat), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+AT, +@@ -362,6 +365,7 @@ static const struct svc_procedure nfsd_acl_procedures2[5] = { + .pc_encode = nfssvc_encode_attrstatres, + .pc_release = nfssvc_release_attrstat, + .pc_argsize = sizeof(struct nfsd_fhandle), ++ .pc_argzero = sizeof(struct nfsd_fhandle), + .pc_ressize = sizeof(struct nfsd_attrstat), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+AT, +@@ -373,6 +377,7 @@ static const struct svc_procedure nfsd_acl_procedures2[5] = { + .pc_encode = nfsaclsvc_encode_accessres, + .pc_release = nfsaclsvc_release_access, + .pc_argsize = sizeof(struct nfsd3_accessargs), ++ .pc_argzero = sizeof(struct nfsd3_accessargs), + .pc_ressize = sizeof(struct nfsd3_accessres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+AT+1, +diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c +index 15bee0339c764..2c451fcd5a3cc 100644 +--- a/fs/nfsd/nfs3acl.c ++++ b/fs/nfsd/nfs3acl.c +@@ -250,6 +250,7 @@ static const struct svc_procedure nfsd_acl_procedures3[3] = { + .pc_decode = nfssvc_decode_voidarg, + .pc_encode = nfssvc_encode_voidres, + .pc_argsize = sizeof(struct nfsd_voidargs), ++ .pc_argzero = sizeof(struct nfsd_voidargs), + .pc_ressize = sizeof(struct nfsd_voidres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST, +@@ -261,6 +262,7 @@ static const struct svc_procedure nfsd_acl_procedures3[3] = { + .pc_encode = nfs3svc_encode_getaclres, + .pc_release = nfs3svc_release_getacl, + .pc_argsize = sizeof(struct nfsd3_getaclargs), ++ .pc_argzero = sizeof(struct nfsd3_getaclargs), + .pc_ressize = sizeof(struct nfsd3_getaclres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+1+2*(1+ACL), +@@ -272,6 +274,7 @@ static const struct svc_procedure nfsd_acl_procedures3[3] = { + .pc_encode = nfs3svc_encode_setaclres, + .pc_release = nfs3svc_release_fhandle, + .pc_argsize = sizeof(struct nfsd3_setaclargs), ++ .pc_argzero = sizeof(struct nfsd3_setaclargs), + .pc_ressize = sizeof(struct nfsd3_attrstat), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+pAT, +diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c +index 8679c41746027..5c2e2b5e5945f 100644 +--- a/fs/nfsd/nfs3proc.c ++++ b/fs/nfsd/nfs3proc.c +@@ -809,6 +809,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { + .pc_decode = nfssvc_decode_voidarg, + .pc_encode = nfssvc_encode_voidres, + .pc_argsize = sizeof(struct nfsd_voidargs), ++ .pc_argzero = sizeof(struct nfsd_voidargs), + .pc_ressize = sizeof(struct nfsd_voidres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST, +@@ -820,6 +821,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { + .pc_encode = nfs3svc_encode_getattrres, + .pc_release = nfs3svc_release_fhandle, + .pc_argsize = sizeof(struct nfsd_fhandle), ++ .pc_argzero = sizeof(struct nfsd_fhandle), + .pc_ressize = sizeof(struct nfsd3_attrstatres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+AT, +@@ -831,6 +833,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { + .pc_encode = nfs3svc_encode_wccstatres, + .pc_release = nfs3svc_release_fhandle, + .pc_argsize = sizeof(struct nfsd3_sattrargs), ++ .pc_argzero = sizeof(struct nfsd3_sattrargs), + .pc_ressize = sizeof(struct nfsd3_wccstatres), + .pc_cachetype = RC_REPLBUFF, + .pc_xdrressize = ST+WC, +@@ -842,6 +845,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { + .pc_encode = nfs3svc_encode_lookupres, + .pc_release = nfs3svc_release_fhandle2, + .pc_argsize = sizeof(struct nfsd3_diropargs), ++ .pc_argzero = sizeof(struct nfsd3_diropargs), + .pc_ressize = sizeof(struct nfsd3_diropres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+FH+pAT+pAT, +@@ -853,6 +857,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { + .pc_encode = nfs3svc_encode_accessres, + .pc_release = nfs3svc_release_fhandle, + .pc_argsize = sizeof(struct nfsd3_accessargs), ++ .pc_argzero = sizeof(struct nfsd3_accessargs), + .pc_ressize = sizeof(struct nfsd3_accessres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+pAT+1, +@@ -864,6 +869,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { + .pc_encode = nfs3svc_encode_readlinkres, + .pc_release = nfs3svc_release_fhandle, + .pc_argsize = sizeof(struct nfsd_fhandle), ++ .pc_argzero = sizeof(struct nfsd_fhandle), + .pc_ressize = sizeof(struct nfsd3_readlinkres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+pAT+1+NFS3_MAXPATHLEN/4, +@@ -875,6 +881,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { + .pc_encode = nfs3svc_encode_readres, + .pc_release = nfs3svc_release_fhandle, + .pc_argsize = sizeof(struct nfsd3_readargs), ++ .pc_argzero = sizeof(struct nfsd3_readargs), + .pc_ressize = sizeof(struct nfsd3_readres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+pAT+4+NFSSVC_MAXBLKSIZE/4, +@@ -886,6 +893,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { + .pc_encode = nfs3svc_encode_writeres, + .pc_release = nfs3svc_release_fhandle, + .pc_argsize = sizeof(struct nfsd3_writeargs), ++ .pc_argzero = sizeof(struct nfsd3_writeargs), + .pc_ressize = sizeof(struct nfsd3_writeres), + .pc_cachetype = RC_REPLBUFF, + .pc_xdrressize = ST+WC+4, +@@ -897,6 +905,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { + .pc_encode = nfs3svc_encode_createres, + .pc_release = nfs3svc_release_fhandle2, + .pc_argsize = sizeof(struct nfsd3_createargs), ++ .pc_argzero = sizeof(struct nfsd3_createargs), + .pc_ressize = sizeof(struct nfsd3_createres), + .pc_cachetype = RC_REPLBUFF, + .pc_xdrressize = ST+(1+FH+pAT)+WC, +@@ -908,6 +917,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { + .pc_encode = nfs3svc_encode_createres, + .pc_release = nfs3svc_release_fhandle2, + .pc_argsize = sizeof(struct nfsd3_mkdirargs), ++ .pc_argzero = sizeof(struct nfsd3_mkdirargs), + .pc_ressize = sizeof(struct nfsd3_createres), + .pc_cachetype = RC_REPLBUFF, + .pc_xdrressize = ST+(1+FH+pAT)+WC, +@@ -919,6 +929,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { + .pc_encode = nfs3svc_encode_createres, + .pc_release = nfs3svc_release_fhandle2, + .pc_argsize = sizeof(struct nfsd3_symlinkargs), ++ .pc_argzero = sizeof(struct nfsd3_symlinkargs), + .pc_ressize = sizeof(struct nfsd3_createres), + .pc_cachetype = RC_REPLBUFF, + .pc_xdrressize = ST+(1+FH+pAT)+WC, +@@ -930,6 +941,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { + .pc_encode = nfs3svc_encode_createres, + .pc_release = nfs3svc_release_fhandle2, + .pc_argsize = sizeof(struct nfsd3_mknodargs), ++ .pc_argzero = sizeof(struct nfsd3_mknodargs), + .pc_ressize = sizeof(struct nfsd3_createres), + .pc_cachetype = RC_REPLBUFF, + .pc_xdrressize = ST+(1+FH+pAT)+WC, +@@ -941,6 +953,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { + .pc_encode = nfs3svc_encode_wccstatres, + .pc_release = nfs3svc_release_fhandle, + .pc_argsize = sizeof(struct nfsd3_diropargs), ++ .pc_argzero = sizeof(struct nfsd3_diropargs), + .pc_ressize = sizeof(struct nfsd3_wccstatres), + .pc_cachetype = RC_REPLBUFF, + .pc_xdrressize = ST+WC, +@@ -952,6 +965,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { + .pc_encode = nfs3svc_encode_wccstatres, + .pc_release = nfs3svc_release_fhandle, + .pc_argsize = sizeof(struct nfsd3_diropargs), ++ .pc_argzero = sizeof(struct nfsd3_diropargs), + .pc_ressize = sizeof(struct nfsd3_wccstatres), + .pc_cachetype = RC_REPLBUFF, + .pc_xdrressize = ST+WC, +@@ -963,6 +977,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { + .pc_encode = nfs3svc_encode_renameres, + .pc_release = nfs3svc_release_fhandle2, + .pc_argsize = sizeof(struct nfsd3_renameargs), ++ .pc_argzero = sizeof(struct nfsd3_renameargs), + .pc_ressize = sizeof(struct nfsd3_renameres), + .pc_cachetype = RC_REPLBUFF, + .pc_xdrressize = ST+WC+WC, +@@ -974,6 +989,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { + .pc_encode = nfs3svc_encode_linkres, + .pc_release = nfs3svc_release_fhandle2, + .pc_argsize = sizeof(struct nfsd3_linkargs), ++ .pc_argzero = sizeof(struct nfsd3_linkargs), + .pc_ressize = sizeof(struct nfsd3_linkres), + .pc_cachetype = RC_REPLBUFF, + .pc_xdrressize = ST+pAT+WC, +@@ -985,6 +1001,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { + .pc_encode = nfs3svc_encode_readdirres, + .pc_release = nfs3svc_release_fhandle, + .pc_argsize = sizeof(struct nfsd3_readdirargs), ++ .pc_argzero = sizeof(struct nfsd3_readdirargs), + .pc_ressize = sizeof(struct nfsd3_readdirres), + .pc_cachetype = RC_NOCACHE, + .pc_name = "READDIR", +@@ -995,6 +1012,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { + .pc_encode = nfs3svc_encode_readdirres, + .pc_release = nfs3svc_release_fhandle, + .pc_argsize = sizeof(struct nfsd3_readdirplusargs), ++ .pc_argzero = sizeof(struct nfsd3_readdirplusargs), + .pc_ressize = sizeof(struct nfsd3_readdirres), + .pc_cachetype = RC_NOCACHE, + .pc_name = "READDIRPLUS", +@@ -1004,6 +1022,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { + .pc_decode = nfs3svc_decode_fhandleargs, + .pc_encode = nfs3svc_encode_fsstatres, + .pc_argsize = sizeof(struct nfsd3_fhandleargs), ++ .pc_argzero = sizeof(struct nfsd3_fhandleargs), + .pc_ressize = sizeof(struct nfsd3_fsstatres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+pAT+2*6+1, +@@ -1014,6 +1033,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { + .pc_decode = nfs3svc_decode_fhandleargs, + .pc_encode = nfs3svc_encode_fsinfores, + .pc_argsize = sizeof(struct nfsd3_fhandleargs), ++ .pc_argzero = sizeof(struct nfsd3_fhandleargs), + .pc_ressize = sizeof(struct nfsd3_fsinfores), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+pAT+12, +@@ -1024,6 +1044,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { + .pc_decode = nfs3svc_decode_fhandleargs, + .pc_encode = nfs3svc_encode_pathconfres, + .pc_argsize = sizeof(struct nfsd3_fhandleargs), ++ .pc_argzero = sizeof(struct nfsd3_fhandleargs), + .pc_ressize = sizeof(struct nfsd3_pathconfres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+pAT+6, +@@ -1035,6 +1056,7 @@ static const struct svc_procedure nfsd_procedures3[22] = { + .pc_encode = nfs3svc_encode_commitres, + .pc_release = nfs3svc_release_fhandle, + .pc_argsize = sizeof(struct nfsd3_commitargs), ++ .pc_argzero = sizeof(struct nfsd3_commitargs), + .pc_ressize = sizeof(struct nfsd3_commitres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+WC+2, +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index 38d60964d8b2d..f6ea7445073fe 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -3577,6 +3577,7 @@ static const struct svc_procedure nfsd_procedures4[2] = { + .pc_decode = nfssvc_decode_voidarg, + .pc_encode = nfssvc_encode_voidres, + .pc_argsize = sizeof(struct nfsd_voidargs), ++ .pc_argzero = sizeof(struct nfsd_voidargs), + .pc_ressize = sizeof(struct nfsd_voidres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = 1, +@@ -3587,6 +3588,7 @@ static const struct svc_procedure nfsd_procedures4[2] = { + .pc_decode = nfs4svc_decode_compoundargs, + .pc_encode = nfs4svc_encode_compoundres, + .pc_argsize = sizeof(struct nfsd4_compoundargs), ++ .pc_argzero = sizeof(struct nfsd4_compoundargs), + .pc_ressize = sizeof(struct nfsd4_compoundres), + .pc_release = nfsd4_release_compoundargs, + .pc_cachetype = RC_NOCACHE, +diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c +index 7ed03ac6bdab3..3509331a66504 100644 +--- a/fs/nfsd/nfsproc.c ++++ b/fs/nfsd/nfsproc.c +@@ -645,6 +645,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { + .pc_decode = nfssvc_decode_voidarg, + .pc_encode = nfssvc_encode_voidres, + .pc_argsize = sizeof(struct nfsd_voidargs), ++ .pc_argzero = sizeof(struct nfsd_voidargs), + .pc_ressize = sizeof(struct nfsd_voidres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = 0, +@@ -656,6 +657,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { + .pc_encode = nfssvc_encode_attrstatres, + .pc_release = nfssvc_release_attrstat, + .pc_argsize = sizeof(struct nfsd_fhandle), ++ .pc_argzero = sizeof(struct nfsd_fhandle), + .pc_ressize = sizeof(struct nfsd_attrstat), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+AT, +@@ -667,6 +669,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { + .pc_encode = nfssvc_encode_attrstatres, + .pc_release = nfssvc_release_attrstat, + .pc_argsize = sizeof(struct nfsd_sattrargs), ++ .pc_argzero = sizeof(struct nfsd_sattrargs), + .pc_ressize = sizeof(struct nfsd_attrstat), + .pc_cachetype = RC_REPLBUFF, + .pc_xdrressize = ST+AT, +@@ -677,6 +680,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { + .pc_decode = nfssvc_decode_voidarg, + .pc_encode = nfssvc_encode_voidres, + .pc_argsize = sizeof(struct nfsd_voidargs), ++ .pc_argzero = sizeof(struct nfsd_voidargs), + .pc_ressize = sizeof(struct nfsd_voidres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = 0, +@@ -688,6 +692,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { + .pc_encode = nfssvc_encode_diropres, + .pc_release = nfssvc_release_diropres, + .pc_argsize = sizeof(struct nfsd_diropargs), ++ .pc_argzero = sizeof(struct nfsd_diropargs), + .pc_ressize = sizeof(struct nfsd_diropres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+FH+AT, +@@ -698,6 +703,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { + .pc_decode = nfssvc_decode_fhandleargs, + .pc_encode = nfssvc_encode_readlinkres, + .pc_argsize = sizeof(struct nfsd_fhandle), ++ .pc_argzero = sizeof(struct nfsd_fhandle), + .pc_ressize = sizeof(struct nfsd_readlinkres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+1+NFS_MAXPATHLEN/4, +@@ -709,6 +715,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { + .pc_encode = nfssvc_encode_readres, + .pc_release = nfssvc_release_readres, + .pc_argsize = sizeof(struct nfsd_readargs), ++ .pc_argzero = sizeof(struct nfsd_readargs), + .pc_ressize = sizeof(struct nfsd_readres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+AT+1+NFSSVC_MAXBLKSIZE_V2/4, +@@ -719,6 +726,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { + .pc_decode = nfssvc_decode_voidarg, + .pc_encode = nfssvc_encode_voidres, + .pc_argsize = sizeof(struct nfsd_voidargs), ++ .pc_argzero = sizeof(struct nfsd_voidargs), + .pc_ressize = sizeof(struct nfsd_voidres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = 0, +@@ -730,6 +738,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { + .pc_encode = nfssvc_encode_attrstatres, + .pc_release = nfssvc_release_attrstat, + .pc_argsize = sizeof(struct nfsd_writeargs), ++ .pc_argzero = sizeof(struct nfsd_writeargs), + .pc_ressize = sizeof(struct nfsd_attrstat), + .pc_cachetype = RC_REPLBUFF, + .pc_xdrressize = ST+AT, +@@ -741,6 +750,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { + .pc_encode = nfssvc_encode_diropres, + .pc_release = nfssvc_release_diropres, + .pc_argsize = sizeof(struct nfsd_createargs), ++ .pc_argzero = sizeof(struct nfsd_createargs), + .pc_ressize = sizeof(struct nfsd_diropres), + .pc_cachetype = RC_REPLBUFF, + .pc_xdrressize = ST+FH+AT, +@@ -751,6 +761,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { + .pc_decode = nfssvc_decode_diropargs, + .pc_encode = nfssvc_encode_statres, + .pc_argsize = sizeof(struct nfsd_diropargs), ++ .pc_argzero = sizeof(struct nfsd_diropargs), + .pc_ressize = sizeof(struct nfsd_stat), + .pc_cachetype = RC_REPLSTAT, + .pc_xdrressize = ST, +@@ -761,6 +772,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { + .pc_decode = nfssvc_decode_renameargs, + .pc_encode = nfssvc_encode_statres, + .pc_argsize = sizeof(struct nfsd_renameargs), ++ .pc_argzero = sizeof(struct nfsd_renameargs), + .pc_ressize = sizeof(struct nfsd_stat), + .pc_cachetype = RC_REPLSTAT, + .pc_xdrressize = ST, +@@ -771,6 +783,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { + .pc_decode = nfssvc_decode_linkargs, + .pc_encode = nfssvc_encode_statres, + .pc_argsize = sizeof(struct nfsd_linkargs), ++ .pc_argzero = sizeof(struct nfsd_linkargs), + .pc_ressize = sizeof(struct nfsd_stat), + .pc_cachetype = RC_REPLSTAT, + .pc_xdrressize = ST, +@@ -781,6 +794,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { + .pc_decode = nfssvc_decode_symlinkargs, + .pc_encode = nfssvc_encode_statres, + .pc_argsize = sizeof(struct nfsd_symlinkargs), ++ .pc_argzero = sizeof(struct nfsd_symlinkargs), + .pc_ressize = sizeof(struct nfsd_stat), + .pc_cachetype = RC_REPLSTAT, + .pc_xdrressize = ST, +@@ -792,6 +806,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { + .pc_encode = nfssvc_encode_diropres, + .pc_release = nfssvc_release_diropres, + .pc_argsize = sizeof(struct nfsd_createargs), ++ .pc_argzero = sizeof(struct nfsd_createargs), + .pc_ressize = sizeof(struct nfsd_diropres), + .pc_cachetype = RC_REPLBUFF, + .pc_xdrressize = ST+FH+AT, +@@ -802,6 +817,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { + .pc_decode = nfssvc_decode_diropargs, + .pc_encode = nfssvc_encode_statres, + .pc_argsize = sizeof(struct nfsd_diropargs), ++ .pc_argzero = sizeof(struct nfsd_diropargs), + .pc_ressize = sizeof(struct nfsd_stat), + .pc_cachetype = RC_REPLSTAT, + .pc_xdrressize = ST, +@@ -812,6 +828,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { + .pc_decode = nfssvc_decode_readdirargs, + .pc_encode = nfssvc_encode_readdirres, + .pc_argsize = sizeof(struct nfsd_readdirargs), ++ .pc_argzero = sizeof(struct nfsd_readdirargs), + .pc_ressize = sizeof(struct nfsd_readdirres), + .pc_cachetype = RC_NOCACHE, + .pc_name = "READDIR", +@@ -821,6 +838,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { + .pc_decode = nfssvc_decode_fhandleargs, + .pc_encode = nfssvc_encode_statfsres, + .pc_argsize = sizeof(struct nfsd_fhandle), ++ .pc_argzero = sizeof(struct nfsd_fhandle), + .pc_ressize = sizeof(struct nfsd_statfsres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+5, +diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h +index 3c908ffbbf45f..5cf6543d3c8e5 100644 +--- a/include/linux/sunrpc/svc.h ++++ b/include/linux/sunrpc/svc.h +@@ -476,6 +476,7 @@ struct svc_procedure { + /* XDR free result: */ + void (*pc_release)(struct svc_rqst *); + unsigned int pc_argsize; /* argument struct size */ ++ unsigned int pc_argzero; /* how much of argument to clear */ + unsigned int pc_ressize; /* result struct size */ + unsigned int pc_cachetype; /* cache info (NFS) */ + unsigned int pc_xdrressize; /* maximum size of XDR reply */ +diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c +index 9caaed1c143e6..8c29181796492 100644 +--- a/net/sunrpc/svc.c ++++ b/net/sunrpc/svc.c +@@ -1237,7 +1237,7 @@ svc_generic_init_request(struct svc_rqst *rqstp, + rqstp->rq_procinfo = procp = &versp->vs_proc[rqstp->rq_proc]; + + /* Initialize storage for argp and resp */ +- memset(rqstp->rq_argp, 0, procp->pc_argsize); ++ memset(rqstp->rq_argp, 0, procp->pc_argzero); + memset(rqstp->rq_resp, 0, procp->pc_ressize); + + /* Bump per-procedure stats counter */ +-- +2.43.0 + diff --git a/queue-5.10/sunrpc-prepare-for-xdr_stream-style-decoding-on-the-.patch b/queue-5.10/sunrpc-prepare-for-xdr_stream-style-decoding-on-the-.patch new file mode 100644 index 00000000000..eed3f8749e4 --- /dev/null +++ b/queue-5.10/sunrpc-prepare-for-xdr_stream-style-decoding-on-the-.patch @@ -0,0 +1,102 @@ +From 6af4d56ee99d883ddf44c417d000032105f7b9fe Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 5 Nov 2020 11:19:42 -0500 +Subject: SUNRPC: Prepare for xdr_stream-style decoding on the server-side + +From: Chuck Lever + +[ Upstream commit 5191955d6fc65e6d4efe8f4f10a6028298f57281 ] + +A "permanent" struct xdr_stream is allocated in struct svc_rqst so +that it is usable by all server-side decoders. A per-rqst scratch +buffer is also allocated to handle decoding XDR data items that +cross page boundaries. + +To demonstrate how it will be used, add the first call site for the +new svcxdr_init_decode() API. + +As an additional part of the overall conversion, add symbolic +constants for successful and failed XDR operations. Returning "0" is +overloaded. Sometimes it means something failed, but sometimes it +means success. To make it more clear when XDR decoding functions +succeed or fail, introduce symbolic constants. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfssvc.c | 2 ++ + include/linux/sunrpc/svc.h | 16 ++++++++++++++++ + net/sunrpc/svc.c | 5 +++++ + 3 files changed, 23 insertions(+) + +diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c +index 2e61a565cdbd8..311b287c5024f 100644 +--- a/fs/nfsd/nfssvc.c ++++ b/fs/nfsd/nfssvc.c +@@ -1052,6 +1052,8 @@ int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) + * (necessary in the NFSv4.0 compound case) + */ + rqstp->rq_cachetype = proc->pc_cachetype; ++ ++ svcxdr_init_decode(rqstp); + if (!proc->pc_decode(rqstp, argv->iov_base)) + goto out_decode_err; + +diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h +index c220b734fa69e..34c2a69820e93 100644 +--- a/include/linux/sunrpc/svc.h ++++ b/include/linux/sunrpc/svc.h +@@ -247,6 +247,8 @@ struct svc_rqst { + + size_t rq_xprt_hlen; /* xprt header len */ + struct xdr_buf rq_arg; ++ struct xdr_stream rq_arg_stream; ++ struct page *rq_scratch_page; + struct xdr_buf rq_res; + struct page *rq_pages[RPCSVC_MAXPAGES + 1]; + struct page * *rq_respages; /* points into rq_pages */ +@@ -557,4 +559,18 @@ static inline void svc_reserve_auth(struct svc_rqst *rqstp, int space) + svc_reserve(rqstp, space + rqstp->rq_auth_slack); + } + ++/** ++ * svcxdr_init_decode - Prepare an xdr_stream for svc Call decoding ++ * @rqstp: controlling server RPC transaction context ++ * ++ */ ++static inline void svcxdr_init_decode(struct svc_rqst *rqstp) ++{ ++ struct xdr_stream *xdr = &rqstp->rq_arg_stream; ++ struct kvec *argv = rqstp->rq_arg.head; ++ ++ xdr_init_decode(xdr, &rqstp->rq_arg, argv->iov_base, NULL); ++ xdr_set_scratch_page(xdr, rqstp->rq_scratch_page); ++} ++ + #endif /* SUNRPC_SVC_H */ +diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c +index e4e4e203ecdad..73e02ba4ed53a 100644 +--- a/net/sunrpc/svc.c ++++ b/net/sunrpc/svc.c +@@ -614,6 +614,10 @@ svc_rqst_alloc(struct svc_serv *serv, struct svc_pool *pool, int node) + rqstp->rq_server = serv; + rqstp->rq_pool = pool; + ++ rqstp->rq_scratch_page = alloc_pages_node(node, GFP_KERNEL, 0); ++ if (!rqstp->rq_scratch_page) ++ goto out_enomem; ++ + rqstp->rq_argp = kmalloc_node(serv->sv_xdrsize, GFP_KERNEL, node); + if (!rqstp->rq_argp) + goto out_enomem; +@@ -846,6 +850,7 @@ void + svc_rqst_free(struct svc_rqst *rqstp) + { + svc_release_buffer(rqstp); ++ put_page(rqstp->rq_scratch_page); + kfree(rqstp->rq_resp); + kfree(rqstp->rq_argp); + kfree(rqstp->rq_auth_data); +-- +2.43.0 + diff --git a/queue-5.10/sunrpc-remove-svc_shutdown_net.patch b/queue-5.10/sunrpc-remove-svc_shutdown_net.patch new file mode 100644 index 00000000000..3c2fa816ad6 --- /dev/null +++ b/queue-5.10/sunrpc-remove-svc_shutdown_net.patch @@ -0,0 +1,152 @@ +From 0b9a9920265e09f8995124333146e0d97a00bd32 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 26 Jan 2022 11:30:55 -0500 +Subject: SUNRPC: Remove svc_shutdown_net() + +From: Chuck Lever + +[ Upstream commit c7d7ec8f043e53ad16e30f5ebb8b9df415ec0f2b ] + +Clean up: svc_shutdown_net() now does nothing but call +svc_close_net(). Replace all external call sites. + +svc_close_net() is renamed to be the inverse of svc_xprt_create(). + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/svc.c | 4 ++-- + fs/nfs/callback.c | 2 +- + fs/nfsd/nfssvc.c | 2 +- + include/linux/sunrpc/svc.h | 1 - + include/linux/sunrpc/svc_xprt.h | 1 + + net/sunrpc/svc.c | 6 ------ + net/sunrpc/svc_xprt.c | 9 +++++++-- + 7 files changed, 12 insertions(+), 13 deletions(-) + +diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c +index bba6f2b45b64a..c83ec4a375bc1 100644 +--- a/fs/lockd/svc.c ++++ b/fs/lockd/svc.c +@@ -248,7 +248,7 @@ static int make_socks(struct svc_serv *serv, struct net *net, + if (warned++ == 0) + printk(KERN_WARNING + "lockd_up: makesock failed, error=%d\n", err); +- svc_shutdown_net(serv, net); ++ svc_xprt_destroy_all(serv, net); + svc_rpcb_cleanup(serv, net); + return err; + } +@@ -287,7 +287,7 @@ static void lockd_down_net(struct svc_serv *serv, struct net *net) + nlm_shutdown_hosts_net(net); + cancel_delayed_work_sync(&ln->grace_period_end); + locks_end_grace(&ln->lockd_manager); +- svc_shutdown_net(serv, net); ++ svc_xprt_destroy_all(serv, net); + svc_rpcb_cleanup(serv, net); + } + } else { +diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c +index c1a8767100ae9..c98c68513590f 100644 +--- a/fs/nfs/callback.c ++++ b/fs/nfs/callback.c +@@ -189,7 +189,7 @@ static void nfs_callback_down_net(u32 minorversion, struct svc_serv *serv, struc + return; + + dprintk("NFS: destroy per-net callback data; net=%x\n", net->ns.inum); +- svc_shutdown_net(serv, net); ++ svc_xprt_destroy_all(serv, net); + } + + static int nfs_callback_up_net(int minorversion, struct svc_serv *serv, +diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c +index 5790b1eaff72b..38895372ec393 100644 +--- a/fs/nfsd/nfssvc.c ++++ b/fs/nfsd/nfssvc.c +@@ -722,7 +722,7 @@ void nfsd_put(struct net *net) + struct nfsd_net *nn = net_generic(net, nfsd_net_id); + + if (kref_put(&nn->nfsd_serv->sv_refcnt, nfsd_noop)) { +- svc_shutdown_net(nn->nfsd_serv, net); ++ svc_xprt_destroy_all(nn->nfsd_serv, net); + nfsd_last_thread(nn->nfsd_serv, net); + svc_destroy(&nn->nfsd_serv->sv_refcnt); + spin_lock(&nfsd_notifier_lock); +diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h +index 6f3ba5c514643..482a024156b11 100644 +--- a/include/linux/sunrpc/svc.h ++++ b/include/linux/sunrpc/svc.h +@@ -511,7 +511,6 @@ struct svc_serv * svc_create_pooled(struct svc_program *, unsigned int, + const struct svc_serv_ops *); + int svc_set_num_threads(struct svc_serv *, struct svc_pool *, int); + int svc_pool_stats_open(struct svc_serv *serv, struct file *file); +-void svc_shutdown_net(struct svc_serv *, struct net *); + int svc_process(struct svc_rqst *); + int bc_svc_process(struct svc_serv *, struct rpc_rqst *, + struct svc_rqst *); +diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h +index f614f8e248e11..dbffb92511ef2 100644 +--- a/include/linux/sunrpc/svc_xprt.h ++++ b/include/linux/sunrpc/svc_xprt.h +@@ -131,6 +131,7 @@ int svc_xprt_create(struct svc_serv *serv, const char *xprt_name, + struct net *net, const int family, + const unsigned short port, int flags, + const struct cred *cred); ++void svc_xprt_destroy_all(struct svc_serv *serv, struct net *net); + void svc_xprt_received(struct svc_xprt *xprt); + void svc_xprt_enqueue(struct svc_xprt *xprt); + void svc_xprt_put(struct svc_xprt *xprt); +diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c +index 9126e1b7d0769..c9195e40959c6 100644 +--- a/net/sunrpc/svc.c ++++ b/net/sunrpc/svc.c +@@ -534,12 +534,6 @@ svc_create_pooled(struct svc_program *prog, unsigned int bufsize, + } + EXPORT_SYMBOL_GPL(svc_create_pooled); + +-void svc_shutdown_net(struct svc_serv *serv, struct net *net) +-{ +- svc_close_net(serv, net); +-} +-EXPORT_SYMBOL_GPL(svc_shutdown_net); +- + /* + * Destroy an RPC service. Should be called with appropriate locking to + * protect sv_permsocks and sv_tempsocks. +diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c +index ee4a6d57056f5..000b737784bd9 100644 +--- a/net/sunrpc/svc_xprt.c ++++ b/net/sunrpc/svc_xprt.c +@@ -1128,7 +1128,11 @@ static void svc_clean_up_xprts(struct svc_serv *serv, struct net *net) + } + } + +-/* ++/** ++ * svc_xprt_destroy_all - Destroy transports associated with @serv ++ * @serv: RPC service to be shut down ++ * @net: target network namespace ++ * + * Server threads may still be running (especially in the case where the + * service is still running in other network namespaces). + * +@@ -1140,7 +1144,7 @@ static void svc_clean_up_xprts(struct svc_serv *serv, struct net *net) + * threads, we may need to wait a little while and then check again to + * see if they're done. + */ +-void svc_close_net(struct svc_serv *serv, struct net *net) ++void svc_xprt_destroy_all(struct svc_serv *serv, struct net *net) + { + int delay = 0; + +@@ -1151,6 +1155,7 @@ void svc_close_net(struct svc_serv *serv, struct net *net) + msleep(delay++); + } + } ++EXPORT_SYMBOL_GPL(svc_xprt_destroy_all); + + /* + * Handle defer and revisit of requests +-- +2.43.0 + diff --git a/queue-5.10/sunrpc-remove-svo_shutdown-method.patch b/queue-5.10/sunrpc-remove-svo_shutdown-method.patch new file mode 100644 index 00000000000..405723063c2 --- /dev/null +++ b/queue-5.10/sunrpc-remove-svo_shutdown-method.patch @@ -0,0 +1,105 @@ +From 7e54b2b301e5dc2e317472b62efbc8a8b49001e0 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 25 Jan 2022 13:49:29 -0500 +Subject: SUNRPC: Remove svo_shutdown method + +From: Chuck Lever + +[ Upstream commit 87cdd8641c8a1ec6afd2468265e20840a57fd888 ] + +Clean up. Neil observed that "any code that calls svc_shutdown_net() +knows what the shutdown function should be, and so can call it +directly." + +Signed-off-by: Chuck Lever +Reviewed-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/svc.c | 5 ++--- + fs/nfsd/nfssvc.c | 2 +- + include/linux/sunrpc/svc.h | 3 --- + net/sunrpc/svc.c | 3 --- + 4 files changed, 3 insertions(+), 10 deletions(-) + +diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c +index 3a05af8736259..f5b688a844aa5 100644 +--- a/fs/lockd/svc.c ++++ b/fs/lockd/svc.c +@@ -249,6 +249,7 @@ static int make_socks(struct svc_serv *serv, struct net *net, + printk(KERN_WARNING + "lockd_up: makesock failed, error=%d\n", err); + svc_shutdown_net(serv, net); ++ svc_rpcb_cleanup(serv, net); + return err; + } + +@@ -287,8 +288,7 @@ static void lockd_down_net(struct svc_serv *serv, struct net *net) + cancel_delayed_work_sync(&ln->grace_period_end); + locks_end_grace(&ln->lockd_manager); + svc_shutdown_net(serv, net); +- dprintk("%s: per-net data destroyed; net=%x\n", +- __func__, net->ns.inum); ++ svc_rpcb_cleanup(serv, net); + } + } else { + pr_err("%s: no users! net=%x\n", +@@ -351,7 +351,6 @@ static struct notifier_block lockd_inet6addr_notifier = { + #endif + + static const struct svc_serv_ops lockd_sv_ops = { +- .svo_shutdown = svc_rpcb_cleanup, + .svo_function = lockd, + .svo_module = THIS_MODULE, + }; +diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c +index 3b79b97f2715d..a1765e751b739 100644 +--- a/fs/nfsd/nfssvc.c ++++ b/fs/nfsd/nfssvc.c +@@ -613,7 +613,6 @@ static int nfsd_get_default_max_blksize(void) + } + + static const struct svc_serv_ops nfsd_thread_sv_ops = { +- .svo_shutdown = nfsd_last_thread, + .svo_function = nfsd, + .svo_module = THIS_MODULE, + }; +@@ -724,6 +723,7 @@ void nfsd_put(struct net *net) + + if (kref_put(&nn->nfsd_serv->sv_refcnt, nfsd_noop)) { + svc_shutdown_net(nn->nfsd_serv, net); ++ nfsd_last_thread(nn->nfsd_serv, net); + svc_destroy(&nn->nfsd_serv->sv_refcnt); + spin_lock(&nfsd_notifier_lock); + nn->nfsd_serv = NULL; +diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h +index 3c8ed018c6868..6f3ba5c514643 100644 +--- a/include/linux/sunrpc/svc.h ++++ b/include/linux/sunrpc/svc.h +@@ -55,9 +55,6 @@ struct svc_pool { + struct svc_serv; + + struct svc_serv_ops { +- /* Callback to use when last thread exits. */ +- void (*svo_shutdown)(struct svc_serv *, struct net *); +- + /* function for service threads to run */ + int (*svo_function)(void *); + +diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c +index d34d03b0bf76b..709118bac4c32 100644 +--- a/net/sunrpc/svc.c ++++ b/net/sunrpc/svc.c +@@ -537,9 +537,6 @@ EXPORT_SYMBOL_GPL(svc_create_pooled); + void svc_shutdown_net(struct svc_serv *serv, struct net *net) + { + svc_close_net(serv, net); +- +- if (serv->sv_ops->svo_shutdown) +- serv->sv_ops->svo_shutdown(serv, net); + } + EXPORT_SYMBOL_GPL(svc_shutdown_net); + +-- +2.43.0 + diff --git a/queue-5.10/sunrpc-remove-the-.svo_enqueue_xprt-method.patch b/queue-5.10/sunrpc-remove-the-.svo_enqueue_xprt-method.patch new file mode 100644 index 00000000000..bfce29d6fd4 --- /dev/null +++ b/queue-5.10/sunrpc-remove-the-.svo_enqueue_xprt-method.patch @@ -0,0 +1,157 @@ +From 9ba2542bc0307a6db5b05f5268d70e5870d789b4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 25 Jan 2022 10:17:59 -0500 +Subject: SUNRPC: Remove the .svo_enqueue_xprt method + +From: Chuck Lever + +[ Upstream commit a9ff2e99e9fa501ec965da03c18a5422b37a2f44 ] + +We have never been able to track down and address the underlying +cause of the performance issues with workqueue-based service +support. svo_enqueue_xprt is called multiple times per RPC, so +it adds instruction path length, but always ends up at the same +function: svc_xprt_do_enqueue(). We do not anticipate needing +this flexibility for dynamic nfsd thread management support. + +As a micro-optimization, remove .svo_enqueue_xprt because +Spectre/Meltdown makes virtual function calls more costly. + +This change essentially reverts commit b9e13cdfac70 ("nfsd/sunrpc: +turn enqueueing a svc_xprt into a svc_serv operation"). + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/svc.c | 1 - + fs/nfs/callback.c | 2 -- + fs/nfsd/nfssvc.c | 1 - + include/linux/sunrpc/svc.h | 3 --- + include/linux/sunrpc/svc_xprt.h | 1 - + net/sunrpc/svc_xprt.c | 10 +++++----- + 6 files changed, 5 insertions(+), 13 deletions(-) + +diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c +index 0475c5a5d061e..3a05af8736259 100644 +--- a/fs/lockd/svc.c ++++ b/fs/lockd/svc.c +@@ -353,7 +353,6 @@ static struct notifier_block lockd_inet6addr_notifier = { + static const struct svc_serv_ops lockd_sv_ops = { + .svo_shutdown = svc_rpcb_cleanup, + .svo_function = lockd, +- .svo_enqueue_xprt = svc_xprt_do_enqueue, + .svo_module = THIS_MODULE, + }; + +diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c +index 054cc1255fac6..7a810f8850632 100644 +--- a/fs/nfs/callback.c ++++ b/fs/nfs/callback.c +@@ -234,13 +234,11 @@ static int nfs_callback_up_net(int minorversion, struct svc_serv *serv, + + static const struct svc_serv_ops nfs40_cb_sv_ops = { + .svo_function = nfs4_callback_svc, +- .svo_enqueue_xprt = svc_xprt_do_enqueue, + .svo_module = THIS_MODULE, + }; + #if defined(CONFIG_NFS_V4_1) + static const struct svc_serv_ops nfs41_cb_sv_ops = { + .svo_function = nfs41_callback_svc, +- .svo_enqueue_xprt = svc_xprt_do_enqueue, + .svo_module = THIS_MODULE, + }; + +diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c +index 2efe9d33a2827..3b79b97f2715d 100644 +--- a/fs/nfsd/nfssvc.c ++++ b/fs/nfsd/nfssvc.c +@@ -615,7 +615,6 @@ static int nfsd_get_default_max_blksize(void) + static const struct svc_serv_ops nfsd_thread_sv_ops = { + .svo_shutdown = nfsd_last_thread, + .svo_function = nfsd, +- .svo_enqueue_xprt = svc_xprt_do_enqueue, + .svo_module = THIS_MODULE, + }; + +diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h +index f116141ea64d0..3c8ed018c6868 100644 +--- a/include/linux/sunrpc/svc.h ++++ b/include/linux/sunrpc/svc.h +@@ -61,9 +61,6 @@ struct svc_serv_ops { + /* function for service threads to run */ + int (*svo_function)(void *); + +- /* queue up a transport for servicing */ +- void (*svo_enqueue_xprt)(struct svc_xprt *); +- + /* optional module to count when adding threads. + * Thread function must call module_put_and_kthread_exit() to exit. + */ +diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h +index c5278871f9e40..1311425ddab7f 100644 +--- a/include/linux/sunrpc/svc_xprt.h ++++ b/include/linux/sunrpc/svc_xprt.h +@@ -131,7 +131,6 @@ int svc_create_xprt(struct svc_serv *, const char *, struct net *, + const int, const unsigned short, int, + const struct cred *); + void svc_xprt_received(struct svc_xprt *xprt); +-void svc_xprt_do_enqueue(struct svc_xprt *xprt); + void svc_xprt_enqueue(struct svc_xprt *xprt); + void svc_xprt_put(struct svc_xprt *xprt); + void svc_xprt_copy_addrs(struct svc_rqst *rqstp, struct svc_xprt *xprt); +diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c +index 570b092165d73..833952db23192 100644 +--- a/net/sunrpc/svc_xprt.c ++++ b/net/sunrpc/svc_xprt.c +@@ -31,6 +31,7 @@ static int svc_deferred_recv(struct svc_rqst *rqstp); + static struct cache_deferred_req *svc_defer(struct cache_req *req); + static void svc_age_temp_xprts(struct timer_list *t); + static void svc_delete_xprt(struct svc_xprt *xprt); ++static void svc_xprt_do_enqueue(struct svc_xprt *xprt); + + /* apparently the "standard" is that clients close + * idle connections after 5 minutes, servers after +@@ -253,12 +254,12 @@ void svc_xprt_received(struct svc_xprt *xprt) + trace_svc_xprt_received(xprt); + + /* As soon as we clear busy, the xprt could be closed and +- * 'put', so we need a reference to call svc_enqueue_xprt with: ++ * 'put', so we need a reference to call svc_xprt_do_enqueue with: + */ + svc_xprt_get(xprt); + smp_mb__before_atomic(); + clear_bit(XPT_BUSY, &xprt->xpt_flags); +- xprt->xpt_server->sv_ops->svo_enqueue_xprt(xprt); ++ svc_xprt_do_enqueue(xprt); + svc_xprt_put(xprt); + } + EXPORT_SYMBOL_GPL(svc_xprt_received); +@@ -410,7 +411,7 @@ static bool svc_xprt_ready(struct svc_xprt *xprt) + return false; + } + +-void svc_xprt_do_enqueue(struct svc_xprt *xprt) ++static void svc_xprt_do_enqueue(struct svc_xprt *xprt) + { + struct svc_pool *pool; + struct svc_rqst *rqstp = NULL; +@@ -454,7 +455,6 @@ void svc_xprt_do_enqueue(struct svc_xprt *xprt) + put_cpu(); + trace_svc_xprt_do_enqueue(xprt, rqstp); + } +-EXPORT_SYMBOL_GPL(svc_xprt_do_enqueue); + + /* + * Queue up a transport with data pending. If there are idle nfsd +@@ -465,7 +465,7 @@ void svc_xprt_enqueue(struct svc_xprt *xprt) + { + if (test_bit(XPT_BUSY, &xprt->xpt_flags)) + return; +- xprt->xpt_server->sv_ops->svo_enqueue_xprt(xprt); ++ svc_xprt_do_enqueue(xprt); + } + EXPORT_SYMBOL_GPL(svc_xprt_enqueue); + +-- +2.43.0 + diff --git a/queue-5.10/sunrpc-rename-svc_close_xprt.patch b/queue-5.10/sunrpc-rename-svc_close_xprt.patch new file mode 100644 index 00000000000..221ce2c32a7 --- /dev/null +++ b/queue-5.10/sunrpc-rename-svc_close_xprt.patch @@ -0,0 +1,104 @@ +From 1bca8784ba3d17a41f57d51197f3278cba537e71 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 31 Jan 2022 13:34:29 -0500 +Subject: SUNRPC: Rename svc_close_xprt() + +From: Chuck Lever + +[ Upstream commit 4355d767a21b9445958fc11bce9a9701f76529d3 ] + +Clean up: Use the "svc_xprt_" function naming convention as +is used for other external APIs. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfsctl.c | 2 +- + include/linux/sunrpc/svc_xprt.h | 2 +- + net/sunrpc/svc.c | 2 +- + net/sunrpc/svc_xprt.c | 9 +++++++-- + net/sunrpc/xprtrdma/svc_rdma_backchannel.c | 2 +- + 5 files changed, 11 insertions(+), 6 deletions(-) + +diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c +index 8fec779994f7b..16920e4512bde 100644 +--- a/fs/nfsd/nfsctl.c ++++ b/fs/nfsd/nfsctl.c +@@ -790,7 +790,7 @@ static ssize_t __write_ports_addxprt(char *buf, struct net *net, const struct cr + out_close: + xprt = svc_find_xprt(nn->nfsd_serv, transport, net, PF_INET, port); + if (xprt != NULL) { +- svc_close_xprt(xprt); ++ svc_xprt_close(xprt); + svc_xprt_put(xprt); + } + out_err: +diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h +index cba9559bba6ff..f614f8e248e11 100644 +--- a/include/linux/sunrpc/svc_xprt.h ++++ b/include/linux/sunrpc/svc_xprt.h +@@ -135,7 +135,7 @@ void svc_xprt_received(struct svc_xprt *xprt); + void svc_xprt_enqueue(struct svc_xprt *xprt); + void svc_xprt_put(struct svc_xprt *xprt); + void svc_xprt_copy_addrs(struct svc_rqst *rqstp, struct svc_xprt *xprt); +-void svc_close_xprt(struct svc_xprt *xprt); ++void svc_xprt_close(struct svc_xprt *xprt); + int svc_port_is_privileged(struct sockaddr *sin); + int svc_print_xprts(char *buf, int maxlen); + struct svc_xprt *svc_find_xprt(struct svc_serv *serv, const char *xcl_name, +diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c +index 709118bac4c32..9126e1b7d0769 100644 +--- a/net/sunrpc/svc.c ++++ b/net/sunrpc/svc.c +@@ -1403,7 +1403,7 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv) + svc_authorise(rqstp); + close_xprt: + if (rqstp->rq_xprt && test_bit(XPT_TEMP, &rqstp->rq_xprt->xpt_flags)) +- svc_close_xprt(rqstp->rq_xprt); ++ svc_xprt_close(rqstp->rq_xprt); + dprintk("svc: svc_process close\n"); + return 0; + +diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c +index 20baa0de70174..ee4a6d57056f5 100644 +--- a/net/sunrpc/svc_xprt.c ++++ b/net/sunrpc/svc_xprt.c +@@ -1056,7 +1056,12 @@ static void svc_delete_xprt(struct svc_xprt *xprt) + svc_xprt_put(xprt); + } + +-void svc_close_xprt(struct svc_xprt *xprt) ++/** ++ * svc_xprt_close - Close a client connection ++ * @xprt: transport to disconnect ++ * ++ */ ++void svc_xprt_close(struct svc_xprt *xprt) + { + trace_svc_xprt_close(xprt); + set_bit(XPT_CLOSE, &xprt->xpt_flags); +@@ -1071,7 +1076,7 @@ void svc_close_xprt(struct svc_xprt *xprt) + */ + svc_delete_xprt(xprt); + } +-EXPORT_SYMBOL_GPL(svc_close_xprt); ++EXPORT_SYMBOL_GPL(svc_xprt_close); + + static int svc_close_list(struct svc_serv *serv, struct list_head *xprt_list, struct net *net) + { +diff --git a/net/sunrpc/xprtrdma/svc_rdma_backchannel.c b/net/sunrpc/xprtrdma/svc_rdma_backchannel.c +index c5154bc38e129..feac8c26fb87d 100644 +--- a/net/sunrpc/xprtrdma/svc_rdma_backchannel.c ++++ b/net/sunrpc/xprtrdma/svc_rdma_backchannel.c +@@ -186,7 +186,7 @@ static int xprt_rdma_bc_send_request(struct rpc_rqst *rqst) + + ret = rpcrdma_bc_send_request(rdma, rqst); + if (ret == -ENOTCONN) +- svc_close_xprt(sxprt); ++ svc_xprt_close(sxprt); + return ret; + } + +-- +2.43.0 + diff --git a/queue-5.10/sunrpc-rename-svc_create_xprt.patch b/queue-5.10/sunrpc-rename-svc_create_xprt.patch new file mode 100644 index 00000000000..6a7ca8b16b4 --- /dev/null +++ b/queue-5.10/sunrpc-rename-svc_create_xprt.patch @@ -0,0 +1,185 @@ +From 5a7850f45ce86e35d8983ff51b503818d5ae67f4 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 26 Jan 2022 11:42:08 -0500 +Subject: SUNRPC: Rename svc_create_xprt() + +From: Chuck Lever + +[ Upstream commit 352ad31448fecc78a2e9b78da64eea5d63b8d0ce ] + +Clean up: Use the "svc_xprt_" function naming convention as +is used for other external APIs. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/svc.c | 4 ++-- + fs/nfs/callback.c | 12 ++++++------ + fs/nfsd/nfsctl.c | 8 ++++---- + fs/nfsd/nfssvc.c | 8 ++++---- + include/linux/sunrpc/svc_xprt.h | 7 ++++--- + net/sunrpc/svc_xprt.c | 24 +++++++++++++++++++----- + 6 files changed, 39 insertions(+), 24 deletions(-) + +diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c +index f5b688a844aa5..bba6f2b45b64a 100644 +--- a/fs/lockd/svc.c ++++ b/fs/lockd/svc.c +@@ -197,8 +197,8 @@ static int create_lockd_listener(struct svc_serv *serv, const char *name, + + xprt = svc_find_xprt(serv, name, net, family, 0); + if (xprt == NULL) +- return svc_create_xprt(serv, name, net, family, port, +- SVC_SOCK_DEFAULTS, cred); ++ return svc_xprt_create(serv, name, net, family, port, ++ SVC_SOCK_DEFAULTS, cred); + svc_xprt_put(xprt); + return 0; + } +diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c +index 7a810f8850632..c1a8767100ae9 100644 +--- a/fs/nfs/callback.c ++++ b/fs/nfs/callback.c +@@ -45,18 +45,18 @@ static int nfs4_callback_up_net(struct svc_serv *serv, struct net *net) + int ret; + struct nfs_net *nn = net_generic(net, nfs_net_id); + +- ret = svc_create_xprt(serv, "tcp", net, PF_INET, +- nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS, +- cred); ++ ret = svc_xprt_create(serv, "tcp", net, PF_INET, ++ nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS, ++ cred); + if (ret <= 0) + goto out_err; + nn->nfs_callback_tcpport = ret; + dprintk("NFS: Callback listener port = %u (af %u, net %x)\n", + nn->nfs_callback_tcpport, PF_INET, net->ns.inum); + +- ret = svc_create_xprt(serv, "tcp", net, PF_INET6, +- nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS, +- cred); ++ ret = svc_xprt_create(serv, "tcp", net, PF_INET6, ++ nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS, ++ cred); + if (ret > 0) { + nn->nfs_callback_tcpport6 = ret; + dprintk("NFS: Callback listener port = %u (af %u, net %x)\n", +diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c +index 68b020f2002b7..8fec779994f7b 100644 +--- a/fs/nfsd/nfsctl.c ++++ b/fs/nfsd/nfsctl.c +@@ -772,13 +772,13 @@ static ssize_t __write_ports_addxprt(char *buf, struct net *net, const struct cr + if (err != 0) + return err; + +- err = svc_create_xprt(nn->nfsd_serv, transport, net, +- PF_INET, port, SVC_SOCK_ANONYMOUS, cred); ++ err = svc_xprt_create(nn->nfsd_serv, transport, net, ++ PF_INET, port, SVC_SOCK_ANONYMOUS, cred); + if (err < 0) + goto out_err; + +- err = svc_create_xprt(nn->nfsd_serv, transport, net, +- PF_INET6, port, SVC_SOCK_ANONYMOUS, cred); ++ err = svc_xprt_create(nn->nfsd_serv, transport, net, ++ PF_INET6, port, SVC_SOCK_ANONYMOUS, cred); + if (err < 0 && err != -EAFNOSUPPORT) + goto out_close; + +diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c +index a1765e751b739..5790b1eaff72b 100644 +--- a/fs/nfsd/nfssvc.c ++++ b/fs/nfsd/nfssvc.c +@@ -293,13 +293,13 @@ static int nfsd_init_socks(struct net *net, const struct cred *cred) + if (!list_empty(&nn->nfsd_serv->sv_permsocks)) + return 0; + +- error = svc_create_xprt(nn->nfsd_serv, "udp", net, PF_INET, NFS_PORT, +- SVC_SOCK_DEFAULTS, cred); ++ error = svc_xprt_create(nn->nfsd_serv, "udp", net, PF_INET, NFS_PORT, ++ SVC_SOCK_DEFAULTS, cred); + if (error < 0) + return error; + +- error = svc_create_xprt(nn->nfsd_serv, "tcp", net, PF_INET, NFS_PORT, +- SVC_SOCK_DEFAULTS, cred); ++ error = svc_xprt_create(nn->nfsd_serv, "tcp", net, PF_INET, NFS_PORT, ++ SVC_SOCK_DEFAULTS, cred); + if (error < 0) + return error; + +diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h +index 1311425ddab7f..cba9559bba6ff 100644 +--- a/include/linux/sunrpc/svc_xprt.h ++++ b/include/linux/sunrpc/svc_xprt.h +@@ -127,9 +127,10 @@ int svc_reg_xprt_class(struct svc_xprt_class *); + void svc_unreg_xprt_class(struct svc_xprt_class *); + void svc_xprt_init(struct net *, struct svc_xprt_class *, struct svc_xprt *, + struct svc_serv *); +-int svc_create_xprt(struct svc_serv *, const char *, struct net *, +- const int, const unsigned short, int, +- const struct cred *); ++int svc_xprt_create(struct svc_serv *serv, const char *xprt_name, ++ struct net *net, const int family, ++ const unsigned short port, int flags, ++ const struct cred *cred); + void svc_xprt_received(struct svc_xprt *xprt); + void svc_xprt_enqueue(struct svc_xprt *xprt); + void svc_xprt_put(struct svc_xprt *xprt); +diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c +index b5e80817b02f5..20baa0de70174 100644 +--- a/net/sunrpc/svc_xprt.c ++++ b/net/sunrpc/svc_xprt.c +@@ -272,7 +272,7 @@ void svc_add_new_perm_xprt(struct svc_serv *serv, struct svc_xprt *new) + svc_xprt_received(new); + } + +-static int _svc_create_xprt(struct svc_serv *serv, const char *xprt_name, ++static int _svc_xprt_create(struct svc_serv *serv, const char *xprt_name, + struct net *net, const int family, + const unsigned short port, int flags, + const struct cred *cred) +@@ -308,21 +308,35 @@ static int _svc_create_xprt(struct svc_serv *serv, const char *xprt_name, + return -EPROTONOSUPPORT; + } + +-int svc_create_xprt(struct svc_serv *serv, const char *xprt_name, ++/** ++ * svc_xprt_create - Add a new listener to @serv ++ * @serv: target RPC service ++ * @xprt_name: transport class name ++ * @net: network namespace ++ * @family: network address family ++ * @port: listener port ++ * @flags: SVC_SOCK flags ++ * @cred: credential to bind to this transport ++ * ++ * Return values: ++ * %0: New listener added successfully ++ * %-EPROTONOSUPPORT: Requested transport type not supported ++ */ ++int svc_xprt_create(struct svc_serv *serv, const char *xprt_name, + struct net *net, const int family, + const unsigned short port, int flags, + const struct cred *cred) + { + int err; + +- err = _svc_create_xprt(serv, xprt_name, net, family, port, flags, cred); ++ err = _svc_xprt_create(serv, xprt_name, net, family, port, flags, cred); + if (err == -EPROTONOSUPPORT) { + request_module("svc%s", xprt_name); +- err = _svc_create_xprt(serv, xprt_name, net, family, port, flags, cred); ++ err = _svc_xprt_create(serv, xprt_name, net, family, port, flags, cred); + } + return err; + } +-EXPORT_SYMBOL_GPL(svc_create_xprt); ++EXPORT_SYMBOL_GPL(svc_xprt_create); + + /* + * Copy the local and remote xprt addresses to the rqstp structure +-- +2.43.0 + diff --git a/queue-5.10/sunrpc-rename-svc_encode_read_payload.patch b/queue-5.10/sunrpc-rename-svc_encode_read_payload.patch new file mode 100644 index 00000000000..f5c13fa28d8 --- /dev/null +++ b/queue-5.10/sunrpc-rename-svc_encode_read_payload.patch @@ -0,0 +1,193 @@ +From 82e3c62b117c6fc65445d6bb3ac0443c971d2688 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 10 Jun 2020 10:36:42 -0400 +Subject: SUNRPC: Rename svc_encode_read_payload() + +From: Chuck Lever + +[ Upstream commit 03493bca084fdca48abc59b00e06ce733aa9eb7d ] + +Clean up: "result payload" is a less confusing name for these +payloads. "READ payload" reflects only the NFS usage. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4xdr.c | 2 +- + include/linux/sunrpc/svc.h | 6 +++--- + include/linux/sunrpc/svc_rdma.h | 4 ++-- + include/linux/sunrpc/svc_xprt.h | 4 ++-- + net/sunrpc/svc.c | 11 ++++++----- + net/sunrpc/svcsock.c | 8 ++++---- + net/sunrpc/xprtrdma/svc_rdma_sendto.c | 8 ++++---- + net/sunrpc/xprtrdma/svc_rdma_transport.c | 2 +- + 8 files changed, 23 insertions(+), 22 deletions(-) + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index dbfa24cf33906..9971d3c295731 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -3843,7 +3843,7 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp, + read->rd_length = maxcount; + if (nfserr) + return nfserr; +- if (svc_encode_read_payload(resp->rqstp, starting_len + 8, maxcount)) ++ if (svc_encode_result_payload(resp->rqstp, starting_len + 8, maxcount)) + return nfserr_io; + xdr_truncate_encode(xdr, starting_len + 8 + xdr_align_size(maxcount)); + +diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h +index 386628b36bc75..c220b734fa69e 100644 +--- a/include/linux/sunrpc/svc.h ++++ b/include/linux/sunrpc/svc.h +@@ -519,9 +519,9 @@ void svc_wake_up(struct svc_serv *); + void svc_reserve(struct svc_rqst *rqstp, int space); + struct svc_pool * svc_pool_for_cpu(struct svc_serv *serv, int cpu); + char * svc_print_addr(struct svc_rqst *, char *, size_t); +-int svc_encode_read_payload(struct svc_rqst *rqstp, +- unsigned int offset, +- unsigned int length); ++int svc_encode_result_payload(struct svc_rqst *rqstp, ++ unsigned int offset, ++ unsigned int length); + unsigned int svc_fill_write_vector(struct svc_rqst *rqstp, + struct page **pages, + struct kvec *first, size_t total); +diff --git a/include/linux/sunrpc/svc_rdma.h b/include/linux/sunrpc/svc_rdma.h +index 9dc3a3b88391b..2b870a3f391b1 100644 +--- a/include/linux/sunrpc/svc_rdma.h ++++ b/include/linux/sunrpc/svc_rdma.h +@@ -207,8 +207,8 @@ extern void svc_rdma_send_error_msg(struct svcxprt_rdma *rdma, + struct svc_rdma_recv_ctxt *rctxt, + int status); + extern int svc_rdma_sendto(struct svc_rqst *); +-extern int svc_rdma_read_payload(struct svc_rqst *rqstp, unsigned int offset, +- unsigned int length); ++extern int svc_rdma_result_payload(struct svc_rqst *rqstp, unsigned int offset, ++ unsigned int length); + + /* svc_rdma_transport.c */ + extern struct svc_xprt_class svc_rdma_class; +diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h +index aca35ab5cff24..92455e0d52445 100644 +--- a/include/linux/sunrpc/svc_xprt.h ++++ b/include/linux/sunrpc/svc_xprt.h +@@ -21,8 +21,8 @@ struct svc_xprt_ops { + int (*xpo_has_wspace)(struct svc_xprt *); + int (*xpo_recvfrom)(struct svc_rqst *); + int (*xpo_sendto)(struct svc_rqst *); +- int (*xpo_read_payload)(struct svc_rqst *, unsigned int, +- unsigned int); ++ int (*xpo_result_payload)(struct svc_rqst *, unsigned int, ++ unsigned int); + void (*xpo_release_rqst)(struct svc_rqst *); + void (*xpo_detach)(struct svc_xprt *); + void (*xpo_free)(struct svc_xprt *); +diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c +index cfe8b911ca013..e4e4e203ecdad 100644 +--- a/net/sunrpc/svc.c ++++ b/net/sunrpc/svc.c +@@ -1626,7 +1626,7 @@ u32 svc_max_payload(const struct svc_rqst *rqstp) + EXPORT_SYMBOL_GPL(svc_max_payload); + + /** +- * svc_encode_read_payload - mark a range of bytes as a READ payload ++ * svc_encode_result_payload - mark a range of bytes as a result payload + * @rqstp: svc_rqst to operate on + * @offset: payload's byte offset in rqstp->rq_res + * @length: size of payload, in bytes +@@ -1634,12 +1634,13 @@ EXPORT_SYMBOL_GPL(svc_max_payload); + * Returns zero on success, or a negative errno if a permanent + * error occurred. + */ +-int svc_encode_read_payload(struct svc_rqst *rqstp, unsigned int offset, +- unsigned int length) ++int svc_encode_result_payload(struct svc_rqst *rqstp, unsigned int offset, ++ unsigned int length) + { +- return rqstp->rq_xprt->xpt_ops->xpo_read_payload(rqstp, offset, length); ++ return rqstp->rq_xprt->xpt_ops->xpo_result_payload(rqstp, offset, ++ length); + } +-EXPORT_SYMBOL_GPL(svc_encode_read_payload); ++EXPORT_SYMBOL_GPL(svc_encode_result_payload); + + /** + * svc_fill_write_vector - Construct data argument for VFS write call +diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c +index 3d5ee042c5015..90f6231d6ed67 100644 +--- a/net/sunrpc/svcsock.c ++++ b/net/sunrpc/svcsock.c +@@ -181,8 +181,8 @@ static void svc_set_cmsg_data(struct svc_rqst *rqstp, struct cmsghdr *cmh) + } + } + +-static int svc_sock_read_payload(struct svc_rqst *rqstp, unsigned int offset, +- unsigned int length) ++static int svc_sock_result_payload(struct svc_rqst *rqstp, unsigned int offset, ++ unsigned int length) + { + return 0; + } +@@ -635,7 +635,7 @@ static const struct svc_xprt_ops svc_udp_ops = { + .xpo_create = svc_udp_create, + .xpo_recvfrom = svc_udp_recvfrom, + .xpo_sendto = svc_udp_sendto, +- .xpo_read_payload = svc_sock_read_payload, ++ .xpo_result_payload = svc_sock_result_payload, + .xpo_release_rqst = svc_udp_release_rqst, + .xpo_detach = svc_sock_detach, + .xpo_free = svc_sock_free, +@@ -1209,7 +1209,7 @@ static const struct svc_xprt_ops svc_tcp_ops = { + .xpo_create = svc_tcp_create, + .xpo_recvfrom = svc_tcp_recvfrom, + .xpo_sendto = svc_tcp_sendto, +- .xpo_read_payload = svc_sock_read_payload, ++ .xpo_result_payload = svc_sock_result_payload, + .xpo_release_rqst = svc_tcp_release_rqst, + .xpo_detach = svc_tcp_sock_detach, + .xpo_free = svc_sock_free, +diff --git a/net/sunrpc/xprtrdma/svc_rdma_sendto.c b/net/sunrpc/xprtrdma/svc_rdma_sendto.c +index c3d588b149aaa..c8411b4f3492a 100644 +--- a/net/sunrpc/xprtrdma/svc_rdma_sendto.c ++++ b/net/sunrpc/xprtrdma/svc_rdma_sendto.c +@@ -979,19 +979,19 @@ int svc_rdma_sendto(struct svc_rqst *rqstp) + } + + /** +- * svc_rdma_read_payload - special processing for a READ payload ++ * svc_rdma_result_payload - special processing for a result payload + * @rqstp: svc_rqst to operate on + * @offset: payload's byte offset in @xdr + * @length: size of payload, in bytes + * + * Returns zero on success. + * +- * For the moment, just record the xdr_buf location of the READ ++ * For the moment, just record the xdr_buf location of the result + * payload. svc_rdma_sendto will use that location later when + * we actually send the payload. + */ +-int svc_rdma_read_payload(struct svc_rqst *rqstp, unsigned int offset, +- unsigned int length) ++int svc_rdma_result_payload(struct svc_rqst *rqstp, unsigned int offset, ++ unsigned int length) + { + struct svc_rdma_recv_ctxt *rctxt = rqstp->rq_xprt_ctxt; + +diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c +index 5f7e3d12523fe..c895f80df659c 100644 +--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c ++++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c +@@ -80,7 +80,7 @@ static const struct svc_xprt_ops svc_rdma_ops = { + .xpo_create = svc_rdma_create, + .xpo_recvfrom = svc_rdma_recvfrom, + .xpo_sendto = svc_rdma_sendto, +- .xpo_read_payload = svc_rdma_read_payload, ++ .xpo_result_payload = svc_rdma_result_payload, + .xpo_release_rqst = svc_rdma_release_rqst, + .xpo_detach = svc_rdma_detach, + .xpo_free = svc_rdma_free, +-- +2.43.0 + diff --git a/queue-5.10/sunrpc-replace-the-__be32-p-parameter-to-.pc_decode.patch b/queue-5.10/sunrpc-replace-the-__be32-p-parameter-to-.pc_decode.patch new file mode 100644 index 00000000000..1a99087777a --- /dev/null +++ b/queue-5.10/sunrpc-replace-the-__be32-p-parameter-to-.pc_decode.patch @@ -0,0 +1,849 @@ +From 325fec72b7ce3ef266c4a517fbacffa9dc0b0325 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 Oct 2021 11:57:22 -0400 +Subject: SUNRPC: Replace the "__be32 *p" parameter to .pc_decode + +From: Chuck Lever + +[ Upstream commit 16c663642c7ec03cd4cee5fec520bb69e97babe4 ] + +The passed-in value of the "__be32 *p" parameter is now unused in +every server-side XDR decoder, and can be removed. + +Note also that there is a line in each decoder that sets up a local +pointer to a struct xdr_stream. Passing that pointer from the +dispatcher instead saves one line per decoder function. + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/svc.c | 3 +-- + fs/lockd/xdr.c | 27 +++++++++-------------- + fs/lockd/xdr4.c | 27 +++++++++-------------- + fs/nfsd/nfs2acl.c | 12 +++++----- + fs/nfsd/nfs3acl.c | 8 +++---- + fs/nfsd/nfs3xdr.c | 45 +++++++++++++------------------------- + fs/nfsd/nfs4xdr.c | 4 ++-- + fs/nfsd/nfsd.h | 3 ++- + fs/nfsd/nfssvc.c | 7 +++--- + fs/nfsd/nfsxdr.c | 30 +++++++++---------------- + fs/nfsd/xdr.h | 21 +++++++++--------- + fs/nfsd/xdr3.h | 31 +++++++++++++------------- + fs/nfsd/xdr4.h | 2 +- + include/linux/lockd/xdr.h | 19 ++++++++-------- + include/linux/lockd/xdr4.h | 19 ++++++++-------- + include/linux/sunrpc/svc.h | 3 ++- + 16 files changed, 112 insertions(+), 149 deletions(-) + +diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c +index b632be3ad57b2..9a82471bda071 100644 +--- a/fs/lockd/svc.c ++++ b/fs/lockd/svc.c +@@ -780,11 +780,10 @@ module_exit(exit_nlm); + static int nlmsvc_dispatch(struct svc_rqst *rqstp, __be32 *statp) + { + const struct svc_procedure *procp = rqstp->rq_procinfo; +- struct kvec *argv = rqstp->rq_arg.head; + struct kvec *resv = rqstp->rq_res.head; + + svcxdr_init_decode(rqstp); +- if (!procp->pc_decode(rqstp, argv->iov_base)) ++ if (!procp->pc_decode(rqstp, &rqstp->rq_arg_stream)) + goto out_decode_err; + + *statp = procp->pc_func(rqstp); +diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c +index 9235e60b17694..895f152221048 100644 +--- a/fs/lockd/xdr.c ++++ b/fs/lockd/xdr.c +@@ -146,15 +146,14 @@ svcxdr_encode_testrply(struct xdr_stream *xdr, const struct nlm_res *resp) + */ + + int +-nlmsvc_decode_void(struct svc_rqst *rqstp, __be32 *p) ++nlmsvc_decode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + return 1; + } + + int +-nlmsvc_decode_testargs(struct svc_rqst *rqstp, __be32 *p) ++nlmsvc_decode_testargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nlm_args *argp = rqstp->rq_argp; + u32 exclusive; + +@@ -171,9 +170,8 @@ nlmsvc_decode_testargs(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nlmsvc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p) ++nlmsvc_decode_lockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nlm_args *argp = rqstp->rq_argp; + u32 exclusive; + +@@ -197,9 +195,8 @@ nlmsvc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nlmsvc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p) ++nlmsvc_decode_cancargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nlm_args *argp = rqstp->rq_argp; + u32 exclusive; + +@@ -218,9 +215,8 @@ nlmsvc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p) ++nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nlm_args *argp = rqstp->rq_argp; + + if (!svcxdr_decode_cookie(xdr, &argp->cookie)) +@@ -233,9 +229,8 @@ nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nlmsvc_decode_res(struct svc_rqst *rqstp, __be32 *p) ++nlmsvc_decode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nlm_res *resp = rqstp->rq_argp; + + if (!svcxdr_decode_cookie(xdr, &resp->cookie)) +@@ -247,10 +242,10 @@ nlmsvc_decode_res(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nlmsvc_decode_reboot(struct svc_rqst *rqstp, __be32 *p) ++nlmsvc_decode_reboot(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nlm_reboot *argp = rqstp->rq_argp; ++ __be32 *p; + u32 len; + + if (xdr_stream_decode_u32(xdr, &len) < 0) +@@ -273,9 +268,8 @@ nlmsvc_decode_reboot(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nlmsvc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p) ++nlmsvc_decode_shareargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nlm_args *argp = rqstp->rq_argp; + struct nlm_lock *lock = &argp->lock; + +@@ -301,9 +295,8 @@ nlmsvc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nlmsvc_decode_notify(struct svc_rqst *rqstp, __be32 *p) ++nlmsvc_decode_notify(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nlm_args *argp = rqstp->rq_argp; + struct nlm_lock *lock = &argp->lock; + +diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c +index 98e957e4566c2..573c7d580a5e6 100644 +--- a/fs/lockd/xdr4.c ++++ b/fs/lockd/xdr4.c +@@ -145,15 +145,14 @@ svcxdr_encode_testrply(struct xdr_stream *xdr, const struct nlm_res *resp) + */ + + int +-nlm4svc_decode_void(struct svc_rqst *rqstp, __be32 *p) ++nlm4svc_decode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + return 1; + } + + int +-nlm4svc_decode_testargs(struct svc_rqst *rqstp, __be32 *p) ++nlm4svc_decode_testargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nlm_args *argp = rqstp->rq_argp; + u32 exclusive; + +@@ -170,9 +169,8 @@ nlm4svc_decode_testargs(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nlm4svc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p) ++nlm4svc_decode_lockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nlm_args *argp = rqstp->rq_argp; + u32 exclusive; + +@@ -196,9 +194,8 @@ nlm4svc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nlm4svc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p) ++nlm4svc_decode_cancargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nlm_args *argp = rqstp->rq_argp; + u32 exclusive; + +@@ -216,9 +213,8 @@ nlm4svc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p) ++nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nlm_args *argp = rqstp->rq_argp; + + if (!svcxdr_decode_cookie(xdr, &argp->cookie)) +@@ -231,9 +227,8 @@ nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nlm4svc_decode_res(struct svc_rqst *rqstp, __be32 *p) ++nlm4svc_decode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nlm_res *resp = rqstp->rq_argp; + + if (!svcxdr_decode_cookie(xdr, &resp->cookie)) +@@ -245,10 +240,10 @@ nlm4svc_decode_res(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nlm4svc_decode_reboot(struct svc_rqst *rqstp, __be32 *p) ++nlm4svc_decode_reboot(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nlm_reboot *argp = rqstp->rq_argp; ++ __be32 *p; + u32 len; + + if (xdr_stream_decode_u32(xdr, &len) < 0) +@@ -271,9 +266,8 @@ nlm4svc_decode_reboot(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nlm4svc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p) ++nlm4svc_decode_shareargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nlm_args *argp = rqstp->rq_argp; + struct nlm_lock *lock = &argp->lock; + +@@ -299,9 +293,8 @@ nlm4svc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nlm4svc_decode_notify(struct svc_rqst *rqstp, __be32 *p) ++nlm4svc_decode_notify(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nlm_args *argp = rqstp->rq_argp; + struct nlm_lock *lock = &argp->lock; + +diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c +index 8703326fc1654..53f793c3606d6 100644 +--- a/fs/nfsd/nfs2acl.c ++++ b/fs/nfsd/nfs2acl.c +@@ -186,9 +186,9 @@ static __be32 nfsacld_proc_access(struct svc_rqst *rqstp) + * XDR decode functions + */ + +-static int nfsaclsvc_decode_getaclargs(struct svc_rqst *rqstp, __be32 *p) ++static int ++nfsaclsvc_decode_getaclargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd3_getaclargs *argp = rqstp->rq_argp; + + if (!svcxdr_decode_fhandle(xdr, &argp->fh)) +@@ -199,9 +199,9 @@ static int nfsaclsvc_decode_getaclargs(struct svc_rqst *rqstp, __be32 *p) + return 1; + } + +-static int nfsaclsvc_decode_setaclargs(struct svc_rqst *rqstp, __be32 *p) ++static int ++nfsaclsvc_decode_setaclargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd3_setaclargs *argp = rqstp->rq_argp; + + if (!svcxdr_decode_fhandle(xdr, &argp->fh)) +@@ -220,9 +220,9 @@ static int nfsaclsvc_decode_setaclargs(struct svc_rqst *rqstp, __be32 *p) + return 1; + } + +-static int nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, __be32 *p) ++static int ++nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd3_accessargs *args = rqstp->rq_argp; + + if (!svcxdr_decode_fhandle(xdr, &args->fh)) +diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c +index 5e13e5f7f92b8..37c8fb184ca4d 100644 +--- a/fs/nfsd/nfs3acl.c ++++ b/fs/nfsd/nfs3acl.c +@@ -125,9 +125,9 @@ static __be32 nfsd3_proc_setacl(struct svc_rqst *rqstp) + * XDR decode functions + */ + +-static int nfs3svc_decode_getaclargs(struct svc_rqst *rqstp, __be32 *p) ++static int ++nfs3svc_decode_getaclargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd3_getaclargs *args = rqstp->rq_argp; + + if (!svcxdr_decode_nfs_fh3(xdr, &args->fh)) +@@ -138,9 +138,9 @@ static int nfs3svc_decode_getaclargs(struct svc_rqst *rqstp, __be32 *p) + return 1; + } + +-static int nfs3svc_decode_setaclargs(struct svc_rqst *rqstp, __be32 *p) ++static int ++nfs3svc_decode_setaclargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd3_setaclargs *argp = rqstp->rq_argp; + + if (!svcxdr_decode_nfs_fh3(xdr, &argp->fh)) +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index 267e56f218af7..5f744f03cda7c 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -557,18 +557,16 @@ void fill_post_wcc(struct svc_fh *fhp) + */ + + int +-nfs3svc_decode_fhandleargs(struct svc_rqst *rqstp, __be32 *p) ++nfs3svc_decode_fhandleargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd_fhandle *args = rqstp->rq_argp; + + return svcxdr_decode_nfs_fh3(xdr, &args->fh); + } + + int +-nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p) ++nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd3_sattrargs *args = rqstp->rq_argp; + + return svcxdr_decode_nfs_fh3(xdr, &args->fh) && +@@ -577,18 +575,16 @@ nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nfs3svc_decode_diropargs(struct svc_rqst *rqstp, __be32 *p) ++nfs3svc_decode_diropargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd3_diropargs *args = rqstp->rq_argp; + + return svcxdr_decode_diropargs3(xdr, &args->fh, &args->name, &args->len); + } + + int +-nfs3svc_decode_accessargs(struct svc_rqst *rqstp, __be32 *p) ++nfs3svc_decode_accessargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd3_accessargs *args = rqstp->rq_argp; + + if (!svcxdr_decode_nfs_fh3(xdr, &args->fh)) +@@ -600,9 +596,8 @@ nfs3svc_decode_accessargs(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nfs3svc_decode_readargs(struct svc_rqst *rqstp, __be32 *p) ++nfs3svc_decode_readargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd3_readargs *args = rqstp->rq_argp; + + if (!svcxdr_decode_nfs_fh3(xdr, &args->fh)) +@@ -616,9 +611,8 @@ nfs3svc_decode_readargs(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p) ++nfs3svc_decode_writeargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd3_writeargs *args = rqstp->rq_argp; + u32 max_blocksize = svc_max_payload(rqstp); + +@@ -649,9 +643,8 @@ nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nfs3svc_decode_createargs(struct svc_rqst *rqstp, __be32 *p) ++nfs3svc_decode_createargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd3_createargs *args = rqstp->rq_argp; + + if (!svcxdr_decode_diropargs3(xdr, &args->fh, &args->name, &args->len)) +@@ -674,9 +667,8 @@ nfs3svc_decode_createargs(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, __be32 *p) ++nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd3_createargs *args = rqstp->rq_argp; + + return svcxdr_decode_diropargs3(xdr, &args->fh, +@@ -685,9 +677,8 @@ nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p) ++nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd3_symlinkargs *args = rqstp->rq_argp; + struct kvec *head = rqstp->rq_arg.head; + struct kvec *tail = rqstp->rq_arg.tail; +@@ -713,9 +704,8 @@ nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, __be32 *p) ++nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd3_mknodargs *args = rqstp->rq_argp; + + if (!svcxdr_decode_diropargs3(xdr, &args->fh, &args->name, &args->len)) +@@ -742,9 +732,8 @@ nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nfs3svc_decode_renameargs(struct svc_rqst *rqstp, __be32 *p) ++nfs3svc_decode_renameargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd3_renameargs *args = rqstp->rq_argp; + + return svcxdr_decode_diropargs3(xdr, &args->ffh, +@@ -754,9 +743,8 @@ nfs3svc_decode_renameargs(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nfs3svc_decode_linkargs(struct svc_rqst *rqstp, __be32 *p) ++nfs3svc_decode_linkargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd3_linkargs *args = rqstp->rq_argp; + + return svcxdr_decode_nfs_fh3(xdr, &args->ffh) && +@@ -765,9 +753,8 @@ nfs3svc_decode_linkargs(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p) ++nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd3_readdirargs *args = rqstp->rq_argp; + + if (!svcxdr_decode_nfs_fh3(xdr, &args->fh)) +@@ -784,9 +771,8 @@ nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, __be32 *p) ++nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd3_readdirargs *args = rqstp->rq_argp; + u32 dircount; + +@@ -807,9 +793,8 @@ nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nfs3svc_decode_commitargs(struct svc_rqst *rqstp, __be32 *p) ++nfs3svc_decode_commitargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd3_commitargs *args = rqstp->rq_argp; + + if (!svcxdr_decode_nfs_fh3(xdr, &args->fh)) +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 899d961372c06..5ee5081c56637 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -5423,14 +5423,14 @@ void nfsd4_release_compoundargs(struct svc_rqst *rqstp) + } + + int +-nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, __be32 *p) ++nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd4_compoundargs *args = rqstp->rq_argp; + + /* svcxdr_tmp_alloc */ + args->to_free = NULL; + +- args->xdr = &rqstp->rq_arg_stream; ++ args->xdr = xdr; + args->ops = args->iops; + args->rqstp = rqstp; + +diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h +index 9664303afdaf3..6e8ad5f9757c8 100644 +--- a/fs/nfsd/nfsd.h ++++ b/fs/nfsd/nfsd.h +@@ -78,7 +78,8 @@ extern const struct seq_operations nfs_exports_op; + */ + struct nfsd_voidargs { }; + struct nfsd_voidres { }; +-int nfssvc_decode_voidarg(struct svc_rqst *rqstp, __be32 *p); ++int nfssvc_decode_voidarg(struct svc_rqst *rqstp, ++ struct xdr_stream *xdr); + int nfssvc_encode_voidres(struct svc_rqst *rqstp, __be32 *p); + + /* +diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c +index 373695cc62a7a..be1d656548cfe 100644 +--- a/fs/nfsd/nfssvc.c ++++ b/fs/nfsd/nfssvc.c +@@ -1004,7 +1004,6 @@ nfsd(void *vrqstp) + int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) + { + const struct svc_procedure *proc = rqstp->rq_procinfo; +- struct kvec *argv = &rqstp->rq_arg.head[0]; + struct kvec *resv = &rqstp->rq_res.head[0]; + __be32 *p; + +@@ -1015,7 +1014,7 @@ int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) + rqstp->rq_cachetype = proc->pc_cachetype; + + svcxdr_init_decode(rqstp); +- if (!proc->pc_decode(rqstp, argv->iov_base)) ++ if (!proc->pc_decode(rqstp, &rqstp->rq_arg_stream)) + goto out_decode_err; + + switch (nfsd_cache_lookup(rqstp)) { +@@ -1065,13 +1064,13 @@ int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) + /** + * nfssvc_decode_voidarg - Decode void arguments + * @rqstp: Server RPC transaction context +- * @p: buffer containing arguments to decode ++ * @xdr: XDR stream positioned at arguments to decode + * + * Return values: + * %0: Arguments were not valid + * %1: Decoding was successful + */ +-int nfssvc_decode_voidarg(struct svc_rqst *rqstp, __be32 *p) ++int nfssvc_decode_voidarg(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + return 1; + } +diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c +index ddcc18adfeb1a..08e899180ee43 100644 +--- a/fs/nfsd/nfsxdr.c ++++ b/fs/nfsd/nfsxdr.c +@@ -273,18 +273,16 @@ svcxdr_encode_fattr(struct svc_rqst *rqstp, struct xdr_stream *xdr, + */ + + int +-nfssvc_decode_fhandleargs(struct svc_rqst *rqstp, __be32 *p) ++nfssvc_decode_fhandleargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd_fhandle *args = rqstp->rq_argp; + + return svcxdr_decode_fhandle(xdr, &args->fh); + } + + int +-nfssvc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p) ++nfssvc_decode_sattrargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd_sattrargs *args = rqstp->rq_argp; + + return svcxdr_decode_fhandle(xdr, &args->fh) && +@@ -292,18 +290,16 @@ nfssvc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nfssvc_decode_diropargs(struct svc_rqst *rqstp, __be32 *p) ++nfssvc_decode_diropargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd_diropargs *args = rqstp->rq_argp; + + return svcxdr_decode_diropargs(xdr, &args->fh, &args->name, &args->len); + } + + int +-nfssvc_decode_readargs(struct svc_rqst *rqstp, __be32 *p) ++nfssvc_decode_readargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd_readargs *args = rqstp->rq_argp; + u32 totalcount; + +@@ -321,9 +317,8 @@ nfssvc_decode_readargs(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p) ++nfssvc_decode_writeargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd_writeargs *args = rqstp->rq_argp; + u32 beginoffset, totalcount; + +@@ -350,9 +345,8 @@ nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nfssvc_decode_createargs(struct svc_rqst *rqstp, __be32 *p) ++nfssvc_decode_createargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd_createargs *args = rqstp->rq_argp; + + return svcxdr_decode_diropargs(xdr, &args->fh, +@@ -361,9 +355,8 @@ nfssvc_decode_createargs(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nfssvc_decode_renameargs(struct svc_rqst *rqstp, __be32 *p) ++nfssvc_decode_renameargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd_renameargs *args = rqstp->rq_argp; + + return svcxdr_decode_diropargs(xdr, &args->ffh, +@@ -373,9 +366,8 @@ nfssvc_decode_renameargs(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nfssvc_decode_linkargs(struct svc_rqst *rqstp, __be32 *p) ++nfssvc_decode_linkargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd_linkargs *args = rqstp->rq_argp; + + return svcxdr_decode_fhandle(xdr, &args->ffh) && +@@ -384,9 +376,8 @@ nfssvc_decode_linkargs(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nfssvc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p) ++nfssvc_decode_symlinkargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd_symlinkargs *args = rqstp->rq_argp; + struct kvec *head = rqstp->rq_arg.head; + +@@ -405,9 +396,8 @@ nfssvc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nfssvc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p) ++nfssvc_decode_readdirargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_arg_stream; + struct nfsd_readdirargs *args = rqstp->rq_argp; + + if (!svcxdr_decode_fhandle(xdr, &args->fh)) +diff --git a/fs/nfsd/xdr.h b/fs/nfsd/xdr.h +index 863a35f24910a..19e281382bb98 100644 +--- a/fs/nfsd/xdr.h ++++ b/fs/nfsd/xdr.h +@@ -141,16 +141,17 @@ union nfsd_xdrstore { + #define NFS2_SVC_XDRSIZE sizeof(union nfsd_xdrstore) + + +-int nfssvc_decode_fhandleargs(struct svc_rqst *, __be32 *); +-int nfssvc_decode_sattrargs(struct svc_rqst *, __be32 *); +-int nfssvc_decode_diropargs(struct svc_rqst *, __be32 *); +-int nfssvc_decode_readargs(struct svc_rqst *, __be32 *); +-int nfssvc_decode_writeargs(struct svc_rqst *, __be32 *); +-int nfssvc_decode_createargs(struct svc_rqst *, __be32 *); +-int nfssvc_decode_renameargs(struct svc_rqst *, __be32 *); +-int nfssvc_decode_linkargs(struct svc_rqst *, __be32 *); +-int nfssvc_decode_symlinkargs(struct svc_rqst *, __be32 *); +-int nfssvc_decode_readdirargs(struct svc_rqst *, __be32 *); ++int nfssvc_decode_fhandleargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nfssvc_decode_sattrargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nfssvc_decode_diropargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nfssvc_decode_readargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nfssvc_decode_writeargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nfssvc_decode_createargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nfssvc_decode_renameargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nfssvc_decode_linkargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nfssvc_decode_symlinkargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nfssvc_decode_readdirargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++ + int nfssvc_encode_statres(struct svc_rqst *, __be32 *); + int nfssvc_encode_attrstatres(struct svc_rqst *, __be32 *); + int nfssvc_encode_diropres(struct svc_rqst *, __be32 *); +diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h +index 712c117300cb7..60a8909205e5a 100644 +--- a/fs/nfsd/xdr3.h ++++ b/fs/nfsd/xdr3.h +@@ -265,21 +265,22 @@ union nfsd3_xdrstore { + + #define NFS3_SVC_XDRSIZE sizeof(union nfsd3_xdrstore) + +-int nfs3svc_decode_fhandleargs(struct svc_rqst *, __be32 *); +-int nfs3svc_decode_sattrargs(struct svc_rqst *, __be32 *); +-int nfs3svc_decode_diropargs(struct svc_rqst *, __be32 *); +-int nfs3svc_decode_accessargs(struct svc_rqst *, __be32 *); +-int nfs3svc_decode_readargs(struct svc_rqst *, __be32 *); +-int nfs3svc_decode_writeargs(struct svc_rqst *, __be32 *); +-int nfs3svc_decode_createargs(struct svc_rqst *, __be32 *); +-int nfs3svc_decode_mkdirargs(struct svc_rqst *, __be32 *); +-int nfs3svc_decode_mknodargs(struct svc_rqst *, __be32 *); +-int nfs3svc_decode_renameargs(struct svc_rqst *, __be32 *); +-int nfs3svc_decode_linkargs(struct svc_rqst *, __be32 *); +-int nfs3svc_decode_symlinkargs(struct svc_rqst *, __be32 *); +-int nfs3svc_decode_readdirargs(struct svc_rqst *, __be32 *); +-int nfs3svc_decode_readdirplusargs(struct svc_rqst *, __be32 *); +-int nfs3svc_decode_commitargs(struct svc_rqst *, __be32 *); ++int nfs3svc_decode_fhandleargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nfs3svc_decode_diropargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nfs3svc_decode_accessargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nfs3svc_decode_readargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nfs3svc_decode_writeargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nfs3svc_decode_createargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nfs3svc_decode_renameargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nfs3svc_decode_linkargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nfs3svc_decode_commitargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++ + int nfs3svc_encode_getattrres(struct svc_rqst *, __be32 *); + int nfs3svc_encode_wccstat(struct svc_rqst *, __be32 *); + int nfs3svc_encode_lookupres(struct svc_rqst *, __be32 *); +diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h +index 37af86e370cb3..c3e18efcd23b6 100644 +--- a/fs/nfsd/xdr4.h ++++ b/fs/nfsd/xdr4.h +@@ -756,7 +756,7 @@ set_change_info(struct nfsd4_change_info *cinfo, struct svc_fh *fhp) + + + bool nfsd4_mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp); +-int nfs4svc_decode_compoundargs(struct svc_rqst *, __be32 *); ++int nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); + int nfs4svc_encode_compoundres(struct svc_rqst *, __be32 *); + __be32 nfsd4_check_resp_size(struct nfsd4_compoundres *, u32); + void nfsd4_encode_operation(struct nfsd4_compoundres *, struct nfsd4_op *); +diff --git a/include/linux/lockd/xdr.h b/include/linux/lockd/xdr.h +index a98309c0121cb..170ad6f5596a0 100644 +--- a/include/linux/lockd/xdr.h ++++ b/include/linux/lockd/xdr.h +@@ -96,18 +96,19 @@ struct nlm_reboot { + */ + #define NLMSVC_XDRSIZE sizeof(struct nlm_args) + +-int nlmsvc_decode_testargs(struct svc_rqst *, __be32 *); ++int nlmsvc_decode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nlmsvc_decode_testargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nlmsvc_decode_lockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nlmsvc_decode_cancargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nlmsvc_decode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nlmsvc_decode_reboot(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nlmsvc_decode_shareargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nlmsvc_decode_notify(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++ + int nlmsvc_encode_testres(struct svc_rqst *, __be32 *); +-int nlmsvc_decode_lockargs(struct svc_rqst *, __be32 *); +-int nlmsvc_decode_cancargs(struct svc_rqst *, __be32 *); +-int nlmsvc_decode_unlockargs(struct svc_rqst *, __be32 *); + int nlmsvc_encode_res(struct svc_rqst *, __be32 *); +-int nlmsvc_decode_res(struct svc_rqst *, __be32 *); + int nlmsvc_encode_void(struct svc_rqst *, __be32 *); +-int nlmsvc_decode_void(struct svc_rqst *, __be32 *); +-int nlmsvc_decode_shareargs(struct svc_rqst *, __be32 *); + int nlmsvc_encode_shareres(struct svc_rqst *, __be32 *); +-int nlmsvc_decode_notify(struct svc_rqst *, __be32 *); +-int nlmsvc_decode_reboot(struct svc_rqst *, __be32 *); + + #endif /* LOCKD_XDR_H */ +diff --git a/include/linux/lockd/xdr4.h b/include/linux/lockd/xdr4.h +index 5ae766f26e04f..68e14e0f2b1fb 100644 +--- a/include/linux/lockd/xdr4.h ++++ b/include/linux/lockd/xdr4.h +@@ -22,21 +22,20 @@ + #define nlm4_fbig cpu_to_be32(NLM_FBIG) + #define nlm4_failed cpu_to_be32(NLM_FAILED) + ++int nlm4svc_decode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nlm4svc_decode_testargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nlm4svc_decode_lockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nlm4svc_decode_cancargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nlm4svc_decode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nlm4svc_decode_reboot(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nlm4svc_decode_shareargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nlm4svc_decode_notify(struct svc_rqst *rqstp, struct xdr_stream *xdr); + +- +-int nlm4svc_decode_testargs(struct svc_rqst *, __be32 *); + int nlm4svc_encode_testres(struct svc_rqst *, __be32 *); +-int nlm4svc_decode_lockargs(struct svc_rqst *, __be32 *); +-int nlm4svc_decode_cancargs(struct svc_rqst *, __be32 *); +-int nlm4svc_decode_unlockargs(struct svc_rqst *, __be32 *); + int nlm4svc_encode_res(struct svc_rqst *, __be32 *); +-int nlm4svc_decode_res(struct svc_rqst *, __be32 *); + int nlm4svc_encode_void(struct svc_rqst *, __be32 *); +-int nlm4svc_decode_void(struct svc_rqst *, __be32 *); +-int nlm4svc_decode_shareargs(struct svc_rqst *, __be32 *); + int nlm4svc_encode_shareres(struct svc_rqst *, __be32 *); +-int nlm4svc_decode_notify(struct svc_rqst *, __be32 *); +-int nlm4svc_decode_reboot(struct svc_rqst *, __be32 *); + + extern const struct rpc_version nlm_version4; + +diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h +index b0986e969c2f4..77e3a9b398275 100644 +--- a/include/linux/sunrpc/svc.h ++++ b/include/linux/sunrpc/svc.h +@@ -457,7 +457,8 @@ struct svc_procedure { + /* process the request: */ + __be32 (*pc_func)(struct svc_rqst *); + /* XDR decode args: */ +- int (*pc_decode)(struct svc_rqst *, __be32 *data); ++ int (*pc_decode)(struct svc_rqst *rqstp, ++ struct xdr_stream *xdr); + /* XDR encode result: */ + int (*pc_encode)(struct svc_rqst *, __be32 *data); + /* XDR free result: */ +-- +2.43.0 + diff --git a/queue-5.10/sunrpc-replace-the-__be32-p-parameter-to-.pc_encode.patch b/queue-5.10/sunrpc-replace-the-__be32-p-parameter-to-.pc_encode.patch new file mode 100644 index 00000000000..a9aedd817c2 --- /dev/null +++ b/queue-5.10/sunrpc-replace-the-__be32-p-parameter-to-.pc_encode.patch @@ -0,0 +1,693 @@ +From e0f0a455a8af4cba2d327dc414dceefde50d8fd9 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Wed, 13 Oct 2021 10:41:06 -0400 +Subject: SUNRPC: Replace the "__be32 *p" parameter to .pc_encode + +From: Chuck Lever + +[ Upstream commit fda494411485aff91768842c532f90fb8eb54943 ] + +The passed-in value of the "__be32 *p" parameter is now unused in +every server-side XDR encoder, and can be removed. + +Note also that there is a line in each encoder that sets up a local +pointer to a struct xdr_stream. Passing that pointer from the +dispatcher instead saves one line per encoder function. + +Signed-off-by: Chuck Lever +Signed-off-by: J. Bruce Fields +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/svc.c | 3 +-- + fs/lockd/xdr.c | 11 ++++----- + fs/lockd/xdr4.c | 11 ++++----- + fs/nfs/callback_xdr.c | 4 ++-- + fs/nfsd/nfs2acl.c | 8 +++---- + fs/nfsd/nfs3acl.c | 8 +++---- + fs/nfsd/nfs3xdr.c | 46 +++++++++++++------------------------- + fs/nfsd/nfs4xdr.c | 7 +++--- + fs/nfsd/nfsd.h | 3 ++- + fs/nfsd/nfssvc.c | 9 +++----- + fs/nfsd/nfsxdr.c | 22 +++++++----------- + fs/nfsd/xdr.h | 14 ++++++------ + fs/nfsd/xdr3.h | 30 ++++++++++++------------- + fs/nfsd/xdr4.h | 2 +- + include/linux/lockd/xdr.h | 8 +++---- + include/linux/lockd/xdr4.h | 8 +++---- + include/linux/sunrpc/svc.h | 3 ++- + 17 files changed, 85 insertions(+), 112 deletions(-) + +diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c +index 9a82471bda071..b220e1b917268 100644 +--- a/fs/lockd/svc.c ++++ b/fs/lockd/svc.c +@@ -780,7 +780,6 @@ module_exit(exit_nlm); + static int nlmsvc_dispatch(struct svc_rqst *rqstp, __be32 *statp) + { + const struct svc_procedure *procp = rqstp->rq_procinfo; +- struct kvec *resv = rqstp->rq_res.head; + + svcxdr_init_decode(rqstp); + if (!procp->pc_decode(rqstp, &rqstp->rq_arg_stream)) +@@ -793,7 +792,7 @@ static int nlmsvc_dispatch(struct svc_rqst *rqstp, __be32 *statp) + return 1; + + svcxdr_init_encode(rqstp); +- if (!procp->pc_encode(rqstp, resv->iov_base + resv->iov_len)) ++ if (!procp->pc_encode(rqstp, &rqstp->rq_res_stream)) + goto out_encode_err; + + return 1; +diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c +index 622c2ca37dbfd..2595b4d14cd44 100644 +--- a/fs/lockd/xdr.c ++++ b/fs/lockd/xdr.c +@@ -314,15 +314,14 @@ nlmsvc_decode_notify(struct svc_rqst *rqstp, struct xdr_stream *xdr) + */ + + int +-nlmsvc_encode_void(struct svc_rqst *rqstp, __be32 *p) ++nlmsvc_encode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + return 1; + } + + int +-nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p) ++nlmsvc_encode_testres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nlm_res *resp = rqstp->rq_resp; + + return svcxdr_encode_cookie(xdr, &resp->cookie) && +@@ -330,9 +329,8 @@ nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nlmsvc_encode_res(struct svc_rqst *rqstp, __be32 *p) ++nlmsvc_encode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nlm_res *resp = rqstp->rq_resp; + + return svcxdr_encode_cookie(xdr, &resp->cookie) && +@@ -340,9 +338,8 @@ nlmsvc_encode_res(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nlmsvc_encode_shareres(struct svc_rqst *rqstp, __be32 *p) ++nlmsvc_encode_shareres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nlm_res *resp = rqstp->rq_resp; + + if (!svcxdr_encode_cookie(xdr, &resp->cookie)) +diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c +index 45551dee26b41..32231c21c22dd 100644 +--- a/fs/lockd/xdr4.c ++++ b/fs/lockd/xdr4.c +@@ -313,15 +313,14 @@ nlm4svc_decode_notify(struct svc_rqst *rqstp, struct xdr_stream *xdr) + */ + + int +-nlm4svc_encode_void(struct svc_rqst *rqstp, __be32 *p) ++nlm4svc_encode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + return 1; + } + + int +-nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p) ++nlm4svc_encode_testres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nlm_res *resp = rqstp->rq_resp; + + return svcxdr_encode_cookie(xdr, &resp->cookie) && +@@ -329,9 +328,8 @@ nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nlm4svc_encode_res(struct svc_rqst *rqstp, __be32 *p) ++nlm4svc_encode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nlm_res *resp = rqstp->rq_resp; + + return svcxdr_encode_cookie(xdr, &resp->cookie) && +@@ -339,9 +337,8 @@ nlm4svc_encode_res(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nlm4svc_encode_shareres(struct svc_rqst *rqstp, __be32 *p) ++nlm4svc_encode_shareres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nlm_res *resp = rqstp->rq_resp; + + if (!svcxdr_encode_cookie(xdr, &resp->cookie)) +diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c +index 600e640682401..c58b3b60bc2c0 100644 +--- a/fs/nfs/callback_xdr.c ++++ b/fs/nfs/callback_xdr.c +@@ -67,9 +67,9 @@ static __be32 nfs4_callback_null(struct svc_rqst *rqstp) + * svc_process_common() looks for an XDR encoder to know when + * not to drop a Reply. + */ +-static int nfs4_encode_void(struct svc_rqst *rqstp, __be32 *p) ++static int nfs4_encode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- return xdr_ressize_check(rqstp, p); ++ return 1; + } + + static __be32 decode_string(struct xdr_stream *xdr, unsigned int *len, +diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c +index eb6a89baf675f..23e4c3eb2c381 100644 +--- a/fs/nfsd/nfs2acl.c ++++ b/fs/nfsd/nfs2acl.c +@@ -238,9 +238,9 @@ nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + */ + + /* GETACL */ +-static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p) ++static int ++nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd3_getaclres *resp = rqstp->rq_resp; + struct dentry *dentry = resp->fh.fh_dentry; + struct inode *inode; +@@ -278,9 +278,9 @@ static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p) + } + + /* ACCESS */ +-static int nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, __be32 *p) ++static int ++nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd3_accessres *resp = rqstp->rq_resp; + + if (!svcxdr_encode_stat(xdr, resp->status)) +diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c +index f60b072ce9ecc..21aacba88ea3e 100644 +--- a/fs/nfsd/nfs3acl.c ++++ b/fs/nfsd/nfs3acl.c +@@ -164,9 +164,9 @@ nfs3svc_decode_setaclargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + */ + + /* GETACL */ +-static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p) ++static int ++nfs3svc_encode_getaclres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd3_getaclres *resp = rqstp->rq_resp; + struct dentry *dentry = resp->fh.fh_dentry; + struct kvec *head = rqstp->rq_res.head; +@@ -216,9 +216,9 @@ static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p) + } + + /* SETACL */ +-static int nfs3svc_encode_setaclres(struct svc_rqst *rqstp, __be32 *p) ++static int ++nfs3svc_encode_setaclres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd3_attrstat *resp = rqstp->rq_resp; + + return svcxdr_encode_nfsstat3(xdr, resp->status) && +diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c +index 1f3de46d24d46..63f0be4e44f70 100644 +--- a/fs/nfsd/nfs3xdr.c ++++ b/fs/nfsd/nfs3xdr.c +@@ -813,9 +813,8 @@ nfs3svc_decode_commitargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + + /* GETATTR */ + int +-nfs3svc_encode_getattrres(struct svc_rqst *rqstp, __be32 *p) ++nfs3svc_encode_getattrres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd3_attrstat *resp = rqstp->rq_resp; + + if (!svcxdr_encode_nfsstat3(xdr, resp->status)) +@@ -833,9 +832,8 @@ nfs3svc_encode_getattrres(struct svc_rqst *rqstp, __be32 *p) + + /* SETATTR, REMOVE, RMDIR */ + int +-nfs3svc_encode_wccstat(struct svc_rqst *rqstp, __be32 *p) ++nfs3svc_encode_wccstat(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd3_attrstat *resp = rqstp->rq_resp; + + return svcxdr_encode_nfsstat3(xdr, resp->status) && +@@ -843,9 +841,9 @@ nfs3svc_encode_wccstat(struct svc_rqst *rqstp, __be32 *p) + } + + /* LOOKUP */ +-int nfs3svc_encode_lookupres(struct svc_rqst *rqstp, __be32 *p) ++int ++nfs3svc_encode_lookupres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd3_diropres *resp = rqstp->rq_resp; + + if (!svcxdr_encode_nfsstat3(xdr, resp->status)) +@@ -869,9 +867,8 @@ int nfs3svc_encode_lookupres(struct svc_rqst *rqstp, __be32 *p) + + /* ACCESS */ + int +-nfs3svc_encode_accessres(struct svc_rqst *rqstp, __be32 *p) ++nfs3svc_encode_accessres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd3_accessres *resp = rqstp->rq_resp; + + if (!svcxdr_encode_nfsstat3(xdr, resp->status)) +@@ -893,9 +890,8 @@ nfs3svc_encode_accessres(struct svc_rqst *rqstp, __be32 *p) + + /* READLINK */ + int +-nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p) ++nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd3_readlinkres *resp = rqstp->rq_resp; + struct kvec *head = rqstp->rq_res.head; + +@@ -921,9 +917,8 @@ nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p) + + /* READ */ + int +-nfs3svc_encode_readres(struct svc_rqst *rqstp, __be32 *p) ++nfs3svc_encode_readres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd3_readres *resp = rqstp->rq_resp; + struct kvec *head = rqstp->rq_res.head; + +@@ -954,9 +949,8 @@ nfs3svc_encode_readres(struct svc_rqst *rqstp, __be32 *p) + + /* WRITE */ + int +-nfs3svc_encode_writeres(struct svc_rqst *rqstp, __be32 *p) ++nfs3svc_encode_writeres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd3_writeres *resp = rqstp->rq_resp; + + if (!svcxdr_encode_nfsstat3(xdr, resp->status)) +@@ -982,9 +976,8 @@ nfs3svc_encode_writeres(struct svc_rqst *rqstp, __be32 *p) + + /* CREATE, MKDIR, SYMLINK, MKNOD */ + int +-nfs3svc_encode_createres(struct svc_rqst *rqstp, __be32 *p) ++nfs3svc_encode_createres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd3_diropres *resp = rqstp->rq_resp; + + if (!svcxdr_encode_nfsstat3(xdr, resp->status)) +@@ -1008,9 +1001,8 @@ nfs3svc_encode_createres(struct svc_rqst *rqstp, __be32 *p) + + /* RENAME */ + int +-nfs3svc_encode_renameres(struct svc_rqst *rqstp, __be32 *p) ++nfs3svc_encode_renameres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd3_renameres *resp = rqstp->rq_resp; + + return svcxdr_encode_nfsstat3(xdr, resp->status) && +@@ -1020,9 +1012,8 @@ nfs3svc_encode_renameres(struct svc_rqst *rqstp, __be32 *p) + + /* LINK */ + int +-nfs3svc_encode_linkres(struct svc_rqst *rqstp, __be32 *p) ++nfs3svc_encode_linkres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd3_linkres *resp = rqstp->rq_resp; + + return svcxdr_encode_nfsstat3(xdr, resp->status) && +@@ -1032,9 +1023,8 @@ nfs3svc_encode_linkres(struct svc_rqst *rqstp, __be32 *p) + + /* READDIR */ + int +-nfs3svc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p) ++nfs3svc_encode_readdirres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd3_readdirres *resp = rqstp->rq_resp; + struct xdr_buf *dirlist = &resp->dirlist; + +@@ -1286,9 +1276,8 @@ svcxdr_encode_fsstat3resok(struct xdr_stream *xdr, + + /* FSSTAT */ + int +-nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, __be32 *p) ++nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd3_fsstatres *resp = rqstp->rq_resp; + + if (!svcxdr_encode_nfsstat3(xdr, resp->status)) +@@ -1333,9 +1322,8 @@ svcxdr_encode_fsinfo3resok(struct xdr_stream *xdr, + + /* FSINFO */ + int +-nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, __be32 *p) ++nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd3_fsinfores *resp = rqstp->rq_resp; + + if (!svcxdr_encode_nfsstat3(xdr, resp->status)) +@@ -1376,9 +1364,8 @@ svcxdr_encode_pathconf3resok(struct xdr_stream *xdr, + + /* PATHCONF */ + int +-nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, __be32 *p) ++nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd3_pathconfres *resp = rqstp->rq_resp; + + if (!svcxdr_encode_nfsstat3(xdr, resp->status)) +@@ -1400,9 +1387,8 @@ nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, __be32 *p) + + /* COMMIT */ + int +-nfs3svc_encode_commitres(struct svc_rqst *rqstp, __be32 *p) ++nfs3svc_encode_commitres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd3_commitres *resp = rqstp->rq_resp; + + if (!svcxdr_encode_nfsstat3(xdr, resp->status)) +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index 3f8d23586ea79..697d61819a59d 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -5438,10 +5438,11 @@ nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + } + + int +-nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p) ++nfs4svc_encode_compoundres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + struct nfsd4_compoundres *resp = rqstp->rq_resp; +- struct xdr_buf *buf = resp->xdr->buf; ++ struct xdr_buf *buf = xdr->buf; ++ __be32 *p; + + WARN_ON_ONCE(buf->len != buf->head[0].iov_len + buf->page_len + + buf->tail[0].iov_len); +@@ -5454,7 +5455,7 @@ nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p) + + *p++ = resp->cstate.status; + +- rqstp->rq_next_page = resp->xdr->page_ptr + 1; ++ rqstp->rq_next_page = xdr->page_ptr + 1; + + *p++ = htonl(resp->taglen); + memcpy(p, resp->tag, resp->taglen); +diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h +index bfcddd4c75345..345f8247d5da9 100644 +--- a/fs/nfsd/nfsd.h ++++ b/fs/nfsd/nfsd.h +@@ -80,7 +80,8 @@ struct nfsd_voidargs { }; + struct nfsd_voidres { }; + bool nfssvc_decode_voidarg(struct svc_rqst *rqstp, + struct xdr_stream *xdr); +-int nfssvc_encode_voidres(struct svc_rqst *rqstp, __be32 *p); ++int nfssvc_encode_voidres(struct svc_rqst *rqstp, ++ struct xdr_stream *xdr); + + /* + * Function prototypes. +diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c +index 00aadc2635032..195f2bcc65384 100644 +--- a/fs/nfsd/nfssvc.c ++++ b/fs/nfsd/nfssvc.c +@@ -1004,8 +1004,6 @@ nfsd(void *vrqstp) + int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) + { + const struct svc_procedure *proc = rqstp->rq_procinfo; +- struct kvec *resv = &rqstp->rq_res.head[0]; +- __be32 *p; + + /* + * Give the xdr decoder a chance to change this if it wants +@@ -1030,14 +1028,13 @@ int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) + * Need to grab the location to store the status, as + * NFSv4 does some encoding while processing + */ +- p = resv->iov_base + resv->iov_len; + svcxdr_init_encode(rqstp); + + *statp = proc->pc_func(rqstp); + if (*statp == rpc_drop_reply || test_bit(RQ_DROPME, &rqstp->rq_flags)) + goto out_update_drop; + +- if (!proc->pc_encode(rqstp, p)) ++ if (!proc->pc_encode(rqstp, &rqstp->rq_res_stream)) + goto out_encode_err; + + nfsd_cache_update(rqstp, rqstp->rq_cachetype, statp + 1); +@@ -1078,13 +1075,13 @@ bool nfssvc_decode_voidarg(struct svc_rqst *rqstp, struct xdr_stream *xdr) + /** + * nfssvc_encode_voidres - Encode void results + * @rqstp: Server RPC transaction context +- * @p: buffer in which to encode results ++ * @xdr: XDR stream into which to encode results + * + * Return values: + * %0: Local error while encoding + * %1: Encoding was successful + */ +-int nfssvc_encode_voidres(struct svc_rqst *rqstp, __be32 *p) ++int nfssvc_encode_voidres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { + return 1; + } +diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c +index b5817a41b3de6..6aa8138ae2f7d 100644 +--- a/fs/nfsd/nfsxdr.c ++++ b/fs/nfsd/nfsxdr.c +@@ -415,18 +415,16 @@ nfssvc_decode_readdirargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) + */ + + int +-nfssvc_encode_statres(struct svc_rqst *rqstp, __be32 *p) ++nfssvc_encode_statres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd_stat *resp = rqstp->rq_resp; + + return svcxdr_encode_stat(xdr, resp->status); + } + + int +-nfssvc_encode_attrstatres(struct svc_rqst *rqstp, __be32 *p) ++nfssvc_encode_attrstatres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd_attrstat *resp = rqstp->rq_resp; + + if (!svcxdr_encode_stat(xdr, resp->status)) +@@ -442,9 +440,8 @@ nfssvc_encode_attrstatres(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nfssvc_encode_diropres(struct svc_rqst *rqstp, __be32 *p) ++nfssvc_encode_diropres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd_diropres *resp = rqstp->rq_resp; + + if (!svcxdr_encode_stat(xdr, resp->status)) +@@ -462,9 +459,8 @@ nfssvc_encode_diropres(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nfssvc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p) ++nfssvc_encode_readlinkres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd_readlinkres *resp = rqstp->rq_resp; + struct kvec *head = rqstp->rq_res.head; + +@@ -484,9 +480,8 @@ nfssvc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nfssvc_encode_readres(struct svc_rqst *rqstp, __be32 *p) ++nfssvc_encode_readres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd_readres *resp = rqstp->rq_resp; + struct kvec *head = rqstp->rq_res.head; + +@@ -509,9 +504,8 @@ nfssvc_encode_readres(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nfssvc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p) ++nfssvc_encode_readdirres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd_readdirres *resp = rqstp->rq_resp; + struct xdr_buf *dirlist = &resp->dirlist; + +@@ -532,11 +526,11 @@ nfssvc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p) + } + + int +-nfssvc_encode_statfsres(struct svc_rqst *rqstp, __be32 *p) ++nfssvc_encode_statfsres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + { +- struct xdr_stream *xdr = &rqstp->rq_res_stream; + struct nfsd_statfsres *resp = rqstp->rq_resp; + struct kstatfs *stat = &resp->stats; ++ __be32 *p; + + if (!svcxdr_encode_stat(xdr, resp->status)) + return 0; +diff --git a/fs/nfsd/xdr.h b/fs/nfsd/xdr.h +index d897c198c9126..bff7258041fc4 100644 +--- a/fs/nfsd/xdr.h ++++ b/fs/nfsd/xdr.h +@@ -152,13 +152,13 @@ bool nfssvc_decode_linkargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); + bool nfssvc_decode_symlinkargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); + bool nfssvc_decode_readdirargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); + +-int nfssvc_encode_statres(struct svc_rqst *, __be32 *); +-int nfssvc_encode_attrstatres(struct svc_rqst *, __be32 *); +-int nfssvc_encode_diropres(struct svc_rqst *, __be32 *); +-int nfssvc_encode_readlinkres(struct svc_rqst *, __be32 *); +-int nfssvc_encode_readres(struct svc_rqst *, __be32 *); +-int nfssvc_encode_statfsres(struct svc_rqst *, __be32 *); +-int nfssvc_encode_readdirres(struct svc_rqst *, __be32 *); ++int nfssvc_encode_statres(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nfssvc_encode_attrstatres(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nfssvc_encode_diropres(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nfssvc_encode_readlinkres(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nfssvc_encode_readres(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nfssvc_encode_statfsres(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nfssvc_encode_readdirres(struct svc_rqst *rqstp, struct xdr_stream *xdr); + + void nfssvc_encode_nfscookie(struct nfsd_readdirres *resp, u32 offset); + int nfssvc_encode_entry(void *data, const char *name, int namlen, +diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h +index ef72bc4868da6..bb017fc7cba19 100644 +--- a/fs/nfsd/xdr3.h ++++ b/fs/nfsd/xdr3.h +@@ -281,21 +281,21 @@ bool nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); + bool nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); + bool nfs3svc_decode_commitargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); + +-int nfs3svc_encode_getattrres(struct svc_rqst *, __be32 *); +-int nfs3svc_encode_wccstat(struct svc_rqst *, __be32 *); +-int nfs3svc_encode_lookupres(struct svc_rqst *, __be32 *); +-int nfs3svc_encode_accessres(struct svc_rqst *, __be32 *); +-int nfs3svc_encode_readlinkres(struct svc_rqst *, __be32 *); +-int nfs3svc_encode_readres(struct svc_rqst *, __be32 *); +-int nfs3svc_encode_writeres(struct svc_rqst *, __be32 *); +-int nfs3svc_encode_createres(struct svc_rqst *, __be32 *); +-int nfs3svc_encode_renameres(struct svc_rqst *, __be32 *); +-int nfs3svc_encode_linkres(struct svc_rqst *, __be32 *); +-int nfs3svc_encode_readdirres(struct svc_rqst *, __be32 *); +-int nfs3svc_encode_fsstatres(struct svc_rqst *, __be32 *); +-int nfs3svc_encode_fsinfores(struct svc_rqst *, __be32 *); +-int nfs3svc_encode_pathconfres(struct svc_rqst *, __be32 *); +-int nfs3svc_encode_commitres(struct svc_rqst *, __be32 *); ++int nfs3svc_encode_getattrres(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nfs3svc_encode_wccstat(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nfs3svc_encode_lookupres(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nfs3svc_encode_accessres(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nfs3svc_encode_readres(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nfs3svc_encode_writeres(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nfs3svc_encode_createres(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nfs3svc_encode_renameres(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nfs3svc_encode_linkres(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nfs3svc_encode_readdirres(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nfs3svc_encode_commitres(struct svc_rqst *rqstp, struct xdr_stream *xdr); + + void nfs3svc_release_fhandle(struct svc_rqst *); + void nfs3svc_release_fhandle2(struct svc_rqst *); +diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h +index 8e11dfdc2563a..5b343d0c6963a 100644 +--- a/fs/nfsd/xdr4.h ++++ b/fs/nfsd/xdr4.h +@@ -758,7 +758,7 @@ set_change_info(struct nfsd4_change_info *cinfo, struct svc_fh *fhp) + + bool nfsd4_mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp); + bool nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); +-int nfs4svc_encode_compoundres(struct svc_rqst *, __be32 *); ++int nfs4svc_encode_compoundres(struct svc_rqst *rqstp, struct xdr_stream *xdr); + __be32 nfsd4_check_resp_size(struct nfsd4_compoundres *, u32); + void nfsd4_encode_operation(struct nfsd4_compoundres *, struct nfsd4_op *); + void nfsd4_encode_replay(struct xdr_stream *xdr, struct nfsd4_op *op); +diff --git a/include/linux/lockd/xdr.h b/include/linux/lockd/xdr.h +index e1362244f909b..d8bd26a5525ef 100644 +--- a/include/linux/lockd/xdr.h ++++ b/include/linux/lockd/xdr.h +@@ -106,9 +106,9 @@ bool nlmsvc_decode_reboot(struct svc_rqst *rqstp, struct xdr_stream *xdr); + bool nlmsvc_decode_shareargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); + bool nlmsvc_decode_notify(struct svc_rqst *rqstp, struct xdr_stream *xdr); + +-int nlmsvc_encode_testres(struct svc_rqst *, __be32 *); +-int nlmsvc_encode_res(struct svc_rqst *, __be32 *); +-int nlmsvc_encode_void(struct svc_rqst *, __be32 *); +-int nlmsvc_encode_shareres(struct svc_rqst *, __be32 *); ++int nlmsvc_encode_testres(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nlmsvc_encode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nlmsvc_encode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nlmsvc_encode_shareres(struct svc_rqst *rqstp, struct xdr_stream *xdr); + + #endif /* LOCKD_XDR_H */ +diff --git a/include/linux/lockd/xdr4.h b/include/linux/lockd/xdr4.h +index 376b8f6a3763a..50677be3557dc 100644 +--- a/include/linux/lockd/xdr4.h ++++ b/include/linux/lockd/xdr4.h +@@ -32,10 +32,10 @@ bool nlm4svc_decode_reboot(struct svc_rqst *rqstp, struct xdr_stream *xdr); + bool nlm4svc_decode_shareargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); + bool nlm4svc_decode_notify(struct svc_rqst *rqstp, struct xdr_stream *xdr); + +-int nlm4svc_encode_testres(struct svc_rqst *, __be32 *); +-int nlm4svc_encode_res(struct svc_rqst *, __be32 *); +-int nlm4svc_encode_void(struct svc_rqst *, __be32 *); +-int nlm4svc_encode_shareres(struct svc_rqst *, __be32 *); ++int nlm4svc_encode_testres(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nlm4svc_encode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nlm4svc_encode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr); ++int nlm4svc_encode_shareres(struct svc_rqst *rqstp, struct xdr_stream *xdr); + + extern const struct rpc_version nlm_version4; + +diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h +index 85a9884b10743..c6a0b4364f4a2 100644 +--- a/include/linux/sunrpc/svc.h ++++ b/include/linux/sunrpc/svc.h +@@ -460,7 +460,8 @@ struct svc_procedure { + bool (*pc_decode)(struct svc_rqst *rqstp, + struct xdr_stream *xdr); + /* XDR encode result: */ +- int (*pc_encode)(struct svc_rqst *, __be32 *data); ++ int (*pc_encode)(struct svc_rqst *rqstp, ++ struct xdr_stream *xdr); + /* XDR free result: */ + void (*pc_release)(struct svc_rqst *); + unsigned int pc_argsize; /* argument struct size */ +-- +2.43.0 + diff --git a/queue-5.10/sunrpc-return-true-false-not-1-0-from-bool-functions.patch b/queue-5.10/sunrpc-return-true-false-not-1-0-from-bool-functions.patch new file mode 100644 index 00000000000..ab3fe2eccff --- /dev/null +++ b/queue-5.10/sunrpc-return-true-false-not-1-0-from-bool-functions.patch @@ -0,0 +1,96 @@ +From 44ec386ddebebb93720044fdd052c7c616ae2361 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 28 Mar 2022 10:48:59 +0800 +Subject: SUNRPC: Return true/false (not 1/0) from bool functions + +From: Haowen Bai + +[ Upstream commit 5f7b839d47dbc74cf4a07beeab5191f93678673e ] + +Return boolean values ("true" or "false") instead of 1 or 0 from bool +functions. This fixes the following warnings from coccicheck: + +./fs/nfsd/nfs2acl.c:289:9-10: WARNING: return of 0/1 in function +'nfsaclsvc_encode_accessres' with return type bool +./fs/nfsd/nfs2acl.c:252:9-10: WARNING: return of 0/1 in function +'nfsaclsvc_encode_getaclres' with return type bool + +Signed-off-by: Haowen Bai +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs2acl.c | 24 ++++++++++++------------ + 1 file changed, 12 insertions(+), 12 deletions(-) + +diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c +index 96733dff354d3..03703b22c81ef 100644 +--- a/fs/nfsd/nfs2acl.c ++++ b/fs/nfsd/nfs2acl.c +@@ -247,34 +247,34 @@ nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + int w; + + if (!svcxdr_encode_stat(xdr, resp->status)) +- return 0; ++ return false; + + if (dentry == NULL || d_really_is_negative(dentry)) +- return 1; ++ return true; + inode = d_inode(dentry); + + if (!svcxdr_encode_fattr(rqstp, xdr, &resp->fh, &resp->stat)) +- return 0; ++ return false; + if (xdr_stream_encode_u32(xdr, resp->mask) < 0) +- return 0; ++ return false; + + rqstp->rq_res.page_len = w = nfsacl_size( + (resp->mask & NFS_ACL) ? resp->acl_access : NULL, + (resp->mask & NFS_DFACL) ? resp->acl_default : NULL); + while (w > 0) { + if (!*(rqstp->rq_next_page++)) +- return 1; ++ return true; + w -= PAGE_SIZE; + } + + if (!nfs_stream_encode_acl(xdr, inode, resp->acl_access, + resp->mask & NFS_ACL, 0)) +- return 0; ++ return false; + if (!nfs_stream_encode_acl(xdr, inode, resp->acl_default, + resp->mask & NFS_DFACL, NFS_ACL_DEFAULT)) +- return 0; ++ return false; + +- return 1; ++ return true; + } + + /* ACCESS */ +@@ -284,17 +284,17 @@ nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, struct xdr_stream *xdr) + struct nfsd3_accessres *resp = rqstp->rq_resp; + + if (!svcxdr_encode_stat(xdr, resp->status)) +- return 0; ++ return false; + switch (resp->status) { + case nfs_ok: + if (!svcxdr_encode_fattr(rqstp, xdr, &resp->fh, &resp->stat)) +- return 0; ++ return false; + if (xdr_stream_encode_u32(xdr, resp->access) < 0) +- return 0; ++ return false; + break; + } + +- return 1; ++ return true; + } + + /* +-- +2.43.0 + diff --git a/queue-5.10/sunrpc-set-rq_auth_stat-in-the-pg_authenticate-callo.patch b/queue-5.10/sunrpc-set-rq_auth_stat-in-the-pg_authenticate-callo.patch new file mode 100644 index 00000000000..dd9ec7cd9ed --- /dev/null +++ b/queue-5.10/sunrpc-set-rq_auth_stat-in-the-pg_authenticate-callo.patch @@ -0,0 +1,137 @@ +From c81bcc897a4a7525ebd84363bcc32d57c7460706 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Thu, 15 Jul 2021 15:52:12 -0400 +Subject: SUNRPC: Set rq_auth_stat in the pg_authenticate() callout + +From: Chuck Lever + +[ Upstream commit 5c2465dfd457f3015eebcc3ace50570e1d896aeb ] + +In a few moments, rq_auth_stat will need to be explicitly set to +rpc_auth_ok before execution gets to the dispatcher. + +svc_authenticate() already sets it, but it often gets reset to +rpc_autherr_badcred right after that call, even when authentication +is successful. Let's ensure that the pg_authenticate callout and +svc_set_client() set it properly in every case. + +Signed-off-by: Chuck Lever +Signed-off-by: Anna Schumaker +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/svc.c | 2 ++ + fs/nfs/callback.c | 4 ++++ + net/sunrpc/auth_gss/svcauth_gss.c | 4 ++++ + net/sunrpc/svc.c | 4 +--- + net/sunrpc/svcauth_unix.c | 6 +++++- + 5 files changed, 16 insertions(+), 4 deletions(-) + +diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c +index 0ab9756ed2359..b632be3ad57b2 100644 +--- a/fs/lockd/svc.c ++++ b/fs/lockd/svc.c +@@ -649,6 +649,7 @@ static int lockd_authenticate(struct svc_rqst *rqstp) + switch (rqstp->rq_authop->flavour) { + case RPC_AUTH_NULL: + case RPC_AUTH_UNIX: ++ rqstp->rq_auth_stat = rpc_auth_ok; + if (rqstp->rq_proc == 0) + return SVC_OK; + if (is_callback(rqstp->rq_proc)) { +@@ -659,6 +660,7 @@ static int lockd_authenticate(struct svc_rqst *rqstp) + } + return svc_set_client(rqstp); + } ++ rqstp->rq_auth_stat = rpc_autherr_badcred; + return SVC_DENIED; + } + +diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c +index 7817ad94a6bae..86d856de1389b 100644 +--- a/fs/nfs/callback.c ++++ b/fs/nfs/callback.c +@@ -429,6 +429,8 @@ check_gss_callback_principal(struct nfs_client *clp, struct svc_rqst *rqstp) + */ + static int nfs_callback_authenticate(struct svc_rqst *rqstp) + { ++ rqstp->rq_auth_stat = rpc_autherr_badcred; ++ + switch (rqstp->rq_authop->flavour) { + case RPC_AUTH_NULL: + if (rqstp->rq_proc != CB_NULL) +@@ -439,6 +441,8 @@ static int nfs_callback_authenticate(struct svc_rqst *rqstp) + if (svc_is_backchannel(rqstp)) + return SVC_DENIED; + } ++ ++ rqstp->rq_auth_stat = rpc_auth_ok; + return SVC_OK; + } + +diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c +index 54303b7efde76..329eac782cc5e 100644 +--- a/net/sunrpc/auth_gss/svcauth_gss.c ++++ b/net/sunrpc/auth_gss/svcauth_gss.c +@@ -1038,6 +1038,8 @@ svcauth_gss_set_client(struct svc_rqst *rqstp) + struct rpc_gss_wire_cred *gc = &svcdata->clcred; + int stat; + ++ rqstp->rq_auth_stat = rpc_autherr_badcred; ++ + /* + * A gss export can be specified either by: + * export *(sec=krb5,rw) +@@ -1053,6 +1055,8 @@ svcauth_gss_set_client(struct svc_rqst *rqstp) + stat = svcauth_unix_set_client(rqstp); + if (stat == SVC_DROP || stat == SVC_CLOSE) + return stat; ++ ++ rqstp->rq_auth_stat = rpc_auth_ok; + return SVC_OK; + } + +diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c +index cbcc951639ad5..f036507275338 100644 +--- a/net/sunrpc/svc.c ++++ b/net/sunrpc/svc.c +@@ -1350,10 +1350,8 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv) + */ + auth_res = svc_authenticate(rqstp); + /* Also give the program a chance to reject this call: */ +- if (auth_res == SVC_OK && progp) { +- rqstp->rq_auth_stat = rpc_autherr_badcred; ++ if (auth_res == SVC_OK && progp) + auth_res = progp->pg_authenticate(rqstp); +- } + if (auth_res != SVC_OK) + trace_svc_authenticate(rqstp, auth_res); + switch (auth_res) { +diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c +index c20c63d651a9c..1868596259af5 100644 +--- a/net/sunrpc/svcauth_unix.c ++++ b/net/sunrpc/svcauth_unix.c +@@ -699,8 +699,9 @@ svcauth_unix_set_client(struct svc_rqst *rqstp) + + rqstp->rq_client = NULL; + if (rqstp->rq_proc == 0) +- return SVC_OK; ++ goto out; + ++ rqstp->rq_auth_stat = rpc_autherr_badcred; + ipm = ip_map_cached_get(xprt); + if (ipm == NULL) + ipm = __ip_map_lookup(sn->ip_map_cache, rqstp->rq_server->sv_program->pg_class, +@@ -737,6 +738,9 @@ svcauth_unix_set_client(struct svc_rqst *rqstp) + put_group_info(cred->cr_group_info); + cred->cr_group_info = gi; + } ++ ++out: ++ rqstp->rq_auth_stat = rpc_auth_ok; + return SVC_OK; + } + +-- +2.43.0 + diff --git a/queue-5.10/sunrpc-stop-using-sv_nrthreads-as-a-refcount.patch b/queue-5.10/sunrpc-stop-using-sv_nrthreads-as-a-refcount.patch new file mode 100644 index 00000000000..933d410c36f --- /dev/null +++ b/queue-5.10/sunrpc-stop-using-sv_nrthreads-as-a-refcount.patch @@ -0,0 +1,356 @@ +From 1095dac9583b914278eb5a0a280d803f619f5970 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Nov 2021 15:51:25 +1100 +Subject: SUNRPC: stop using ->sv_nrthreads as a refcount + +From: NeilBrown + +[ Upstream commit ec52361df99b490f6af412b046df9799b92c1050 ] + +The use of sv_nrthreads as a general refcount results in clumsy code, as +is seen by various comments needed to explain the situation. + +This patch introduces a 'struct kref' and uses that for reference +counting, leaving sv_nrthreads to be a pure count of threads. The kref +is managed particularly in svc_get() and svc_put(), and also nfsd_put(); + +svc_destroy() now takes a pointer to the embedded kref, rather than to +the serv. + +nfsd allows the svc_serv to exist with ->sv_nrhtreads being zero. This +happens when a transport is created before the first thread is started. +To support this, a 'keep_active' flag is introduced which holds a ref on +the svc_serv. This is set when any listening socket is successfully +added (unless there are running threads), and cleared when the number of +threads is set. So when the last thread exits, the nfs_serv will be +destroyed. +The use of 'keep_active' replaces previous code which checked if there +were any permanent sockets. + +We no longer clear ->rq_server when nfsd() exits. This was done +to prevent svc_exit_thread() from calling svc_destroy(). +Instead we take an extra reference to the svc_serv to prevent +svc_destroy() from being called. + +Signed-off-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/svc.c | 4 ---- + fs/nfs/callback.c | 2 +- + fs/nfsd/netns.h | 7 +++++++ + fs/nfsd/nfsctl.c | 22 +++++++++----------- + fs/nfsd/nfssvc.c | 42 +++++++++++++++++++++++--------------- + include/linux/sunrpc/svc.h | 14 ++++--------- + net/sunrpc/svc.c | 22 ++++++++++---------- + 7 files changed, 59 insertions(+), 54 deletions(-) + +diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c +index 135bd86ed3adb..a9669b106dbde 100644 +--- a/fs/lockd/svc.c ++++ b/fs/lockd/svc.c +@@ -486,10 +486,6 @@ int lockd_up(struct net *net, const struct cred *cred) + goto err_put; + } + nlmsvc_users++; +- /* +- * Note: svc_serv structures have an initial use count of 1, +- * so we exit through here on both success and failure. +- */ + err_put: + svc_put(serv); + err_create: +diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c +index dddd66749a881..09ec60b99f65e 100644 +--- a/fs/nfs/callback.c ++++ b/fs/nfs/callback.c +@@ -169,7 +169,7 @@ static int nfs_callback_start_svc(int minorversion, struct rpc_xprt *xprt, + if (nrservs < NFS4_MIN_NR_CALLBACK_THREADS) + nrservs = NFS4_MIN_NR_CALLBACK_THREADS; + +- if (serv->sv_nrthreads-1 == nrservs) ++ if (serv->sv_nrthreads == nrservs) + return 0; + + ret = serv->sv_ops->svo_setup(serv, NULL, nrservs); +diff --git a/fs/nfsd/netns.h b/fs/nfsd/netns.h +index 935c1028c2175..08bcd8f23b013 100644 +--- a/fs/nfsd/netns.h ++++ b/fs/nfsd/netns.h +@@ -123,6 +123,13 @@ struct nfsd_net { + u32 clverifier_counter; + + struct svc_serv *nfsd_serv; ++ /* When a listening socket is added to nfsd, keep_active is set ++ * and this justifies a reference on nfsd_serv. This stops ++ * nfsd_serv from being freed. When the number of threads is ++ * set, keep_active is cleared and the reference is dropped. So ++ * when the last thread exits, the service will be destroyed. ++ */ ++ int keep_active; + + wait_queue_head_t ntf_wq; + atomic_t ntf_refcnt; +diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c +index 5c8d985acf5fb..53076c5afe62c 100644 +--- a/fs/nfsd/nfsctl.c ++++ b/fs/nfsd/nfsctl.c +@@ -742,13 +742,12 @@ static ssize_t __write_ports_addfd(char *buf, struct net *net, const struct cred + return err; + + err = svc_addsock(nn->nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT, cred); +- if (err < 0 && list_empty(&nn->nfsd_serv->sv_permsocks)) { +- nfsd_put(net); +- return err; +- } + +- /* Decrease the count, but don't shut down the service */ +- nn->nfsd_serv->sv_nrthreads--; ++ if (err >= 0 && ++ !nn->nfsd_serv->sv_nrthreads && !xchg(&nn->keep_active, 1)) ++ svc_get(nn->nfsd_serv); ++ ++ nfsd_put(net); + return err; + } + +@@ -783,8 +782,10 @@ static ssize_t __write_ports_addxprt(char *buf, struct net *net, const struct cr + if (err < 0 && err != -EAFNOSUPPORT) + goto out_close; + +- /* Decrease the count, but don't shut down the service */ +- nn->nfsd_serv->sv_nrthreads--; ++ if (!nn->nfsd_serv->sv_nrthreads && !xchg(&nn->keep_active, 1)) ++ svc_get(nn->nfsd_serv); ++ ++ nfsd_put(net); + return 0; + out_close: + xprt = svc_find_xprt(nn->nfsd_serv, transport, net, PF_INET, port); +@@ -793,10 +794,7 @@ static ssize_t __write_ports_addxprt(char *buf, struct net *net, const struct cr + svc_xprt_put(xprt); + } + out_err: +- if (!list_empty(&nn->nfsd_serv->sv_permsocks)) +- nn->nfsd_serv->sv_nrthreads--; +- else +- nfsd_put(net); ++ nfsd_put(net); + return err; + } + +diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c +index 4aee1cfe0d1bb..141d884fee4f4 100644 +--- a/fs/nfsd/nfssvc.c ++++ b/fs/nfsd/nfssvc.c +@@ -60,13 +60,13 @@ static __be32 nfsd_init_request(struct svc_rqst *, + * extent ->sv_temp_socks and ->sv_permsocks. It also protects nfsdstats.th_cnt + * + * If (out side the lock) nn->nfsd_serv is non-NULL, then it must point to a +- * properly initialised 'struct svc_serv' with ->sv_nrthreads > 0. That number +- * of nfsd threads must exist and each must listed in ->sp_all_threads in each +- * entry of ->sv_pools[]. ++ * properly initialised 'struct svc_serv' with ->sv_nrthreads > 0 (unless ++ * nn->keep_active is set). That number of nfsd threads must ++ * exist and each must be listed in ->sp_all_threads in some entry of ++ * ->sv_pools[]. + * +- * Transitions of the thread count between zero and non-zero are of particular +- * interest since the svc_serv needs to be created and initialized at that +- * point, or freed. ++ * Each active thread holds a counted reference on nn->nfsd_serv, as does ++ * the nn->keep_active flag and various transient calls to svc_get(). + * + * Finally, the nfsd_mutex also protects some of the global variables that are + * accessed when nfsd starts and that are settable via the write_* routines in +@@ -700,14 +700,22 @@ int nfsd_get_nrthreads(int n, int *nthreads, struct net *net) + return 0; + } + ++/* This is the callback for kref_put() below. ++ * There is no code here as the first thing to be done is ++ * call svc_shutdown_net(), but we cannot get the 'net' from ++ * the kref. So do all the work when kref_put returns true. ++ */ ++static void nfsd_noop(struct kref *ref) ++{ ++} ++ + void nfsd_put(struct net *net) + { + struct nfsd_net *nn = net_generic(net, nfsd_net_id); + +- nn->nfsd_serv->sv_nrthreads -= 1; +- if (nn->nfsd_serv->sv_nrthreads == 0) { ++ if (kref_put(&nn->nfsd_serv->sv_refcnt, nfsd_noop)) { + svc_shutdown_net(nn->nfsd_serv, net); +- svc_destroy(nn->nfsd_serv); ++ svc_destroy(&nn->nfsd_serv->sv_refcnt); + nfsd_complete_shutdown(net); + } + } +@@ -803,15 +811,14 @@ nfsd_svc(int nrservs, struct net *net, const struct cred *cred) + NULL, nrservs); + if (error) + goto out_shutdown; +- /* We are holding a reference to nn->nfsd_serv which +- * we don't want to count in the return value, +- * so subtract 1 +- */ +- error = nn->nfsd_serv->sv_nrthreads - 1; ++ error = nn->nfsd_serv->sv_nrthreads; + out_shutdown: + if (error < 0 && !nfsd_up_before) + nfsd_shutdown_net(net); + out_put: ++ /* Threads now hold service active */ ++ if (xchg(&nn->keep_active, 0)) ++ nfsd_put(net); + nfsd_put(net); + out: + mutex_unlock(&nfsd_mutex); +@@ -980,11 +987,15 @@ nfsd(void *vrqstp) + nfsdstats.th_cnt --; + + out: +- rqstp->rq_server = NULL; ++ /* Take an extra ref so that the svc_put in svc_exit_thread() ++ * doesn't call svc_destroy() ++ */ ++ svc_get(nn->nfsd_serv); + + /* Release the thread */ + svc_exit_thread(rqstp); + ++ /* Now if needed we call svc_destroy in appropriate context */ + nfsd_put(net); + + /* Release module */ +@@ -1099,7 +1110,6 @@ int nfsd_pool_stats_open(struct inode *inode, struct file *file) + mutex_unlock(&nfsd_mutex); + return -ENODEV; + } +- /* bump up the psudo refcount while traversing */ + svc_get(nn->nfsd_serv); + ret = svc_pool_stats_open(nn->nfsd_serv, file); + mutex_unlock(&nfsd_mutex); +diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h +index f7b582d3a65ac..6829c4ee36544 100644 +--- a/include/linux/sunrpc/svc.h ++++ b/include/linux/sunrpc/svc.h +@@ -85,6 +85,7 @@ struct svc_serv { + struct svc_program * sv_program; /* RPC program */ + struct svc_stat * sv_stats; /* RPC statistics */ + spinlock_t sv_lock; ++ struct kref sv_refcnt; + unsigned int sv_nrthreads; /* # of server threads */ + unsigned int sv_maxconn; /* max connections allowed or + * '0' causing max to be based +@@ -119,19 +120,14 @@ struct svc_serv { + * @serv: the svc_serv to have count incremented + * + * Returns: the svc_serv that was passed in. +- * +- * We use sv_nrthreads as a reference count. svc_put() drops +- * this refcount, so we need to bump it up around operations that +- * change the number of threads. Horrible, but there it is. +- * Should be called with the "service mutex" held. + */ + static inline struct svc_serv *svc_get(struct svc_serv *serv) + { +- serv->sv_nrthreads++; ++ kref_get(&serv->sv_refcnt); + return serv; + } + +-void svc_destroy(struct svc_serv *serv); ++void svc_destroy(struct kref *); + + /** + * svc_put - decrement reference count on a SUNRPC serv +@@ -142,9 +138,7 @@ void svc_destroy(struct svc_serv *serv); + */ + static inline void svc_put(struct svc_serv *serv) + { +- serv->sv_nrthreads -= 1; +- if (serv->sv_nrthreads == 0) +- svc_destroy(serv); ++ kref_put(&serv->sv_refcnt, svc_destroy); + } + + /* +diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c +index 00d464f6dbe60..19c9d8bf77beb 100644 +--- a/net/sunrpc/svc.c ++++ b/net/sunrpc/svc.c +@@ -433,7 +433,7 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools, + return NULL; + serv->sv_name = prog->pg_name; + serv->sv_program = prog; +- serv->sv_nrthreads = 1; ++ kref_init(&serv->sv_refcnt); + serv->sv_stats = prog->pg_stats; + if (bufsize > RPCSVC_MAXPAYLOAD) + bufsize = RPCSVC_MAXPAYLOAD; +@@ -524,10 +524,11 @@ EXPORT_SYMBOL_GPL(svc_shutdown_net); + * protect the sv_nrthreads, sv_permsocks and sv_tempsocks. + */ + void +-svc_destroy(struct svc_serv *serv) ++svc_destroy(struct kref *ref) + { +- dprintk("svc: svc_destroy(%s)\n", serv->sv_program->pg_name); ++ struct svc_serv *serv = container_of(ref, struct svc_serv, sv_refcnt); + ++ dprintk("svc: svc_destroy(%s)\n", serv->sv_program->pg_name); + del_timer_sync(&serv->sv_temptimer); + + /* +@@ -635,6 +636,7 @@ svc_prepare_thread(struct svc_serv *serv, struct svc_pool *pool, int node) + if (!rqstp) + return ERR_PTR(-ENOMEM); + ++ svc_get(serv); + serv->sv_nrthreads++; + spin_lock_bh(&pool->sp_lock); + pool->sp_nrthreads++; +@@ -774,8 +776,7 @@ int + svc_set_num_threads(struct svc_serv *serv, struct svc_pool *pool, int nrservs) + { + if (pool == NULL) { +- /* The -1 assumes caller has done a svc_get() */ +- nrservs -= (serv->sv_nrthreads-1); ++ nrservs -= serv->sv_nrthreads; + } else { + spin_lock_bh(&pool->sp_lock); + nrservs -= pool->sp_nrthreads; +@@ -816,8 +817,7 @@ int + svc_set_num_threads_sync(struct svc_serv *serv, struct svc_pool *pool, int nrservs) + { + if (pool == NULL) { +- /* The -1 assumes caller has done a svc_get() */ +- nrservs -= (serv->sv_nrthreads-1); ++ nrservs -= serv->sv_nrthreads; + } else { + spin_lock_bh(&pool->sp_lock); + nrservs -= pool->sp_nrthreads; +@@ -881,12 +881,12 @@ svc_exit_thread(struct svc_rqst *rqstp) + list_del_rcu(&rqstp->rq_all); + spin_unlock_bh(&pool->sp_lock); + ++ serv->sv_nrthreads -= 1; ++ svc_sock_update_bufs(serv); ++ + svc_rqst_free(rqstp); + +- if (!serv) +- return; +- svc_sock_update_bufs(serv); +- svc_destroy(serv); ++ svc_put(serv); + } + EXPORT_SYMBOL_GPL(svc_exit_thread); + +-- +2.43.0 + diff --git a/queue-5.10/sunrpc-trace-calls-to-.rpc_call_done.patch b/queue-5.10/sunrpc-trace-calls-to-.rpc_call_done.patch new file mode 100644 index 00000000000..7d2eb7ad30c --- /dev/null +++ b/queue-5.10/sunrpc-trace-calls-to-.rpc_call_done.patch @@ -0,0 +1,153 @@ +From 17a42584c433bc8992be0fba2753ae6ea8c54689 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Sat, 16 Oct 2021 18:02:57 -0400 +Subject: SUNRPC: Trace calls to .rpc_call_done + +From: Chuck Lever + +[ Upstream commit b40887e10dcacc5e8ae3c1a99dcba20877c4831b ] + +Introduce a single tracepoint that can replace simple dprintk call +sites in upper layer "rpc_call_done" callbacks. Example: + + kworker/u24:2-1254 [001] 771.026677: rpc_stats_latency: task:00000001@00000002 xid=0x16a6f3c0 rpcbindv2 GETPORT backlog=446 rtt=101 execute=555 + kworker/u24:2-1254 [001] 771.026677: rpc_task_call_done: task:00000001@00000002 flags=ASYNC|DYNAMIC|SOFT|SOFTCONN|SENT runstate=RUNNING|ACTIVE status=0 action=rpcb_getport_done + kworker/u24:2-1254 [001] 771.026678: rpcb_setport: task:00000001@00000002 status=0 port=20048 + +Signed-off-by: Chuck Lever +Signed-off-by: Trond Myklebust +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/lockd/clntproc.c | 3 --- + fs/lockd/svc4proc.c | 2 -- + fs/lockd/svcproc.c | 2 -- + fs/nfs/filelayout/filelayout.c | 2 -- + fs/nfs/flexfilelayout/flexfilelayout.c | 2 -- + fs/nfs/pagelist.c | 3 --- + fs/nfs/write.c | 3 --- + include/trace/events/sunrpc.h | 1 + + net/sunrpc/sched.c | 1 + + 9 files changed, 2 insertions(+), 17 deletions(-) + +diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c +index b11f2afa84f1f..99fffc9cb9585 100644 +--- a/fs/lockd/clntproc.c ++++ b/fs/lockd/clntproc.c +@@ -794,9 +794,6 @@ static void nlmclnt_cancel_callback(struct rpc_task *task, void *data) + goto retry_cancel; + } + +- dprintk("lockd: cancel status %u (task %u)\n", +- status, task->tk_pid); +- + switch (status) { + case NLM_LCK_GRANTED: + case NLM_LCK_DENIED_GRACE_PERIOD: +diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c +index e10ae2c41279e..176b468a61c75 100644 +--- a/fs/lockd/svc4proc.c ++++ b/fs/lockd/svc4proc.c +@@ -269,8 +269,6 @@ nlm4svc_proc_granted(struct svc_rqst *rqstp) + */ + static void nlm4svc_callback_exit(struct rpc_task *task, void *data) + { +- dprintk("lockd: %5u callback returned %d\n", task->tk_pid, +- -task->tk_status); + } + + static void nlm4svc_callback_release(void *data) +diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c +index 99696d3f6dd66..4dc1b40a489a2 100644 +--- a/fs/lockd/svcproc.c ++++ b/fs/lockd/svcproc.c +@@ -301,8 +301,6 @@ nlmsvc_proc_granted(struct svc_rqst *rqstp) + */ + static void nlmsvc_callback_exit(struct rpc_task *task, void *data) + { +- dprintk("lockd: %5u callback returned %d\n", task->tk_pid, +- -task->tk_status); + } + + void nlmsvc_release_call(struct nlm_rqst *call) +diff --git a/fs/nfs/filelayout/filelayout.c b/fs/nfs/filelayout/filelayout.c +index 45eec08ec904f..2ed8b6885b091 100644 +--- a/fs/nfs/filelayout/filelayout.c ++++ b/fs/nfs/filelayout/filelayout.c +@@ -293,8 +293,6 @@ static void filelayout_read_call_done(struct rpc_task *task, void *data) + { + struct nfs_pgio_header *hdr = data; + +- dprintk("--> %s task->tk_status %d\n", __func__, task->tk_status); +- + if (test_bit(NFS_IOHDR_REDO, &hdr->flags) && + task->tk_status == 0) { + nfs41_sequence_done(task, &hdr->res.seq_res); +diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c +index f2ae271fe7ec7..a263bfec4244d 100644 +--- a/fs/nfs/flexfilelayout/flexfilelayout.c ++++ b/fs/nfs/flexfilelayout/flexfilelayout.c +@@ -1419,8 +1419,6 @@ static void ff_layout_read_call_done(struct rpc_task *task, void *data) + { + struct nfs_pgio_header *hdr = data; + +- dprintk("--> %s task->tk_status %d\n", __func__, task->tk_status); +- + if (test_bit(NFS_IOHDR_REDO, &hdr->flags) && + task->tk_status == 0) { + nfs4_sequence_done(task, &hdr->res.seq_res); +diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c +index 17fef6eb490c5..d79a3b6cb0701 100644 +--- a/fs/nfs/pagelist.c ++++ b/fs/nfs/pagelist.c +@@ -870,9 +870,6 @@ static void nfs_pgio_result(struct rpc_task *task, void *calldata) + struct nfs_pgio_header *hdr = calldata; + struct inode *inode = hdr->inode; + +- dprintk("NFS: %s: %5u, (status %d)\n", __func__, +- task->tk_pid, task->tk_status); +- + if (hdr->rw_ops->rw_done(task, hdr, inode) != 0) + return; + if (task->tk_status < 0) +diff --git a/fs/nfs/write.c b/fs/nfs/write.c +index 4cf0606919794..2bde35921f2b2 100644 +--- a/fs/nfs/write.c ++++ b/fs/nfs/write.c +@@ -1809,9 +1809,6 @@ static void nfs_commit_done(struct rpc_task *task, void *calldata) + { + struct nfs_commit_data *data = calldata; + +- dprintk("NFS: %5u nfs_commit_done (status %d)\n", +- task->tk_pid, task->tk_status); +- + /* Call the NFS version-specific code */ + NFS_PROTO(data->inode)->commit_done(task, data); + trace_nfs_commit_done(task, data); +diff --git a/include/trace/events/sunrpc.h b/include/trace/events/sunrpc.h +index fce071f39f51f..56e4a57d25382 100644 +--- a/include/trace/events/sunrpc.h ++++ b/include/trace/events/sunrpc.h +@@ -394,6 +394,7 @@ DEFINE_RPC_RUNNING_EVENT(complete); + DEFINE_RPC_RUNNING_EVENT(timeout); + DEFINE_RPC_RUNNING_EVENT(signalled); + DEFINE_RPC_RUNNING_EVENT(end); ++DEFINE_RPC_RUNNING_EVENT(call_done); + + DECLARE_EVENT_CLASS(rpc_task_queued, + +diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c +index a00890962e115..a4c9d410eb8d5 100644 +--- a/net/sunrpc/sched.c ++++ b/net/sunrpc/sched.c +@@ -821,6 +821,7 @@ void rpc_exit_task(struct rpc_task *task) + else if (task->tk_client) + rpc_count_iostats(task, task->tk_client->cl_metrics); + if (task->tk_ops->rpc_call_done != NULL) { ++ trace_rpc_task_call_done(task, task->tk_ops->rpc_call_done); + task->tk_ops->rpc_call_done(task, task->tk_calldata); + if (task->tk_action != NULL) { + /* Always release the RPC slot and buffer memory */ +-- +2.43.0 + diff --git a/queue-5.10/sunrpc-use-rmw-bitops-in-single-threaded-hot-paths.patch b/queue-5.10/sunrpc-use-rmw-bitops-in-single-threaded-hot-paths.patch new file mode 100644 index 00000000000..01ebe78b6c8 --- /dev/null +++ b/queue-5.10/sunrpc-use-rmw-bitops-in-single-threaded-hot-paths.patch @@ -0,0 +1,173 @@ +From 3cf0997c71e93359510fa51a72d34184485aaf8c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 29 Apr 2022 10:06:21 -0400 +Subject: SUNRPC: Use RMW bitops in single-threaded hot paths + +From: Chuck Lever + +[ Upstream commit 28df0988815f63e2af5e6718193c9f68681ad7ff ] + +I noticed CPU pipeline stalls while using perf. + +Once an svc thread is scheduled and executing an RPC, no other +processes will touch svc_rqst::rq_flags. Thus bus-locked atomics are +not needed outside the svc thread scheduler. + +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfs4proc.c | 7 ++++--- + fs/nfsd/nfs4xdr.c | 2 +- + net/sunrpc/auth_gss/svcauth_gss.c | 4 ++-- + net/sunrpc/svc.c | 6 +++--- + net/sunrpc/svc_xprt.c | 2 +- + net/sunrpc/svcsock.c | 8 ++++---- + net/sunrpc/xprtrdma/svc_rdma_transport.c | 2 +- + 7 files changed, 16 insertions(+), 15 deletions(-) + +diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c +index d62d962ed2f13..adbac1e77e9e2 100644 +--- a/fs/nfsd/nfs4proc.c ++++ b/fs/nfsd/nfs4proc.c +@@ -970,7 +970,7 @@ nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, + * the client wants us to do more in this compound: + */ + if (!nfsd4_last_compound_op(rqstp)) +- clear_bit(RQ_SPLICE_OK, &rqstp->rq_flags); ++ __clear_bit(RQ_SPLICE_OK, &rqstp->rq_flags); + + /* check stateid */ + status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh, +@@ -2642,11 +2642,12 @@ nfsd4_proc_compound(struct svc_rqst *rqstp) + cstate->minorversion = args->minorversion; + fh_init(current_fh, NFS4_FHSIZE); + fh_init(save_fh, NFS4_FHSIZE); ++ + /* + * Don't use the deferral mechanism for NFSv4; compounds make it + * too hard to avoid non-idempotency problems. + */ +- clear_bit(RQ_USEDEFERRAL, &rqstp->rq_flags); ++ __clear_bit(RQ_USEDEFERRAL, &rqstp->rq_flags); + + /* + * According to RFC3010, this takes precedence over all other errors. +@@ -2761,7 +2762,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp) + out: + cstate->status = status; + /* Reset deferral mechanism for RPC deferrals */ +- set_bit(RQ_USEDEFERRAL, &rqstp->rq_flags); ++ __set_bit(RQ_USEDEFERRAL, &rqstp->rq_flags); + return rpc_success; + } + +diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c +index a9f6c7eeb756e..804c137fabec5 100644 +--- a/fs/nfsd/nfs4xdr.c ++++ b/fs/nfsd/nfs4xdr.c +@@ -2411,7 +2411,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) + argp->rqstp->rq_cachetype = cachethis ? RC_REPLBUFF : RC_NOCACHE; + + if (readcount > 1 || max_reply > PAGE_SIZE - auth_slack) +- clear_bit(RQ_SPLICE_OK, &argp->rqstp->rq_flags); ++ __clear_bit(RQ_SPLICE_OK, &argp->rqstp->rq_flags); + + return true; + } +diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c +index 329eac782cc5e..abaa952ae7518 100644 +--- a/net/sunrpc/auth_gss/svcauth_gss.c ++++ b/net/sunrpc/auth_gss/svcauth_gss.c +@@ -898,7 +898,7 @@ unwrap_integ_data(struct svc_rqst *rqstp, struct xdr_buf *buf, u32 seq, struct g + * rejecting the server-computed MIC in this somewhat rare case, + * do not use splice with the GSS integrity service. + */ +- clear_bit(RQ_SPLICE_OK, &rqstp->rq_flags); ++ __clear_bit(RQ_SPLICE_OK, &rqstp->rq_flags); + + /* Did we already verify the signature on the original pass through? */ + if (rqstp->rq_deferred) +@@ -970,7 +970,7 @@ unwrap_priv_data(struct svc_rqst *rqstp, struct xdr_buf *buf, u32 seq, struct gs + int pad, remaining_len, offset; + u32 rseqno; + +- clear_bit(RQ_SPLICE_OK, &rqstp->rq_flags); ++ __clear_bit(RQ_SPLICE_OK, &rqstp->rq_flags); + + priv_len = svc_getnl(&buf->head[0]); + if (rqstp->rq_deferred) { +diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c +index 7f231947347ea..9caaed1c143e6 100644 +--- a/net/sunrpc/svc.c ++++ b/net/sunrpc/svc.c +@@ -1276,10 +1276,10 @@ svc_process_common(struct svc_rqst *rqstp, struct kvec *argv, struct kvec *resv) + goto err_short_len; + + /* Will be turned off by GSS integrity and privacy services */ +- set_bit(RQ_SPLICE_OK, &rqstp->rq_flags); ++ __set_bit(RQ_SPLICE_OK, &rqstp->rq_flags); + /* Will be turned off only when NFSv4 Sessions are used */ +- set_bit(RQ_USEDEFERRAL, &rqstp->rq_flags); +- clear_bit(RQ_DROPME, &rqstp->rq_flags); ++ __set_bit(RQ_USEDEFERRAL, &rqstp->rq_flags); ++ __clear_bit(RQ_DROPME, &rqstp->rq_flags); + + svc_putu32(resv, rqstp->rq_xid); + +diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c +index 000b737784bd9..ea65036dc5068 100644 +--- a/net/sunrpc/svc_xprt.c ++++ b/net/sunrpc/svc_xprt.c +@@ -1228,7 +1228,7 @@ static struct cache_deferred_req *svc_defer(struct cache_req *req) + trace_svc_defer(rqstp); + svc_xprt_get(rqstp->rq_xprt); + dr->xprt = rqstp->rq_xprt; +- set_bit(RQ_DROPME, &rqstp->rq_flags); ++ __set_bit(RQ_DROPME, &rqstp->rq_flags); + + dr->handle.revisit = svc_revisit; + return &dr->handle; +diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c +index 90f6231d6ed67..ff8dcebbdfc4e 100644 +--- a/net/sunrpc/svcsock.c ++++ b/net/sunrpc/svcsock.c +@@ -309,9 +309,9 @@ static void svc_sock_setbufsize(struct svc_sock *svsk, unsigned int nreqs) + static void svc_sock_secure_port(struct svc_rqst *rqstp) + { + if (svc_port_is_privileged(svc_addr(rqstp))) +- set_bit(RQ_SECURE, &rqstp->rq_flags); ++ __set_bit(RQ_SECURE, &rqstp->rq_flags); + else +- clear_bit(RQ_SECURE, &rqstp->rq_flags); ++ __clear_bit(RQ_SECURE, &rqstp->rq_flags); + } + + /* +@@ -1014,9 +1014,9 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp) + rqstp->rq_xprt_ctxt = NULL; + rqstp->rq_prot = IPPROTO_TCP; + if (test_bit(XPT_LOCAL, &svsk->sk_xprt.xpt_flags)) +- set_bit(RQ_LOCAL, &rqstp->rq_flags); ++ __set_bit(RQ_LOCAL, &rqstp->rq_flags); + else +- clear_bit(RQ_LOCAL, &rqstp->rq_flags); ++ __clear_bit(RQ_LOCAL, &rqstp->rq_flags); + + p = (__be32 *)rqstp->rq_arg.head[0].iov_base; + calldir = p[1]; +diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c +index c895f80df659c..e72e36989985f 100644 +--- a/net/sunrpc/xprtrdma/svc_rdma_transport.c ++++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c +@@ -606,7 +606,7 @@ static int svc_rdma_has_wspace(struct svc_xprt *xprt) + + static void svc_rdma_secure_port(struct svc_rqst *rqstp) + { +- set_bit(RQ_SECURE, &rqstp->rq_flags); ++ __set_bit(RQ_SECURE, &rqstp->rq_flags); + } + + static void svc_rdma_kill_temp_xprt(struct svc_xprt *xprt) +-- +2.43.0 + diff --git a/queue-5.10/sunrpc-use-sv_lock-to-protect-updates-to-sv_nrthread.patch b/queue-5.10/sunrpc-use-sv_lock-to-protect-updates-to-sv_nrthread.patch new file mode 100644 index 00000000000..47e6f9fac41 --- /dev/null +++ b/queue-5.10/sunrpc-use-sv_lock-to-protect-updates-to-sv_nrthread.patch @@ -0,0 +1,81 @@ +From e1ebac03eb114bfd20493248dd9b736069d1b24d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 29 Nov 2021 15:51:25 +1100 +Subject: SUNRPC: use sv_lock to protect updates to sv_nrthreads. + +From: NeilBrown + +[ Upstream commit 2a36395fac3b72771f87c3ee4387e3a96d85a7cc ] + +Using sv_lock means we don't need to hold the service mutex over these +updates. + +In particular, svc_exit_thread() no longer requires synchronisation, so +threads can exit asynchronously. + +Note that we could use an atomic_t, but as there are many more read +sites than writes, that would add unnecessary noise to the code. +Some reads are already racy, and there is no need for them to not be. + +Signed-off-by: NeilBrown +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + fs/nfsd/nfssvc.c | 5 ++--- + net/sunrpc/svc.c | 9 +++++++-- + 2 files changed, 9 insertions(+), 5 deletions(-) + +diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c +index 32f2c46a38323..16884a90e1ab0 100644 +--- a/fs/nfsd/nfssvc.c ++++ b/fs/nfsd/nfssvc.c +@@ -55,9 +55,8 @@ static __be32 nfsd_init_request(struct svc_rqst *, + struct svc_process_info *); + + /* +- * nfsd_mutex protects nn->nfsd_serv -- both the pointer itself and the members +- * of the svc_serv struct. In particular, ->sv_nrthreads but also to some +- * extent ->sv_temp_socks and ->sv_permsocks. ++ * nfsd_mutex protects nn->nfsd_serv -- both the pointer itself and some members ++ * of the svc_serv struct such as ->sv_temp_socks and ->sv_permsocks. + * + * If (out side the lock) nn->nfsd_serv is non-NULL, then it must point to a + * properly initialised 'struct svc_serv' with ->sv_nrthreads > 0 (unless +diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c +index 19c9d8bf77beb..283088f3215e6 100644 +--- a/net/sunrpc/svc.c ++++ b/net/sunrpc/svc.c +@@ -521,7 +521,7 @@ EXPORT_SYMBOL_GPL(svc_shutdown_net); + + /* + * Destroy an RPC service. Should be called with appropriate locking to +- * protect the sv_nrthreads, sv_permsocks and sv_tempsocks. ++ * protect sv_permsocks and sv_tempsocks. + */ + void + svc_destroy(struct kref *ref) +@@ -637,7 +637,10 @@ svc_prepare_thread(struct svc_serv *serv, struct svc_pool *pool, int node) + return ERR_PTR(-ENOMEM); + + svc_get(serv); +- serv->sv_nrthreads++; ++ spin_lock_bh(&serv->sv_lock); ++ serv->sv_nrthreads += 1; ++ spin_unlock_bh(&serv->sv_lock); ++ + spin_lock_bh(&pool->sp_lock); + pool->sp_nrthreads++; + list_add_rcu(&rqstp->rq_all, &pool->sp_all_threads); +@@ -881,7 +884,9 @@ svc_exit_thread(struct svc_rqst *rqstp) + list_del_rcu(&rqstp->rq_all); + spin_unlock_bh(&pool->sp_lock); + ++ spin_lock_bh(&serv->sv_lock); + serv->sv_nrthreads -= 1; ++ spin_unlock_bh(&serv->sv_lock); + svc_sock_update_bufs(serv); + + svc_rqst_free(rqstp); +-- +2.43.0 + diff --git a/queue-5.10/sysctl-introduce-new-proc-handler-proc_dobool.patch b/queue-5.10/sysctl-introduce-new-proc-handler-proc_dobool.patch new file mode 100644 index 00000000000..59e102f3873 --- /dev/null +++ b/queue-5.10/sysctl-introduce-new-proc-handler-proc_dobool.patch @@ -0,0 +1,114 @@ +From bbf31a200888318ee55f83362148ad4511f3408c Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 3 Aug 2021 12:59:36 +0200 +Subject: sysctl: introduce new proc handler proc_dobool + +From: Jia He + +[ Upstream commit a2071573d6346819cc4e5787b4206f2184985160 ] + +This is to let bool variable could be correctly displayed in +big/little endian sysctl procfs. sizeof(bool) is arch dependent, +proc_dobool should work in all arches. + +Suggested-by: Pan Xinhui +Signed-off-by: Jia He +[thuth: rebased the patch to the current kernel version] +Signed-off-by: Thomas Huth +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + include/linux/sysctl.h | 2 ++ + kernel/sysctl.c | 42 ++++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 44 insertions(+) + +diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h +index c202a72e16906..47cf70c8eb93c 100644 +--- a/include/linux/sysctl.h ++++ b/include/linux/sysctl.h +@@ -55,6 +55,8 @@ typedef int proc_handler(struct ctl_table *ctl, int write, void *buffer, + size_t *lenp, loff_t *ppos); + + int proc_dostring(struct ctl_table *, int, void *, size_t *, loff_t *); ++int proc_dobool(struct ctl_table *table, int write, void *buffer, ++ size_t *lenp, loff_t *ppos); + int proc_dointvec(struct ctl_table *, int, void *, size_t *, loff_t *); + int proc_douintvec(struct ctl_table *, int, void *, size_t *, loff_t *); + int proc_dointvec_minmax(struct ctl_table *, int, void *, size_t *, loff_t *); +diff --git a/kernel/sysctl.c b/kernel/sysctl.c +index b29a9568ebbe4..abe0f16d53641 100644 +--- a/kernel/sysctl.c ++++ b/kernel/sysctl.c +@@ -546,6 +546,21 @@ static void proc_put_char(void **buf, size_t *size, char c) + } + } + ++static int do_proc_dobool_conv(bool *negp, unsigned long *lvalp, ++ int *valp, ++ int write, void *data) ++{ ++ if (write) { ++ *(bool *)valp = *lvalp; ++ } else { ++ int val = *(bool *)valp; ++ ++ *lvalp = (unsigned long)val; ++ *negp = false; ++ } ++ return 0; ++} ++ + static int do_proc_dointvec_conv(bool *negp, unsigned long *lvalp, + int *valp, + int write, void *data) +@@ -808,6 +823,26 @@ static int do_proc_douintvec(struct ctl_table *table, int write, + buffer, lenp, ppos, conv, data); + } + ++/** ++ * proc_dobool - read/write a bool ++ * @table: the sysctl table ++ * @write: %TRUE if this is a write to the sysctl file ++ * @buffer: the user buffer ++ * @lenp: the size of the user buffer ++ * @ppos: file position ++ * ++ * Reads/writes up to table->maxlen/sizeof(unsigned int) integer ++ * values from/to the user buffer, treated as an ASCII string. ++ * ++ * Returns 0 on success. ++ */ ++int proc_dobool(struct ctl_table *table, int write, void *buffer, ++ size_t *lenp, loff_t *ppos) ++{ ++ return do_proc_dointvec(table, write, buffer, lenp, ppos, ++ do_proc_dobool_conv, NULL); ++} ++ + /** + * proc_dointvec - read a vector of integers + * @table: the sysctl table +@@ -1644,6 +1679,12 @@ int proc_dostring(struct ctl_table *table, int write, + return -ENOSYS; + } + ++int proc_dobool(struct ctl_table *table, int write, ++ void *buffer, size_t *lenp, loff_t *ppos) ++{ ++ return -ENOSYS; ++} ++ + int proc_dointvec(struct ctl_table *table, int write, + void *buffer, size_t *lenp, loff_t *ppos) + { +@@ -3503,6 +3544,7 @@ int __init sysctl_init(void) + * No sense putting this after each symbol definition, twice, + * exception granted :-) + */ ++EXPORT_SYMBOL(proc_dobool); + EXPORT_SYMBOL(proc_dointvec); + EXPORT_SYMBOL(proc_douintvec); + EXPORT_SYMBOL(proc_dointvec_jiffies); +-- +2.43.0 + diff --git a/queue-5.10/uapi-nfsfh.h-replace-one-element-array-with-flexible.patch b/queue-5.10/uapi-nfsfh.h-replace-one-element-array-with-flexible.patch new file mode 100644 index 00000000000..1c108301958 --- /dev/null +++ b/queue-5.10/uapi-nfsfh.h-replace-one-element-array-with-flexible.patch @@ -0,0 +1,132 @@ +From 1718a70f54bc92ba3e0fb23a5be87f207ff4d8fa Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 23 Mar 2021 17:48:58 -0500 +Subject: UAPI: nfsfh.h: Replace one-element array with flexible-array member +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Gustavo A. R. Silva + +[ Upstream commit c0a744dcaa29e9537e8607ae9c965ad936124a4d ] + +There is a regular need in the kernel to provide a way to declare having +a dynamically sized set of trailing elements in a structure. Kernel code +should always use “flexible array members”[1] for these cases. The older +style of one-element or zero-length arrays should no longer be used[2]. + +Use an anonymous union with a couple of anonymous structs in order to +keep userspace unchanged: + +$ pahole -C nfs_fhbase_new fs/nfsd/nfsfh.o +struct nfs_fhbase_new { + union { + struct { + __u8 fb_version_aux; /* 0 1 */ + __u8 fb_auth_type_aux; /* 1 1 */ + __u8 fb_fsid_type_aux; /* 2 1 */ + __u8 fb_fileid_type_aux; /* 3 1 */ + __u32 fb_auth[1]; /* 4 4 */ + }; /* 0 8 */ + struct { + __u8 fb_version; /* 0 1 */ + __u8 fb_auth_type; /* 1 1 */ + __u8 fb_fsid_type; /* 2 1 */ + __u8 fb_fileid_type; /* 3 1 */ + __u32 fb_auth_flex[0]; /* 4 0 */ + }; /* 0 4 */ + }; /* 0 8 */ + + /* size: 8, cachelines: 1, members: 1 */ + /* last cacheline: 8 bytes */ +}; + +Also, this helps with the ongoing efforts to enable -Warray-bounds by +fixing the following warnings: + +fs/nfsd/nfsfh.c: In function ‘nfsd_set_fh_dentry’: +fs/nfsd/nfsfh.c:191:41: warning: array subscript 1 is above array bounds of ‘__u32[1]’ {aka ‘unsigned int[1]’} [-Warray-bounds] + 191 | ntohl((__force __be32)fh->fh_fsid[1]))); + | ~~~~~~~~~~~^~~ +./include/linux/kdev_t.h:12:46: note: in definition of macro ‘MKDEV’ + 12 | #define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi)) + | ^~ +./include/uapi/linux/byteorder/little_endian.h:40:26: note: in expansion of macro ‘__swab32’ + 40 | #define __be32_to_cpu(x) __swab32((__force __u32)(__be32)(x)) + | ^~~~~~~~ +./include/linux/byteorder/generic.h:136:21: note: in expansion of macro ‘__be32_to_cpu’ + 136 | #define ___ntohl(x) __be32_to_cpu(x) + | ^~~~~~~~~~~~~ +./include/linux/byteorder/generic.h:140:18: note: in expansion of macro ‘___ntohl’ + 140 | #define ntohl(x) ___ntohl(x) + | ^~~~~~~~ +fs/nfsd/nfsfh.c:191:8: note: in expansion of macro ‘ntohl’ + 191 | ntohl((__force __be32)fh->fh_fsid[1]))); + | ^~~~~ +fs/nfsd/nfsfh.c:192:32: warning: array subscript 2 is above array bounds of ‘__u32[1]’ {aka ‘unsigned int[1]’} [-Warray-bounds] + 192 | fh->fh_fsid[1] = fh->fh_fsid[2]; + | ~~~~~~~~~~~^~~ +fs/nfsd/nfsfh.c:192:15: warning: array subscript 1 is above array bounds of ‘__u32[1]’ {aka ‘unsigned int[1]’} [-Warray-bounds] + 192 | fh->fh_fsid[1] = fh->fh_fsid[2]; + | ~~~~~~~~~~~^~~ + +[1] https://en.wikipedia.org/wiki/Flexible_array_member +[2] https://www.kernel.org/doc/html/v5.10/process/deprecated.html#zero-length-and-one-element-arrays + +Link: https://github.com/KSPP/linux/issues/79 +Link: https://github.com/KSPP/linux/issues/109 +Signed-off-by: Gustavo A. R. Silva +Signed-off-by: Chuck Lever +Signed-off-by: Sasha Levin +--- + include/uapi/linux/nfsd/nfsfh.h | 27 +++++++++++++++++++-------- + 1 file changed, 19 insertions(+), 8 deletions(-) + +diff --git a/include/uapi/linux/nfsd/nfsfh.h b/include/uapi/linux/nfsd/nfsfh.h +index ff0ca88b1c8f6..427294dd56a1b 100644 +--- a/include/uapi/linux/nfsd/nfsfh.h ++++ b/include/uapi/linux/nfsd/nfsfh.h +@@ -64,13 +64,24 @@ struct nfs_fhbase_old { + * in include/linux/exportfs.h for currently registered values. + */ + struct nfs_fhbase_new { +- __u8 fb_version; /* == 1, even => nfs_fhbase_old */ +- __u8 fb_auth_type; +- __u8 fb_fsid_type; +- __u8 fb_fileid_type; +- __u32 fb_auth[1]; +-/* __u32 fb_fsid[0]; floating */ +-/* __u32 fb_fileid[0]; floating */ ++ union { ++ struct { ++ __u8 fb_version_aux; /* == 1, even => nfs_fhbase_old */ ++ __u8 fb_auth_type_aux; ++ __u8 fb_fsid_type_aux; ++ __u8 fb_fileid_type_aux; ++ __u32 fb_auth[1]; ++ /* __u32 fb_fsid[0]; floating */ ++ /* __u32 fb_fileid[0]; floating */ ++ }; ++ struct { ++ __u8 fb_version; /* == 1, even => nfs_fhbase_old */ ++ __u8 fb_auth_type; ++ __u8 fb_fsid_type; ++ __u8 fb_fileid_type; ++ __u32 fb_auth_flex[]; /* flexible-array member */ ++ }; ++ }; + }; + + struct knfsd_fh { +@@ -97,7 +108,7 @@ struct knfsd_fh { + #define fh_fsid_type fh_base.fh_new.fb_fsid_type + #define fh_auth_type fh_base.fh_new.fb_auth_type + #define fh_fileid_type fh_base.fh_new.fb_fileid_type +-#define fh_fsid fh_base.fh_new.fb_auth ++#define fh_fsid fh_base.fh_new.fb_auth_flex + + /* Do not use, provided for userspace compatiblity. */ + #define fh_auth fh_base.fh_new.fb_auth +-- +2.43.0 + -- 2.47.3