Pull NFS client updates from Trond Myklebust: "Bugfixes: - Fix 'nlink' attribute update races when unlinking a file - Add missing initialisers for the directory verifier in various places - Don't regress the NFSv4 open state due to misordered racing replies - Ensure the NFSv4.x callback server uses the correct transport connection - Fix potential use-after-free races when shutting down the NFSv4.x callback server - Fix a pNFS layout commit crash - Assorted fixes to ensure correct propagation of mount options when the client crosses a filesystem boundary and triggers the VFS automount code - More localio fixes Features and cleanups: - Add initial support for basic directory delegations - SunRPC back channel code cleanups" * tag 'nfs-for-6.19-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: (24 commits) NFSv4: Handle NFS4ERR_NOTSUPP errors for directory delegations nfs/localio: remove 61 byte hole from needless ____cacheline_aligned nfs/localio: remove alignment size checking in nfs_is_local_dio_possible NFS: Fix up the automount fs_context to use the correct cred NFS: Fix inheritance of the block sizes when automounting NFS: Automounted filesystems should inherit ro,noexec,nodev,sync flags Revert "nfs: ignore SB_RDONLY when mounting nfs" Revert "nfs: clear SB_RDONLY before getting superblock" Revert "nfs: ignore SB_RDONLY when remounting nfs" NFS: Add a module option to disable directory delegations NFS: Shortcut lookup revalidations if we have a directory delegation NFS: Request a directory delegation during RENAME NFS: Request a directory delegation on ACCESS, CREATE, and UNLINK NFS: Add support for sending GDD_GETATTR NFSv4/pNFS: Clear NFS_INO_LAYOUTCOMMIT in pnfs_mark_layout_stateid_invalid NFSv4.1: protect destroying and nullifying bc_serv structure SUNRPC: new helper function for stopping backchannel server SUNRPC: cleanup common code in backchannel request NFSv4.1: pass transport for callback shutdown NFSv4: ensure the open stateid seqid doesn't go backwards ...
Unified · Split
| @@ -258,7 +258,7 @@ err_start: · 257 unmodified lines | ||
| 258 | 258 | /* |
| 259 | 259 | * Kill the callback thread if it's no longer being used. |
| 260 | 260 | */ |
| 261 | −void nfs_callback_down(int minorversion, struct net *net) | |
| 261 | +void nfs_callback_down(int minorversion, struct net *net, struct rpc_xprt *xprt) | |
| 262 | 262 | { |
| 263 | 263 | struct nfs_callback_data *cb_info = &nfs_callback_info[minorversion]; |
| 264 | 264 | struct svc_serv *serv; |
| @@ -270,7 +270,7 @@ void nfs_callback_down(int minorversion, struct net *net) · 5 unmodified lines | ||
| 270 | 270 | if (cb_info->users == 0) { |
| 271 | 271 | svc_set_num_threads(serv, NULL, 0); |
| 272 | 272 | dprintk("nfs_callback_down: service destroyed\n"); |
| 273 | − svc_destroy(&cb_info->serv); | |
| 273 | + xprt_svc_destroy_nullify_bc(xprt, &cb_info->serv); | |
| 274 | 274 | } |
| 275 | 275 | mutex_unlock(&nfs_callback_mutex); |
| 276 | 276 | } |
| @@ -188,7 +188,8 @@ extern __be32 nfs4_callback_recall(void *argp, void *resp, · 187 unmodified lines | ||
| 188 | 188 | struct cb_process_state *cps); |
| 189 | 189 | #if IS_ENABLED(CONFIG_NFS_V4) |
| 190 | 190 | extern int nfs_callback_up(u32 minorversion, struct rpc_xprt *xprt); |
| 191 | −extern void nfs_callback_down(int minorversion, struct net *net); | |
| 191 | +extern void nfs_callback_down(int minorversion, struct net *net, | |
| 192 | + struct rpc_xprt *xprt); | |
| 192 | 193 | #endif /* CONFIG_NFS_V4 */ |
| 193 | 194 | /* |
| 194 | 195 | * nfs41: Callbacks are expected to not cause substantial latency, |
| @@ -784,10 +784,18 @@ static int nfs_init_server(struct nfs_server *server, · 783 unmodified lines | ||
| 784 | 784 | server->fattr_valid = NFS_ATTR_FATTR_V4; |
| 785 | 785 | } |
| 786 | 786 | |
| 787 | − if (ctx->rsize) | |
| 787 | + if (ctx->bsize) { | |
| 788 | + server->bsize = ctx->bsize; | |
| 789 | + server->automount_inherit |= NFS_AUTOMOUNT_INHERIT_BSIZE; | |
| 790 | + } | |
| 791 | + if (ctx->rsize) { | |
| 788 | 792 | server->rsize = nfs_io_size(ctx->rsize, clp->cl_proto); |
| 789 | − if (ctx->wsize) | |
| 793 | + server->automount_inherit |= NFS_AUTOMOUNT_INHERIT_RSIZE; | |
| 794 | + } | |
| 795 | + if (ctx->wsize) { | |
| 790 | 796 | server->wsize = nfs_io_size(ctx->wsize, clp->cl_proto); |
| 797 | + server->automount_inherit |= NFS_AUTOMOUNT_INHERIT_WSIZE; | |
| 798 | + } | |
| 791 | 799 | |
| 792 | 800 | server->acregmin = ctx->acregmin * HZ; |
| 793 | 801 | server->acregmax = ctx->acregmax * HZ; |
| @@ -977,8 +985,13 @@ EXPORT_SYMBOL_GPL(nfs_probe_server); · 183 unmodified lines | ||
| 977 | 985 | void nfs_server_copy_userdata(struct nfs_server *target, struct nfs_server *source) |
| 978 | 986 | { |
| 979 | 987 | target->flags = source->flags; |
| 980 | − target->rsize = source->rsize; | |
| 981 | − target->wsize = source->wsize; | |
| 988 | + target->automount_inherit = source->automount_inherit; | |
| 989 | + if (source->automount_inherit & NFS_AUTOMOUNT_INHERIT_BSIZE) | |
| 990 | + target->bsize = source->bsize; | |
| 991 | + if (source->automount_inherit & NFS_AUTOMOUNT_INHERIT_RSIZE) | |
| 992 | + target->rsize = source->rsize; | |
| 993 | + if (source->automount_inherit & NFS_AUTOMOUNT_INHERIT_WSIZE) | |
| 994 | + target->wsize = source->wsize; | |
| 982 | 995 | target->acregmin = source->acregmin; |
| 983 | 996 | target->acregmax = source->acregmax; |
| 984 | 997 | target->acdirmin = source->acdirmin; |
| @@ -30,6 +30,11 @@ · 29 unmodified lines | ||
| 30 | 30 | static unsigned nfs_delegation_watermark = NFS_DEFAULT_DELEGATION_WATERMARK; |
| 31 | 31 | module_param_named(delegation_watermark, nfs_delegation_watermark, uint, 0644); |
| 32 | 32 | |
| 33 | +bool directory_delegations = true; | |
| 34 | +module_param(directory_delegations, bool, 0644); | |
| 35 | +MODULE_PARM_DESC(directory_delegations, | |
| 36 | + "Enable the use of directory delegations, defaults to on."); | |
| 37 | + | |
| 33 | 38 | static struct hlist_head *nfs_delegation_hash(struct nfs_server *server, |
| 34 | 39 | const struct nfs_fh *fhandle) |
| 35 | 40 | { |
| @@ -143,6 +148,8 @@ static int nfs4_do_check_delegation(struct inode *inode, fmode_t type, · 107 unmodified lines | ||
| 143 | 148 | */ |
| 144 | 149 | int nfs4_have_delegation(struct inode *inode, fmode_t type, int flags) |
| 145 | 150 | { |
| 151 | + if (S_ISDIR(inode->i_mode) && !directory_delegations) | |
| 152 | + nfs_inode_evict_delegation(inode); | |
| 146 | 153 | return nfs4_do_check_delegation(inode, type, flags, true); |
| 147 | 154 | } |
| 148 | 155 | |
| @@ -379,6 +386,7 @@ nfs_detach_delegation_locked(struct nfs_inode *nfsi, · 230 unmodified lines | ||
| 379 | 386 | delegation->inode = NULL; |
| 380 | 387 | rcu_assign_pointer(nfsi->delegation, NULL); |
| 381 | 388 | spin_unlock(&delegation->lock); |
| 389 | + clear_bit(NFS_INO_REQ_DIR_DELEG, &nfsi->flags); | |
| 382 | 390 | return delegation; |
| 383 | 391 | } |
| 384 | 392 | |
| @@ -124,6 +124,19 @@ static inline int nfs_have_delegated_mtime(struct inode *inode) · 123 unmodified lines | ||
| 124 | 124 | NFS_DELEGATION_FLAG_TIME); |
| 125 | 125 | } |
| 126 | 126 | |
| 127 | +extern bool directory_delegations; | |
| 128 | + | |
| 129 | +static inline void nfs_request_directory_delegation(struct inode *inode) | |
| 130 | +{ | |
| 131 | + if (S_ISDIR(inode->i_mode)) | |
| 132 | + set_bit(NFS_INO_REQ_DIR_DELEG, &NFS_I(inode)->flags); | |
| 133 | +} | |
| 134 | + | |
| 135 | +static inline bool nfs_have_directory_delegation(struct inode *inode) | |
| 136 | +{ | |
| 137 | + return S_ISDIR(inode->i_mode) && nfs_have_delegated_attributes(inode); | |
| 138 | +} | |
| 139 | + | |
| 127 | 140 | int nfs4_delegation_hash_alloc(struct nfs_server *server); |
| 128 | 141 | |
| 129 | 142 | #endif |
| @@ -789,16 +789,17 @@ again: · 788 unmodified lines | ||
| 789 | 789 | goto out; |
| 790 | 790 | } |
| 791 | 791 | |
| 792 | + nfs_set_verifier(dentry, dir_verifier); | |
| 792 | 793 | inode = nfs_fhget(dentry->d_sb, entry->fh, entry->fattr); |
| 793 | 794 | alias = d_splice_alias(inode, dentry); |
| 794 | 795 | d_lookup_done(dentry); |
| 795 | 796 | if (alias) { |
| 796 | 797 | if (IS_ERR(alias)) |
| 797 | 798 | goto out; |
| 799 | + nfs_set_verifier(alias, dir_verifier); | |
| 798 | 800 | dput(dentry); |
| 799 | 801 | dentry = alias; |
| 800 | 802 | } |
| 801 | − nfs_set_verifier(dentry, dir_verifier); | |
| 802 | 803 | trace_nfs_readdir_lookup(d_inode(parent), dentry, 0); |
| 803 | 804 | out: |
| 804 | 805 | dput(dentry); |
| @@ -1514,6 +1515,15 @@ static int nfs_check_verifier(struct inode *dir, struct dentry *dentry, · 709 unmodified lines | ||
| 1514 | 1515 | return 0; |
| 1515 | 1516 | if (!nfs_dentry_verify_change(dir, dentry)) |
| 1516 | 1517 | return 0; |
| 1518 | + | |
| 1519 | + /* | |
| 1520 | + * If we have a directory delegation then we don't need to revalidate | |
| 1521 | + * the directory. The delegation will either get recalled or we will | |
| 1522 | + * receive a notification when it changes. | |
| 1523 | + */ | |
| 1524 | + if (nfs_have_directory_delegation(dir)) | |
| 1525 | + return 0; | |
| 1526 | + | |
| 1517 | 1527 | /* Revalidate nfsi->cache_change_attribute before we declare a match */ |
| 1518 | 1528 | if (nfs_mapping_need_revalidate_inode(dir)) { |
| 1519 | 1529 | if (rcu_walk) |
| @@ -1894,13 +1904,15 @@ static int nfs_dentry_delete(const struct dentry *dentry) · 374 unmodified lines | ||
| 1894 | 1904 | } |
| 1895 | 1905 | |
| 1896 | 1906 | /* Ensure that we revalidate inode->i_nlink */ |
| 1897 | −static void nfs_drop_nlink(struct inode *inode) | |
| 1907 | +static void nfs_drop_nlink(struct inode *inode, unsigned long gencount) | |
| 1898 | 1908 | { |
| 1909 | + struct nfs_inode *nfsi = NFS_I(inode); | |
| 1910 | + | |
| 1899 | 1911 | spin_lock(&inode->i_lock); |
| 1900 | 1912 | /* drop the inode if we're reasonably sure this is the last link */ |
| 1901 | − if (inode->i_nlink > 0) | |
| 1913 | + if (inode->i_nlink > 0 && gencount == nfsi->attr_gencount) | |
| 1902 | 1914 | drop_nlink(inode); |
| 1903 | − NFS_I(inode)->attr_gencount = nfs_inc_attr_generation_counter(); | |
| 1915 | + nfsi->attr_gencount = nfs_inc_attr_generation_counter(); | |
| 1904 | 1916 | nfs_set_cache_invalid( |
| 1905 | 1917 | inode, NFS_INO_INVALID_CHANGE | NFS_INO_INVALID_CTIME | |
| 1906 | 1918 | NFS_INO_INVALID_NLINK); |
| @@ -1914,8 +1926,9 @@ static void nfs_drop_nlink(struct inode *inode) · 7 unmodified lines | ||
| 1914 | 1926 | static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode) |
| 1915 | 1927 | { |
| 1916 | 1928 | if (dentry->d_flags & DCACHE_NFSFS_RENAMED) { |
| 1929 | + unsigned long gencount = READ_ONCE(NFS_I(inode)->attr_gencount); | |
| 1917 | 1930 | nfs_complete_unlink(dentry, inode); |
| 1918 | − nfs_drop_nlink(inode); | |
| 1931 | + nfs_drop_nlink(inode, gencount); | |
| 1919 | 1932 | } |
| 1920 | 1933 | iput(inode); |
| 1921 | 1934 | } |
| @@ -1991,13 +2004,14 @@ struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned in · 69 unmodified lines | ||
| 1991 | 2004 | nfs_lookup_advise_force_readdirplus(dir, flags); |
| 1992 | 2005 | |
| 1993 | 2006 | no_entry: |
| 2007 | + nfs_set_verifier(dentry, dir_verifier); | |
| 1994 | 2008 | res = d_splice_alias(inode, dentry); |
| 1995 | 2009 | if (res != NULL) { |
| 1996 | 2010 | if (IS_ERR(res)) |
| 1997 | 2011 | goto out; |
| 2012 | + nfs_set_verifier(res, dir_verifier); | |
| 1998 | 2013 | dentry = res; |
| 1999 | 2014 | } |
| 2000 | − nfs_set_verifier(dentry, dir_verifier); | |
| 2001 | 2015 | out: |
| 2002 | 2016 | trace_nfs_lookup_exit(dir, dentry, flags, PTR_ERR_OR_ZERO(res)); |
| 2003 | 2017 | nfs_free_fattr(fattr); |
| @@ -2139,12 +2153,12 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry, · 135 unmodified lines | ||
| 2139 | 2153 | d_drop(dentry); |
| 2140 | 2154 | switch (err) { |
| 2141 | 2155 | case -ENOENT: |
| 2142 | − d_splice_alias(NULL, dentry); | |
| 2143 | 2156 | if (nfs_server_capable(dir, NFS_CAP_CASE_INSENSITIVE)) |
| 2144 | 2157 | dir_verifier = inode_peek_iversion_raw(dir); |
| 2145 | 2158 | else |
| 2146 | 2159 | dir_verifier = nfs_save_change_attribute(dir); |
| 2147 | 2160 | nfs_set_verifier(dentry, dir_verifier); |
| 2161 | + d_splice_alias(NULL, dentry); | |
| 2148 | 2162 | break; |
| 2149 | 2163 | case -EISDIR: |
| 2150 | 2164 | case -ENOTDIR: |
| @@ -2202,6 +2216,13 @@ no_open: · 51 unmodified lines | ||
| 2202 | 2216 | } |
| 2203 | 2217 | EXPORT_SYMBOL_GPL(nfs_atomic_open); |
| 2204 | 2218 | |
| 2219 | +static int | |
| 2220 | +nfs_lookup_revalidate_delegated_parent(struct inode *dir, struct dentry *dentry, | |
| 2221 | + struct inode *inode) | |
| 2222 | +{ | |
| 2223 | + return nfs_lookup_revalidate_done(dir, dentry, inode, 1); | |
| 2224 | +} | |
| 2225 | + | |
| 2205 | 2226 | static int |
| 2206 | 2227 | nfs4_lookup_revalidate(struct inode *dir, const struct qstr *name, |
| 2207 | 2228 | struct dentry *dentry, unsigned int flags) |
| @@ -2229,6 +2250,9 @@ nfs4_lookup_revalidate(struct inode *dir, const struct qstr *name, · 21 unmodified lines | ||
| 2229 | 2250 | if (nfs_verifier_is_delegated(dentry)) |
| 2230 | 2251 | return nfs_lookup_revalidate_delegated(dir, dentry, inode); |
| 2231 | 2252 | |
| 2253 | + if (nfs_have_directory_delegation(dir)) | |
| 2254 | + return nfs_lookup_revalidate_delegated_parent(dir, dentry, inode); | |
| 2255 | + | |
| 2232 | 2256 | /* NFS only supports OPEN on regular files */ |
| 2233 | 2257 | if (!S_ISREG(inode->i_mode)) |
| 2234 | 2258 | goto full_reval; |
| @@ -2507,9 +2531,11 @@ static int nfs_safe_remove(struct dentry *dentry) · 272 unmodified lines | ||
| 2507 | 2531 | |
| 2508 | 2532 | trace_nfs_remove_enter(dir, dentry); |
| 2509 | 2533 | if (inode != NULL) { |
| 2534 | + unsigned long gencount = READ_ONCE(NFS_I(inode)->attr_gencount); | |
| 2535 | + | |
| 2510 | 2536 | error = NFS_PROTO(dir)->remove(dir, dentry); |
| 2511 | 2537 | if (error == 0) |
| 2512 | − nfs_drop_nlink(inode); | |
| 2538 | + nfs_drop_nlink(inode, gencount); | |
| 2513 | 2539 | } else |
| 2514 | 2540 | error = NFS_PROTO(dir)->remove(dir, dentry); |
| 2515 | 2541 | if (error == -ENOENT) |
| @@ -2709,6 +2735,7 @@ int nfs_rename(struct mnt_idmap *idmap, struct inode *old_dir, · 193 unmodified lines | ||
| 2709 | 2735 | { |
| 2710 | 2736 | struct inode *old_inode = d_inode(old_dentry); |
| 2711 | 2737 | struct inode *new_inode = d_inode(new_dentry); |
| 2738 | + unsigned long new_gencount = 0; | |
| 2712 | 2739 | struct dentry *dentry = NULL; |
| 2713 | 2740 | struct rpc_task *task; |
| 2714 | 2741 | bool must_unblock = false; |
| @@ -2761,6 +2788,7 @@ int nfs_rename(struct mnt_idmap *idmap, struct inode *old_dir, · 46 unmodified lines | ||
| 2761 | 2788 | } else { |
| 2762 | 2789 | block_revalidate(new_dentry); |
| 2763 | 2790 | must_unblock = true; |
| 2791 | + new_gencount = NFS_I(new_inode)->attr_gencount; | |
| 2764 | 2792 | spin_unlock(&new_dentry->d_lock); |
| 2765 | 2793 | } |
| 2766 | 2794 | |
| @@ -2800,7 +2828,7 @@ out: · 33 unmodified lines | ||
| 2800 | 2828 | new_dir, new_dentry, error); |
| 2801 | 2829 | if (!error) { |
| 2802 | 2830 | if (new_inode != NULL) |
| 2803 | − nfs_drop_nlink(new_inode); | |
| 2831 | + nfs_drop_nlink(new_inode, new_gencount); | |
| 2804 | 2832 | /* |
| 2805 | 2833 | * The d_move() should be here instead of in an async RPC completion |
| 2806 | 2834 | * handler because we need the proper locks to move the dentry. If |
| @@ -1389,6 +1389,9 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) · 1388 unmodified lines | ||
| 1389 | 1389 | status = pnfs_sync_inode(inode, false); |
| 1390 | 1390 | if (status) |
| 1391 | 1391 | goto out; |
| 1392 | + } else if (nfs_have_directory_delegation(inode)) { | |
| 1393 | + status = 0; | |
| 1394 | + goto out; | |
| 1392 | 1395 | } |
| 1393 | 1396 | |
| 1394 | 1397 | status = -ENOMEM; |
| @@ -13,7 +13,7 @@ · 12 unmodified lines | ||
| 13 | 13 | #include <linux/nfslocalio.h> |
| 14 | 14 | #include <linux/wait_bit.h> |
| 15 | 15 | |
| 16 | −#define NFS_SB_MASK (SB_NOSUID|SB_NODEV|SB_NOEXEC|SB_SYNCHRONOUS) | |
| 16 | +#define NFS_SB_MASK (SB_RDONLY|SB_NOSUID|SB_NODEV|SB_NOEXEC|SB_SYNCHRONOUS) | |
| 17 | 17 | |
| 18 | 18 | extern const struct export_operations nfs_export_ops; |
| 19 | 19 | |
| @@ -152,7 +152,6 @@ struct nfs_fs_context { · 132 unmodified lines | ||
| 152 | 152 | struct super_block *sb; |
| 153 | 153 | struct dentry *dentry; |
| 154 | 154 | struct nfs_fattr *fattr; |
| 155 | − unsigned int inherited_bsize; | |
| 156 | 155 | } clone_data; |
| 157 | 156 | }; |
| 158 | 157 | |
| @@ -43,8 +43,8 @@ struct nfs_local_kiocb { · 42 unmodified lines | ||
| 43 | 43 | size_t end_len; |
| 44 | 44 | short int end_iter_index; |
| 45 | 45 | atomic_t n_iters; |
| 46 | + struct iov_iter iters[NFSLOCAL_MAX_IOS]; | |
| 46 | 47 | bool iter_is_dio_aligned[NFSLOCAL_MAX_IOS]; |
| 47 | − struct iov_iter iters[NFSLOCAL_MAX_IOS] ____cacheline_aligned; | |
| 48 | 48 | /* End mostly DIO-specific members */ |
| 49 | 49 | }; |
| 50 | 50 | |
| @@ -339,8 +339,6 @@ nfs_is_local_dio_possible(struct nfs_local_kiocb *iocb, int rw, · 288 unmodified lines | ||
| 339 | 339 | |
| 340 | 340 | if (unlikely(!nf_dio_mem_align || !nf_dio_offset_align)) |
| 341 | 341 | return false; |
| 342 | − if (unlikely(nf_dio_offset_align > PAGE_SIZE)) | |
| 343 | − return false; | |
| 344 | 342 | if (unlikely(len < nf_dio_offset_align)) |
| 345 | 343 | return false; |
| 346 | 344 | |
| @@ -149,6 +149,7 @@ struct vfsmount *nfs_d_automount(struct path *path) · 148 unmodified lines | ||
| 149 | 149 | struct vfsmount *mnt = ERR_PTR(-ENOMEM); |
| 150 | 150 | struct nfs_server *server = NFS_SB(path->dentry->d_sb); |
| 151 | 151 | struct nfs_client *client = server->nfs_client; |
| 152 | + unsigned long s_flags = path->dentry->d_sb->s_flags; | |
| 152 | 153 | int timeout = READ_ONCE(nfs_mountpoint_expiry_timeout); |
| 153 | 154 | int ret; |
| 154 | 155 | |
| @@ -169,11 +170,21 @@ struct vfsmount *nfs_d_automount(struct path *path) · 14 unmodified lines | ||
| 169 | 170 | if (!ctx->clone_data.fattr) |
| 170 | 171 | goto out_fc; |
| 171 | 172 | |
| 173 | + if (fc->cred != server->cred) { | |
| 174 | + put_cred(fc->cred); | |
| 175 | + fc->cred = get_cred(server->cred); | |
| 176 | + } | |
| 177 | + | |
| 172 | 178 | if (fc->net_ns != client->cl_net) { |
| 173 | 179 | put_net(fc->net_ns); |
| 174 | 180 | fc->net_ns = get_net(client->cl_net); |
| 175 | 181 | } |
| 176 | 182 | |
| 183 | + /* Inherit the flags covered by NFS_SB_MASK */ | |
| 184 | + fc->sb_flags_mask |= NFS_SB_MASK; | |
| 185 | + fc->sb_flags &= ~NFS_SB_MASK; | |
| 186 | + fc->sb_flags |= s_flags & NFS_SB_MASK; | |
| 187 | + | |
| 177 | 188 | /* for submounts we want the same server; referrals will reassign */ |
| 178 | 189 | memcpy(&ctx->nfs_server._address, &client->cl_addr, client->cl_addrlen); |
| 179 | 190 | ctx->nfs_server.addrlen = client->cl_addrlen; |
| @@ -184,6 +195,10 @@ struct vfsmount *nfs_d_automount(struct path *path) · 4 unmodified lines | ||
| 184 | 195 | ctx->nfs_mod = client->cl_nfs_mod; |
| 185 | 196 | get_nfs_version(ctx->nfs_mod); |
| 186 | 197 | |
| 198 | + /* Inherit block sizes if they were specified as mount parameters */ | |
| 199 | + if (server->automount_inherit & NFS_AUTOMOUNT_INHERIT_BSIZE) | |
| 200 | + ctx->bsize = server->bsize; | |
| 201 | + | |
| 187 | 202 | ret = client->rpc_ops->submount(fc, server); |
| 188 | 203 | if (ret < 0) { |
| 189 | 204 | mnt = ERR_PTR(ret); |
| @@ -283,7 +298,6 @@ int nfs_do_submount(struct fs_context *fc) · 93 unmodified lines | ||
| 283 | 298 | return -ENOMEM; |
| 284 | 299 | |
| 285 | 300 | ctx->internal = true; |
| 286 | − ctx->clone_data.inherited_bsize = ctx->clone_data.sb->s_blocksize_bits; | |
| 287 | 301 | |
| 288 | 302 | p = nfs_devname(dentry, buffer, 4096); |
| 289 | 303 | if (IS_ERR(p)) { |
| @@ -483,7 +483,8 @@ nfs3_proc_unlink_done(struct rpc_task *task, struct inode *dir) · 482 unmodified lines | ||
| 483 | 483 | static void |
| 484 | 484 | nfs3_proc_rename_setup(struct rpc_message *msg, |
| 485 | 485 | struct dentry *old_dentry, |
| 486 | − struct dentry *new_dentry) | |
| 486 | + struct dentry *new_dentry, | |
| 487 | + struct inode *same_parent) | |
| 487 | 488 | { |
| 488 | 489 | msg->rpc_proc = &nfs3_procedures[NFS3PROC_RENAME]; |
| 489 | 490 | } |
| @@ -281,8 +281,13 @@ error: · 280 unmodified lines | ||
| 281 | 281 | */ |
| 282 | 282 | static void nfs4_destroy_callback(struct nfs_client *clp) |
| 283 | 283 | { |
| 284 | − if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) | |
| 285 | − nfs_callback_down(clp->cl_mvops->minor_version, clp->cl_net); | |
| 284 | + if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) { | |
| 285 | + struct rpc_xprt *xprt; | |
| 286 | + | |
| 287 | + xprt = rcu_dereference_raw(clp->cl_rpcclient->cl_xprt); | |
| 288 | + nfs_callback_down(clp->cl_mvops->minor_version, clp->cl_net, | |
| 289 | + xprt); | |
| 290 | + } | |
| 286 | 291 | } |
| 287 | 292 | |
| 288 | 293 | static void nfs4_shutdown_client(struct nfs_client *clp) |
| @@ -1174,10 +1179,20 @@ static int nfs4_init_server(struct nfs_server *server, struct fs_context *fc) · 885 unmodified lines | ||
| 1174 | 1179 | if (error < 0) |
| 1175 | 1180 | return error; |
| 1176 | 1181 | |
| 1177 | − if (ctx->rsize) | |
| 1178 | − server->rsize = nfs_io_size(ctx->rsize, server->nfs_client->cl_proto); | |
| 1179 | − if (ctx->wsize) | |
| 1180 | − server->wsize = nfs_io_size(ctx->wsize, server->nfs_client->cl_proto); | |
| 1182 | + if (ctx->bsize) { | |
| 1183 | + server->bsize = ctx->bsize; | |
| 1184 | + server->automount_inherit |= NFS_AUTOMOUNT_INHERIT_BSIZE; | |
| 1185 | + } | |
| 1186 | + if (ctx->rsize) { | |
| 1187 | + server->rsize = | |
| 1188 | + nfs_io_size(ctx->rsize, server->nfs_client->cl_proto); | |
| 1189 | + server->automount_inherit |= NFS_AUTOMOUNT_INHERIT_RSIZE; | |
| 1190 | + } | |
| 1191 | + if (ctx->wsize) { | |
| 1192 | + server->wsize = | |
| 1193 | + nfs_io_size(ctx->wsize, server->nfs_client->cl_proto); | |
| 1194 | + server->automount_inherit |= NFS_AUTOMOUNT_INHERIT_WSIZE; | |
| 1195 | + } | |
| 1181 | 1196 | |
| 1182 | 1197 | server->acregmin = ctx->acregmin * HZ; |
| 1183 | 1198 | server->acregmax = ctx->acregmax * HZ; |
| @@ -1780,8 +1780,17 @@ static void nfs_set_open_stateid_locked(struct nfs4_state *state, · 1779 unmodified lines | ||
| 1780 | 1780 | if (nfs_stateid_is_sequential(state, stateid)) |
| 1781 | 1781 | break; |
| 1782 | 1782 | |
| 1783 | − if (status) | |
| 1784 | − break; | |
| 1783 | + if (status) { | |
| 1784 | + if (nfs4_stateid_match_other(stateid, &state->open_stateid) && | |
| 1785 | + !nfs4_stateid_is_newer(stateid, &state->open_stateid)) { | |
| 1786 | + trace_nfs4_open_stateid_update_skip(state->inode, | |
| 1787 | + stateid, status); | |
| 1788 | + return; | |
| 1789 | + } else { | |
| 1790 | + break; | |
| 1791 | + } | |
| 1792 | + } | |
| 1793 | + | |
| 1785 | 1794 | /* Rely on seqids for serialisation with NFSv4.0 */ |
| 1786 | 1795 | if (!nfs4_has_session(NFS_SERVER(state->inode)->nfs_client)) |
| 1787 | 1796 | break; |
| @@ -3174,18 +3183,6 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata, · 1386 unmodified lines | ||
| 3174 | 3183 | if (opendata->o_res.rflags & NFS4_OPEN_RESULT_PRESERVE_UNLINKED) |
| 3175 | 3184 | set_bit(NFS_INO_PRESERVE_UNLINKED, &NFS_I(state->inode)->flags); |
| 3176 | 3185 | |
| 3177 | − dentry = opendata->dentry; | |
| 3178 | − if (d_really_is_negative(dentry)) { | |
| 3179 | − struct dentry *alias; | |
| 3180 | − d_drop(dentry); | |
| 3181 | − alias = d_splice_alias(igrab(state->inode), dentry); | |
| 3182 | − /* d_splice_alias() can't fail here - it's a non-directory */ | |
| 3183 | − if (alias) { | |
| 3184 | − dput(ctx->dentry); | |
| 3185 | − ctx->dentry = dentry = alias; | |
| 3186 | − } | |
| 3187 | − } | |
| 3188 | − | |
| 3189 | 3186 | switch(opendata->o_arg.claim) { |
| 3190 | 3187 | default: |
| 3191 | 3188 | break; |
| @@ -3196,7 +3193,20 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata, · 4 unmodified lines | ||
| 3196 | 3193 | break; |
| 3197 | 3194 | if (opendata->o_res.delegation.type != 0) |
| 3198 | 3195 | dir_verifier = nfs_save_change_attribute(dir); |
| 3199 | − nfs_set_verifier(dentry, dir_verifier); | |
| 3196 | + } | |
| 3197 | + | |
| 3198 | + dentry = opendata->dentry; | |
| 3199 | + nfs_set_verifier(dentry, dir_verifier); | |
| 3200 | + if (d_really_is_negative(dentry)) { | |
| 3201 | + struct dentry *alias; | |
| 3202 | + d_drop(dentry); | |
| 3203 | + alias = d_splice_alias(igrab(state->inode), dentry); | |
| 3204 | + /* d_splice_alias() can't fail here - it's a non-directory */ | |
| 3205 | + if (alias) { | |
| 3206 | + dput(ctx->dentry); | |
| 3207 | + nfs_set_verifier(alias, dir_verifier); | |
| 3208 | + ctx->dentry = dentry = alias; | |
| 3209 | + } | |
| 3200 | 3210 | } |
| 3201 | 3211 | |
| 3202 | 3212 | /* Parse layoutget results before we check for access */ |
| @@ -4460,6 +4470,30 @@ out: · 1257 unmodified lines | ||
| 4460 | 4470 | return status; |
| 4461 | 4471 | } |
| 4462 | 4472 | |
| 4473 | +#if IS_ENABLED(CONFIG_NFS_V4_1) | |
| 4474 | +static bool should_request_dir_deleg(struct inode *inode) | |
| 4475 | +{ | |
| 4476 | + if (!directory_delegations) | |
| 4477 | + return false; | |
| 4478 | + if (!inode) | |
| 4479 | + return false; | |
| 4480 | + if (!S_ISDIR(inode->i_mode)) | |
| 4481 | + return false; | |
| 4482 | + if (!nfs_server_capable(inode, NFS_CAP_DIR_DELEG)) | |
| 4483 | + return false; | |
| 4484 | + if (!test_and_clear_bit(NFS_INO_REQ_DIR_DELEG, &(NFS_I(inode)->flags))) | |
| 4485 | + return false; | |
| 4486 | + if (nfs4_have_delegation(inode, FMODE_READ, 0)) | |
| 4487 | + return false; | |
| 4488 | + return true; | |
| 4489 | +} | |
| 4490 | +#else | |
| 4491 | +static bool should_request_dir_deleg(struct inode *inode) | |
| 4492 | +{ | |
| 4493 | + return false; | |
| 4494 | +} | |
| 4495 | +#endif /* CONFIG_NFS_V4_1 */ | |
| 4496 | + | |
| 4463 | 4497 | static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, |
| 4464 | 4498 | struct nfs_fattr *fattr, struct inode *inode) |
| 4465 | 4499 | { |
| @@ -4477,7 +4511,9 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, · 11 unmodified lines | ||
| 4477 | 4511 | .rpc_argp = &args, |
| 4478 | 4512 | .rpc_resp = &res, |
| 4479 | 4513 | }; |
| 4514 | + struct nfs4_gdd_res gdd_res; | |
| 4480 | 4515 | unsigned short task_flags = 0; |
| 4516 | + int status; | |
| 4481 | 4517 | |
| 4482 | 4518 | if (nfs4_has_session(server->nfs_client)) |
| 4483 | 4519 | task_flags = RPC_TASK_MOVEABLE; |
| @@ -4486,11 +4522,31 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, · 2 unmodified lines | ||
| 4486 | 4522 | if (inode && (server->flags & NFS_MOUNT_SOFTREVAL)) |
| 4487 | 4523 | task_flags |= RPC_TASK_TIMEOUT; |
| 4488 | 4524 | |
| 4525 | + args.get_dir_deleg = should_request_dir_deleg(inode); | |
| 4526 | + if (args.get_dir_deleg) | |
| 4527 | + res.gdd_res = &gdd_res; | |
| 4528 | + | |
| 4489 | 4529 | nfs4_bitmap_copy_adjust(bitmask, nfs4_bitmask(server, fattr->label), inode, 0); |
| 4490 | 4530 | nfs_fattr_init(fattr); |
| 4491 | 4531 | nfs4_init_sequence(&args.seq_args, &res.seq_res, 0, 0); |
| 4492 | − return nfs4_do_call_sync(server->client, server, &msg, | |
| 4493 | − &args.seq_args, &res.seq_res, task_flags); | |
| 4532 | + | |
| 4533 | + status = nfs4_do_call_sync(server->client, server, &msg, | |
| 4534 | + &args.seq_args, &res.seq_res, task_flags); | |
| 4535 | + if (args.get_dir_deleg) { | |
| 4536 | + switch (status) { | |
| 4537 | + case 0: | |
| 4538 | + if (gdd_res.status != GDD4_OK) | |
| 4539 | + break; | |
| 4540 | + status = nfs_inode_set_delegation( | |
| 4541 | + inode, current_cred(), FMODE_READ, | |
| 4542 | + &gdd_res.deleg, 0, NFS4_OPEN_DELEGATE_READ); | |
| 4543 | + break; | |
| 4544 | + case -ENOTSUPP: | |
| 4545 | + case -EOPNOTSUPP: | |
| 4546 | + server->caps &= ~NFS_CAP_DIR_DELEG; | |
| 4547 | + } | |
| 4548 | + } | |
| 4549 | + return status; | |
| 4494 | 4550 | } |
| 4495 | 4551 | |
| 4496 | 4552 | int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, |
| @@ -4503,8 +4559,14 @@ int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, · 6 unmodified lines | ||
| 4503 | 4559 | do { |
| 4504 | 4560 | err = _nfs4_proc_getattr(server, fhandle, fattr, inode); |
| 4505 | 4561 | trace_nfs4_getattr(server, fhandle, fattr, err); |
| 4506 | − err = nfs4_handle_exception(server, err, | |
| 4507 | − &exception); | |
| 4562 | + switch (err) { | |
| 4563 | + default: | |
| 4564 | + err = nfs4_handle_exception(server, err, &exception); | |
| 4565 | + break; | |
| 4566 | + case -ENOTSUPP: | |
| 4567 | + case -EOPNOTSUPP: | |
| 4568 | + exception.retry = true; | |
| 4569 | + } | |
| 4508 | 4570 | } while (exception.retry); |
| 4509 | 4571 | return err; |
| 4510 | 4572 | } |
| @@ -4768,6 +4830,7 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry · 257 unmodified lines | ||
| 4768 | 4830 | int status = 0; |
| 4769 | 4831 | |
| 4770 | 4832 | if (!nfs4_have_delegation(inode, FMODE_READ, 0)) { |
| 4833 | + nfs_request_directory_delegation(inode); | |
| 4771 | 4834 | res.fattr = nfs_alloc_fattr(); |
| 4772 | 4835 | if (res.fattr == NULL) |
| 4773 | 4836 | return -ENOMEM; |
| @@ -4875,6 +4938,8 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, · 101 unmodified lines | ||
| 4875 | 4938 | |
| 4876 | 4939 | ilabel = nfs4_label_init_security(dir, dentry, sattr, &l); |
| 4877 | 4940 | |
| 4941 | + nfs_request_directory_delegation(dir); | |
| 4942 | + | |
| 4878 | 4943 | if (!(server->attr_bitmask[2] & FATTR4_WORD2_MODE_UMASK)) |
| 4879 | 4944 | sattr->ia_mode &= ~current_umask(); |
| 4880 | 4945 | state = nfs4_do_open(dir, ctx, flags, sattr, ilabel, NULL); |
| @@ -4971,6 +5036,7 @@ static void nfs4_proc_unlink_setup(struct rpc_message *msg, · 90 unmodified lines | ||
| 4971 | 5036 | nfs4_init_sequence(&args->seq_args, &res->seq_res, 1, 0); |
| 4972 | 5037 | |
| 4973 | 5038 | nfs_fattr_init(res->dir_attr); |
| 5039 | + nfs_request_directory_delegation(d_inode(dentry->d_parent)); | |
| 4974 | 5040 | |
| 4975 | 5041 | if (inode) { |
| 4976 | 5042 | nfs4_inode_return_delegation(inode); |
| @@ -5005,7 +5071,8 @@ static int nfs4_proc_unlink_done(struct rpc_task *task, struct inode *dir) · 28 unmodified lines | ||
| 5005 | 5071 | |
| 5006 | 5072 | static void nfs4_proc_rename_setup(struct rpc_message *msg, |
| 5007 | 5073 | struct dentry *old_dentry, |
| 5008 | − struct dentry *new_dentry) | |
| 5074 | + struct dentry *new_dentry, | |
| 5075 | + struct inode *same_parent) | |
| 5009 | 5076 | { |
| 5010 | 5077 | struct nfs_renameargs *arg = msg->rpc_argp; |
| 5011 | 5078 | struct nfs_renameres *res = msg->rpc_resp; |
| @@ -5016,6 +5083,8 @@ static void nfs4_proc_rename_setup(struct rpc_message *msg, · 4 unmodified lines | ||
| 5016 | 5083 | nfs4_inode_make_writeable(old_inode); |
| 5017 | 5084 | if (new_inode) |
| 5018 | 5085 | nfs4_inode_return_delegation(new_inode); |
| 5086 | + if (same_parent) | |
| 5087 | + nfs_request_directory_delegation(same_parent); | |
| 5019 | 5088 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENAME]; |
| 5020 | 5089 | res->server = NFS_SB(old_dentry->d_sb); |
| 5021 | 5090 | nfs4_init_sequence(&arg->seq_args, &res->seq_res, 1, 0); |
| @@ -10822,6 +10891,7 @@ static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = { · 5800 unmodified lines | ||
| 10822 | 10891 | .minor_version = 1, |
| 10823 | 10892 | .init_caps = NFS_CAP_READDIRPLUS |
| 10824 | 10893 | | NFS_CAP_ATOMIC_OPEN |
| 10894 | + | NFS_CAP_DIR_DELEG | |
| 10825 | 10895 | | NFS_CAP_POSIX_LOCK |
| 10826 | 10896 | | NFS_CAP_STATEID_NFSV41 |
| 10827 | 10897 | | NFS_CAP_ATOMIC_OPEN_V1 |
| @@ -10848,6 +10918,7 @@ static const struct nfs4_minor_version_ops nfs_v4_2_minor_ops = { · 20 unmodified lines | ||
| 10848 | 10918 | .minor_version = 2, |
| 10849 | 10919 | .init_caps = NFS_CAP_READDIRPLUS |
| 10850 | 10920 | | NFS_CAP_ATOMIC_OPEN |
| 10921 | + | NFS_CAP_DIR_DELEG | |
| 10851 | 10922 | | NFS_CAP_POSIX_LOCK |
| 10852 | 10923 | | NFS_CAP_STATEID_NFSV41 |
| 10853 | 10924 | | NFS_CAP_ATOMIC_OPEN_V1 |
| @@ -1353,6 +1353,7 @@ DEFINE_NFS4_INODE_STATEID_EVENT(nfs4_setattr); · 1352 unmodified lines | ||
| 1353 | 1353 | DEFINE_NFS4_INODE_STATEID_EVENT(nfs4_delegreturn); |
| 1354 | 1354 | DEFINE_NFS4_INODE_STATEID_EVENT(nfs4_open_stateid_update); |
| 1355 | 1355 | DEFINE_NFS4_INODE_STATEID_EVENT(nfs4_open_stateid_update_wait); |
| 1356 | +DEFINE_NFS4_INODE_STATEID_EVENT(nfs4_open_stateid_update_skip); | |
| 1356 | 1357 | DEFINE_NFS4_INODE_STATEID_EVENT(nfs4_close_stateid_update_wait); |
| 1357 | 1358 | |
| 1358 | 1359 | DECLARE_EVENT_CLASS(nfs4_getattr_event, |
| @@ -393,6 +393,20 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req, · 392 unmodified lines | ||
| 393 | 393 | XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + 5) |
| 394 | 394 | #define encode_reclaim_complete_maxsz (op_encode_hdr_maxsz + 4) |
| 395 | 395 | #define decode_reclaim_complete_maxsz (op_decode_hdr_maxsz + 4) |
| 396 | +#define encode_get_dir_deleg_maxsz (op_encode_hdr_maxsz + \ | |
| 397 | + 4 /* gdda_signal_deleg_avail */ + \ | |
| 398 | + 8 /* gdda_notification_types */ + \ | |
| 399 | + nfstime4_maxsz /* gdda_child_attr_delay */ + \ | |
| 400 | + nfstime4_maxsz /* gdda_dir_attr_delay */ + \ | |
| 401 | + nfs4_fattr_bitmap_maxsz /* gdda_child_attributes */ + \ | |
| 402 | + nfs4_fattr_bitmap_maxsz /* gdda_dir_attributes */) | |
| 403 | +#define decode_get_dir_deleg_maxsz (op_decode_hdr_maxsz + \ | |
| 404 | + 4 /* gddrnf_status */ + \ | |
| 405 | + encode_verifier_maxsz /* gddr_cookieverf */ + \ | |
| 406 | + encode_stateid_maxsz /* gddr_stateid */ + \ | |
| 407 | + 8 /* gddr_notification */ + \ | |
| 408 | + nfs4_fattr_maxsz /* gddr_child_attributes */ + \ | |
| 409 | + nfs4_fattr_maxsz /* gddr_dir_attributes */) | |
| 396 | 410 | #define encode_getdeviceinfo_maxsz (op_encode_hdr_maxsz + \ |
| 397 | 411 | XDR_QUADLEN(NFS4_DEVICEID4_SIZE) + \ |
| 398 | 412 | 1 /* layout type */ + \ |
| @@ -444,6 +458,8 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req, · 45 unmodified lines | ||
| 444 | 458 | #else /* CONFIG_NFS_V4_1 */ |
| 445 | 459 | #define encode_sequence_maxsz 0 |
| 446 | 460 | #define decode_sequence_maxsz 0 |
| 461 | +#define encode_get_dir_deleg_maxsz 0 | |
| 462 | +#define decode_get_dir_deleg_maxsz 0 | |
| 447 | 463 | #define encode_layoutreturn_maxsz 0 |
| 448 | 464 | #define decode_layoutreturn_maxsz 0 |
| 449 | 465 | #define encode_layoutget_maxsz 0 |
| @@ -631,11 +647,13 @@ static int decode_layoutget(struct xdr_stream *xdr, struct rpc_rqst *req, · 181 unmodified lines | ||
| 631 | 647 | #define NFS4_enc_getattr_sz (compound_encode_hdr_maxsz + \ |
| 632 | 648 | encode_sequence_maxsz + \ |
| 633 | 649 | encode_putfh_maxsz + \ |
| 650 | + encode_get_dir_deleg_maxsz + \ | |
| 634 | 651 | encode_getattr_maxsz + \ |
| 635 | 652 | encode_renew_maxsz) |
| 636 | 653 | #define NFS4_dec_getattr_sz (compound_decode_hdr_maxsz + \ |
| 637 | 654 | decode_sequence_maxsz + \ |
| 638 | 655 | decode_putfh_maxsz + \ |
| 656 | + decode_get_dir_deleg_maxsz + \ | |
| 639 | 657 | decode_getattr_maxsz + \ |
| 640 | 658 | decode_renew_maxsz) |
| 641 | 659 | #define NFS4_enc_lookup_sz (compound_encode_hdr_maxsz + \ |
| @@ -2007,6 +2025,33 @@ static void encode_sequence(struct xdr_stream *xdr, · 1365 unmodified lines | ||
| 2007 | 2025 | } |
| 2008 | 2026 | |
| 2009 | 2027 | #ifdef CONFIG_NFS_V4_1 |
| 2028 | +static void | |
| 2029 | +encode_get_dir_delegation(struct xdr_stream *xdr, struct compound_hdr *hdr) | |
| 2030 | +{ | |
| 2031 | + struct timespec64 ts = { 0, 0 }; | |
| 2032 | + u32 notifications[1] = { 0 }; | |
| 2033 | + u32 attributes[1] = { 0 }; | |
| 2034 | + __be32 *p; | |
| 2035 | + | |
| 2036 | + encode_op_hdr(xdr, OP_GET_DIR_DELEGATION, decode_get_dir_deleg_maxsz, hdr); | |
| 2037 | + | |
| 2038 | + /* We don't handle CB_RECALLABLE_OBJ_AVAIL yet. */ | |
| 2039 | + xdr_stream_encode_bool(xdr, false); | |
| 2040 | + | |
| 2041 | + xdr_encode_bitmap4(xdr, notifications, ARRAY_SIZE(notifications)); | |
| 2042 | + | |
| 2043 | + /* Request no delay on attribute updates */ | |
| 2044 | + p = reserve_space(xdr, 12 + 12); | |
| 2045 | + p = xdr_encode_nfstime4(p, &ts); | |
| 2046 | + xdr_encode_nfstime4(p, &ts); | |
| 2047 | + | |
| 2048 | + /* Requested child attributes */ | |
| 2049 | + xdr_encode_bitmap4(xdr, attributes, ARRAY_SIZE(attributes)); | |
| 2050 | + | |
| 2051 | + /* Requested dir attributes */ | |
| 2052 | + xdr_encode_bitmap4(xdr, attributes, ARRAY_SIZE(attributes)); | |
| 2053 | +} | |
| 2054 | + | |
| 2010 | 2055 | static void |
| 2011 | 2056 | encode_getdeviceinfo(struct xdr_stream *xdr, |
| 2012 | 2057 | const struct nfs4_getdeviceinfo_args *args, |
| @@ -2142,6 +2187,11 @@ static void encode_free_stateid(struct xdr_stream *xdr, · 129 unmodified lines | ||
| 2142 | 2187 | encode_nfs4_stateid(xdr, &args->stateid); |
| 2143 | 2188 | } |
| 2144 | 2189 | #else |
| 2190 | +static inline void | |
| 2191 | +encode_get_dir_delegation(struct xdr_stream *xdr, struct compound_hdr *hdr) | |
| 2192 | +{ | |
| 2193 | +} | |
| 2194 | + | |
| 2145 | 2195 | static inline void |
| 2146 | 2196 | encode_layoutreturn(struct xdr_stream *xdr, |
| 2147 | 2197 | const struct nfs4_layoutreturn_args *args, |
| @@ -2356,6 +2406,8 @@ static void nfs4_xdr_enc_getattr(struct rpc_rqst *req, struct xdr_stream *xdr, · 208 unmodified lines | ||
| 2356 | 2406 | encode_compound_hdr(xdr, req, &hdr); |
| 2357 | 2407 | encode_sequence(xdr, &args->seq_args, &hdr); |
| 2358 | 2408 | encode_putfh(xdr, args->fh, &hdr); |
| 2409 | + if (args->get_dir_deleg) | |
| 2410 | + encode_get_dir_delegation(xdr, &hdr); | |
| 2359 | 2411 | encode_getfattr(xdr, args->bitmask, &hdr); |
| 2360 | 2412 | encode_nops(&hdr); |
| 2361 | 2413 | } |
| @@ -5994,6 +6046,49 @@ static int decode_layout_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid) · 3632 unmodified lines | ||
| 5994 | 6046 | return decode_stateid(xdr, stateid); |
| 5995 | 6047 | } |
| 5996 | 6048 | |
| 6049 | +static int decode_get_dir_delegation(struct xdr_stream *xdr, | |
| 6050 | + struct nfs4_getattr_res *res) | |
| 6051 | +{ | |
| 6052 | + struct nfs4_gdd_res *gdd_res = res->gdd_res; | |
| 6053 | + nfs4_verifier cookieverf; | |
| 6054 | + u32 bitmap[1]; | |
| 6055 | + int status; | |
| 6056 | + | |
| 6057 | + status = decode_op_hdr(xdr, OP_GET_DIR_DELEGATION); | |
| 6058 | + if (status) | |
| 6059 | + return status; | |
| 6060 | + | |
| 6061 | + if (xdr_stream_decode_u32(xdr, &gdd_res->status)) | |
| 6062 | + return -EIO; | |
| 6063 | + | |
| 6064 | + if (gdd_res->status == GDD4_UNAVAIL) | |
| 6065 | + return xdr_inline_decode(xdr, 4) ? 0 : -EIO; | |
| 6066 | + | |
| 6067 | + status = decode_verifier(xdr, &cookieverf); | |
| 6068 | + if (status) | |
| 6069 | + return status; | |
| 6070 | + | |
| 6071 | + status = decode_delegation_stateid(xdr, &gdd_res->deleg); | |
| 6072 | + if (status) | |
| 6073 | + return status; | |
| 6074 | + | |
| 6075 | + /* Decode supported notification types. */ | |
| 6076 | + status = decode_bitmap4(xdr, bitmap, ARRAY_SIZE(bitmap)); | |
| 6077 | + if (status < 0) | |
| 6078 | + return status; | |
| 6079 | + | |
| 6080 | + /* Decode supported child attributes. */ | |
| 6081 | + status = decode_bitmap4(xdr, bitmap, ARRAY_SIZE(bitmap)); | |
| 6082 | + if (status < 0) | |
| 6083 | + return status; | |
| 6084 | + | |
| 6085 | + /* Decode supported attributes. */ | |
| 6086 | + status = decode_bitmap4(xdr, bitmap, ARRAY_SIZE(bitmap)); | |
| 6087 | + if (status < 0) | |
| 6088 | + return status; | |
| 6089 | + return 0; | |
| 6090 | +} | |
| 6091 | + | |
| 5997 | 6092 | static int decode_getdeviceinfo(struct xdr_stream *xdr, |
| 5998 | 6093 | struct nfs4_getdeviceinfo_res *res) |
| 5999 | 6094 | { |
| @@ -6208,6 +6303,12 @@ static int decode_free_stateid(struct xdr_stream *xdr, · 208 unmodified lines | ||
| 6208 | 6303 | return res->status; |
| 6209 | 6304 | } |
| 6210 | 6305 | #else |
| 6306 | +static int decode_get_dir_delegation(struct xdr_stream *xdr, | |
| 6307 | + struct nfs4_getattr_res *res) | |
| 6308 | +{ | |
| 6309 | + return 0; | |
| 6310 | +} | |
| 6311 | + | |
| 6211 | 6312 | static inline |
| 6212 | 6313 | int decode_layoutreturn(struct xdr_stream *xdr, |
| 6213 | 6314 | struct nfs4_layoutreturn_res *res) |
| @@ -6525,6 +6626,11 @@ static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, struct xdr_stream *xdr, · 311 unmodified lines | ||
| 6525 | 6626 | status = decode_putfh(xdr); |
| 6526 | 6627 | if (status) |
| 6527 | 6628 | goto out; |
| 6629 | + if (res->gdd_res) { | |
| 6630 | + status = decode_get_dir_delegation(xdr, res); | |
| 6631 | + if (status) | |
| 6632 | + goto out; | |
| 6633 | + } | |
| 6528 | 6634 | status = decode_getfattr(xdr, res->fattr, res->server); |
| 6529 | 6635 | out: |
| 6530 | 6636 | return status; |
| @@ -464,6 +464,7 @@ pnfs_mark_layout_stateid_invalid(struct pnfs_layout_hdr *lo, · 463 unmodified lines | ||
| 464 | 464 | struct pnfs_layout_segment *lseg, *next; |
| 465 | 465 | |
| 466 | 466 | set_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags); |
| 467 | + clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(lo->plh_inode)->flags); | |
| 467 | 468 | list_for_each_entry_safe(lseg, next, &lo->plh_segs, pls_list) |
| 468 | 469 | pnfs_clear_lseg_state(lseg, lseg_list); |
| 469 | 470 | pnfs_clear_layoutreturn_info(lo); |
| @@ -353,7 +353,8 @@ static int nfs_proc_unlink_done(struct rpc_task *task, struct inode *dir) · 352 unmodified lines | ||
| 353 | 353 | static void |
| 354 | 354 | nfs_proc_rename_setup(struct rpc_message *msg, |
| 355 | 355 | struct dentry *old_dentry, |
| 356 | − struct dentry *new_dentry) | |
| 356 | + struct dentry *new_dentry, | |
| 357 | + struct inode *same_parent) | |
| 357 | 358 | { |
| 358 | 359 | msg->rpc_proc = &nfs_procedures[NFSPROC_RENAME]; |
| 359 | 360 | } |
| @@ -1051,16 +1051,6 @@ int nfs_reconfigure(struct fs_context *fc) · 1050 unmodified lines | ||
| 1051 | 1051 | |
| 1052 | 1052 | sync_filesystem(sb); |
| 1053 | 1053 | |
| 1054 | − /* | |
| 1055 | − * The SB_RDONLY flag has been removed from the superblock during | |
| 1056 | − * mounts to prevent interference between different filesystems. | |
| 1057 | − * Similarly, it is also necessary to ignore the SB_RDONLY flag | |
| 1058 | − * during reconfiguration; otherwise, it may also result in the | |
| 1059 | − * creation of redundant superblocks when mounting a directory with | |
| 1060 | − * different rw and ro flags multiple times. | |
| 1061 | − */ | |
| 1062 | − fc->sb_flags_mask &= ~SB_RDONLY; | |
| 1063 | − | |
| 1064 | 1054 | /* |
| 1065 | 1055 | * Userspace mount programs that send binary options generally send |
| 1066 | 1056 | * them populated with default values. We have no way to know which |
| @@ -1101,8 +1091,9 @@ static void nfs_fill_super(struct super_block *sb, struct nfs_fs_context *ctx) · 34 unmodified lines | ||
| 1101 | 1091 | sb->s_blocksize = 0; |
| 1102 | 1092 | sb->s_xattr = server->nfs_client->cl_nfs_mod->xattr; |
| 1103 | 1093 | sb->s_op = server->nfs_client->cl_nfs_mod->sops; |
| 1104 | − if (ctx->bsize) | |
| 1105 | − sb->s_blocksize = nfs_block_size(ctx->bsize, &sb->s_blocksize_bits); | |
| 1094 | + if (server->bsize) | |
| 1095 | + sb->s_blocksize = | |
| 1096 | + nfs_block_size(server->bsize, &sb->s_blocksize_bits); | |
| 1106 | 1097 | |
| 1107 | 1098 | switch (server->nfs_client->rpc_ops->version) { |
| 1108 | 1099 | case 2: |
| @@ -1318,26 +1309,13 @@ int nfs_get_tree_common(struct fs_context *fc) · 209 unmodified lines | ||
| 1318 | 1309 | if (IS_ERR(server)) |
| 1319 | 1310 | return PTR_ERR(server); |
| 1320 | 1311 | |
| 1321 | − /* | |
| 1322 | − * When NFS_MOUNT_UNSHARED is not set, NFS forces the sharing of a | |
| 1323 | − * superblock among each filesystem that mounts sub-directories | |
| 1324 | − * belonging to a single exported root path. | |
| 1325 | − * To prevent interference between different filesystems, the | |
| 1326 | − * SB_RDONLY flag should be removed from the superblock. | |
| 1327 | − */ | |
| 1328 | 1312 | if (server->flags & NFS_MOUNT_UNSHARED) |
| 1329 | 1313 | compare_super = NULL; |
| 1330 | − else | |
| 1331 | − fc->sb_flags &= ~SB_RDONLY; | |
| 1332 | 1314 | |
| 1333 | 1315 | /* -o noac implies -o sync */ |
| 1334 | 1316 | if (server->flags & NFS_MOUNT_NOAC) |
| 1335 | 1317 | fc->sb_flags |= SB_SYNCHRONOUS; |
| 1336 | 1318 | |
| 1337 | − if (ctx->clone_data.sb) | |
| 1338 | − if (ctx->clone_data.sb->s_flags & SB_SYNCHRONOUS) | |
| 1339 | − fc->sb_flags |= SB_SYNCHRONOUS; | |
| 1340 | − | |
| 1341 | 1319 | /* Get a superblock - note that we may end up sharing one that already exists */ |
| 1342 | 1320 | fc->s_fs_info = server; |
| 1343 | 1321 | s = sget_fc(fc, compare_super, nfs_set_super); |
| @@ -1361,13 +1339,8 @@ int nfs_get_tree_common(struct fs_context *fc) · 17 unmodified lines | ||
| 1361 | 1339 | } |
| 1362 | 1340 | |
| 1363 | 1341 | if (!s->s_root) { |
| 1364 | − unsigned bsize = ctx->clone_data.inherited_bsize; | |
| 1365 | 1342 | /* initial superblock/root creation */ |
| 1366 | 1343 | nfs_fill_super(s, ctx); |
| 1367 | − if (bsize) { | |
| 1368 | − s->s_blocksize_bits = bsize; | |
| 1369 | − s->s_blocksize = 1U << bsize; | |
| 1370 | − } | |
| 1371 | 1344 | error = nfs_get_cache_cookie(s, ctx); |
| 1372 | 1345 | if (error < 0) |
| 1373 | 1346 | goto error_splat_super; |
| @@ -390,7 +390,8 @@ nfs_async_rename(struct inode *old_dir, struct inode *new_dir, · 389 unmodified lines | ||
| 390 | 390 | |
| 391 | 391 | nfs_sb_active(old_dir->i_sb); |
| 392 | 392 | |
| 393 | − NFS_PROTO(data->old_dir)->rename_setup(&msg, old_dentry, new_dentry); | |
| 393 | + NFS_PROTO(data->old_dir)->rename_setup(&msg, old_dentry, new_dentry, | |
| 394 | + old_dir == new_dir ? old_dir : NULL); | |
| 394 | 395 | |
| 395 | 396 | return rpc_run_task(&task_setup_data); |
| 396 | 397 | } |
| @@ -344,6 +344,7 @@ struct nfs4_copy_state { · 343 unmodified lines | ||
| 344 | 344 | #define NFS_INO_LAYOUTCOMMITTING (10) /* layoutcommit inflight */ |
| 345 | 345 | #define NFS_INO_LAYOUTSTATS (11) /* layoutstats inflight */ |
| 346 | 346 | #define NFS_INO_ODIRECT (12) /* I/O setting is O_DIRECT */ |
| 347 | +#define NFS_INO_REQ_DIR_DELEG (13) /* Request a directory delegation */ | |
| 347 | 348 | |
| 348 | 349 | static inline struct nfs_inode *NFS_I(const struct inode *inode) |
| 349 | 350 | { |
| @@ -172,6 +172,11 @@ struct nfs_server { · 171 unmodified lines | ||
| 172 | 172 | #define NFS_MOUNT_FORCE_RDIRPLUS 0x20000000 |
| 173 | 173 | #define NFS_MOUNT_NETUNREACH_FATAL 0x40000000 |
| 174 | 174 | |
| 175 | + unsigned int automount_inherit; /* Properties inherited by automount */ | |
| 176 | +#define NFS_AUTOMOUNT_INHERIT_BSIZE 0x0001 | |
| 177 | +#define NFS_AUTOMOUNT_INHERIT_RSIZE 0x0002 | |
| 178 | +#define NFS_AUTOMOUNT_INHERIT_WSIZE 0x0004 | |
| 179 | + | |
| 175 | 180 | unsigned int caps; /* server capabilities */ |
| 176 | 181 | __u64 fattr_valid; /* Valid attributes */ |
| 177 | 182 | unsigned int rsize; /* read size */ |
| @@ -305,6 +310,7 @@ struct nfs_server { · 127 unmodified lines | ||
| 305 | 310 | #define NFS_CAP_REBOOT_LAYOUTRETURN (1U << 8) |
| 306 | 311 | #define NFS_CAP_OFFLOAD_STATUS (1U << 9) |
| 307 | 312 | #define NFS_CAP_ZERO_RANGE (1U << 10) |
| 313 | +#define NFS_CAP_DIR_DELEG (1U << 11) | |
| 308 | 314 | #define NFS_CAP_OPEN_XOR (1U << 12) |
| 309 | 315 | #define NFS_CAP_DELEGTIME (1U << 13) |
| 310 | 316 | #define NFS_CAP_POSIX_LOCK (1U << 14) |
| @@ -1092,12 +1092,19 @@ struct nfs4_getattr_arg { · 1091 unmodified lines | ||
| 1092 | 1092 | struct nfs4_sequence_args seq_args; |
| 1093 | 1093 | const struct nfs_fh * fh; |
| 1094 | 1094 | const u32 * bitmask; |
| 1095 | + bool get_dir_deleg; | |
| 1096 | +}; | |
| 1097 | + | |
| 1098 | +struct nfs4_gdd_res { | |
| 1099 | + u32 status; | |
| 1100 | + nfs4_stateid deleg; | |
| 1095 | 1101 | }; |
| 1096 | 1102 | |
| 1097 | 1103 | struct nfs4_getattr_res { |
| 1098 | 1104 | struct nfs4_sequence_res seq_res; |
| 1099 | 1105 | const struct nfs_server * server; |
| 1100 | 1106 | struct nfs_fattr * fattr; |
| 1107 | + struct nfs4_gdd_res * gdd_res; | |
| 1101 | 1108 | }; |
| 1102 | 1109 | |
| 1103 | 1110 | struct nfs4_link_arg { |
| @@ -1801,7 +1808,8 @@ struct nfs_rpc_ops { · 697 unmodified lines | ||
| 1801 | 1808 | int (*unlink_done) (struct rpc_task *, struct inode *); |
| 1802 | 1809 | void (*rename_setup) (struct rpc_message *msg, |
| 1803 | 1810 | struct dentry *old_dentry, |
| 1804 | − struct dentry *new_dentry); | |
| 1811 | + struct dentry *new_dentry, | |
| 1812 | + struct inode *same_parent); | |
| 1805 | 1813 | void (*rename_rpc_prepare)(struct rpc_task *task, struct nfs_renamedata *); |
| 1806 | 1814 | int (*rename_done) (struct rpc_task *task, struct inode *old_dir, struct inode *new_dir); |
| 1807 | 1815 | int (*link) (struct inode *, struct inode *, const struct qstr *); |
| @@ -25,12 +25,14 @@ void xprt_init_bc_request(struct rpc_rqst *req, struct rpc_task *task, · 24 unmodified lines | ||
| 25 | 25 | void xprt_free_bc_request(struct rpc_rqst *req); |
| 26 | 26 | int xprt_setup_backchannel(struct rpc_xprt *, unsigned int min_reqs); |
| 27 | 27 | void xprt_destroy_backchannel(struct rpc_xprt *, unsigned int max_reqs); |
| 28 | +void xprt_enqueue_bc_request(struct rpc_rqst *req); | |
| 28 | 29 | |
| 29 | 30 | /* Socket backchannel transport methods */ |
| 30 | 31 | int xprt_setup_bc(struct rpc_xprt *xprt, unsigned int min_reqs); |
| 31 | 32 | void xprt_destroy_bc(struct rpc_xprt *xprt, unsigned int max_reqs); |
| 32 | 33 | void xprt_free_bc_rqst(struct rpc_rqst *req); |
| 33 | 34 | unsigned int xprt_bc_max_slots(struct rpc_xprt *xprt); |
| 35 | +void xprt_svc_destroy_nullify_bc(struct rpc_xprt *xprt, struct svc_serv **serv); | |
| 34 | 36 | |
| 35 | 37 | /* |
| 36 | 38 | * Determine if a shared backchannel is in use |
| @@ -68,5 +70,10 @@ static inline void set_bc_enabled(struct svc_serv *serv) · 31 unmodified lines | ||
| 68 | 70 | static inline void xprt_free_bc_request(struct rpc_rqst *req) |
| 69 | 71 | { |
| 70 | 72 | } |
| 73 | + | |
| 74 | +static inline void xprt_svc_destroy_nullify_bc(struct rpc_xprt *xprt, struct svc_serv **serv) | |
| 75 | +{ | |
| 76 | + svc_destroy(serv); | |
| 77 | +} | |
| 71 | 78 | #endif /* CONFIG_SUNRPC_BACKCHANNEL */ |
| 72 | 79 | #endif /* _LINUX_SUNRPC_BC_XPRT_H */ |
| @@ -24,6 +24,22 @@ unsigned int xprt_bc_max_slots(struct rpc_xprt *xprt) · 23 unmodified lines | ||
| 24 | 24 | return BC_MAX_SLOTS; |
| 25 | 25 | } |
| 26 | 26 | |
| 27 | +/* | |
| 28 | + * Helper function to nullify backchannel server pointer in transport. | |
| 29 | + * We need to synchronize setting the pointer to NULL (done so after | |
| 30 | + * the backchannel server is shutdown) with the usage of that pointer | |
| 31 | + * by the backchannel request processing routines | |
| 32 | + * xprt_complete_bc_request() and rpcrdma_bc_receive_call(). | |
| 33 | + */ | |
| 34 | +void xprt_svc_destroy_nullify_bc(struct rpc_xprt *xprt, struct svc_serv **serv) | |
| 35 | +{ | |
| 36 | + spin_lock(&xprt->bc_pa_lock); | |
| 37 | + svc_destroy(serv); | |
| 38 | + xprt->bc_serv = NULL; | |
| 39 | + spin_unlock(&xprt->bc_pa_lock); | |
| 40 | +} | |
| 41 | +EXPORT_SYMBOL_GPL(xprt_svc_destroy_nullify_bc); | |
| 42 | + | |
| 27 | 43 | /* |
| 28 | 44 | * Helper routines that track the number of preallocation elements |
| 29 | 45 | * on the transport. |
| @@ -354,7 +370,6 @@ found: · 324 unmodified lines | ||
| 354 | 370 | void xprt_complete_bc_request(struct rpc_rqst *req, uint32_t copied) |
| 355 | 371 | { |
| 356 | 372 | struct rpc_xprt *xprt = req->rq_xprt; |
| 357 | − struct svc_serv *bc_serv = xprt->bc_serv; | |
| 358 | 373 | |
| 359 | 374 | spin_lock(&xprt->bc_pa_lock); |
| 360 | 375 | list_del(&req->rq_bc_pa_list); |
| @@ -365,7 +380,21 @@ void xprt_complete_bc_request(struct rpc_rqst *req, uint32_t copied) · 4 unmodified lines | ||
| 365 | 380 | set_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state); |
| 366 | 381 | |
| 367 | 382 | dprintk("RPC: add callback request to list\n"); |
| 383 | + xprt_enqueue_bc_request(req); | |
| 384 | +} | |
| 385 | + | |
| 386 | +void xprt_enqueue_bc_request(struct rpc_rqst *req) | |
| 387 | +{ | |
| 388 | + struct rpc_xprt *xprt = req->rq_xprt; | |
| 389 | + struct svc_serv *bc_serv; | |
| 390 | + | |
| 368 | 391 | xprt_get(xprt); |
| 369 | − lwq_enqueue(&req->rq_bc_list, &bc_serv->sv_cb_list); | |
| 370 | − svc_pool_wake_idle_thread(&bc_serv->sv_pools[0]); | |
| 392 | + spin_lock(&xprt->bc_pa_lock); | |
| 393 | + bc_serv = xprt->bc_serv; | |
| 394 | + if (bc_serv) { | |
| 395 | + lwq_enqueue(&req->rq_bc_list, &bc_serv->sv_cb_list); | |
| 396 | + svc_pool_wake_idle_thread(&bc_serv->sv_pools[0]); | |
| 397 | + } | |
| 398 | + spin_unlock(&xprt->bc_pa_lock); | |
| 371 | 399 | } |
| 400 | +EXPORT_SYMBOL_GPL(xprt_enqueue_bc_request); | |
| @@ -9,6 +9,7 @@ · 8 unmodified lines | ||
| 9 | 9 | #include <linux/sunrpc/svc.h> |
| 10 | 10 | #include <linux/sunrpc/svc_xprt.h> |
| 11 | 11 | #include <linux/sunrpc/svc_rdma.h> |
| 12 | +#include <linux/sunrpc/bc_xprt.h> | |
| 12 | 13 | |
| 13 | 14 | #include "xprt_rdma.h" |
| 14 | 15 | #include <trace/events/rpcrdma.h> |
| @@ -220,7 +221,6 @@ void rpcrdma_bc_receive_call(struct rpcrdma_xprt *r_xprt, · 205 unmodified lines | ||
| 220 | 221 | struct rpcrdma_rep *rep) |
| 221 | 222 | { |
| 222 | 223 | struct rpc_xprt *xprt = &r_xprt->rx_xprt; |
| 223 | − struct svc_serv *bc_serv; | |
| 224 | 224 | struct rpcrdma_req *req; |
| 225 | 225 | struct rpc_rqst *rqst; |
| 226 | 226 | struct xdr_buf *buf; |
| @@ -261,11 +261,7 @@ void rpcrdma_bc_receive_call(struct rpcrdma_xprt *r_xprt, · 34 unmodified lines | ||
| 261 | 261 | trace_xprtrdma_cb_call(r_xprt, rqst); |
| 262 | 262 | |
| 263 | 263 | /* Queue rqst for ULP's callback service */ |
| 264 | − bc_serv = xprt->bc_serv; | |
| 265 | − xprt_get(xprt); | |
| 266 | − lwq_enqueue(&rqst->rq_bc_list, &bc_serv->sv_cb_list); | |
| 267 | − | |
| 268 | − svc_pool_wake_idle_thread(&bc_serv->sv_pools[0]); | |
| 264 | + xprt_enqueue_bc_request(rqst); | |
| 269 | 265 | |
| 270 | 266 | r_xprt->rx_stats.bcall_count++; |
| 271 | 267 | return; |