Pull NFS client updates from Anna Schumaker: "Stable bugfixes: - Fix -EACCESS on commit to DS handling - Fix initialization of nfs_page_array->npages - Only invalidate dentries that are actually invalid Features: - Enable NFSoRDMA transparent state migration - Add support for lookup-by-filehandle - Add support for nfs re-exporting Other bugfixes and cleanups: - Christoph cleaned up the way we declare NFS operations - Clean up various internal structures - Various cleanups to commits - Various improvements to error handling - Set the dt_type of . and .. entries in NFS v4 - Make slot allocation more reliable - Fix fscache stat printing - Fix uninitialized variable warnings - Fix potential list overrun in nfs_atomic_open() - Fix a race in NFSoRDMA RPC reply handler - Fix return size for nfs42_proc_copy() - Fix against MAC forgery timing attacks" * tag 'nfs-for-4.13-1' of git://git.linux-nfs.org/projects/anna/linux-nfs: (68 commits) NFS: Don't run wake_up_bit() when nobody is waiting... nfs: add export operations nfs4: add NFSv4 LOOKUPP handlers nfs: add a nfs_ilookup helper nfs: replace d_add with d_splice_alias in atomic_open sunrpc: use constant time memory comparison for mac NFSv4.2 fix size storage for nfs42_proc_copy xprtrdma: Fix documenting comments in frwr_ops.c xprtrdma: Replace PAGE_MASK with offset_in_page() xprtrdma: FMR does not need list_del_init() xprtrdma: Demote "connect" log messages NFSv4.1: Use seqid returned by EXCHANGE_ID after state migration NFSv4.1: Handle EXCHGID4_FLAG_CONFIRMED_R during NFSv4.1 migration xprtrdma: Don't defer MR recovery if ro_map fails xprtrdma: Fix FRWR invalidation error recovery xprtrdma: Fix client lock-up after application signal fires xprtrdma: Rename rpcrdma_req::rl_free xprtrdma: Pass only the list of registered MRs to ro_unmap_sync xprtrdma: Pre-mark remotely invalidated MRs xprtrdma: On invalidation failure, remove MWs from rl_registered ...
Unified · Split
| @@ -7,7 +7,7 @@ obj-$(CONFIG_NFS_FS) += nfs.o · 6 unmodified lines | ||
| 7 | 7 | CFLAGS_nfstrace.o += -I$(src) |
| 8 | 8 | nfs-y := client.o dir.o file.o getroot.o inode.o super.o \ |
| 9 | 9 | io.o direct.o pagelist.o read.o symlink.o unlink.o \ |
| 10 | − write.o namespace.o mount_clnt.o nfstrace.o | |
| 10 | + write.o namespace.o mount_clnt.o nfstrace.o export.o | |
| 11 | 11 | nfs-$(CONFIG_ROOT_NFS) += nfsroot.o |
| 12 | 12 | nfs-$(CONFIG_SYSCTL) += sysctl.o |
| 13 | 13 | nfs-$(CONFIG_NFS_FSCACHE) += fscache.o fscache-index.o |
| @@ -151,7 +151,7 @@ struct nfs_cache_array { · 150 unmodified lines | ||
| 151 | 151 | struct nfs_cache_array_entry array[0]; |
| 152 | 152 | }; |
| 153 | 153 | |
| 154 | −typedef int (*decode_dirent_t)(struct xdr_stream *, struct nfs_entry *, int); | |
| 154 | +typedef int (*decode_dirent_t)(struct xdr_stream *, struct nfs_entry *, bool); | |
| 155 | 155 | typedef struct { |
| 156 | 156 | struct file *file; |
| 157 | 157 | struct page *page; |
| @@ -165,8 +165,8 @@ typedef struct { · 7 unmodified lines | ||
| 165 | 165 | unsigned long timestamp; |
| 166 | 166 | unsigned long gencount; |
| 167 | 167 | unsigned int cache_entry_index; |
| 168 | − unsigned int plus:1; | |
| 169 | − unsigned int eof:1; | |
| 168 | + bool plus; | |
| 169 | + bool eof; | |
| 170 | 170 | } nfs_readdir_descriptor_t; |
| 171 | 171 | |
| 172 | 172 | /* |
| @@ -355,7 +355,7 @@ int nfs_readdir_xdr_filler(struct page **pages, nfs_readdir_descriptor_t *desc, · 182 unmodified lines | ||
| 355 | 355 | if (error == -ENOTSUPP && desc->plus) { |
| 356 | 356 | NFS_SERVER(inode)->caps &= ~NFS_CAP_READDIRPLUS; |
| 357 | 357 | clear_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(inode)->flags); |
| 358 | − desc->plus = 0; | |
| 358 | + desc->plus = false; | |
| 359 | 359 | goto again; |
| 360 | 360 | } |
| 361 | 361 | goto error; |
| @@ -557,7 +557,7 @@ int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *en · 195 unmodified lines | ||
| 557 | 557 | |
| 558 | 558 | count++; |
| 559 | 559 | |
| 560 | − if (desc->plus != 0) | |
| 560 | + if (desc->plus) | |
| 561 | 561 | nfs_prime_dcache(file_dentry(desc->file), entry); |
| 562 | 562 | |
| 563 | 563 | status = nfs_readdir_add_to_array(entry, page); |
| @@ -860,7 +860,7 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx) · 296 unmodified lines | ||
| 860 | 860 | desc->ctx = ctx; |
| 861 | 861 | desc->dir_cookie = &dir_ctx->dir_cookie; |
| 862 | 862 | desc->decode = NFS_PROTO(inode)->decode_dirent; |
| 863 | − desc->plus = nfs_use_readdirplus(inode, ctx) ? 1 : 0; | |
| 863 | + desc->plus = nfs_use_readdirplus(inode, ctx); | |
| 864 | 864 | |
| 865 | 865 | if (ctx->pos == 0 || nfs_attribute_cache_expired(inode)) |
| 866 | 866 | res = nfs_revalidate_mapping(inode, file->f_mapping); |
| @@ -885,8 +885,8 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx) · 18 unmodified lines | ||
| 885 | 885 | clear_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(inode)->flags); |
| 886 | 886 | nfs_zap_caches(inode); |
| 887 | 887 | desc->page_index = 0; |
| 888 | − desc->plus = 0; | |
| 889 | − desc->eof = 0; | |
| 888 | + desc->plus = false; | |
| 889 | + desc->eof = false; | |
| 890 | 890 | continue; |
| 891 | 891 | } |
| 892 | 892 | if (res < 0) |
| @@ -1115,11 +1115,13 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags) · 222 unmodified lines | ||
| 1115 | 1115 | /* Force a full look up iff the parent directory has changed */ |
| 1116 | 1116 | if (!nfs_is_exclusive_create(dir, flags) && |
| 1117 | 1117 | nfs_check_verifier(dir, dentry, flags & LOOKUP_RCU)) { |
| 1118 | − | |
| 1119 | − if (nfs_lookup_verify_inode(inode, flags)) { | |
| 1118 | + error = nfs_lookup_verify_inode(inode, flags); | |
| 1119 | + if (error) { | |
| 1120 | 1120 | if (flags & LOOKUP_RCU) |
| 1121 | 1121 | return -ECHILD; |
| 1122 | − goto out_zap_parent; | |
| 1122 | + if (error == -ESTALE) | |
| 1123 | + goto out_zap_parent; | |
| 1124 | + goto out_error; | |
| 1123 | 1125 | } |
| 1124 | 1126 | nfs_advise_use_readdirplus(dir); |
| 1125 | 1127 | goto out_valid; |
| @@ -1144,8 +1146,10 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags) · 18 unmodified lines | ||
| 1144 | 1146 | trace_nfs_lookup_revalidate_enter(dir, dentry, flags); |
| 1145 | 1147 | error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, label); |
| 1146 | 1148 | trace_nfs_lookup_revalidate_exit(dir, dentry, flags, error); |
| 1147 | − if (error) | |
| 1149 | + if (error == -ESTALE || error == -ENOENT) | |
| 1148 | 1150 | goto out_bad; |
| 1151 | + if (error) | |
| 1152 | + goto out_error; | |
| 1149 | 1153 | if (nfs_compare_fh(NFS_FH(inode), fhandle)) |
| 1150 | 1154 | goto out_bad; |
| 1151 | 1155 | if ((error = nfs_refresh_inode(inode, fattr)) != 0) |
| @@ -1427,8 +1431,10 @@ static int nfs_finish_open(struct nfs_open_context *ctx, · 275 unmodified lines | ||
| 1427 | 1431 | err = finish_open(file, dentry, do_open, opened); |
| 1428 | 1432 | if (err) |
| 1429 | 1433 | goto out; |
| 1430 | − nfs_file_set_open_context(file, ctx); | |
| 1431 | − | |
| 1434 | + if (S_ISREG(file->f_path.dentry->d_inode->i_mode)) | |
| 1435 | + nfs_file_set_open_context(file, ctx); | |
| 1436 | + else | |
| 1437 | + err = -ESTALE; | |
| 1432 | 1438 | out: |
| 1433 | 1439 | return err; |
| 1434 | 1440 | } |
| @@ -1512,7 +1518,7 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry, · 77 unmodified lines | ||
| 1512 | 1518 | d_drop(dentry); |
| 1513 | 1519 | switch (err) { |
| 1514 | 1520 | case -ENOENT: |
| 1515 | − d_add(dentry, NULL); | |
| 1521 | + d_splice_alias(NULL, dentry); | |
| 1516 | 1522 | nfs_set_verifier(dentry, nfs_save_change_attribute(dir)); |
| 1517 | 1523 | break; |
| 1518 | 1524 | case -EISDIR: |
| @@ -2035,7 +2041,11 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry, · 516 unmodified lines | ||
| 2035 | 2041 | } |
| 2036 | 2042 | |
| 2037 | 2043 | error = rpc_wait_for_completion_task(task); |
| 2038 | − if (error == 0) | |
| 2044 | + if (error != 0) { | |
| 2045 | + ((struct nfs_renamedata *)task->tk_calldata)->cancelled = 1; | |
| 2046 | + /* Paired with the atomic_dec_and_test() barrier in rpc_do_put_task() */ | |
| 2047 | + smp_wmb(); | |
| 2048 | + } else | |
| 2039 | 2049 | error = task->tk_status; |
| 2040 | 2050 | rpc_put_task(task); |
| 2041 | 2051 | nfs_mark_for_revalidate(old_inode); |
| @@ -0,0 +1,177 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (c) 2015, Primary Data, Inc. All rights reserved. | |
| 3 | + * | |
| 4 | + * Tao Peng <bergwolf@primarydata.com> | |
| 5 | + */ | |
| 6 | +#include <linux/dcache.h> | |
| 7 | +#include <linux/exportfs.h> | |
| 8 | +#include <linux/nfs.h> | |
| 9 | +#include <linux/nfs_fs.h> | |
| 10 | + | |
| 11 | +#include "internal.h" | |
| 12 | +#include "nfstrace.h" | |
| 13 | + | |
| 14 | +#define NFSDBG_FACILITY NFSDBG_VFS | |
| 15 | + | |
| 16 | +enum { | |
| 17 | + FILEID_HIGH_OFF = 0, /* inode fileid high */ | |
| 18 | + FILEID_LOW_OFF, /* inode fileid low */ | |
| 19 | + FILE_I_TYPE_OFF, /* inode type */ | |
| 20 | + EMBED_FH_OFF /* embeded server fh */ | |
| 21 | +}; | |
| 22 | + | |
| 23 | + | |
| 24 | +static struct nfs_fh *nfs_exp_embedfh(__u32 *p) | |
| 25 | +{ | |
| 26 | + return (struct nfs_fh *)(p + EMBED_FH_OFF); | |
| 27 | +} | |
| 28 | + | |
| 29 | +/* | |
| 30 | + * Let's break subtree checking for now... otherwise we'll have to embed parent fh | |
| 31 | + * but there might not be enough space. | |
| 32 | + */ | |
| 33 | +static int | |
| 34 | +nfs_encode_fh(struct inode *inode, __u32 *p, int *max_len, struct inode *parent) | |
| 35 | +{ | |
| 36 | + struct nfs_fh *server_fh = NFS_FH(inode); | |
| 37 | + struct nfs_fh *clnt_fh = nfs_exp_embedfh(p); | |
| 38 | + size_t fh_size = offsetof(struct nfs_fh, data) + server_fh->size; | |
| 39 | + int len = EMBED_FH_OFF + XDR_QUADLEN(fh_size); | |
| 40 | + | |
| 41 | + dprintk("%s: max fh len %d inode %p parent %p", | |
| 42 | + __func__, *max_len, inode, parent); | |
| 43 | + | |
| 44 | + if (*max_len < len || IS_AUTOMOUNT(inode)) { | |
| 45 | + dprintk("%s: fh len %d too small, required %d\n", | |
| 46 | + __func__, *max_len, len); | |
| 47 | + *max_len = len; | |
| 48 | + return FILEID_INVALID; | |
| 49 | + } | |
| 50 | + if (IS_AUTOMOUNT(inode)) { | |
| 51 | + *max_len = FILEID_INVALID; | |
| 52 | + goto out; | |
| 53 | + } | |
| 54 | + | |
| 55 | + p[FILEID_HIGH_OFF] = NFS_FILEID(inode) >> 32; | |
| 56 | + p[FILEID_LOW_OFF] = NFS_FILEID(inode); | |
| 57 | + p[FILE_I_TYPE_OFF] = inode->i_mode & S_IFMT; | |
| 58 | + p[len - 1] = 0; /* Padding */ | |
| 59 | + nfs_copy_fh(clnt_fh, server_fh); | |
| 60 | + *max_len = len; | |
| 61 | +out: | |
| 62 | + dprintk("%s: result fh fileid %llu mode %u size %d\n", | |
| 63 | + __func__, NFS_FILEID(inode), inode->i_mode, *max_len); | |
| 64 | + return *max_len; | |
| 65 | +} | |
| 66 | + | |
| 67 | +static struct dentry * | |
| 68 | +nfs_fh_to_dentry(struct super_block *sb, struct fid *fid, | |
| 69 | + int fh_len, int fh_type) | |
| 70 | +{ | |
| 71 | + struct nfs4_label *label = NULL; | |
| 72 | + struct nfs_fattr *fattr = NULL; | |
| 73 | + struct nfs_fh *server_fh = nfs_exp_embedfh(fid->raw); | |
| 74 | + size_t fh_size = offsetof(struct nfs_fh, data) + server_fh->size; | |
| 75 | + const struct nfs_rpc_ops *rpc_ops; | |
| 76 | + struct dentry *dentry; | |
| 77 | + struct inode *inode; | |
| 78 | + int len = EMBED_FH_OFF + XDR_QUADLEN(fh_size); | |
| 79 | + u32 *p = fid->raw; | |
| 80 | + int ret; | |
| 81 | + | |
| 82 | + /* NULL translates to ESTALE */ | |
| 83 | + if (fh_len < len || fh_type != len) | |
| 84 | + return NULL; | |
| 85 | + | |
| 86 | + fattr = nfs_alloc_fattr(); | |
| 87 | + if (fattr == NULL) { | |
| 88 | + dentry = ERR_PTR(-ENOMEM); | |
| 89 | + goto out; | |
| 90 | + } | |
| 91 | + | |
| 92 | + fattr->fileid = ((u64)p[FILEID_HIGH_OFF] << 32) + p[FILEID_LOW_OFF]; | |
| 93 | + fattr->mode = p[FILE_I_TYPE_OFF]; | |
| 94 | + fattr->valid |= NFS_ATTR_FATTR_FILEID | NFS_ATTR_FATTR_TYPE; | |
| 95 | + | |
| 96 | + dprintk("%s: fileid %llu mode %d\n", __func__, fattr->fileid, fattr->mode); | |
| 97 | + | |
| 98 | + inode = nfs_ilookup(sb, fattr, server_fh); | |
| 99 | + if (inode) | |
| 100 | + goto out_found; | |
| 101 | + | |
| 102 | + label = nfs4_label_alloc(NFS_SB(sb), GFP_KERNEL); | |
| 103 | + if (IS_ERR(label)) { | |
| 104 | + dentry = ERR_CAST(label); | |
| 105 | + goto out_free_fattr; | |
| 106 | + } | |
| 107 | + | |
| 108 | + rpc_ops = NFS_SB(sb)->nfs_client->rpc_ops; | |
| 109 | + ret = rpc_ops->getattr(NFS_SB(sb), server_fh, fattr, label); | |
| 110 | + if (ret) { | |
| 111 | + dprintk("%s: getattr failed %d\n", __func__, ret); | |
| 112 | + dentry = ERR_PTR(ret); | |
| 113 | + goto out_free_label; | |
| 114 | + } | |
| 115 | + | |
| 116 | + inode = nfs_fhget(sb, server_fh, fattr, label); | |
| 117 | + | |
| 118 | +out_found: | |
| 119 | + dentry = d_obtain_alias(inode); | |
| 120 | + | |
| 121 | +out_free_label: | |
| 122 | + nfs4_label_free(label); | |
| 123 | +out_free_fattr: | |
| 124 | + nfs_free_fattr(fattr); | |
| 125 | +out: | |
| 126 | + return dentry; | |
| 127 | +} | |
| 128 | + | |
| 129 | +static struct dentry * | |
| 130 | +nfs_get_parent(struct dentry *dentry) | |
| 131 | +{ | |
| 132 | + int ret; | |
| 133 | + struct inode *inode = d_inode(dentry), *pinode; | |
| 134 | + struct super_block *sb = inode->i_sb; | |
| 135 | + struct nfs_server *server = NFS_SB(sb); | |
| 136 | + struct nfs_fattr *fattr = NULL; | |
| 137 | + struct nfs4_label *label = NULL; | |
| 138 | + struct dentry *parent; | |
| 139 | + struct nfs_rpc_ops const *ops = server->nfs_client->rpc_ops; | |
| 140 | + struct nfs_fh fh; | |
| 141 | + | |
| 142 | + if (!ops->lookupp) | |
| 143 | + return ERR_PTR(-EACCES); | |
| 144 | + | |
| 145 | + fattr = nfs_alloc_fattr(); | |
| 146 | + if (fattr == NULL) { | |
| 147 | + parent = ERR_PTR(-ENOMEM); | |
| 148 | + goto out; | |
| 149 | + } | |
| 150 | + | |
| 151 | + label = nfs4_label_alloc(server, GFP_KERNEL); | |
| 152 | + if (IS_ERR(label)) { | |
| 153 | + parent = ERR_CAST(label); | |
| 154 | + goto out_free_fattr; | |
| 155 | + } | |
| 156 | + | |
| 157 | + ret = ops->lookupp(inode, &fh, fattr, label); | |
| 158 | + if (ret) { | |
| 159 | + parent = ERR_PTR(ret); | |
| 160 | + goto out_free_label; | |
| 161 | + } | |
| 162 | + | |
| 163 | + pinode = nfs_fhget(sb, &fh, fattr, label); | |
| 164 | + parent = d_obtain_alias(pinode); | |
| 165 | +out_free_label: | |
| 166 | + nfs4_label_free(label); | |
| 167 | +out_free_fattr: | |
| 168 | + nfs_free_fattr(fattr); | |
| 169 | +out: | |
| 170 | + return parent; | |
| 171 | +} | |
| 172 | + | |
| 173 | +const struct export_operations nfs_export_ops = { | |
| 174 | + .encode_fh = nfs_encode_fh, | |
| 175 | + .fh_to_dentry = nfs_fh_to_dentry, | |
| 176 | + .get_parent = nfs_get_parent, | |
| 177 | +}; | |
| @@ -126,32 +126,13 @@ static int filelayout_async_handle_error(struct rpc_task *task, · 125 unmodified lines | ||
| 126 | 126 | { |
| 127 | 127 | struct pnfs_layout_hdr *lo = lseg->pls_layout; |
| 128 | 128 | struct inode *inode = lo->plh_inode; |
| 129 | − struct nfs_server *mds_server = NFS_SERVER(inode); | |
| 130 | 129 | struct nfs4_deviceid_node *devid = FILELAYOUT_DEVID_NODE(lseg); |
| 131 | − struct nfs_client *mds_client = mds_server->nfs_client; | |
| 132 | 130 | struct nfs4_slot_table *tbl = &clp->cl_session->fc_slot_table; |
| 133 | 131 | |
| 134 | 132 | if (task->tk_status >= 0) |
| 135 | 133 | return 0; |
| 136 | 134 | |
| 137 | 135 | switch (task->tk_status) { |
| 138 | − /* MDS state errors */ | |
| 139 | − case -NFS4ERR_DELEG_REVOKED: | |
| 140 | − case -NFS4ERR_ADMIN_REVOKED: | |
| 141 | − case -NFS4ERR_BAD_STATEID: | |
| 142 | − case -NFS4ERR_OPENMODE: | |
| 143 | − if (state == NULL) | |
| 144 | − break; | |
| 145 | − if (nfs4_schedule_stateid_recovery(mds_server, state) < 0) | |
| 146 | − goto out_bad_stateid; | |
| 147 | − goto wait_on_recovery; | |
| 148 | − case -NFS4ERR_EXPIRED: | |
| 149 | − if (state != NULL) { | |
| 150 | − if (nfs4_schedule_stateid_recovery(mds_server, state) < 0) | |
| 151 | − goto out_bad_stateid; | |
| 152 | − } | |
| 153 | − nfs4_schedule_lease_recovery(mds_client); | |
| 154 | − goto wait_on_recovery; | |
| 155 | 136 | /* DS session errors */ |
| 156 | 137 | case -NFS4ERR_BADSESSION: |
| 157 | 138 | case -NFS4ERR_BADSLOT: |
| @@ -172,6 +153,7 @@ static int filelayout_async_handle_error(struct rpc_task *task, · 14 unmodified lines | ||
| 172 | 153 | case -NFS4ERR_RETRY_UNCACHED_REP: |
| 173 | 154 | break; |
| 174 | 155 | /* Invalidate Layout errors */ |
| 156 | + case -NFS4ERR_ACCESS: | |
| 175 | 157 | case -NFS4ERR_PNFS_NO_LAYOUT: |
| 176 | 158 | case -ESTALE: /* mapped NFS4ERR_STALE */ |
| 177 | 159 | case -EBADHANDLE: /* mapped NFS4ERR_BADHANDLE */ |
| @@ -202,26 +184,17 @@ static int filelayout_async_handle_error(struct rpc_task *task, · 24 unmodified lines | ||
| 202 | 184 | task->tk_status); |
| 203 | 185 | nfs4_mark_deviceid_unavailable(devid); |
| 204 | 186 | pnfs_error_mark_layout_for_return(inode, lseg); |
| 187 | + pnfs_set_lo_fail(lseg); | |
| 205 | 188 | rpc_wake_up(&tbl->slot_tbl_waitq); |
| 206 | 189 | /* fall through */ |
| 207 | 190 | default: |
| 208 | − pnfs_set_lo_fail(lseg); | |
| 209 | 191 | reset: |
| 210 | 192 | dprintk("%s Retry through MDS. Error %d\n", __func__, |
| 211 | 193 | task->tk_status); |
| 212 | 194 | return -NFS4ERR_RESET_TO_MDS; |
| 213 | 195 | } |
| 214 | −out: | |
| 215 | 196 | task->tk_status = 0; |
| 216 | 197 | return -EAGAIN; |
| 217 | −out_bad_stateid: | |
| 218 | − task->tk_status = -EIO; | |
| 219 | − return 0; | |
| 220 | −wait_on_recovery: | |
| 221 | − rpc_sleep_on(&mds_client->cl_rpcwaitq, task, NULL); | |
| 222 | − if (test_bit(NFS4CLNT_MANAGER_RUNNING, &mds_client->cl_state) == 0) | |
| 223 | − rpc_wake_up_queued_task(&mds_client->cl_rpcwaitq, task); | |
| 224 | − goto out; | |
| 225 | 198 | } |
| 226 | 199 | |
| 227 | 200 | /* NFS_PROTO call done callback routines */ |
| @@ -1050,34 +1050,10 @@ static int ff_layout_async_handle_error_v4(struct rpc_task *task, · 1049 unmodified lines | ||
| 1050 | 1050 | { |
| 1051 | 1051 | struct pnfs_layout_hdr *lo = lseg->pls_layout; |
| 1052 | 1052 | struct inode *inode = lo->plh_inode; |
| 1053 | − struct nfs_server *mds_server = NFS_SERVER(inode); | |
| 1054 | − | |
| 1055 | 1053 | struct nfs4_deviceid_node *devid = FF_LAYOUT_DEVID_NODE(lseg, idx); |
| 1056 | − struct nfs_client *mds_client = mds_server->nfs_client; | |
| 1057 | 1054 | struct nfs4_slot_table *tbl = &clp->cl_session->fc_slot_table; |
| 1058 | 1055 | |
| 1059 | 1056 | switch (task->tk_status) { |
| 1060 | − /* MDS state errors */ | |
| 1061 | − case -NFS4ERR_DELEG_REVOKED: | |
| 1062 | − case -NFS4ERR_ADMIN_REVOKED: | |
| 1063 | − case -NFS4ERR_BAD_STATEID: | |
| 1064 | − if (state == NULL) | |
| 1065 | − break; | |
| 1066 | − nfs_remove_bad_delegation(state->inode, NULL); | |
| 1067 | − case -NFS4ERR_OPENMODE: | |
| 1068 | − if (state == NULL) | |
| 1069 | − break; | |
| 1070 | − if (nfs4_schedule_stateid_recovery(mds_server, state) < 0) | |
| 1071 | − goto out_bad_stateid; | |
| 1072 | − goto wait_on_recovery; | |
| 1073 | − case -NFS4ERR_EXPIRED: | |
| 1074 | − if (state != NULL) { | |
| 1075 | − if (nfs4_schedule_stateid_recovery(mds_server, state) < 0) | |
| 1076 | − goto out_bad_stateid; | |
| 1077 | − } | |
| 1078 | − nfs4_schedule_lease_recovery(mds_client); | |
| 1079 | − goto wait_on_recovery; | |
| 1080 | − /* DS session errors */ | |
| 1081 | 1057 | case -NFS4ERR_BADSESSION: |
| 1082 | 1058 | case -NFS4ERR_BADSLOT: |
| 1083 | 1059 | case -NFS4ERR_BAD_HIGH_SLOT: |
| @@ -1137,17 +1113,8 @@ reset: · 53 unmodified lines | ||
| 1137 | 1113 | task->tk_status); |
| 1138 | 1114 | return -NFS4ERR_RESET_TO_MDS; |
| 1139 | 1115 | } |
| 1140 | −out: | |
| 1141 | 1116 | task->tk_status = 0; |
| 1142 | 1117 | return -EAGAIN; |
| 1143 | −out_bad_stateid: | |
| 1144 | − task->tk_status = -EIO; | |
| 1145 | − return 0; | |
| 1146 | −wait_on_recovery: | |
| 1147 | − rpc_sleep_on(&mds_client->cl_rpcwaitq, task, NULL); | |
| 1148 | − if (test_bit(NFS4CLNT_MANAGER_RUNNING, &mds_client->cl_state) == 0) | |
| 1149 | − rpc_wake_up_queued_task(&mds_client->cl_rpcwaitq, task); | |
| 1150 | − goto out; | |
| 1151 | 1118 | } |
| 1152 | 1119 | |
| 1153 | 1120 | /* Retry all errors through either pNFS or MDS except for -EJUKEBOX */ |
| @@ -386,6 +386,28 @@ void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr, · 385 unmodified lines | ||
| 386 | 386 | #endif |
| 387 | 387 | EXPORT_SYMBOL_GPL(nfs_setsecurity); |
| 388 | 388 | |
| 389 | +/* Search for inode identified by fh, fileid and i_mode in inode cache. */ | |
| 390 | +struct inode * | |
| 391 | +nfs_ilookup(struct super_block *sb, struct nfs_fattr *fattr, struct nfs_fh *fh) | |
| 392 | +{ | |
| 393 | + struct nfs_find_desc desc = { | |
| 394 | + .fh = fh, | |
| 395 | + .fattr = fattr, | |
| 396 | + }; | |
| 397 | + struct inode *inode; | |
| 398 | + unsigned long hash; | |
| 399 | + | |
| 400 | + if (!(fattr->valid & NFS_ATTR_FATTR_FILEID) || | |
| 401 | + !(fattr->valid & NFS_ATTR_FATTR_TYPE)) | |
| 402 | + return NULL; | |
| 403 | + | |
| 404 | + hash = nfs_fattr_to_ino_t(fattr); | |
| 405 | + inode = ilookup5(sb, hash, nfs_find_actor, &desc); | |
| 406 | + | |
| 407 | + dprintk("%s: returning %p\n", __func__, inode); | |
| 408 | + return inode; | |
| 409 | +} | |
| 410 | + | |
| 389 | 411 | /* |
| 390 | 412 | * This is our front-end to iget that looks up inodes by file handle |
| 391 | 413 | * instead of inode number. |
| @@ -525,8 +547,14 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr, st · 133 unmodified lines | ||
| 525 | 547 | nfs_fscache_init_inode(inode); |
| 526 | 548 | |
| 527 | 549 | unlock_new_inode(inode); |
| 528 | − } else | |
| 529 | − nfs_refresh_inode(inode, fattr); | |
| 550 | + } else { | |
| 551 | + int err = nfs_refresh_inode(inode, fattr); | |
| 552 | + if (err < 0) { | |
| 553 | + iput(inode); | |
| 554 | + inode = ERR_PTR(err); | |
| 555 | + goto out_no_inode; | |
| 556 | + } | |
| 557 | + } | |
| 530 | 558 | dprintk("NFS: nfs_fhget(%s/%Lu fh_crc=0x%08x ct=%d)\n", |
| 531 | 559 | inode->i_sb->s_id, |
| 532 | 560 | (unsigned long long)NFS_FILEID(inode), |
| @@ -1315,9 +1343,9 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat · 782 unmodified lines | ||
| 1315 | 1343 | return 0; |
| 1316 | 1344 | /* Has the inode gone and changed behind our back? */ |
| 1317 | 1345 | if ((fattr->valid & NFS_ATTR_FATTR_FILEID) && nfsi->fileid != fattr->fileid) |
| 1318 | − return -EIO; | |
| 1346 | + return -ESTALE; | |
| 1319 | 1347 | if ((fattr->valid & NFS_ATTR_FATTR_TYPE) && (inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT)) |
| 1320 | − return -EIO; | |
| 1348 | + return -ESTALE; | |
| 1321 | 1349 | |
| 1322 | 1350 | if (!nfs_file_has_buffered_writers(nfsi)) { |
| 1323 | 1351 | /* Verify a few of the more important attributes */ |
| @@ -11,6 +11,8 @@ · 10 unmodified lines | ||
| 11 | 11 | |
| 12 | 12 | #define NFS_MS_MASK (MS_RDONLY|MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_SYNCHRONOUS) |
| 13 | 13 | |
| 14 | +extern const struct export_operations nfs_export_ops; | |
| 15 | + | |
| 14 | 16 | struct nfs_string; |
| 15 | 17 | |
| 16 | 18 | /* Maximum number of readahead requests |
| @@ -273,17 +275,17 @@ static inline bool nfs_match_open_context(const struct nfs_open_context *ctx1, · 256 unmodified lines | ||
| 273 | 275 | /* nfs2xdr.c */ |
| 274 | 276 | extern const struct rpc_procinfo nfs_procedures[]; |
| 275 | 277 | extern int nfs2_decode_dirent(struct xdr_stream *, |
| 276 | − struct nfs_entry *, int); | |
| 278 | + struct nfs_entry *, bool); | |
| 277 | 279 | |
| 278 | 280 | /* nfs3xdr.c */ |
| 279 | 281 | extern const struct rpc_procinfo nfs3_procedures[]; |
| 280 | 282 | extern int nfs3_decode_dirent(struct xdr_stream *, |
| 281 | − struct nfs_entry *, int); | |
| 283 | + struct nfs_entry *, bool); | |
| 282 | 284 | |
| 283 | 285 | /* nfs4xdr.c */ |
| 284 | 286 | #if IS_ENABLED(CONFIG_NFS_V4) |
| 285 | 287 | extern int nfs4_decode_dirent(struct xdr_stream *, |
| 286 | − struct nfs_entry *, int); | |
| 288 | + struct nfs_entry *, bool); | |
| 287 | 289 | #endif |
| 288 | 290 | #ifdef CONFIG_NFS_V4_1 |
| 289 | 291 | extern const u32 nfs41_maxread_overhead; |
| @@ -939,7 +939,7 @@ static int nfs2_xdr_dec_writeres(struct rpc_rqst *req, struct xdr_stream *xdr, · 938 unmodified lines | ||
| 939 | 939 | * }; |
| 940 | 940 | */ |
| 941 | 941 | int nfs2_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, |
| 942 | − int plus) | |
| 942 | + bool plus) | |
| 943 | 943 | { |
| 944 | 944 | __be32 *p; |
| 945 | 945 | int error; |
| @@ -621,7 +621,7 @@ out: · 620 unmodified lines | ||
| 621 | 621 | */ |
| 622 | 622 | static int |
| 623 | 623 | nfs3_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, |
| 624 | − u64 cookie, struct page **pages, unsigned int count, int plus) | |
| 624 | + u64 cookie, struct page **pages, unsigned int count, bool plus) | |
| 625 | 625 | { |
| 626 | 626 | struct inode *dir = d_inode(dentry); |
| 627 | 627 | __be32 *verf = NFS_I(dir)->cookieverf; |
| @@ -1991,7 +1991,7 @@ out_status: · 1990 unmodified lines | ||
| 1991 | 1991 | * }; |
| 1992 | 1992 | */ |
| 1993 | 1993 | int nfs3_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, |
| 1994 | − int plus) | |
| 1994 | + bool plus) | |
| 1995 | 1995 | { |
| 1996 | 1996 | struct nfs_entry old = *entry; |
| 1997 | 1997 | __be32 *p; |
| @@ -146,7 +146,7 @@ static ssize_t _nfs42_proc_copy(struct file *src, · 145 unmodified lines | ||
| 146 | 146 | loff_t pos_src = args->src_pos; |
| 147 | 147 | loff_t pos_dst = args->dst_pos; |
| 148 | 148 | size_t count = args->count; |
| 149 | − int status; | |
| 149 | + ssize_t status; | |
| 150 | 150 | |
| 151 | 151 | status = nfs4_set_rw_stateid(&args->src_stateid, src_lock->open_context, |
| 152 | 152 | src_lock, FMODE_READ); |
| @@ -414,6 +414,7 @@ struct nfs_client *nfs4_init_client(struct nfs_client *clp, · 413 unmodified lines | ||
| 414 | 414 | if (clp != old) |
| 415 | 415 | clp->cl_preserve_clid = true; |
| 416 | 416 | nfs_put_client(clp); |
| 417 | + clear_bit(NFS_CS_TSM_POSSIBLE, &clp->cl_flags); | |
| 417 | 418 | return old; |
| 418 | 419 | |
| 419 | 420 | error: |
| @@ -852,6 +853,8 @@ static int nfs4_set_client(struct nfs_server *server, · 432 unmodified lines | ||
| 852 | 853 | set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags); |
| 853 | 854 | if (server->options & NFS_OPTION_MIGRATION) |
| 854 | 855 | set_bit(NFS_CS_MIGRATION, &cl_init.init_flags); |
| 856 | + if (test_bit(NFS_MIG_TSM_POSSIBLE, &server->mig_status)) | |
| 857 | + set_bit(NFS_CS_TSM_POSSIBLE, &cl_init.init_flags); | |
| 855 | 858 | |
| 856 | 859 | /* Allocate or find a client reference we can use */ |
| 857 | 860 | clp = nfs_get_client(&cl_init); |
| @@ -1212,9 +1215,11 @@ int nfs4_update_server(struct nfs_server *server, const char *hostname, · 354 unmodified lines | ||
| 1212 | 1215 | return -EAFNOSUPPORT; |
| 1213 | 1216 | |
| 1214 | 1217 | nfs_server_remove_lists(server); |
| 1218 | + set_bit(NFS_MIG_TSM_POSSIBLE, &server->mig_status); | |
| 1215 | 1219 | error = nfs4_set_client(server, hostname, sap, salen, buf, |
| 1216 | 1220 | clp->cl_proto, clnt->cl_timeout, |
| 1217 | 1221 | clp->cl_minorversion, net); |
| 1222 | + clear_bit(NFS_MIG_TSM_POSSIBLE, &server->mig_status); | |
| 1218 | 1223 | nfs_put_client(clp); |
| 1219 | 1224 | if (error != 0) { |
| 1220 | 1225 | nfs_server_insert_lists(server); |
| @@ -364,7 +364,8 @@ static int nfs_idmap_lookup_id(const char *name, size_t namelen, const char *typ · 363 unmodified lines | ||
| 364 | 364 | ret = -EINVAL; |
| 365 | 365 | } else { |
| 366 | 366 | ret = kstrtol(id_str, 10, &id_long); |
| 367 | − *id = (__u32)id_long; | |
| 367 | + if (!ret) | |
| 368 | + *id = (__u32)id_long; | |
| 368 | 369 | } |
| 369 | 370 | return ret; |
| 370 | 371 | } |
| @@ -275,6 +275,7 @@ const u32 nfs4_fs_locations_bitmap[3] = { · 274 unmodified lines | ||
| 275 | 275 | static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dentry, |
| 276 | 276 | struct nfs4_readdir_arg *readdir) |
| 277 | 277 | { |
| 278 | + unsigned int attrs = FATTR4_WORD0_FILEID | FATTR4_WORD0_TYPE; | |
| 278 | 279 | __be32 *start, *p; |
| 279 | 280 | |
| 280 | 281 | if (cookie > 2) { |
| @@ -305,8 +306,9 @@ static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dent · 24 unmodified lines | ||
| 305 | 306 | memcpy(p, ".\0\0\0", 4); /* entry */ |
| 306 | 307 | p++; |
| 307 | 308 | *p++ = xdr_one; /* bitmap length */ |
| 308 | − *p++ = htonl(FATTR4_WORD0_FILEID); /* bitmap */ | |
| 309 | − *p++ = htonl(8); /* attribute buffer length */ | |
| 309 | + *p++ = htonl(attrs); /* bitmap */ | |
| 310 | + *p++ = htonl(12); /* attribute buffer length */ | |
| 311 | + *p++ = htonl(NF4DIR); | |
| 310 | 312 | p = xdr_encode_hyper(p, NFS_FILEID(d_inode(dentry))); |
| 311 | 313 | } |
| 312 | 314 | |
| @@ -317,8 +319,9 @@ static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dent · 4 unmodified lines | ||
| 317 | 319 | memcpy(p, "..\0\0", 4); /* entry */ |
| 318 | 320 | p++; |
| 319 | 321 | *p++ = xdr_one; /* bitmap length */ |
| 320 | − *p++ = htonl(FATTR4_WORD0_FILEID); /* bitmap */ | |
| 321 | − *p++ = htonl(8); /* attribute buffer length */ | |
| 322 | + *p++ = htonl(attrs); /* bitmap */ | |
| 323 | + *p++ = htonl(12); /* attribute buffer length */ | |
| 324 | + *p++ = htonl(NF4DIR); | |
| 322 | 325 | p = xdr_encode_hyper(p, NFS_FILEID(d_inode(dentry->d_parent))); |
| 323 | 326 | |
| 324 | 327 | readdir->pgbase = (char *)p - (char *)start; |
| @@ -1034,11 +1037,11 @@ struct nfs4_opendata { · 709 unmodified lines | ||
| 1034 | 1037 | struct nfs4_state *state; |
| 1035 | 1038 | struct iattr attrs; |
| 1036 | 1039 | unsigned long timestamp; |
| 1037 | − unsigned int rpc_done : 1; | |
| 1038 | − unsigned int file_created : 1; | |
| 1039 | − unsigned int is_recover : 1; | |
| 1040 | + bool rpc_done; | |
| 1041 | + bool file_created; | |
| 1042 | + bool is_recover; | |
| 1043 | + bool cancelled; | |
| 1040 | 1044 | int rpc_status; |
| 1041 | − int cancelled; | |
| 1042 | 1045 | }; |
| 1043 | 1046 | |
| 1044 | 1047 | static bool nfs4_clear_cap_atomic_open_v1(struct nfs_server *server, |
| @@ -1962,7 +1965,7 @@ static void nfs4_open_confirm_done(struct rpc_task *task, void *calldata) · 917 unmodified lines | ||
| 1962 | 1965 | nfs4_stateid_copy(&data->o_res.stateid, &data->c_res.stateid); |
| 1963 | 1966 | nfs_confirm_seqid(&data->owner->so_seqid, 0); |
| 1964 | 1967 | renew_lease(data->o_res.server, data->timestamp); |
| 1965 | − data->rpc_done = 1; | |
| 1968 | + data->rpc_done = true; | |
| 1966 | 1969 | } |
| 1967 | 1970 | } |
| 1968 | 1971 | |
| @@ -1972,7 +1975,7 @@ static void nfs4_open_confirm_release(void *calldata) · 3 unmodified lines | ||
| 1972 | 1975 | struct nfs4_state *state = NULL; |
| 1973 | 1976 | |
| 1974 | 1977 | /* If this request hasn't been cancelled, do nothing */ |
| 1975 | − if (data->cancelled == 0) | |
| 1978 | + if (!data->cancelled) | |
| 1976 | 1979 | goto out_free; |
| 1977 | 1980 | /* In case of error, no cleanup! */ |
| 1978 | 1981 | if (!data->rpc_done) |
| @@ -2015,7 +2018,7 @@ static int _nfs4_proc_open_confirm(struct nfs4_opendata *data) · 36 unmodified lines | ||
| 2015 | 2018 | |
| 2016 | 2019 | nfs4_init_sequence(&data->c_arg.seq_args, &data->c_res.seq_res, 1); |
| 2017 | 2020 | kref_get(&data->kref); |
| 2018 | − data->rpc_done = 0; | |
| 2021 | + data->rpc_done = false; | |
| 2019 | 2022 | data->rpc_status = 0; |
| 2020 | 2023 | data->timestamp = jiffies; |
| 2021 | 2024 | if (data->is_recover) |
| @@ -2025,7 +2028,7 @@ static int _nfs4_proc_open_confirm(struct nfs4_opendata *data) · 3 unmodified lines | ||
| 2025 | 2028 | return PTR_ERR(task); |
| 2026 | 2029 | status = rpc_wait_for_completion_task(task); |
| 2027 | 2030 | if (status != 0) { |
| 2028 | − data->cancelled = 1; | |
| 2031 | + data->cancelled = true; | |
| 2029 | 2032 | smp_wmb(); |
| 2030 | 2033 | } else |
| 2031 | 2034 | status = data->rpc_status; |
| @@ -2124,7 +2127,7 @@ static void nfs4_open_done(struct rpc_task *task, void *calldata) · 92 unmodified lines | ||
| 2124 | 2127 | if (!(data->o_res.rflags & NFS4_OPEN_RESULT_CONFIRM)) |
| 2125 | 2128 | nfs_confirm_seqid(&data->owner->so_seqid, 0); |
| 2126 | 2129 | } |
| 2127 | − data->rpc_done = 1; | |
| 2130 | + data->rpc_done = true; | |
| 2128 | 2131 | } |
| 2129 | 2132 | |
| 2130 | 2133 | static void nfs4_open_release(void *calldata) |
| @@ -2133,7 +2136,7 @@ static void nfs4_open_release(void *calldata) · 2 unmodified lines | ||
| 2133 | 2136 | struct nfs4_state *state = NULL; |
| 2134 | 2137 | |
| 2135 | 2138 | /* If this request hasn't been cancelled, do nothing */ |
| 2136 | − if (data->cancelled == 0) | |
| 2139 | + if (!data->cancelled) | |
| 2137 | 2140 | goto out_free; |
| 2138 | 2141 | /* In case of error, no cleanup! */ |
| 2139 | 2142 | if (data->rpc_status != 0 || !data->rpc_done) |
| @@ -2179,20 +2182,20 @@ static int nfs4_run_open_task(struct nfs4_opendata *data, int isrecover) · 39 unmodified lines | ||
| 2179 | 2182 | |
| 2180 | 2183 | nfs4_init_sequence(&o_arg->seq_args, &o_res->seq_res, 1); |
| 2181 | 2184 | kref_get(&data->kref); |
| 2182 | − data->rpc_done = 0; | |
| 2185 | + data->rpc_done = false; | |
| 2183 | 2186 | data->rpc_status = 0; |
| 2184 | − data->cancelled = 0; | |
| 2185 | − data->is_recover = 0; | |
| 2187 | + data->cancelled = false; | |
| 2188 | + data->is_recover = false; | |
| 2186 | 2189 | if (isrecover) { |
| 2187 | 2190 | nfs4_set_sequence_privileged(&o_arg->seq_args); |
| 2188 | − data->is_recover = 1; | |
| 2191 | + data->is_recover = true; | |
| 2189 | 2192 | } |
| 2190 | 2193 | task = rpc_run_task(&task_setup_data); |
| 2191 | 2194 | if (IS_ERR(task)) |
| 2192 | 2195 | return PTR_ERR(task); |
| 2193 | 2196 | status = rpc_wait_for_completion_task(task); |
| 2194 | 2197 | if (status != 0) { |
| 2195 | − data->cancelled = 1; | |
| 2198 | + data->cancelled = true; | |
| 2196 | 2199 | smp_wmb(); |
| 2197 | 2200 | } else |
| 2198 | 2201 | status = data->rpc_status; |
| @@ -2287,9 +2290,9 @@ static int _nfs4_proc_open(struct nfs4_opendata *data) · 88 unmodified lines | ||
| 2287 | 2290 | |
| 2288 | 2291 | if (o_arg->open_flags & O_CREAT) { |
| 2289 | 2292 | if (o_arg->open_flags & O_EXCL) |
| 2290 | − data->file_created = 1; | |
| 2293 | + data->file_created = true; | |
| 2291 | 2294 | else if (o_res->cinfo.before != o_res->cinfo.after) |
| 2292 | − data->file_created = 1; | |
| 2295 | + data->file_created = true; | |
| 2293 | 2296 | if (data->file_created || dir->i_version != o_res->cinfo.after) |
| 2294 | 2297 | update_changeattr(dir, &o_res->cinfo, |
| 2295 | 2298 | o_res->f_attr->time_start); |
| @@ -3803,6 +3806,54 @@ nfs4_proc_lookup_mountpoint(struct inode *dir, const struct qstr *name, · 1507 unmodified lines | ||
| 3803 | 3806 | return (client == NFS_CLIENT(dir)) ? rpc_clone_client(client) : client; |
| 3804 | 3807 | } |
| 3805 | 3808 | |
| 3809 | +static int _nfs4_proc_lookupp(struct inode *inode, | |
| 3810 | + struct nfs_fh *fhandle, struct nfs_fattr *fattr, | |
| 3811 | + struct nfs4_label *label) | |
| 3812 | +{ | |
| 3813 | + struct rpc_clnt *clnt = NFS_CLIENT(inode); | |
| 3814 | + struct nfs_server *server = NFS_SERVER(inode); | |
| 3815 | + int status; | |
| 3816 | + struct nfs4_lookupp_arg args = { | |
| 3817 | + .bitmask = server->attr_bitmask, | |
| 3818 | + .fh = NFS_FH(inode), | |
| 3819 | + }; | |
| 3820 | + struct nfs4_lookupp_res res = { | |
| 3821 | + .server = server, | |
| 3822 | + .fattr = fattr, | |
| 3823 | + .label = label, | |
| 3824 | + .fh = fhandle, | |
| 3825 | + }; | |
| 3826 | + struct rpc_message msg = { | |
| 3827 | + .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUPP], | |
| 3828 | + .rpc_argp = &args, | |
| 3829 | + .rpc_resp = &res, | |
| 3830 | + }; | |
| 3831 | + | |
| 3832 | + args.bitmask = nfs4_bitmask(server, label); | |
| 3833 | + | |
| 3834 | + nfs_fattr_init(fattr); | |
| 3835 | + | |
| 3836 | + dprintk("NFS call lookupp ino=0x%lx\n", inode->i_ino); | |
| 3837 | + status = nfs4_call_sync(clnt, server, &msg, &args.seq_args, | |
| 3838 | + &res.seq_res, 0); | |
| 3839 | + dprintk("NFS reply lookupp: %d\n", status); | |
| 3840 | + return status; | |
| 3841 | +} | |
| 3842 | + | |
| 3843 | +static int nfs4_proc_lookupp(struct inode *inode, struct nfs_fh *fhandle, | |
| 3844 | + struct nfs_fattr *fattr, struct nfs4_label *label) | |
| 3845 | +{ | |
| 3846 | + struct nfs4_exception exception = { }; | |
| 3847 | + int err; | |
| 3848 | + do { | |
| 3849 | + err = _nfs4_proc_lookupp(inode, fhandle, fattr, label); | |
| 3850 | + trace_nfs4_lookupp(inode, err); | |
| 3851 | + err = nfs4_handle_exception(NFS_SERVER(inode), err, | |
| 3852 | + &exception); | |
| 3853 | + } while (exception.retry); | |
| 3854 | + return err; | |
| 3855 | +} | |
| 3856 | + | |
| 3806 | 3857 | static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry) |
| 3807 | 3858 | { |
| 3808 | 3859 | struct nfs_server *server = NFS_SERVER(inode); |
| @@ -4273,7 +4324,7 @@ static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry, · 464 unmodified lines | ||
| 4273 | 4324 | } |
| 4274 | 4325 | |
| 4275 | 4326 | static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, |
| 4276 | − u64 cookie, struct page **pages, unsigned int count, int plus) | |
| 4327 | + u64 cookie, struct page **pages, unsigned int count, bool plus) | |
| 4277 | 4328 | { |
| 4278 | 4329 | struct inode *dir = d_inode(dentry); |
| 4279 | 4330 | struct nfs4_readdir_arg args = { |
| @@ -4311,7 +4362,7 @@ static int _nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, · 31 unmodified lines | ||
| 4311 | 4362 | } |
| 4312 | 4363 | |
| 4313 | 4364 | static int nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, |
| 4314 | − u64 cookie, struct page **pages, unsigned int count, int plus) | |
| 4365 | + u64 cookie, struct page **pages, unsigned int count, bool plus) | |
| 4315 | 4366 | { |
| 4316 | 4367 | struct nfs4_exception exception = { }; |
| 4317 | 4368 | int err; |
| @@ -6135,7 +6186,7 @@ static void nfs4_lock_release(void *calldata) · 1817 unmodified lines | ||
| 6135 | 6186 | |
| 6136 | 6187 | dprintk("%s: begin!\n", __func__); |
| 6137 | 6188 | nfs_free_seqid(data->arg.open_seqid); |
| 6138 | − if (data->cancelled != 0) { | |
| 6189 | + if (data->cancelled) { | |
| 6139 | 6190 | struct rpc_task *task; |
| 6140 | 6191 | task = nfs4_do_unlck(&data->fl, data->ctx, data->lsp, |
| 6141 | 6192 | data->arg.lock_seqid); |
| @@ -6218,7 +6269,7 @@ static int _nfs4_do_setlk(struct nfs4_state *state, int cmd, struct file_lock *f · 76 unmodified lines | ||
| 6218 | 6269 | nfs4_handle_setlk_error(data->server, data->lsp, |
| 6219 | 6270 | data->arg.new_lock_owner, ret); |
| 6220 | 6271 | } else |
| 6221 | − data->cancelled = 1; | |
| 6272 | + data->cancelled = true; | |
| 6222 | 6273 | rpc_put_task(task); |
| 6223 | 6274 | dprintk("%s: done, ret = %d!\n", __func__, ret); |
| 6224 | 6275 | trace_nfs4_set_lock(fl, state, &data->res.stateid, cmd, ret); |
| @@ -7376,12 +7427,11 @@ static void nfs4_exchange_id_done(struct rpc_task *task, void *data) · 1151 unmodified lines | ||
| 7376 | 7427 | if (status == 0) { |
| 7377 | 7428 | clp->cl_clientid = cdata->res.clientid; |
| 7378 | 7429 | clp->cl_exchange_flags = cdata->res.flags; |
| 7430 | + clp->cl_seqid = cdata->res.seqid; | |
| 7379 | 7431 | /* Client ID is not confirmed */ |
| 7380 | − if (!(cdata->res.flags & EXCHGID4_FLAG_CONFIRMED_R)) { | |
| 7432 | + if (!(cdata->res.flags & EXCHGID4_FLAG_CONFIRMED_R)) | |
| 7381 | 7433 | clear_bit(NFS4_SESSION_ESTABLISHED, |
| 7382 | − &clp->cl_session->session_state); | |
| 7383 | − clp->cl_seqid = cdata->res.seqid; | |
| 7384 | − } | |
| 7434 | + &clp->cl_session->session_state); | |
| 7385 | 7435 | |
| 7386 | 7436 | kfree(clp->cl_serverowner); |
| 7387 | 7437 | clp->cl_serverowner = cdata->res.server_owner; |
| @@ -9313,6 +9363,7 @@ const struct nfs_rpc_ops nfs_v4_clientops = { · 1925 unmodified lines | ||
| 9313 | 9363 | .getattr = nfs4_proc_getattr, |
| 9314 | 9364 | .setattr = nfs4_proc_setattr, |
| 9315 | 9365 | .lookup = nfs4_proc_lookup, |
| 9366 | + .lookupp = nfs4_proc_lookupp, | |
| 9316 | 9367 | .access = nfs4_proc_access, |
| 9317 | 9368 | .readlink = nfs4_proc_readlink, |
| 9318 | 9369 | .create = nfs4_proc_create, |
| @@ -352,11 +352,17 @@ int nfs41_discover_server_trunking(struct nfs_client *clp, · 351 unmodified lines | ||
| 352 | 352 | if (clp != *result) |
| 353 | 353 | return 0; |
| 354 | 354 | |
| 355 | − /* Purge state if the client id was established in a prior instance */ | |
| 356 | − if (clp->cl_exchange_flags & EXCHGID4_FLAG_CONFIRMED_R) | |
| 357 | − set_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state); | |
| 358 | − else | |
| 359 | − set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); | |
| 355 | + /* | |
| 356 | + * Purge state if the client id was established in a prior | |
| 357 | + * instance and the client id could not have arrived on the | |
| 358 | + * server via Transparent State Migration. | |
| 359 | + */ | |
| 360 | + if (clp->cl_exchange_flags & EXCHGID4_FLAG_CONFIRMED_R) { | |
| 361 | + if (!test_bit(NFS_CS_TSM_POSSIBLE, &clp->cl_flags)) | |
| 362 | + set_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state); | |
| 363 | + else | |
| 364 | + set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state); | |
| 365 | + } | |
| 360 | 366 | nfs4_schedule_state_manager(clp); |
| 361 | 367 | status = nfs_wait_client_init_complete(clp); |
| 362 | 368 | if (status < 0) |
| @@ -891,6 +891,35 @@ DEFINE_NFS4_LOOKUP_EVENT(nfs4_remove); · 890 unmodified lines | ||
| 891 | 891 | DEFINE_NFS4_LOOKUP_EVENT(nfs4_get_fs_locations); |
| 892 | 892 | DEFINE_NFS4_LOOKUP_EVENT(nfs4_secinfo); |
| 893 | 893 | |
| 894 | +TRACE_EVENT(nfs4_lookupp, | |
| 895 | + TP_PROTO( | |
| 896 | + const struct inode *inode, | |
| 897 | + int error | |
| 898 | + ), | |
| 899 | + | |
| 900 | + TP_ARGS(inode, error), | |
| 901 | + | |
| 902 | + TP_STRUCT__entry( | |
| 903 | + __field(dev_t, dev) | |
| 904 | + __field(u64, ino) | |
| 905 | + __field(int, error) | |
| 906 | + ), | |
| 907 | + | |
| 908 | + TP_fast_assign( | |
| 909 | + __entry->dev = inode->i_sb->s_dev; | |
| 910 | + __entry->ino = NFS_FILEID(inode); | |
| 911 | + __entry->error = error; | |
| 912 | + ), | |
| 913 | + | |
| 914 | + TP_printk( | |
| 915 | + "error=%d (%s) inode=%02x:%02x:%llu", | |
| 916 | + __entry->error, | |
| 917 | + show_nfsv4_errors(__entry->error), | |
| 918 | + MAJOR(__entry->dev), MINOR(__entry->dev), | |
| 919 | + (unsigned long long)__entry->ino | |
| 920 | + ) | |
| 921 | +); | |
| 922 | + | |
| 894 | 923 | TRACE_EVENT(nfs4_rename, |
| 895 | 924 | TP_PROTO( |
| 896 | 925 | const struct inode *olddir, |
| @@ -159,6 +159,8 @@ static int nfs4_stat_to_errno(int); · 158 unmodified lines | ||
| 159 | 159 | (op_decode_hdr_maxsz) |
| 160 | 160 | #define encode_lookup_maxsz (op_encode_hdr_maxsz + nfs4_name_maxsz) |
| 161 | 161 | #define decode_lookup_maxsz (op_decode_hdr_maxsz) |
| 162 | +#define encode_lookupp_maxsz (op_encode_hdr_maxsz) | |
| 163 | +#define decode_lookupp_maxsz (op_decode_hdr_maxsz) | |
| 162 | 164 | #define encode_share_access_maxsz \ |
| 163 | 165 | (2) |
| 164 | 166 | #define encode_createmode_maxsz (1 + encode_attrs_maxsz + encode_verifier_maxsz) |
| @@ -618,6 +620,18 @@ static int nfs4_stat_to_errno(int); · 453 unmodified lines | ||
| 618 | 620 | decode_lookup_maxsz + \ |
| 619 | 621 | decode_getattr_maxsz + \ |
| 620 | 622 | decode_getfh_maxsz) |
| 623 | +#define NFS4_enc_lookupp_sz (compound_encode_hdr_maxsz + \ | |
| 624 | + encode_sequence_maxsz + \ | |
| 625 | + encode_putfh_maxsz + \ | |
| 626 | + encode_lookupp_maxsz + \ | |
| 627 | + encode_getattr_maxsz + \ | |
| 628 | + encode_getfh_maxsz) | |
| 629 | +#define NFS4_dec_lookupp_sz (compound_decode_hdr_maxsz + \ | |
| 630 | + decode_sequence_maxsz + \ | |
| 631 | + decode_putfh_maxsz + \ | |
| 632 | + decode_lookupp_maxsz + \ | |
| 633 | + decode_getattr_maxsz + \ | |
| 634 | + decode_getfh_maxsz) | |
| 621 | 635 | #define NFS4_enc_lookup_root_sz (compound_encode_hdr_maxsz + \ |
| 622 | 636 | encode_sequence_maxsz + \ |
| 623 | 637 | encode_putrootfh_maxsz + \ |
| @@ -1368,6 +1382,11 @@ static void encode_lookup(struct xdr_stream *xdr, const struct qstr *name, struc · 744 unmodified lines | ||
| 1368 | 1382 | encode_string(xdr, name->len, name->name); |
| 1369 | 1383 | } |
| 1370 | 1384 | |
| 1385 | +static void encode_lookupp(struct xdr_stream *xdr, struct compound_hdr *hdr) | |
| 1386 | +{ | |
| 1387 | + encode_op_hdr(xdr, OP_LOOKUPP, decode_lookupp_maxsz, hdr); | |
| 1388 | +} | |
| 1389 | + | |
| 1371 | 1390 | static void encode_share_access(struct xdr_stream *xdr, u32 share_access) |
| 1372 | 1391 | { |
| 1373 | 1392 | __be32 *p; |
| @@ -2122,6 +2141,26 @@ static void nfs4_xdr_enc_lookup(struct rpc_rqst *req, struct xdr_stream *xdr, · 748 unmodified lines | ||
| 2122 | 2141 | encode_nops(&hdr); |
| 2123 | 2142 | } |
| 2124 | 2143 | |
| 2144 | +/* | |
| 2145 | + * Encode LOOKUPP request | |
| 2146 | + */ | |
| 2147 | +static void nfs4_xdr_enc_lookupp(struct rpc_rqst *req, struct xdr_stream *xdr, | |
| 2148 | + const void *data) | |
| 2149 | +{ | |
| 2150 | + const struct nfs4_lookupp_arg *args = data; | |
| 2151 | + struct compound_hdr hdr = { | |
| 2152 | + .minorversion = nfs4_xdr_minorversion(&args->seq_args), | |
| 2153 | + }; | |
| 2154 | + | |
| 2155 | + encode_compound_hdr(xdr, req, &hdr); | |
| 2156 | + encode_sequence(xdr, &args->seq_args, &hdr); | |
| 2157 | + encode_putfh(xdr, args->fh, &hdr); | |
| 2158 | + encode_lookupp(xdr, &hdr); | |
| 2159 | + encode_getfh(xdr, &hdr); | |
| 2160 | + encode_getfattr(xdr, args->bitmask, &hdr); | |
| 2161 | + encode_nops(&hdr); | |
| 2162 | +} | |
| 2163 | + | |
| 2125 | 2164 | /* |
| 2126 | 2165 | * Encode LOOKUP_ROOT request |
| 2127 | 2166 | */ |
| @@ -5058,6 +5097,11 @@ static int decode_lookup(struct xdr_stream *xdr) · 2930 unmodified lines | ||
| 5058 | 5097 | return decode_op_hdr(xdr, OP_LOOKUP); |
| 5059 | 5098 | } |
| 5060 | 5099 | |
| 5100 | +static int decode_lookupp(struct xdr_stream *xdr) | |
| 5101 | +{ | |
| 5102 | + return decode_op_hdr(xdr, OP_LOOKUPP); | |
| 5103 | +} | |
| 5104 | + | |
| 5061 | 5105 | /* This is too sick! */ |
| 5062 | 5106 | static int decode_space_limit(struct xdr_stream *xdr, |
| 5063 | 5107 | unsigned long *pagemod_limit) |
| @@ -6237,6 +6281,36 @@ out: · 1173 unmodified lines | ||
| 6237 | 6281 | return status; |
| 6238 | 6282 | } |
| 6239 | 6283 | |
| 6284 | +/* | |
| 6285 | + * Decode LOOKUPP response | |
| 6286 | + */ | |
| 6287 | +static int nfs4_xdr_dec_lookupp(struct rpc_rqst *rqstp, struct xdr_stream *xdr, | |
| 6288 | + void *data) | |
| 6289 | +{ | |
| 6290 | + struct nfs4_lookupp_res *res = data; | |
| 6291 | + struct compound_hdr hdr; | |
| 6292 | + int status; | |
| 6293 | + | |
| 6294 | + status = decode_compound_hdr(xdr, &hdr); | |
| 6295 | + if (status) | |
| 6296 | + goto out; | |
| 6297 | + status = decode_sequence(xdr, &res->seq_res, rqstp); | |
| 6298 | + if (status) | |
| 6299 | + goto out; | |
| 6300 | + status = decode_putfh(xdr); | |
| 6301 | + if (status) | |
| 6302 | + goto out; | |
| 6303 | + status = decode_lookupp(xdr); | |
| 6304 | + if (status) | |
| 6305 | + goto out; | |
| 6306 | + status = decode_getfh(xdr, res->fh); | |
| 6307 | + if (status) | |
| 6308 | + goto out; | |
| 6309 | + status = decode_getfattr_label(xdr, res->fattr, res->label, res->server); | |
| 6310 | +out: | |
| 6311 | + return status; | |
| 6312 | +} | |
| 6313 | + | |
| 6240 | 6314 | /* |
| 6241 | 6315 | * Decode LOOKUP_ROOT response |
| 6242 | 6316 | */ |
| @@ -7447,7 +7521,7 @@ out: · 1204 unmodified lines | ||
| 7447 | 7521 | * on a directory already in our cache. |
| 7448 | 7522 | */ |
| 7449 | 7523 | int nfs4_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, |
| 7450 | − int plus) | |
| 7524 | + bool plus) | |
| 7451 | 7525 | { |
| 7452 | 7526 | unsigned int savep; |
| 7453 | 7527 | uint32_t bitmap[3] = {0}; |
| @@ -7614,6 +7688,7 @@ const struct rpc_procinfo nfs4_procedures[] = { · 160 unmodified lines | ||
| 7614 | 7688 | PROC(ACCESS, enc_access, dec_access), |
| 7615 | 7689 | PROC(GETATTR, enc_getattr, dec_getattr), |
| 7616 | 7690 | PROC(LOOKUP, enc_lookup, dec_lookup), |
| 7691 | + PROC(LOOKUPP, enc_lookupp, dec_lookupp), | |
| 7617 | 7692 | PROC(LOOKUP_ROOT, enc_lookup_root, dec_lookup_root), |
| 7618 | 7693 | PROC(REMOVE, enc_remove, dec_remove), |
| 7619 | 7694 | PROC(RENAME, enc_rename, dec_rename), |
| @@ -50,8 +50,8 @@ void nfs_pgheader_init(struct nfs_pageio_descriptor *desc, · 49 unmodified lines | ||
| 50 | 50 | hdr->cred = hdr->req->wb_context->cred; |
| 51 | 51 | hdr->io_start = req_offset(hdr->req); |
| 52 | 52 | hdr->good_bytes = mirror->pg_count; |
| 53 | + hdr->io_completion = desc->pg_io_completion; | |
| 53 | 54 | hdr->dreq = desc->pg_dreq; |
| 54 | − hdr->layout_private = desc->pg_layout_private; | |
| 55 | 55 | hdr->release = release; |
| 56 | 56 | hdr->completion_ops = desc->pg_completion_ops; |
| 57 | 57 | if (hdr->completion_ops->init_hdr) |
| @@ -155,9 +155,12 @@ nfs_page_group_lock(struct nfs_page *req, bool nonblock) · 97 unmodified lines | ||
| 155 | 155 | if (!test_and_set_bit(PG_HEADLOCK, &head->wb_flags)) |
| 156 | 156 | return 0; |
| 157 | 157 | |
| 158 | − if (!nonblock) | |
| 158 | + if (!nonblock) { | |
| 159 | + set_bit(PG_CONTENDED1, &head->wb_flags); | |
| 160 | + smp_mb__after_atomic(); | |
| 159 | 161 | return wait_on_bit_lock(&head->wb_flags, PG_HEADLOCK, |
| 160 | 162 | TASK_UNINTERRUPTIBLE); |
| 163 | + } | |
| 161 | 164 | |
| 162 | 165 | return -EAGAIN; |
| 163 | 166 | } |
| @@ -175,6 +178,10 @@ nfs_page_group_lock_wait(struct nfs_page *req) · 11 unmodified lines | ||
| 175 | 178 | |
| 176 | 179 | WARN_ON_ONCE(head != head->wb_head); |
| 177 | 180 | |
| 181 | + if (!test_bit(PG_HEADLOCK, &head->wb_flags)) | |
| 182 | + return; | |
| 183 | + set_bit(PG_CONTENDED1, &head->wb_flags); | |
| 184 | + smp_mb__after_atomic(); | |
| 178 | 185 | wait_on_bit(&head->wb_flags, PG_HEADLOCK, |
| 179 | 186 | TASK_UNINTERRUPTIBLE); |
| 180 | 187 | } |
| @@ -193,6 +200,8 @@ nfs_page_group_unlock(struct nfs_page *req) · 12 unmodified lines | ||
| 193 | 200 | smp_mb__before_atomic(); |
| 194 | 201 | clear_bit(PG_HEADLOCK, &head->wb_flags); |
| 195 | 202 | smp_mb__after_atomic(); |
| 203 | + if (!test_bit(PG_CONTENDED1, &head->wb_flags)) | |
| 204 | + return; | |
| 196 | 205 | wake_up_bit(&head->wb_flags, PG_HEADLOCK); |
| 197 | 206 | } |
| 198 | 207 | |
| @@ -383,6 +392,8 @@ void nfs_unlock_request(struct nfs_page *req) · 184 unmodified lines | ||
| 383 | 392 | smp_mb__before_atomic(); |
| 384 | 393 | clear_bit(PG_BUSY, &req->wb_flags); |
| 385 | 394 | smp_mb__after_atomic(); |
| 395 | + if (!test_bit(PG_CONTENDED2, &req->wb_flags)) | |
| 396 | + return; | |
| 386 | 397 | wake_up_bit(&req->wb_flags, PG_BUSY); |
| 387 | 398 | } |
| 388 | 399 | |
| @@ -465,6 +476,10 @@ void nfs_release_request(struct nfs_page *req) · 76 unmodified lines | ||
| 465 | 476 | int |
| 466 | 477 | nfs_wait_on_request(struct nfs_page *req) |
| 467 | 478 | { |
| 479 | + if (!test_bit(PG_BUSY, &req->wb_flags)) | |
| 480 | + return 0; | |
| 481 | + set_bit(PG_CONTENDED2, &req->wb_flags); | |
| 482 | + smp_mb__after_atomic(); | |
| 468 | 483 | return wait_on_bit_io(&req->wb_flags, PG_BUSY, |
| 469 | 484 | TASK_UNINTERRUPTIBLE); |
| 470 | 485 | } |
| @@ -710,8 +725,8 @@ void nfs_pageio_init(struct nfs_pageio_descriptor *desc, · 239 unmodified lines | ||
| 710 | 725 | desc->pg_ioflags = io_flags; |
| 711 | 726 | desc->pg_error = 0; |
| 712 | 727 | desc->pg_lseg = NULL; |
| 728 | + desc->pg_io_completion = NULL; | |
| 713 | 729 | desc->pg_dreq = NULL; |
| 714 | − desc->pg_layout_private = NULL; | |
| 715 | 730 | desc->pg_bsize = bsize; |
| 716 | 731 | |
| 717 | 732 | desc->pg_mirror_count = 1; |
| @@ -779,6 +794,7 @@ int nfs_generic_pgio(struct nfs_pageio_descriptor *desc, · 61 unmodified lines | ||
| 779 | 794 | gfp_t gfp_flags = GFP_KERNEL; |
| 780 | 795 | |
| 781 | 796 | pagecount = nfs_page_array_len(mirror->pg_base, mirror->pg_count); |
| 797 | + pg_array->npages = pagecount; | |
| 782 | 798 | |
| 783 | 799 | if (pagecount <= ARRAY_SIZE(pg_array->page_array)) |
| 784 | 800 | pg_array->pagevec = pg_array->page_array; |
| @@ -1233,6 +1249,7 @@ int nfs_pageio_resend(struct nfs_pageio_descriptor *desc, · 448 unmodified lines | ||
| 1233 | 1249 | { |
| 1234 | 1250 | LIST_HEAD(failed); |
| 1235 | 1251 | |
| 1252 | + desc->pg_io_completion = hdr->io_completion; | |
| 1236 | 1253 | desc->pg_dreq = hdr->dreq; |
| 1237 | 1254 | while (!list_empty(&hdr->pages)) { |
| 1238 | 1255 | struct nfs_page *req = nfs_list_entry(hdr->pages.next); |
| @@ -485,7 +485,7 @@ nfs_proc_rmdir(struct inode *dir, const struct qstr *name) · 484 unmodified lines | ||
| 485 | 485 | */ |
| 486 | 486 | static int |
| 487 | 487 | nfs_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, |
| 488 | − u64 cookie, struct page **pages, unsigned int count, int plus) | |
| 488 | + u64 cookie, struct page **pages, unsigned int count, bool plus) | |
| 489 | 489 | { |
| 490 | 490 | struct inode *dir = d_inode(dentry); |
| 491 | 491 | struct nfs_readdirargs arg = { |
| @@ -879,7 +879,7 @@ int nfs_show_stats(struct seq_file *m, struct dentry *root) · 878 unmodified lines | ||
| 879 | 879 | if (nfss->options & NFS_OPTION_FSCACHE) { |
| 880 | 880 | seq_printf(m, "\n\tfsc:\t"); |
| 881 | 881 | for (i = 0; i < __NFSIOS_FSCACHEMAX; i++) |
| 882 | − seq_printf(m, "%Lu ", totals.bytes[i]); | |
| 882 | + seq_printf(m, "%Lu ", totals.fscache[i]); | |
| 883 | 883 | } |
| 884 | 884 | #endif |
| 885 | 885 | seq_printf(m, "\n"); |
| @@ -2339,6 +2339,7 @@ void nfs_fill_super(struct super_block *sb, struct nfs_mount_info *mount_info) · 1453 unmodified lines | ||
| 2339 | 2339 | */ |
| 2340 | 2340 | sb->s_flags |= MS_POSIXACL; |
| 2341 | 2341 | sb->s_time_gran = 1; |
| 2342 | + sb->s_export_op = &nfs_export_ops; | |
| 2342 | 2343 | } |
| 2343 | 2344 | |
| 2344 | 2345 | nfs_initialise_sb(sb); |
| @@ -2360,6 +2361,7 @@ static void nfs_clone_super(struct super_block *sb, · 15 unmodified lines | ||
| 2360 | 2361 | sb->s_xattr = old_sb->s_xattr; |
| 2361 | 2362 | sb->s_op = old_sb->s_op; |
| 2362 | 2363 | sb->s_time_gran = 1; |
| 2364 | + sb->s_export_op = old_sb->s_export_op; | |
| 2363 | 2365 | |
| 2364 | 2366 | if (server->nfs_client->rpc_ops->version != 2) { |
| 2365 | 2367 | /* The VFS shouldn't apply the umask to mode bits. We will do |
| @@ -288,6 +288,19 @@ static void nfs_async_rename_release(void *calldata) · 287 unmodified lines | ||
| 288 | 288 | if (d_really_is_positive(data->old_dentry)) |
| 289 | 289 | nfs_mark_for_revalidate(d_inode(data->old_dentry)); |
| 290 | 290 | |
| 291 | + /* The result of the rename is unknown. Play it safe by | |
| 292 | + * forcing a new lookup */ | |
| 293 | + if (data->cancelled) { | |
| 294 | + spin_lock(&data->old_dir->i_lock); | |
| 295 | + nfs_force_lookup_revalidate(data->old_dir); | |
| 296 | + spin_unlock(&data->old_dir->i_lock); | |
| 297 | + if (data->new_dir != data->old_dir) { | |
| 298 | + spin_lock(&data->new_dir->i_lock); | |
| 299 | + nfs_force_lookup_revalidate(data->new_dir); | |
| 300 | + spin_unlock(&data->new_dir->i_lock); | |
| 301 | + } | |
| 302 | + } | |
| 303 | + | |
| 291 | 304 | dput(data->old_dentry); |
| 292 | 305 | dput(data->new_dentry); |
| 293 | 306 | iput(data->old_dir); |
| @@ -40,6 +40,12 @@ · 39 unmodified lines | ||
| 40 | 40 | #define MIN_POOL_WRITE (32) |
| 41 | 41 | #define MIN_POOL_COMMIT (4) |
| 42 | 42 | |
| 43 | +struct nfs_io_completion { | |
| 44 | + void (*complete)(void *data); | |
| 45 | + void *data; | |
| 46 | + struct kref refcount; | |
| 47 | +}; | |
| 48 | + | |
| 43 | 49 | /* |
| 44 | 50 | * Local function declarations |
| 45 | 51 | */ |
| @@ -108,6 +114,39 @@ static void nfs_writehdr_free(struct nfs_pgio_header *hdr) · 62 unmodified lines | ||
| 108 | 114 | mempool_free(hdr, nfs_wdata_mempool); |
| 109 | 115 | } |
| 110 | 116 | |
| 117 | +static struct nfs_io_completion *nfs_io_completion_alloc(gfp_t gfp_flags) | |
| 118 | +{ | |
| 119 | + return kmalloc(sizeof(struct nfs_io_completion), gfp_flags); | |
| 120 | +} | |
| 121 | + | |
| 122 | +static void nfs_io_completion_init(struct nfs_io_completion *ioc, | |
| 123 | + void (*complete)(void *), void *data) | |
| 124 | +{ | |
| 125 | + ioc->complete = complete; | |
| 126 | + ioc->data = data; | |
| 127 | + kref_init(&ioc->refcount); | |
| 128 | +} | |
| 129 | + | |
| 130 | +static void nfs_io_completion_release(struct kref *kref) | |
| 131 | +{ | |
| 132 | + struct nfs_io_completion *ioc = container_of(kref, | |
| 133 | + struct nfs_io_completion, refcount); | |
| 134 | + ioc->complete(ioc->data); | |
| 135 | + kfree(ioc); | |
| 136 | +} | |
| 137 | + | |
| 138 | +static void nfs_io_completion_get(struct nfs_io_completion *ioc) | |
| 139 | +{ | |
| 140 | + if (ioc != NULL) | |
| 141 | + kref_get(&ioc->refcount); | |
| 142 | +} | |
| 143 | + | |
| 144 | +static void nfs_io_completion_put(struct nfs_io_completion *ioc) | |
| 145 | +{ | |
| 146 | + if (ioc != NULL) | |
| 147 | + kref_put(&ioc->refcount, nfs_io_completion_release); | |
| 148 | +} | |
| 149 | + | |
| 111 | 150 | static void nfs_context_set_write_error(struct nfs_open_context *ctx, int error) |
| 112 | 151 | { |
| 113 | 152 | ctx->error = error; |
| @@ -681,18 +720,29 @@ static int nfs_writepages_callback(struct page *page, struct writeback_control * · 567 unmodified lines | ||
| 681 | 720 | return ret; |
| 682 | 721 | } |
| 683 | 722 | |
| 723 | +static void nfs_io_completion_commit(void *inode) | |
| 724 | +{ | |
| 725 | + nfs_commit_inode(inode, 0); | |
| 726 | +} | |
| 727 | + | |
| 684 | 728 | int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc) |
| 685 | 729 | { |
| 686 | 730 | struct inode *inode = mapping->host; |
| 687 | 731 | struct nfs_pageio_descriptor pgio; |
| 732 | + struct nfs_io_completion *ioc = nfs_io_completion_alloc(GFP_NOFS); | |
| 688 | 733 | int err; |
| 689 | 734 | |
| 690 | 735 | nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGES); |
| 691 | 736 | |
| 737 | + if (ioc) | |
| 738 | + nfs_io_completion_init(ioc, nfs_io_completion_commit, inode); | |
| 739 | + | |
| 692 | 740 | nfs_pageio_init_write(&pgio, inode, wb_priority(wbc), false, |
| 693 | 741 | &nfs_async_write_completion_ops); |
| 742 | + pgio.pg_io_completion = ioc; | |
| 694 | 743 | err = write_cache_pages(mapping, wbc, nfs_writepages_callback, &pgio); |
| 695 | 744 | nfs_pageio_complete(&pgio); |
| 745 | + nfs_io_completion_put(ioc); | |
| 696 | 746 | |
| 697 | 747 | if (err < 0) |
| 698 | 748 | goto out_err; |
| @@ -940,6 +990,11 @@ int nfs_write_need_commit(struct nfs_pgio_header *hdr) · 241 unmodified lines | ||
| 940 | 990 | return hdr->verf.committed != NFS_FILE_SYNC; |
| 941 | 991 | } |
| 942 | 992 | |
| 993 | +static void nfs_async_write_init(struct nfs_pgio_header *hdr) | |
| 994 | +{ | |
| 995 | + nfs_io_completion_get(hdr->io_completion); | |
| 996 | +} | |
| 997 | + | |
| 943 | 998 | static void nfs_write_completion(struct nfs_pgio_header *hdr) |
| 944 | 999 | { |
| 945 | 1000 | struct nfs_commit_info cinfo; |
| @@ -973,6 +1028,7 @@ next: · 27 unmodified lines | ||
| 973 | 1028 | nfs_release_request(req); |
| 974 | 1029 | } |
| 975 | 1030 | out: |
| 1031 | + nfs_io_completion_put(hdr->io_completion); | |
| 976 | 1032 | hdr->release(hdr); |
| 977 | 1033 | } |
| 978 | 1034 | |
| @@ -1378,6 +1434,7 @@ static void nfs_async_write_reschedule_io(struct nfs_pgio_header *hdr) · 399 unmodified lines | ||
| 1378 | 1434 | } |
| 1379 | 1435 | |
| 1380 | 1436 | static const struct nfs_pgio_completion_ops nfs_async_write_completion_ops = { |
| 1437 | + .init_hdr = nfs_async_write_init, | |
| 1381 | 1438 | .error_cleanup = nfs_async_write_error, |
| 1382 | 1439 | .completion = nfs_write_completion, |
| 1383 | 1440 | .reschedule_io = nfs_async_write_reschedule_io, |
| @@ -1884,7 +1941,7 @@ int nfs_write_inode(struct inode *inode, struct writeback_control *wbc) · 500 unmodified lines | ||
| 1884 | 1941 | /* Don't commit yet if this is a non-blocking flush and there |
| 1885 | 1942 | * are a lot of outstanding writes for this mapping. |
| 1886 | 1943 | */ |
| 1887 | − if (nfsi->commit_info.ncommit <= (nfsi->nrequests >> 1)) | |
| 1944 | + if (mapping_tagged(inode->i_mapping, PAGECACHE_TAG_WRITEBACK)) | |
| 1888 | 1945 | goto out_mark_dirty; |
| 1889 | 1946 | |
| 1890 | 1947 | /* don't wait for the COMMIT response */ |
| @@ -479,6 +479,7 @@ enum { · 478 unmodified lines | ||
| 479 | 479 | NFSPROC4_CLNT_ACCESS, |
| 480 | 480 | NFSPROC4_CLNT_GETATTR, |
| 481 | 481 | NFSPROC4_CLNT_LOOKUP, |
| 482 | + NFSPROC4_CLNT_LOOKUPP, | |
| 482 | 483 | NFSPROC4_CLNT_LOOKUP_ROOT, |
| 483 | 484 | NFSPROC4_CLNT_REMOVE, |
| 484 | 485 | NFSPROC4_CLNT_RENAME, |
| @@ -332,6 +332,7 @@ extern void nfs_zap_caches(struct inode *); · 331 unmodified lines | ||
| 332 | 332 | extern void nfs_invalidate_atime(struct inode *); |
| 333 | 333 | extern struct inode *nfs_fhget(struct super_block *, struct nfs_fh *, |
| 334 | 334 | struct nfs_fattr *, struct nfs4_label *); |
| 335 | +struct inode *nfs_ilookup(struct super_block *sb, struct nfs_fattr *, struct nfs_fh *); | |
| 335 | 336 | extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *); |
| 336 | 337 | extern int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr); |
| 337 | 338 | extern int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr); |
| @@ -42,6 +42,7 @@ struct nfs_client { · 41 unmodified lines | ||
| 42 | 42 | #define NFS_CS_MIGRATION 2 /* - transparent state migr */ |
| 43 | 43 | #define NFS_CS_INFINITE_SLOTS 3 /* - don't limit TCP slots */ |
| 44 | 44 | #define NFS_CS_NO_RETRANS_TIMEOUT 4 /* - Disable retransmit timeouts */ |
| 45 | +#define NFS_CS_TSM_POSSIBLE 5 /* - Maybe state migration */ | |
| 45 | 46 | struct sockaddr_storage cl_addr; /* server identifier */ |
| 46 | 47 | size_t cl_addrlen; |
| 47 | 48 | char * cl_hostname; /* hostname of server */ |
| @@ -210,6 +211,7 @@ struct nfs_server { · 162 unmodified lines | ||
| 210 | 211 | unsigned long mig_status; |
| 211 | 212 | #define NFS_MIG_IN_TRANSITION (1) |
| 212 | 213 | #define NFS_MIG_FAILED (2) |
| 214 | +#define NFS_MIG_TSM_POSSIBLE (3) | |
| 213 | 215 | |
| 214 | 216 | void (*destroy)(struct nfs_server *); |
| 215 | 217 | |
| @@ -33,6 +33,8 @@ enum { · 32 unmodified lines | ||
| 33 | 33 | PG_UPTODATE, /* page group sync bit in read path */ |
| 34 | 34 | PG_WB_END, /* page group sync bit in write path */ |
| 35 | 35 | PG_REMOVE, /* page group sync bit in write path */ |
| 36 | + PG_CONTENDED1, /* Is someone waiting for a lock? */ | |
| 37 | + PG_CONTENDED2, /* Is someone waiting for a lock? */ | |
| 36 | 38 | }; |
| 37 | 39 | |
| 38 | 40 | struct nfs_inode; |
| @@ -93,8 +95,8 @@ struct nfs_pageio_descriptor { · 54 unmodified lines | ||
| 93 | 95 | const struct rpc_call_ops *pg_rpc_callops; |
| 94 | 96 | const struct nfs_pgio_completion_ops *pg_completion_ops; |
| 95 | 97 | struct pnfs_layout_segment *pg_lseg; |
| 98 | + struct nfs_io_completion *pg_io_completion; | |
| 96 | 99 | struct nfs_direct_req *pg_dreq; |
| 97 | − void *pg_layout_private; | |
| 98 | 100 | unsigned int pg_bsize; /* default bsize for mirrors */ |
| 99 | 101 | |
| 100 | 102 | u32 pg_mirror_count; |
| @@ -878,7 +878,7 @@ struct nfs3_readdirargs { · 877 unmodified lines | ||
| 878 | 878 | struct nfs_fh * fh; |
| 879 | 879 | __u64 cookie; |
| 880 | 880 | __be32 verf[2]; |
| 881 | − int plus; | |
| 881 | + bool plus; | |
| 882 | 882 | unsigned int count; |
| 883 | 883 | struct page ** pages; |
| 884 | 884 | }; |
| @@ -909,7 +909,7 @@ struct nfs3_linkres { · 24 unmodified lines | ||
| 909 | 909 | struct nfs3_readdirres { |
| 910 | 910 | struct nfs_fattr * dir_attr; |
| 911 | 911 | __be32 * verf; |
| 912 | − int plus; | |
| 912 | + bool plus; | |
| 913 | 913 | }; |
| 914 | 914 | |
| 915 | 915 | struct nfs3_getaclres { |
| @@ -1012,7 +1012,6 @@ struct nfs4_link_res { · 96 unmodified lines | ||
| 1012 | 1012 | struct nfs_fattr * dir_attr; |
| 1013 | 1013 | }; |
| 1014 | 1014 | |
| 1015 | − | |
| 1016 | 1015 | struct nfs4_lookup_arg { |
| 1017 | 1016 | struct nfs4_sequence_args seq_args; |
| 1018 | 1017 | const struct nfs_fh * dir_fh; |
| @@ -1028,6 +1027,20 @@ struct nfs4_lookup_res { · 9 unmodified lines | ||
| 1028 | 1027 | struct nfs4_label *label; |
| 1029 | 1028 | }; |
| 1030 | 1029 | |
| 1030 | +struct nfs4_lookupp_arg { | |
| 1031 | + struct nfs4_sequence_args seq_args; | |
| 1032 | + const struct nfs_fh *fh; | |
| 1033 | + const u32 *bitmask; | |
| 1034 | +}; | |
| 1035 | + | |
| 1036 | +struct nfs4_lookupp_res { | |
| 1037 | + struct nfs4_sequence_res seq_res; | |
| 1038 | + const struct nfs_server *server; | |
| 1039 | + struct nfs_fattr *fattr; | |
| 1040 | + struct nfs_fh *fh; | |
| 1041 | + struct nfs4_label *label; | |
| 1042 | +}; | |
| 1043 | + | |
| 1031 | 1044 | struct nfs4_lookup_root_arg { |
| 1032 | 1045 | struct nfs4_sequence_args seq_args; |
| 1033 | 1046 | const u32 * bitmask; |
| @@ -1053,7 +1066,7 @@ struct nfs4_readdir_arg { · 19 unmodified lines | ||
| 1053 | 1066 | struct page ** pages; /* zero-copy data */ |
| 1054 | 1067 | unsigned int pgbase; /* zero-copy data */ |
| 1055 | 1068 | const u32 * bitmask; |
| 1056 | − int plus; | |
| 1069 | + bool plus; | |
| 1057 | 1070 | }; |
| 1058 | 1071 | |
| 1059 | 1072 | struct nfs4_readdir_res { |
| @@ -1422,6 +1435,7 @@ enum { · 362 unmodified lines | ||
| 1422 | 1435 | NFS_IOHDR_STAT, |
| 1423 | 1436 | }; |
| 1424 | 1437 | |
| 1438 | +struct nfs_io_completion; | |
| 1425 | 1439 | struct nfs_pgio_header { |
| 1426 | 1440 | struct inode *inode; |
| 1427 | 1441 | struct rpc_cred *cred; |
| @@ -1435,8 +1449,8 @@ struct nfs_pgio_header { · 7 unmodified lines | ||
| 1435 | 1449 | void (*release) (struct nfs_pgio_header *hdr); |
| 1436 | 1450 | const struct nfs_pgio_completion_ops *completion_ops; |
| 1437 | 1451 | const struct nfs_rw_ops *rw_ops; |
| 1452 | + struct nfs_io_completion *io_completion; | |
| 1438 | 1453 | struct nfs_direct_req *dreq; |
| 1439 | − void *layout_private; | |
| 1440 | 1454 | spinlock_t lock; |
| 1441 | 1455 | /* fields protected by lock */ |
| 1442 | 1456 | int pnfs_error; |
| @@ -1533,6 +1547,7 @@ struct nfs_renamedata { · 90 unmodified lines | ||
| 1533 | 1547 | struct nfs_fattr new_fattr; |
| 1534 | 1548 | void (*complete)(struct rpc_task *, struct nfs_renamedata *); |
| 1535 | 1549 | long timeout; |
| 1550 | + bool cancelled; | |
| 1536 | 1551 | }; |
| 1537 | 1552 | |
| 1538 | 1553 | struct nfs_access_entry; |
| @@ -1567,6 +1582,8 @@ struct nfs_rpc_ops { · 28 unmodified lines | ||
| 1567 | 1582 | int (*lookup) (struct inode *, const struct qstr *, |
| 1568 | 1583 | struct nfs_fh *, struct nfs_fattr *, |
| 1569 | 1584 | struct nfs4_label *); |
| 1585 | + int (*lookupp) (struct inode *, struct nfs_fh *, | |
| 1586 | + struct nfs_fattr *, struct nfs4_label *); | |
| 1570 | 1587 | int (*access) (struct inode *, struct nfs_access_entry *); |
| 1571 | 1588 | int (*readlink)(struct inode *, struct page *, unsigned int, |
| 1572 | 1589 | unsigned int); |
| @@ -1585,7 +1602,7 @@ struct nfs_rpc_ops { · 12 unmodified lines | ||
| 1585 | 1602 | int (*mkdir) (struct inode *, struct dentry *, struct iattr *); |
| 1586 | 1603 | int (*rmdir) (struct inode *, const struct qstr *); |
| 1587 | 1604 | int (*readdir) (struct dentry *, struct rpc_cred *, |
| 1588 | − u64, struct page **, unsigned int, int); | |
| 1605 | + u64, struct page **, unsigned int, bool); | |
| 1589 | 1606 | int (*mknod) (struct inode *, struct dentry *, struct iattr *, |
| 1590 | 1607 | dev_t); |
| 1591 | 1608 | int (*statfs) (struct nfs_server *, struct nfs_fh *, |
| @@ -1595,7 +1612,7 @@ struct nfs_rpc_ops { · 3 unmodified lines | ||
| 1595 | 1612 | int (*pathconf) (struct nfs_server *, struct nfs_fh *, |
| 1596 | 1613 | struct nfs_pathconf *); |
| 1597 | 1614 | int (*set_capabilities)(struct nfs_server *, struct nfs_fh *); |
| 1598 | − int (*decode_dirent)(struct xdr_stream *, struct nfs_entry *, int); | |
| 1615 | + int (*decode_dirent)(struct xdr_stream *, struct nfs_entry *, bool); | |
| 1599 | 1616 | int (*pgio_rpc_prepare)(struct rpc_task *, |
| 1600 | 1617 | struct nfs_pgio_header *); |
| 1601 | 1618 | void (*read_setup)(struct nfs_pgio_header *, struct rpc_message *); |
| @@ -34,6 +34,7 @@ · 33 unmodified lines | ||
| 34 | 34 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
| 35 | 35 | */ |
| 36 | 36 | |
| 37 | +#include <crypto/algapi.h> | |
| 37 | 38 | #include <crypto/hash.h> |
| 38 | 39 | #include <crypto/skcipher.h> |
| 39 | 40 | #include <linux/err.h> |
| @@ -927,7 +928,7 @@ gss_krb5_aes_decrypt(struct krb5_ctx *kctx, u32 offset, struct xdr_buf *buf, · 887 unmodified lines | ||
| 927 | 928 | if (ret) |
| 928 | 929 | goto out_err; |
| 929 | 930 | |
| 930 | − if (memcmp(pkt_hmac, our_hmac, kctx->gk5e->cksumlength) != 0) { | |
| 931 | + if (crypto_memneq(pkt_hmac, our_hmac, kctx->gk5e->cksumlength) != 0) { | |
| 931 | 932 | ret = GSS_S_BAD_SIG; |
| 932 | 933 | goto out_err; |
| 933 | 934 | } |
| @@ -1047,13 +1047,15 @@ out: · 1046 unmodified lines | ||
| 1047 | 1047 | return ret; |
| 1048 | 1048 | } |
| 1049 | 1049 | |
| 1050 | −static struct rpc_rqst *xprt_dynamic_alloc_slot(struct rpc_xprt *xprt, gfp_t gfp_flags) | |
| 1050 | +static struct rpc_rqst *xprt_dynamic_alloc_slot(struct rpc_xprt *xprt) | |
| 1051 | 1051 | { |
| 1052 | 1052 | struct rpc_rqst *req = ERR_PTR(-EAGAIN); |
| 1053 | 1053 | |
| 1054 | 1054 | if (!atomic_add_unless(&xprt->num_reqs, 1, xprt->max_reqs)) |
| 1055 | 1055 | goto out; |
| 1056 | − req = kzalloc(sizeof(struct rpc_rqst), gfp_flags); | |
| 1056 | + spin_unlock(&xprt->reserve_lock); | |
| 1057 | + req = kzalloc(sizeof(struct rpc_rqst), GFP_NOFS); | |
| 1058 | + spin_lock(&xprt->reserve_lock); | |
| 1057 | 1059 | if (req != NULL) |
| 1058 | 1060 | goto out; |
| 1059 | 1061 | atomic_dec(&xprt->num_reqs); |
| @@ -1081,7 +1083,7 @@ void xprt_alloc_slot(struct rpc_xprt *xprt, struct rpc_task *task) · 21 unmodified lines | ||
| 1081 | 1083 | list_del(&req->rq_list); |
| 1082 | 1084 | goto out_init_req; |
| 1083 | 1085 | } |
| 1084 | − req = xprt_dynamic_alloc_slot(xprt, GFP_NOWAIT|__GFP_NOWARN); | |
| 1086 | + req = xprt_dynamic_alloc_slot(xprt); | |
| 1085 | 1087 | if (!IS_ERR(req)) |
| 1086 | 1088 | goto out_init_req; |
| 1087 | 1089 | switch (PTR_ERR(req)) { |
| @@ -91,7 +91,7 @@ __fmr_unmap(struct rpcrdma_mw *mw) · 90 unmodified lines | ||
| 91 | 91 | |
| 92 | 92 | list_add(&mw->fmr.fm_mr->list, &l); |
| 93 | 93 | rc = ib_unmap_fmr(&l); |
| 94 | − list_del_init(&mw->fmr.fm_mr->list); | |
| 94 | + list_del(&mw->fmr.fm_mr->list); | |
| 95 | 95 | return rc; |
| 96 | 96 | } |
| 97 | 97 | |
| @@ -213,13 +213,11 @@ fmr_op_map(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *seg, · 115 unmodified lines | ||
| 213 | 213 | offset_in_page((seg-1)->mr_offset + (seg-1)->mr_len)) |
| 214 | 214 | break; |
| 215 | 215 | } |
| 216 | − mw->mw_nents = i; | |
| 217 | 216 | mw->mw_dir = rpcrdma_data_dir(writing); |
| 218 | − if (i == 0) | |
| 219 | − goto out_dmamap_err; | |
| 220 | 217 | |
| 221 | − if (!ib_dma_map_sg(r_xprt->rx_ia.ri_device, | |
| 222 | − mw->mw_sg, mw->mw_nents, mw->mw_dir)) | |
| 218 | + mw->mw_nents = ib_dma_map_sg(r_xprt->rx_ia.ri_device, | |
| 219 | + mw->mw_sg, i, mw->mw_dir); | |
| 220 | + if (!mw->mw_nents) | |
| 223 | 221 | goto out_dmamap_err; |
| 224 | 222 | |
| 225 | 223 | for (i = 0, dma_pages = mw->fmr.fm_physaddrs; i < mw->mw_nents; i++) |
| @@ -237,16 +235,18 @@ fmr_op_map(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *seg, · 11 unmodified lines | ||
| 237 | 235 | return mw->mw_nents; |
| 238 | 236 | |
| 239 | 237 | out_dmamap_err: |
| 240 | − pr_err("rpcrdma: failed to dma map sg %p sg_nents %u\n", | |
| 241 | − mw->mw_sg, mw->mw_nents); | |
| 242 | − rpcrdma_defer_mr_recovery(mw); | |
| 238 | + pr_err("rpcrdma: failed to DMA map sg %p sg_nents %d\n", | |
| 239 | + mw->mw_sg, i); | |
| 240 | + rpcrdma_put_mw(r_xprt, mw); | |
| 243 | 241 | return -EIO; |
| 244 | 242 | |
| 245 | 243 | out_maperr: |
| 246 | 244 | pr_err("rpcrdma: ib_map_phys_fmr %u@0x%llx+%i (%d) status %i\n", |
| 247 | 245 | len, (unsigned long long)dma_pages[0], |
| 248 | 246 | pageoff, mw->mw_nents, rc); |
| 249 | − rpcrdma_defer_mr_recovery(mw); | |
| 247 | + ib_dma_unmap_sg(r_xprt->rx_ia.ri_device, | |
| 248 | + mw->mw_sg, mw->mw_nents, mw->mw_dir); | |
| 249 | + rpcrdma_put_mw(r_xprt, mw); | |
| 250 | 250 | return -EIO; |
| 251 | 251 | } |
| 252 | 252 | |
| @@ -255,24 +255,26 @@ out_maperr: · 2 unmodified lines | ||
| 255 | 255 | * Sleeps until it is safe for the host CPU to access the |
| 256 | 256 | * previously mapped memory regions. |
| 257 | 257 | * |
| 258 | − * Caller ensures that req->rl_registered is not empty. | |
| 258 | + * Caller ensures that @mws is not empty before the call. This | |
| 259 | + * function empties the list. | |
| 259 | 260 | */ |
| 260 | 261 | static void |
| 261 | −fmr_op_unmap_sync(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req) | |
| 262 | +fmr_op_unmap_sync(struct rpcrdma_xprt *r_xprt, struct list_head *mws) | |
| 262 | 263 | { |
| 263 | − struct rpcrdma_mw *mw, *tmp; | |
| 264 | + struct rpcrdma_mw *mw; | |
| 264 | 265 | LIST_HEAD(unmap_list); |
| 265 | 266 | int rc; |
| 266 | 267 | |
| 267 | − dprintk("RPC: %s: req %p\n", __func__, req); | |
| 268 | − | |
| 269 | 268 | /* ORDER: Invalidate all of the req's MRs first |
| 270 | 269 | * |
| 271 | 270 | * ib_unmap_fmr() is slow, so use a single call instead |
| 272 | 271 | * of one call per mapped FMR. |
| 273 | 272 | */ |
| 274 | − list_for_each_entry(mw, &req->rl_registered, mw_list) | |
| 273 | + list_for_each_entry(mw, mws, mw_list) { | |
| 274 | + dprintk("RPC: %s: unmapping fmr %p\n", | |
| 275 | + __func__, &mw->fmr); | |
| 275 | 276 | list_add_tail(&mw->fmr.fm_mr->list, &unmap_list); |
| 277 | + } | |
| 276 | 278 | r_xprt->rx_stats.local_inv_needed++; |
| 277 | 279 | rc = ib_unmap_fmr(&unmap_list); |
| 278 | 280 | if (rc) |
| @@ -281,9 +283,11 @@ fmr_op_unmap_sync(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req) · 2 unmodified lines | ||
| 281 | 283 | /* ORDER: Now DMA unmap all of the req's MRs, and return |
| 282 | 284 | * them to the free MW list. |
| 283 | 285 | */ |
| 284 | − list_for_each_entry_safe(mw, tmp, &req->rl_registered, mw_list) { | |
| 285 | − list_del_init(&mw->mw_list); | |
| 286 | − list_del_init(&mw->fmr.fm_mr->list); | |
| 286 | + while (!list_empty(mws)) { | |
| 287 | + mw = rpcrdma_pop_mw(mws); | |
| 288 | + dprintk("RPC: %s: DMA unmapping fmr %p\n", | |
| 289 | + __func__, &mw->fmr); | |
| 290 | + list_del(&mw->fmr.fm_mr->list); | |
| 287 | 291 | ib_dma_unmap_sg(r_xprt->rx_ia.ri_device, |
| 288 | 292 | mw->mw_sg, mw->mw_nents, mw->mw_dir); |
| 289 | 293 | rpcrdma_put_mw(r_xprt, mw); |
| @@ -294,8 +298,9 @@ fmr_op_unmap_sync(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req) · 4 unmodified lines | ||
| 294 | 298 | out_reset: |
| 295 | 299 | pr_err("rpcrdma: ib_unmap_fmr failed (%i)\n", rc); |
| 296 | 300 | |
| 297 | − list_for_each_entry_safe(mw, tmp, &req->rl_registered, mw_list) { | |
| 298 | − list_del_init(&mw->fmr.fm_mr->list); | |
| 301 | + while (!list_empty(mws)) { | |
| 302 | + mw = rpcrdma_pop_mw(mws); | |
| 303 | + list_del(&mw->fmr.fm_mr->list); | |
| 299 | 304 | fmr_op_recover_mr(mw); |
| 300 | 305 | } |
| 301 | 306 | } |
| @@ -277,7 +277,7 @@ __frwr_sendcompletion_flush(struct ib_wc *wc, const char *wr) · 276 unmodified lines | ||
| 277 | 277 | } |
| 278 | 278 | |
| 279 | 279 | /** |
| 280 | − * frwr_wc_fastreg - Invoked by RDMA provider for each polled FastReg WC | |
| 280 | + * frwr_wc_fastreg - Invoked by RDMA provider for a flushed FastReg WC | |
| 281 | 281 | * @cq: completion queue (ignored) |
| 282 | 282 | * @wc: completed WR |
| 283 | 283 | * |
| @@ -298,7 +298,7 @@ frwr_wc_fastreg(struct ib_cq *cq, struct ib_wc *wc) · 14 unmodified lines | ||
| 298 | 298 | } |
| 299 | 299 | |
| 300 | 300 | /** |
| 301 | − * frwr_wc_localinv - Invoked by RDMA provider for each polled LocalInv WC | |
| 301 | + * frwr_wc_localinv - Invoked by RDMA provider for a flushed LocalInv WC | |
| 302 | 302 | * @cq: completion queue (ignored) |
| 303 | 303 | * @wc: completed WR |
| 304 | 304 | * |
| @@ -319,7 +319,7 @@ frwr_wc_localinv(struct ib_cq *cq, struct ib_wc *wc) · 14 unmodified lines | ||
| 319 | 319 | } |
| 320 | 320 | |
| 321 | 321 | /** |
| 322 | − * frwr_wc_localinv - Invoked by RDMA provider for each polled LocalInv WC | |
| 322 | + * frwr_wc_localinv_wake - Invoked by RDMA provider for a signaled LocalInv WC | |
| 323 | 323 | * @cq: completion queue (ignored) |
| 324 | 324 | * @wc: completed WR |
| 325 | 325 | * |
| @@ -355,7 +355,7 @@ frwr_op_map(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *seg, · 29 unmodified lines | ||
| 355 | 355 | struct ib_mr *mr; |
| 356 | 356 | struct ib_reg_wr *reg_wr; |
| 357 | 357 | struct ib_send_wr *bad_wr; |
| 358 | − int rc, i, n, dma_nents; | |
| 358 | + int rc, i, n; | |
| 359 | 359 | u8 key; |
| 360 | 360 | |
| 361 | 361 | mw = NULL; |
| @@ -391,14 +391,10 @@ frwr_op_map(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *seg, · 29 unmodified lines | ||
| 391 | 391 | offset_in_page((seg-1)->mr_offset + (seg-1)->mr_len)) |
| 392 | 392 | break; |
| 393 | 393 | } |
| 394 | − mw->mw_nents = i; | |
| 395 | 394 | mw->mw_dir = rpcrdma_data_dir(writing); |
| 396 | − if (i == 0) | |
| 397 | − goto out_dmamap_err; | |
| 398 | 395 | |
| 399 | − dma_nents = ib_dma_map_sg(ia->ri_device, | |
| 400 | − mw->mw_sg, mw->mw_nents, mw->mw_dir); | |
| 401 | − if (!dma_nents) | |
| 396 | + mw->mw_nents = ib_dma_map_sg(ia->ri_device, mw->mw_sg, i, mw->mw_dir); | |
| 397 | + if (!mw->mw_nents) | |
| 402 | 398 | goto out_dmamap_err; |
| 403 | 399 | |
| 404 | 400 | n = ib_map_mr_sg(mr, mw->mw_sg, mw->mw_nents, NULL, PAGE_SIZE); |
| @@ -436,13 +432,14 @@ frwr_op_map(struct rpcrdma_xprt *r_xprt, struct rpcrdma_mr_seg *seg, · 31 unmodified lines | ||
| 436 | 432 | return mw->mw_nents; |
| 437 | 433 | |
| 438 | 434 | out_dmamap_err: |
| 439 | − pr_err("rpcrdma: failed to dma map sg %p sg_nents %u\n", | |
| 440 | − mw->mw_sg, mw->mw_nents); | |
| 441 | − rpcrdma_defer_mr_recovery(mw); | |
| 435 | + pr_err("rpcrdma: failed to DMA map sg %p sg_nents %d\n", | |
| 436 | + mw->mw_sg, i); | |
| 437 | + frmr->fr_state = FRMR_IS_INVALID; | |
| 438 | + rpcrdma_put_mw(r_xprt, mw); | |
| 442 | 439 | return -EIO; |
| 443 | 440 | |
| 444 | 441 | out_mapmr_err: |
| 445 | − pr_err("rpcrdma: failed to map mr %p (%u/%u)\n", | |
| 442 | + pr_err("rpcrdma: failed to map mr %p (%d/%d)\n", | |
| 446 | 443 | frmr->fr_mr, n, mw->mw_nents); |
| 447 | 444 | rpcrdma_defer_mr_recovery(mw); |
| 448 | 445 | return -EIO; |
| @@ -458,21 +455,19 @@ out_senderr: · 9 unmodified lines | ||
| 458 | 455 | * Sleeps until it is safe for the host CPU to access the |
| 459 | 456 | * previously mapped memory regions. |
| 460 | 457 | * |
| 461 | − * Caller ensures that req->rl_registered is not empty. | |
| 458 | + * Caller ensures that @mws is not empty before the call. This | |
| 459 | + * function empties the list. | |
| 462 | 460 | */ |
| 463 | 461 | static void |
| 464 | −frwr_op_unmap_sync(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req) | |
| 462 | +frwr_op_unmap_sync(struct rpcrdma_xprt *r_xprt, struct list_head *mws) | |
| 465 | 463 | { |
| 466 | 464 | struct ib_send_wr *first, **prev, *last, *bad_wr; |
| 467 | − struct rpcrdma_rep *rep = req->rl_reply; | |
| 468 | 465 | struct rpcrdma_ia *ia = &r_xprt->rx_ia; |
| 469 | 466 | struct rpcrdma_frmr *f; |
| 470 | 467 | struct rpcrdma_mw *mw; |
| 471 | 468 | int count, rc; |
| 472 | 469 | |
| 473 | − dprintk("RPC: %s: req %p\n", __func__, req); | |
| 474 | − | |
| 475 | − /* ORDER: Invalidate all of the req's MRs first | |
| 470 | + /* ORDER: Invalidate all of the MRs first | |
| 476 | 471 | * |
| 477 | 472 | * Chain the LOCAL_INV Work Requests and post them with |
| 478 | 473 | * a single ib_post_send() call. |
| @@ -480,11 +475,10 @@ frwr_op_unmap_sync(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req) · 1 unmodified line | ||
| 480 | 475 | f = NULL; |
| 481 | 476 | count = 0; |
| 482 | 477 | prev = &first; |
| 483 | − list_for_each_entry(mw, &req->rl_registered, mw_list) { | |
| 478 | + list_for_each_entry(mw, mws, mw_list) { | |
| 484 | 479 | mw->frmr.fr_state = FRMR_IS_INVALID; |
| 485 | 480 | |
| 486 | − if ((rep->rr_wc_flags & IB_WC_WITH_INVALIDATE) && | |
| 487 | − (mw->mw_handle == rep->rr_inv_rkey)) | |
| 481 | + if (mw->mw_flags & RPCRDMA_MW_F_RI) | |
| 488 | 482 | continue; |
| 489 | 483 | |
| 490 | 484 | f = &mw->frmr; |
| @@ -524,18 +518,19 @@ frwr_op_unmap_sync(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req) · 33 unmodified lines | ||
| 524 | 518 | * unless ri_id->qp is a valid pointer. |
| 525 | 519 | */ |
| 526 | 520 | r_xprt->rx_stats.local_inv_needed++; |
| 521 | + bad_wr = NULL; | |
| 527 | 522 | rc = ib_post_send(ia->ri_id->qp, first, &bad_wr); |
| 523 | + if (bad_wr != first) | |
| 524 | + wait_for_completion(&f->fr_linv_done); | |
| 528 | 525 | if (rc) |
| 529 | 526 | goto reset_mrs; |
| 530 | 527 | |
| 531 | − wait_for_completion(&f->fr_linv_done); | |
| 532 | − | |
| 533 | − /* ORDER: Now DMA unmap all of the req's MRs, and return | |
| 528 | + /* ORDER: Now DMA unmap all of the MRs, and return | |
| 534 | 529 | * them to the free MW list. |
| 535 | 530 | */ |
| 536 | 531 | unmap: |
| 537 | − while (!list_empty(&req->rl_registered)) { | |
| 538 | − mw = rpcrdma_pop_mw(&req->rl_registered); | |
| 532 | + while (!list_empty(mws)) { | |
| 533 | + mw = rpcrdma_pop_mw(mws); | |
| 539 | 534 | dprintk("RPC: %s: DMA unmapping frmr %p\n", |
| 540 | 535 | __func__, &mw->frmr); |
| 541 | 536 | ib_dma_unmap_sg(ia->ri_device, |
| @@ -546,17 +541,19 @@ unmap: · 4 unmodified lines | ||
| 546 | 541 | |
| 547 | 542 | reset_mrs: |
| 548 | 543 | pr_err("rpcrdma: FRMR invalidate ib_post_send returned %i\n", rc); |
| 549 | − rdma_disconnect(ia->ri_id); | |
| 550 | 544 | |
| 551 | 545 | /* Find and reset the MRs in the LOCAL_INV WRs that did not |
| 552 | − * get posted. This is synchronous, and slow. | |
| 546 | + * get posted. | |
| 553 | 547 | */ |
| 554 | − list_for_each_entry(mw, &req->rl_registered, mw_list) { | |
| 555 | − f = &mw->frmr; | |
| 556 | − if (mw->mw_handle == bad_wr->ex.invalidate_rkey) { | |
| 557 | − __frwr_reset_mr(ia, mw); | |
| 558 | − bad_wr = bad_wr->next; | |
| 559 | − } | |
| 548 | + rpcrdma_init_cqcount(&r_xprt->rx_ep, -count); | |
| 549 | + while (bad_wr) { | |
| 550 | + f = container_of(bad_wr, struct rpcrdma_frmr, | |
| 551 | + fr_invwr); | |
| 552 | + mw = container_of(f, struct rpcrdma_mw, frmr); | |
| 553 | + | |
| 554 | + __frwr_reset_mr(ia, mw); | |
| 555 | + | |
| 556 | + bad_wr = bad_wr->next; | |
| 560 | 557 | } |
| 561 | 558 | goto unmap; |
| 562 | 559 | } |
| @@ -141,7 +141,7 @@ static bool rpcrdma_args_inline(struct rpcrdma_xprt *r_xprt, · 140 unmodified lines | ||
| 141 | 141 | |
| 142 | 142 | if (xdr->page_len) { |
| 143 | 143 | remaining = xdr->page_len; |
| 144 | − offset = xdr->page_base & ~PAGE_MASK; | |
| 144 | + offset = offset_in_page(xdr->page_base); | |
| 145 | 145 | count = 0; |
| 146 | 146 | while (remaining) { |
| 147 | 147 | remaining -= min_t(unsigned int, |
| @@ -222,7 +222,7 @@ rpcrdma_convert_iovs(struct rpcrdma_xprt *r_xprt, struct xdr_buf *xdrbuf, · 74 unmodified lines | ||
| 222 | 222 | |
| 223 | 223 | len = xdrbuf->page_len; |
| 224 | 224 | ppages = xdrbuf->pages + (xdrbuf->page_base >> PAGE_SHIFT); |
| 225 | − page_base = xdrbuf->page_base & ~PAGE_MASK; | |
| 225 | + page_base = offset_in_page(xdrbuf->page_base); | |
| 226 | 226 | p = 0; |
| 227 | 227 | while (len && n < RPCRDMA_MAX_SEGS) { |
| 228 | 228 | if (!ppages[p]) { |
| @@ -540,7 +540,7 @@ rpcrdma_prepare_msg_sges(struct rpcrdma_ia *ia, struct rpcrdma_req *req, · 311 unmodified lines | ||
| 540 | 540 | goto out; |
| 541 | 541 | |
| 542 | 542 | page = virt_to_page(xdr->tail[0].iov_base); |
| 543 | − page_base = (unsigned long)xdr->tail[0].iov_base & ~PAGE_MASK; | |
| 543 | + page_base = offset_in_page(xdr->tail[0].iov_base); | |
| 544 | 544 | |
| 545 | 545 | /* If the content in the page list is an odd length, |
| 546 | 546 | * xdr_write_pages() has added a pad at the beginning |
| @@ -557,7 +557,7 @@ rpcrdma_prepare_msg_sges(struct rpcrdma_ia *ia, struct rpcrdma_req *req, · 10 unmodified lines | ||
| 557 | 557 | */ |
| 558 | 558 | if (xdr->page_len) { |
| 559 | 559 | ppages = xdr->pages + (xdr->page_base >> PAGE_SHIFT); |
| 560 | − page_base = xdr->page_base & ~PAGE_MASK; | |
| 560 | + page_base = offset_in_page(xdr->page_base); | |
| 561 | 561 | remaining = xdr->page_len; |
| 562 | 562 | while (remaining) { |
| 563 | 563 | sge_no++; |
| @@ -587,7 +587,7 @@ rpcrdma_prepare_msg_sges(struct rpcrdma_ia *ia, struct rpcrdma_req *req, · 23 unmodified lines | ||
| 587 | 587 | */ |
| 588 | 588 | if (xdr->tail[0].iov_len) { |
| 589 | 589 | page = virt_to_page(xdr->tail[0].iov_base); |
| 590 | − page_base = (unsigned long)xdr->tail[0].iov_base & ~PAGE_MASK; | |
| 590 | + page_base = offset_in_page(xdr->tail[0].iov_base); | |
| 591 | 591 | len = xdr->tail[0].iov_len; |
| 592 | 592 | |
| 593 | 593 | map_tail: |
| @@ -734,6 +734,9 @@ rpcrdma_marshal_req(struct rpc_rqst *rqst) · 140 unmodified lines | ||
| 734 | 734 | rpclen = 0; |
| 735 | 735 | } |
| 736 | 736 | |
| 737 | + req->rl_xid = rqst->rq_xid; | |
| 738 | + rpcrdma_insert_req(&r_xprt->rx_buf, req); | |
| 739 | + | |
| 737 | 740 | /* This implementation supports the following combinations |
| 738 | 741 | * of chunk lists in one RPC-over-RDMA Call message: |
| 739 | 742 | * |
| @@ -875,9 +878,9 @@ rpcrdma_inline_fixup(struct rpc_rqst *rqst, char *srcp, int copy_len, int pad) · 135 unmodified lines | ||
| 875 | 878 | srcp += curlen; |
| 876 | 879 | copy_len -= curlen; |
| 877 | 880 | |
| 878 | − page_base = rqst->rq_rcv_buf.page_base; | |
| 879 | − ppages = rqst->rq_rcv_buf.pages + (page_base >> PAGE_SHIFT); | |
| 880 | − page_base &= ~PAGE_MASK; | |
| 881 | + ppages = rqst->rq_rcv_buf.pages + | |
| 882 | + (rqst->rq_rcv_buf.page_base >> PAGE_SHIFT); | |
| 883 | + page_base = offset_in_page(rqst->rq_rcv_buf.page_base); | |
| 881 | 884 | fixup_copy_count = 0; |
| 882 | 885 | if (copy_len && rqst->rq_rcv_buf.page_len) { |
| 883 | 886 | int pagelist_len; |
| @@ -928,6 +931,24 @@ rpcrdma_inline_fixup(struct rpc_rqst *rqst, char *srcp, int copy_len, int pad) · 44 unmodified lines | ||
| 928 | 931 | return fixup_copy_count; |
| 929 | 932 | } |
| 930 | 933 | |
| 934 | +/* Caller must guarantee @rep remains stable during this call. | |
| 935 | + */ | |
| 936 | +static void | |
| 937 | +rpcrdma_mark_remote_invalidation(struct list_head *mws, | |
| 938 | + struct rpcrdma_rep *rep) | |
| 939 | +{ | |
| 940 | + struct rpcrdma_mw *mw; | |
| 941 | + | |
| 942 | + if (!(rep->rr_wc_flags & IB_WC_WITH_INVALIDATE)) | |
| 943 | + return; | |
| 944 | + | |
| 945 | + list_for_each_entry(mw, mws, mw_list) | |
| 946 | + if (mw->mw_handle == rep->rr_inv_rkey) { | |
| 947 | + mw->mw_flags = RPCRDMA_MW_F_RI; | |
| 948 | + break; /* only one invalidated MR per RPC */ | |
| 949 | + } | |
| 950 | +} | |
| 951 | + | |
| 931 | 952 | #if defined(CONFIG_SUNRPC_BACKCHANNEL) |
| 932 | 953 | /* By convention, backchannel calls arrive via rdma_msg type |
| 933 | 954 | * messages, and never populate the chunk lists. This makes |
| @@ -969,14 +990,16 @@ rpcrdma_reply_handler(struct work_struct *work) · 35 unmodified lines | ||
| 969 | 990 | { |
| 970 | 991 | struct rpcrdma_rep *rep = |
| 971 | 992 | container_of(work, struct rpcrdma_rep, rr_work); |
| 993 | + struct rpcrdma_xprt *r_xprt = rep->rr_rxprt; | |
| 994 | + struct rpcrdma_buffer *buf = &r_xprt->rx_buf; | |
| 995 | + struct rpc_xprt *xprt = &r_xprt->rx_xprt; | |
| 972 | 996 | struct rpcrdma_msg *headerp; |
| 973 | 997 | struct rpcrdma_req *req; |
| 974 | 998 | struct rpc_rqst *rqst; |
| 975 | − struct rpcrdma_xprt *r_xprt = rep->rr_rxprt; | |
| 976 | − struct rpc_xprt *xprt = &r_xprt->rx_xprt; | |
| 977 | 999 | __be32 *iptr; |
| 978 | 1000 | int rdmalen, status, rmerr; |
| 979 | 1001 | unsigned long cwnd; |
| 1002 | + struct list_head mws; | |
| 980 | 1003 | |
| 981 | 1004 | dprintk("RPC: %s: incoming rep %p\n", __func__, rep); |
| 982 | 1005 | |
| @@ -994,27 +1017,45 @@ rpcrdma_reply_handler(struct work_struct *work) · 11 unmodified lines | ||
| 994 | 1017 | /* Match incoming rpcrdma_rep to an rpcrdma_req to |
| 995 | 1018 | * get context for handling any incoming chunks. |
| 996 | 1019 | */ |
| 997 | − spin_lock_bh(&xprt->transport_lock); | |
| 998 | − rqst = xprt_lookup_rqst(xprt, headerp->rm_xid); | |
| 999 | − if (!rqst) | |
| 1020 | + spin_lock(&buf->rb_lock); | |
| 1021 | + req = rpcrdma_lookup_req_locked(&r_xprt->rx_buf, | |
| 1022 | + headerp->rm_xid); | |
| 1023 | + if (!req) | |
| 1000 | 1024 | goto out_nomatch; |
| 1001 | − | |
| 1002 | − req = rpcr_to_rdmar(rqst); | |
| 1003 | 1025 | if (req->rl_reply) |
| 1004 | 1026 | goto out_duplicate; |
| 1005 | 1027 | |
| 1006 | − /* Sanity checking has passed. We are now committed | |
| 1007 | − * to complete this transaction. | |
| 1028 | + list_replace_init(&req->rl_registered, &mws); | |
| 1029 | + rpcrdma_mark_remote_invalidation(&mws, rep); | |
| 1030 | + | |
| 1031 | + /* Avoid races with signals and duplicate replies | |
| 1032 | + * by marking this req as matched. | |
| 1008 | 1033 | */ |
| 1009 | − list_del_init(&rqst->rq_list); | |
| 1010 | − spin_unlock_bh(&xprt->transport_lock); | |
| 1034 | + req->rl_reply = rep; | |
| 1035 | + spin_unlock(&buf->rb_lock); | |
| 1036 | + | |
| 1011 | 1037 | dprintk("RPC: %s: reply %p completes request %p (xid 0x%08x)\n", |
| 1012 | 1038 | __func__, rep, req, be32_to_cpu(headerp->rm_xid)); |
| 1013 | 1039 | |
| 1014 | − /* from here on, the reply is no longer an orphan */ | |
| 1015 | − req->rl_reply = rep; | |
| 1016 | − xprt->reestablish_timeout = 0; | |
| 1040 | + /* Invalidate and unmap the data payloads before waking the | |
| 1041 | + * waiting application. This guarantees the memory regions | |
| 1042 | + * are properly fenced from the server before the application | |
| 1043 | + * accesses the data. It also ensures proper send flow control: | |
| 1044 | + * waking the next RPC waits until this RPC has relinquished | |
| 1045 | + * all its Send Queue entries. | |
| 1046 | + */ | |
| 1047 | + if (!list_empty(&mws)) | |
| 1048 | + r_xprt->rx_ia.ri_ops->ro_unmap_sync(r_xprt, &mws); | |
| 1017 | 1049 | |
| 1050 | + /* Perform XID lookup, reconstruction of the RPC reply, and | |
| 1051 | + * RPC completion while holding the transport lock to ensure | |
| 1052 | + * the rep, rqst, and rq_task pointers remain stable. | |
| 1053 | + */ | |
| 1054 | + spin_lock_bh(&xprt->transport_lock); | |
| 1055 | + rqst = xprt_lookup_rqst(xprt, headerp->rm_xid); | |
| 1056 | + if (!rqst) | |
| 1057 | + goto out_norqst; | |
| 1058 | + xprt->reestablish_timeout = 0; | |
| 1018 | 1059 | if (headerp->rm_vers != rpcrdma_version) |
| 1019 | 1060 | goto out_badversion; |
| 1020 | 1061 | |
| @@ -1024,12 +1065,9 @@ rpcrdma_reply_handler(struct work_struct *work) · 3 unmodified lines | ||
| 1024 | 1065 | case rdma_msg: |
| 1025 | 1066 | /* never expect read chunks */ |
| 1026 | 1067 | /* never expect reply chunks (two ways to check) */ |
| 1027 | − /* never expect write chunks without having offered RDMA */ | |
| 1028 | 1068 | if (headerp->rm_body.rm_chunks[0] != xdr_zero || |
| 1029 | 1069 | (headerp->rm_body.rm_chunks[1] == xdr_zero && |
| 1030 | − headerp->rm_body.rm_chunks[2] != xdr_zero) || | |
| 1031 | − (headerp->rm_body.rm_chunks[1] != xdr_zero && | |
| 1032 | − list_empty(&req->rl_registered))) | |
| 1070 | + headerp->rm_body.rm_chunks[2] != xdr_zero)) | |
| 1033 | 1071 | goto badheader; |
| 1034 | 1072 | if (headerp->rm_body.rm_chunks[1] != xdr_zero) { |
| 1035 | 1073 | /* count any expected write chunks in read reply */ |
| @@ -1066,8 +1104,7 @@ rpcrdma_reply_handler(struct work_struct *work) · 30 unmodified lines | ||
| 1066 | 1104 | /* never expect read or write chunks, always reply chunks */ |
| 1067 | 1105 | if (headerp->rm_body.rm_chunks[0] != xdr_zero || |
| 1068 | 1106 | headerp->rm_body.rm_chunks[1] != xdr_zero || |
| 1069 | − headerp->rm_body.rm_chunks[2] != xdr_one || | |
| 1070 | − list_empty(&req->rl_registered)) | |
| 1107 | + headerp->rm_body.rm_chunks[2] != xdr_one) | |
| 1071 | 1108 | goto badheader; |
| 1072 | 1109 | iptr = (__be32 *)((unsigned char *)headerp + |
| 1073 | 1110 | RPCRDMA_HDRLEN_MIN); |
| @@ -1093,17 +1130,6 @@ badheader: · 19 unmodified lines | ||
| 1093 | 1130 | } |
| 1094 | 1131 | |
| 1095 | 1132 | out: |
| 1096 | − /* Invalidate and flush the data payloads before waking the | |
| 1097 | − * waiting application. This guarantees the memory region is | |
| 1098 | − * properly fenced from the server before the application | |
| 1099 | − * accesses the data. It also ensures proper send flow | |
| 1100 | − * control: waking the next RPC waits until this RPC has | |
| 1101 | − * relinquished all its Send Queue entries. | |
| 1102 | − */ | |
| 1103 | − if (!list_empty(&req->rl_registered)) | |
| 1104 | − r_xprt->rx_ia.ri_ops->ro_unmap_sync(r_xprt, req); | |
| 1105 | − | |
| 1106 | − spin_lock_bh(&xprt->transport_lock); | |
| 1107 | 1133 | cwnd = xprt->cwnd; |
| 1108 | 1134 | xprt->cwnd = atomic_read(&r_xprt->rx_buf.rb_credits) << RPC_CWNDSHIFT; |
| 1109 | 1135 | if (xprt->cwnd > cwnd) |
| @@ -1112,7 +1138,7 @@ out: · 2 unmodified lines | ||
| 1112 | 1138 | xprt_complete_rqst(rqst->rq_task, status); |
| 1113 | 1139 | spin_unlock_bh(&xprt->transport_lock); |
| 1114 | 1140 | dprintk("RPC: %s: xprt_complete_rqst(0x%p, 0x%p, %d)\n", |
| 1115 | − __func__, xprt, rqst, status); | |
| 1141 | + __func__, xprt, rqst, status); | |
| 1116 | 1142 | return; |
| 1117 | 1143 | |
| 1118 | 1144 | out_badstatus: |
| @@ -1161,26 +1187,37 @@ out_rdmaerr: · 42 unmodified lines | ||
| 1161 | 1187 | r_xprt->rx_stats.bad_reply_count++; |
| 1162 | 1188 | goto out; |
| 1163 | 1189 | |
| 1164 | −/* If no pending RPC transaction was matched, post a replacement | |
| 1165 | − * receive buffer before returning. | |
| 1190 | +/* The req was still available, but by the time the transport_lock | |
| 1191 | + * was acquired, the rqst and task had been released. Thus the RPC | |
| 1192 | + * has already been terminated. | |
| 1166 | 1193 | */ |
| 1194 | +out_norqst: | |
| 1195 | + spin_unlock_bh(&xprt->transport_lock); | |
| 1196 | + rpcrdma_buffer_put(req); | |
| 1197 | + dprintk("RPC: %s: race, no rqst left for req %p\n", | |
| 1198 | + __func__, req); | |
| 1199 | + return; | |
| 1200 | + | |
| 1167 | 1201 | out_shortreply: |
| 1168 | 1202 | dprintk("RPC: %s: short/invalid reply\n", __func__); |
| 1169 | 1203 | goto repost; |
| 1170 | 1204 | |
| 1171 | 1205 | out_nomatch: |
| 1172 | − spin_unlock_bh(&xprt->transport_lock); | |
| 1206 | + spin_unlock(&buf->rb_lock); | |
| 1173 | 1207 | dprintk("RPC: %s: no match for incoming xid 0x%08x len %d\n", |
| 1174 | 1208 | __func__, be32_to_cpu(headerp->rm_xid), |
| 1175 | 1209 | rep->rr_len); |
| 1176 | 1210 | goto repost; |
| 1177 | 1211 | |
| 1178 | 1212 | out_duplicate: |
| 1179 | − spin_unlock_bh(&xprt->transport_lock); | |
| 1213 | + spin_unlock(&buf->rb_lock); | |
| 1180 | 1214 | dprintk("RPC: %s: " |
| 1181 | 1215 | "duplicate reply %p to RPC request %p: xid 0x%08x\n", |
| 1182 | 1216 | __func__, rep, req, be32_to_cpu(headerp->rm_xid)); |
| 1183 | 1217 | |
| 1218 | +/* If no pending RPC transaction was matched, post a replacement | |
| 1219 | + * receive buffer before returning. | |
| 1220 | + */ | |
| 1184 | 1221 | repost: |
| 1185 | 1222 | r_xprt->rx_stats.bad_reply_count++; |
| 1186 | 1223 | if (rpcrdma_ep_post_recv(&r_xprt->rx_ia, rep)) |
| @@ -684,7 +684,8 @@ xprt_rdma_free(struct rpc_task *task) · 683 unmodified lines | ||
| 684 | 684 | |
| 685 | 685 | dprintk("RPC: %s: called on 0x%p\n", __func__, req->rl_reply); |
| 686 | 686 | |
| 687 | − if (unlikely(!list_empty(&req->rl_registered))) | |
| 687 | + rpcrdma_remove_req(&r_xprt->rx_buf, req); | |
| 688 | + if (!list_empty(&req->rl_registered)) | |
| 688 | 689 | ia->ri_ops->ro_unmap_safe(r_xprt, req, !RPC_IS_ASYNC(task)); |
| 689 | 690 | rpcrdma_unmap_sges(ia, req); |
| 690 | 691 | rpcrdma_buffer_put(req); |
| @@ -243,8 +243,6 @@ rpcrdma_conn_upcall(struct rdma_cm_id *id, struct rdma_cm_event *event) · 242 unmodified lines | ||
| 243 | 243 | #if IS_ENABLED(CONFIG_SUNRPC_DEBUG) |
| 244 | 244 | struct sockaddr *sap = (struct sockaddr *)&ep->rep_remote_addr; |
| 245 | 245 | #endif |
| 246 | − struct ib_qp_attr *attr = &ia->ri_qp_attr; | |
| 247 | − struct ib_qp_init_attr *iattr = &ia->ri_qp_init_attr; | |
| 248 | 246 | int connstate = 0; |
| 249 | 247 | |
| 250 | 248 | switch (event->event) { |
| @@ -267,7 +265,8 @@ rpcrdma_conn_upcall(struct rdma_cm_id *id, struct rdma_cm_event *event) · 16 unmodified lines | ||
| 267 | 265 | break; |
| 268 | 266 | case RDMA_CM_EVENT_DEVICE_REMOVAL: |
| 269 | 267 | #if IS_ENABLED(CONFIG_SUNRPC_DEBUG) |
| 270 | − pr_info("rpcrdma: removing device for %pIS:%u\n", | |
| 268 | + pr_info("rpcrdma: removing device %s for %pIS:%u\n", | |
| 269 | + ia->ri_device->name, | |
| 271 | 270 | sap, rpc_get_port(sap)); |
| 272 | 271 | #endif |
| 273 | 272 | set_bit(RPCRDMA_IAF_REMOVING, &ia->ri_flags); |
| @@ -282,13 +281,6 @@ rpcrdma_conn_upcall(struct rdma_cm_id *id, struct rdma_cm_event *event) · 8 unmodified lines | ||
| 282 | 281 | return 1; |
| 283 | 282 | case RDMA_CM_EVENT_ESTABLISHED: |
| 284 | 283 | connstate = 1; |
| 285 | − ib_query_qp(ia->ri_id->qp, attr, | |
| 286 | − IB_QP_MAX_QP_RD_ATOMIC | IB_QP_MAX_DEST_RD_ATOMIC, | |
| 287 | − iattr); | |
| 288 | − dprintk("RPC: %s: %d responder resources" | |
| 289 | − " (%d initiator)\n", | |
| 290 | − __func__, attr->max_dest_rd_atomic, | |
| 291 | − attr->max_rd_atomic); | |
| 292 | 284 | rpcrdma_update_connect_private(xprt, &event->param.conn); |
| 293 | 285 | goto connected; |
| 294 | 286 | case RDMA_CM_EVENT_CONNECT_ERROR: |
| @@ -298,11 +290,9 @@ rpcrdma_conn_upcall(struct rdma_cm_id *id, struct rdma_cm_event *event) · 3 unmodified lines | ||
| 298 | 290 | connstate = -ENETDOWN; |
| 299 | 291 | goto connected; |
| 300 | 292 | case RDMA_CM_EVENT_REJECTED: |
| 301 | −#if IS_ENABLED(CONFIG_SUNRPC_DEBUG) | |
| 302 | − pr_info("rpcrdma: connection to %pIS:%u on %s rejected: %s\n", | |
| 303 | − sap, rpc_get_port(sap), ia->ri_device->name, | |
| 293 | + dprintk("rpcrdma: connection to %pIS:%u rejected: %s\n", | |
| 294 | + sap, rpc_get_port(sap), | |
| 304 | 295 | rdma_reject_msg(id, event->status)); |
| 305 | −#endif | |
| 306 | 296 | connstate = -ECONNREFUSED; |
| 307 | 297 | if (event->status == IB_CM_REJ_STALE_CONN) |
| 308 | 298 | connstate = -EAGAIN; |
| @@ -310,37 +300,19 @@ rpcrdma_conn_upcall(struct rdma_cm_id *id, struct rdma_cm_event *event) · 1 unmodified line | ||
| 310 | 300 | case RDMA_CM_EVENT_DISCONNECTED: |
| 311 | 301 | connstate = -ECONNABORTED; |
| 312 | 302 | connected: |
| 313 | − dprintk("RPC: %s: %sconnected\n", | |
| 314 | − __func__, connstate > 0 ? "" : "dis"); | |
| 315 | 303 | atomic_set(&xprt->rx_buf.rb_credits, 1); |
| 316 | 304 | ep->rep_connected = connstate; |
| 317 | 305 | rpcrdma_conn_func(ep); |
| 318 | 306 | wake_up_all(&ep->rep_connect_wait); |
| 319 | 307 | /*FALLTHROUGH*/ |
| 320 | 308 | default: |
| 321 | − dprintk("RPC: %s: %pIS:%u (ep 0x%p): %s\n", | |
| 322 | − __func__, sap, rpc_get_port(sap), ep, | |
| 323 | − rdma_event_msg(event->event)); | |
| 309 | + dprintk("RPC: %s: %pIS:%u on %s/%s (ep 0x%p): %s\n", | |
| 310 | + __func__, sap, rpc_get_port(sap), | |
| 311 | + ia->ri_device->name, ia->ri_ops->ro_displayname, | |
| 312 | + ep, rdma_event_msg(event->event)); | |
| 324 | 313 | break; |
| 325 | 314 | } |
| 326 | 315 | |
| 327 | −#if IS_ENABLED(CONFIG_SUNRPC_DEBUG) | |
| 328 | − if (connstate == 1) { | |
| 329 | − int ird = attr->max_dest_rd_atomic; | |
| 330 | − int tird = ep->rep_remote_cma.responder_resources; | |
| 331 | − | |
| 332 | − pr_info("rpcrdma: connection to %pIS:%u on %s, memreg '%s', %d credits, %d responders%s\n", | |
| 333 | − sap, rpc_get_port(sap), | |
| 334 | − ia->ri_device->name, | |
| 335 | − ia->ri_ops->ro_displayname, | |
| 336 | − xprt->rx_buf.rb_max_requests, | |
| 337 | − ird, ird < 4 && ird < tird / 2 ? " (low!)" : ""); | |
| 338 | − } else if (connstate < 0) { | |
| 339 | − pr_info("rpcrdma: connection to %pIS:%u closed (%d)\n", | |
| 340 | − sap, rpc_get_port(sap), connstate); | |
| 341 | − } | |
| 342 | −#endif | |
| 343 | − | |
| 344 | 316 | return 0; |
| 345 | 317 | } |
| 346 | 318 | |
| @@ -971,7 +943,6 @@ rpcrdma_create_req(struct rpcrdma_xprt *r_xprt) · 624 unmodified lines | ||
| 971 | 943 | if (req == NULL) |
| 972 | 944 | return ERR_PTR(-ENOMEM); |
| 973 | 945 | |
| 974 | − INIT_LIST_HEAD(&req->rl_free); | |
| 975 | 946 | spin_lock(&buffer->rb_reqslock); |
| 976 | 947 | list_add(&req->rl_all, &buffer->rb_allreqs); |
| 977 | 948 | spin_unlock(&buffer->rb_reqslock); |
| @@ -1033,6 +1004,7 @@ rpcrdma_buffer_create(struct rpcrdma_xprt *r_xprt) · 55 unmodified lines | ||
| 1033 | 1004 | spin_lock_init(&buf->rb_recovery_lock); |
| 1034 | 1005 | INIT_LIST_HEAD(&buf->rb_mws); |
| 1035 | 1006 | INIT_LIST_HEAD(&buf->rb_all); |
| 1007 | + INIT_LIST_HEAD(&buf->rb_pending); | |
| 1036 | 1008 | INIT_LIST_HEAD(&buf->rb_stale_mrs); |
| 1037 | 1009 | INIT_DELAYED_WORK(&buf->rb_refresh_worker, |
| 1038 | 1010 | rpcrdma_mr_refresh_worker); |
| @@ -1055,7 +1027,7 @@ rpcrdma_buffer_create(struct rpcrdma_xprt *r_xprt) · 16 unmodified lines | ||
| 1055 | 1027 | goto out; |
| 1056 | 1028 | } |
| 1057 | 1029 | req->rl_backchannel = false; |
| 1058 | − list_add(&req->rl_free, &buf->rb_send_bufs); | |
| 1030 | + list_add(&req->rl_list, &buf->rb_send_bufs); | |
| 1059 | 1031 | } |
| 1060 | 1032 | |
| 1061 | 1033 | INIT_LIST_HEAD(&buf->rb_recv_bufs); |
| @@ -1084,8 +1056,8 @@ rpcrdma_buffer_get_req_locked(struct rpcrdma_buffer *buf) · 22 unmodified lines | ||
| 1084 | 1056 | struct rpcrdma_req *req; |
| 1085 | 1057 | |
| 1086 | 1058 | req = list_first_entry(&buf->rb_send_bufs, |
| 1087 | − struct rpcrdma_req, rl_free); | |
| 1088 | − list_del(&req->rl_free); | |
| 1059 | + struct rpcrdma_req, rl_list); | |
| 1060 | + list_del_init(&req->rl_list); | |
| 1089 | 1061 | return req; |
| 1090 | 1062 | } |
| 1091 | 1063 | |
| @@ -1187,6 +1159,7 @@ rpcrdma_get_mw(struct rpcrdma_xprt *r_xprt) · 95 unmodified lines | ||
| 1187 | 1159 | |
| 1188 | 1160 | if (!mw) |
| 1189 | 1161 | goto out_nomws; |
| 1162 | + mw->mw_flags = 0; | |
| 1190 | 1163 | return mw; |
| 1191 | 1164 | |
| 1192 | 1165 | out_nomws: |
| @@ -1267,7 +1240,7 @@ rpcrdma_buffer_put(struct rpcrdma_req *req) · 74 unmodified lines | ||
| 1267 | 1240 | |
| 1268 | 1241 | spin_lock(&buffers->rb_lock); |
| 1269 | 1242 | buffers->rb_send_count--; |
| 1270 | − list_add_tail(&req->rl_free, &buffers->rb_send_bufs); | |
| 1243 | + list_add_tail(&req->rl_list, &buffers->rb_send_bufs); | |
| 1271 | 1244 | if (rep) { |
| 1272 | 1245 | buffers->rb_recv_count--; |
| 1273 | 1246 | list_add_tail(&rep->rr_list, &buffers->rb_recv_bufs); |
| @@ -271,6 +271,7 @@ struct rpcrdma_mw { · 270 unmodified lines | ||
| 271 | 271 | struct scatterlist *mw_sg; |
| 272 | 272 | int mw_nents; |
| 273 | 273 | enum dma_data_direction mw_dir; |
| 274 | + unsigned long mw_flags; | |
| 274 | 275 | union { |
| 275 | 276 | struct rpcrdma_fmr fmr; |
| 276 | 277 | struct rpcrdma_frmr frmr; |
| @@ -282,6 +283,11 @@ struct rpcrdma_mw { · 5 unmodified lines | ||
| 282 | 283 | struct list_head mw_all; |
| 283 | 284 | }; |
| 284 | 285 | |
| 286 | +/* mw_flags */ | |
| 287 | +enum { | |
| 288 | + RPCRDMA_MW_F_RI = 1, | |
| 289 | +}; | |
| 290 | + | |
| 285 | 291 | /* |
| 286 | 292 | * struct rpcrdma_req -- structure central to the request/reply sequence. |
| 287 | 293 | * |
| @@ -334,7 +340,8 @@ enum { · 46 unmodified lines | ||
| 334 | 340 | |
| 335 | 341 | struct rpcrdma_buffer; |
| 336 | 342 | struct rpcrdma_req { |
| 337 | − struct list_head rl_free; | |
| 343 | + struct list_head rl_list; | |
| 344 | + __be32 rl_xid; | |
| 338 | 345 | unsigned int rl_mapped_sges; |
| 339 | 346 | unsigned int rl_connect_cookie; |
| 340 | 347 | struct rpcrdma_buffer *rl_buffer; |
| @@ -396,6 +403,7 @@ struct rpcrdma_buffer { · 55 unmodified lines | ||
| 396 | 403 | int rb_send_count, rb_recv_count; |
| 397 | 404 | struct list_head rb_send_bufs; |
| 398 | 405 | struct list_head rb_recv_bufs; |
| 406 | + struct list_head rb_pending; | |
| 399 | 407 | u32 rb_max_requests; |
| 400 | 408 | atomic_t rb_credits; /* most recent credit grant */ |
| 401 | 409 | |
| @@ -461,7 +469,7 @@ struct rpcrdma_memreg_ops { · 59 unmodified lines | ||
| 461 | 469 | struct rpcrdma_mr_seg *, int, bool, |
| 462 | 470 | struct rpcrdma_mw **); |
| 463 | 471 | void (*ro_unmap_sync)(struct rpcrdma_xprt *, |
| 464 | − struct rpcrdma_req *); | |
| 472 | + struct list_head *); | |
| 465 | 473 | void (*ro_unmap_safe)(struct rpcrdma_xprt *, |
| 466 | 474 | struct rpcrdma_req *, bool); |
| 467 | 475 | void (*ro_recover_mr)(struct rpcrdma_mw *); |
| @@ -544,6 +552,34 @@ void rpcrdma_destroy_req(struct rpcrdma_req *); · 76 unmodified lines | ||
| 544 | 552 | int rpcrdma_buffer_create(struct rpcrdma_xprt *); |
| 545 | 553 | void rpcrdma_buffer_destroy(struct rpcrdma_buffer *); |
| 546 | 554 | |
| 555 | +static inline void | |
| 556 | +rpcrdma_insert_req(struct rpcrdma_buffer *buffers, struct rpcrdma_req *req) | |
| 557 | +{ | |
| 558 | + spin_lock(&buffers->rb_lock); | |
| 559 | + if (list_empty(&req->rl_list)) | |
| 560 | + list_add_tail(&req->rl_list, &buffers->rb_pending); | |
| 561 | + spin_unlock(&buffers->rb_lock); | |
| 562 | +} | |
| 563 | + | |
| 564 | +static inline struct rpcrdma_req * | |
| 565 | +rpcrdma_lookup_req_locked(struct rpcrdma_buffer *buffers, __be32 xid) | |
| 566 | +{ | |
| 567 | + struct rpcrdma_req *pos; | |
| 568 | + | |
| 569 | + list_for_each_entry(pos, &buffers->rb_pending, rl_list) | |
| 570 | + if (pos->rl_xid == xid) | |
| 571 | + return pos; | |
| 572 | + return NULL; | |
| 573 | +} | |
| 574 | + | |
| 575 | +static inline void | |
| 576 | +rpcrdma_remove_req(struct rpcrdma_buffer *buffers, struct rpcrdma_req *req) | |
| 577 | +{ | |
| 578 | + spin_lock(&buffers->rb_lock); | |
| 579 | + list_del(&req->rl_list); | |
| 580 | + spin_unlock(&buffers->rb_lock); | |
| 581 | +} | |
| 582 | + | |
| 547 | 583 | struct rpcrdma_mw *rpcrdma_get_mw(struct rpcrdma_xprt *); |
| 548 | 584 | void rpcrdma_put_mw(struct rpcrdma_xprt *, struct rpcrdma_mw *); |
| 549 | 585 | struct rpcrdma_req *rpcrdma_buffer_get(struct rpcrdma_buffer *); |