Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

pnfs: support multiple verfs per direct req

Support direct requests that span multiple pnfs data servers by
comparing nfs_pgio_header->verf to a cached verf in pnfs_commit_bucket.
Continue to use dreq->verf if the MDS is used / non-pNFS.

Signed-off-by: Weston Andros Adamson <dros@primarydata.com>
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>

authored by

Weston Andros Adamson and committed by
Trond Myklebust
5002c586 7f714720

+109 -6
+97 -5
fs/nfs/direct.c
··· 108 108 return atomic_dec_and_test(&dreq->io_count); 109 109 } 110 110 111 + /* 112 + * nfs_direct_select_verf - select the right verifier 113 + * @dreq - direct request possibly spanning multiple servers 114 + * @ds_clp - nfs_client of data server or NULL if MDS / non-pnfs 115 + * @ds_idx - index of data server in data server list, only valid if ds_clp set 116 + * 117 + * returns the correct verifier to use given the role of the server 118 + */ 119 + static struct nfs_writeverf * 120 + nfs_direct_select_verf(struct nfs_direct_req *dreq, 121 + struct nfs_client *ds_clp, 122 + int ds_idx) 123 + { 124 + struct nfs_writeverf *verfp = &dreq->verf; 125 + 126 + #ifdef CONFIG_NFS_V4_1 127 + if (ds_clp) { 128 + /* pNFS is in use, use the DS verf */ 129 + if (ds_idx >= 0 && ds_idx < dreq->ds_cinfo.nbuckets) 130 + verfp = &dreq->ds_cinfo.buckets[ds_idx].direct_verf; 131 + else 132 + WARN_ON_ONCE(1); 133 + } 134 + #endif 135 + return verfp; 136 + } 137 + 138 + 139 + /* 140 + * nfs_direct_set_hdr_verf - set the write/commit verifier 141 + * @dreq - direct request possibly spanning multiple servers 142 + * @hdr - pageio header to validate against previously seen verfs 143 + * 144 + * Set the server's (MDS or DS) "seen" verifier 145 + */ 146 + static void nfs_direct_set_hdr_verf(struct nfs_direct_req *dreq, 147 + struct nfs_pgio_header *hdr) 148 + { 149 + struct nfs_writeverf *verfp; 150 + 151 + verfp = nfs_direct_select_verf(dreq, hdr->data->ds_clp, 152 + hdr->data->ds_idx); 153 + WARN_ON_ONCE(verfp->committed >= 0); 154 + memcpy(verfp, &hdr->verf, sizeof(struct nfs_writeverf)); 155 + WARN_ON_ONCE(verfp->committed < 0); 156 + } 157 + 158 + /* 159 + * nfs_direct_cmp_hdr_verf - compare verifier for pgio header 160 + * @dreq - direct request possibly spanning multiple servers 161 + * @hdr - pageio header to validate against previously seen verf 162 + * 163 + * set the server's "seen" verf if not initialized. 164 + * returns result of comparison between @hdr->verf and the "seen" 165 + * verf of the server used by @hdr (DS or MDS) 166 + */ 167 + static int nfs_direct_set_or_cmp_hdr_verf(struct nfs_direct_req *dreq, 168 + struct nfs_pgio_header *hdr) 169 + { 170 + struct nfs_writeverf *verfp; 171 + 172 + verfp = nfs_direct_select_verf(dreq, hdr->data->ds_clp, 173 + hdr->data->ds_idx); 174 + if (verfp->committed < 0) { 175 + nfs_direct_set_hdr_verf(dreq, hdr); 176 + return 0; 177 + } 178 + return memcmp(verfp, &hdr->verf, sizeof(struct nfs_writeverf)); 179 + } 180 + 181 + #if IS_ENABLED(CONFIG_NFS_V3) || IS_ENABLED(CONFIG_NFS_V4) 182 + /* 183 + * nfs_direct_cmp_commit_data_verf - compare verifier for commit data 184 + * @dreq - direct request possibly spanning multiple servers 185 + * @data - commit data to validate against previously seen verf 186 + * 187 + * returns result of comparison between @data->verf and the verf of 188 + * the server used by @data (DS or MDS) 189 + */ 190 + static int nfs_direct_cmp_commit_data_verf(struct nfs_direct_req *dreq, 191 + struct nfs_commit_data *data) 192 + { 193 + struct nfs_writeverf *verfp; 194 + 195 + verfp = nfs_direct_select_verf(dreq, data->ds_clp, 196 + data->ds_commit_index); 197 + WARN_ON_ONCE(verfp->committed < 0); 198 + return memcmp(verfp, &data->verf, sizeof(struct nfs_writeverf)); 199 + } 200 + #endif 201 + 111 202 /** 112 203 * nfs_direct_IO - NFS address space operation for direct I/O 113 204 * @rw: direction (read or write) ··· 259 168 kref_get(&dreq->kref); 260 169 init_completion(&dreq->completion); 261 170 INIT_LIST_HEAD(&dreq->mds_cinfo.list); 171 + dreq->verf.committed = NFS_INVALID_STABLE_HOW; /* not set yet */ 262 172 INIT_WORK(&dreq->work, nfs_direct_write_schedule_work); 263 173 spin_lock_init(&dreq->lock); 264 174 ··· 694 602 dprintk("NFS: %5u commit failed with error %d.\n", 695 603 data->task.tk_pid, status); 696 604 dreq->flags = NFS_ODIRECT_RESCHED_WRITES; 697 - } else if (memcmp(&dreq->verf, &data->verf, sizeof(data->verf))) { 605 + } else if (nfs_direct_cmp_commit_data_verf(dreq, data)) { 698 606 dprintk("NFS: %5u commit verify failed\n", data->task.tk_pid); 699 607 dreq->flags = NFS_ODIRECT_RESCHED_WRITES; 700 608 } ··· 903 811 if (dreq->flags == NFS_ODIRECT_RESCHED_WRITES) 904 812 bit = NFS_IOHDR_NEED_RESCHED; 905 813 else if (dreq->flags == 0) { 906 - memcpy(&dreq->verf, &hdr->verf, 907 - sizeof(dreq->verf)); 814 + nfs_direct_set_hdr_verf(dreq, hdr); 908 815 bit = NFS_IOHDR_NEED_COMMIT; 909 816 dreq->flags = NFS_ODIRECT_DO_COMMIT; 910 817 } else if (dreq->flags == NFS_ODIRECT_DO_COMMIT) { 911 - if (memcmp(&dreq->verf, &hdr->verf, sizeof(dreq->verf))) { 912 - dreq->flags = NFS_ODIRECT_RESCHED_WRITES; 818 + if (nfs_direct_set_or_cmp_hdr_verf(dreq, hdr)) { 819 + dreq->flags = 820 + NFS_ODIRECT_RESCHED_WRITES; 913 821 bit = NFS_IOHDR_NEED_RESCHED; 914 822 } else 915 823 bit = NFS_IOHDR_NEED_COMMIT;
+6
fs/nfs/nfs4filelayout.c
··· 560 560 /* No multipath support. Use first DS */ 561 561 atomic_inc(&ds->ds_clp->cl_count); 562 562 data->ds_clp = ds->ds_clp; 563 + data->ds_idx = idx; 563 564 fh = nfs4_fl_select_ds_fh(lseg, j); 564 565 if (fh) 565 566 data->args.fh = fh; ··· 604 603 data->pgio_done_cb = filelayout_write_done_cb; 605 604 atomic_inc(&ds->ds_clp->cl_count); 606 605 data->ds_clp = ds->ds_clp; 606 + data->ds_idx = idx; 607 607 fh = nfs4_fl_select_ds_fh(lseg, j); 608 608 if (fh) 609 609 data->args.fh = fh; ··· 877 875 for (i = 0; i < size; i++) { 878 876 INIT_LIST_HEAD(&buckets[i].written); 879 877 INIT_LIST_HEAD(&buckets[i].committing); 878 + /* mark direct verifier as unset */ 879 + buckets[i].direct_verf.committed = NFS_INVALID_STABLE_HOW; 880 880 } 881 881 882 882 spin_lock(cinfo->lock); ··· 889 885 &buckets[i].written); 890 886 list_splice(&cinfo->ds->buckets[i].committing, 891 887 &buckets[i].committing); 888 + buckets[i].direct_verf.committed = 889 + cinfo->ds->buckets[i].direct_verf.committed; 892 890 buckets[i].wlseg = cinfo->ds->buckets[i].wlseg; 893 891 buckets[i].clseg = cinfo->ds->buckets[i].clseg; 894 892 }
+4 -1
include/linux/nfs.h
··· 46 46 enum nfs3_stable_how { 47 47 NFS_UNSTABLE = 0, 48 48 NFS_DATA_SYNC = 1, 49 - NFS_FILE_SYNC = 2 49 + NFS_FILE_SYNC = 2, 50 + 51 + /* used by direct.c to mark verf as invalid */ 52 + NFS_INVALID_STABLE_HOW = -1 50 53 }; 51 54 #endif /* _LINUX_NFS_H */
+2
include/linux/nfs_xdr.h
··· 1112 1112 struct list_head committing; 1113 1113 struct pnfs_layout_segment *wlseg; 1114 1114 struct pnfs_layout_segment *clseg; 1115 + struct nfs_writeverf direct_verf; 1115 1116 }; 1116 1117 1117 1118 struct pnfs_ds_commit_info { ··· 1295 1294 __u64 mds_offset; /* Filelayout dense stripe */ 1296 1295 struct nfs_page_array pages; 1297 1296 struct nfs_client *ds_clp; /* pNFS data server */ 1297 + int ds_idx; /* ds index if ds_clp is set */ 1298 1298 }; 1299 1299 1300 1300 struct nfs_rw_header {