1 /* 2 * Device operations for the pnfs nfs4 file layout driver. 3 * 4 * Copyright (c) 2002 5 * The Regents of the University of Michigan 6 * All Rights Reserved 7 * 8 * Dean Hildebrand <dhildebz@umich.edu> 9 * Garth Goodson <Garth.Goodson@netapp.com> 10 * 11 * Permission is granted to use, copy, create derivative works, and 12 * redistribute this software and such derivative works for any purpose, 13 * so long as the name of the University of Michigan is not used in 14 * any advertising or publicity pertaining to the use or distribution 15 * of this software without specific, written prior authorization. If 16 * the above copyright notice or any other identification of the 17 * University of Michigan is included in any copy of any portion of 18 * this software, then the disclaimer below must also be included. 19 * 20 * This software is provided as is, without representation or warranty 21 * of any kind either express or implied, including without limitation 22 * the implied warranties of merchantability, fitness for a particular 23 * purpose, or noninfringement. The Regents of the University of 24 * Michigan shall not be liable for any damages, including special, 25 * indirect, incidental, or consequential damages, with respect to any 26 * claim arising out of or in connection with the use of the software, 27 * even if it has been or is hereafter advised of the possibility of 28 * such damages. 29 */ 30 31 #include <linux/nfs_fs.h> 32 #include <linux/vmalloc.h> 33 #include <linux/module.h> 34 35 #include "../internal.h" 36 #include "../nfs4session.h" 37 #include "filelayout.h" 38 #include "../nfs4trace.h" 39 40 #define NFSDBG_FACILITY NFSDBG_PNFS_LD 41 42 static unsigned int dataserver_timeo = NFS4_DEF_DS_TIMEO; 43 static unsigned int dataserver_retrans = NFS4_DEF_DS_RETRANS; 44 45 void 46 nfs4_fl_free_deviceid(struct nfs4_file_layout_dsaddr *dsaddr) 47 { 48 struct nfs4_pnfs_ds *ds; 49 int i; 50 51 nfs4_print_deviceid(&dsaddr->id_node.deviceid); 52 53 for (i = 0; i < dsaddr->ds_num; i++) { 54 ds = dsaddr->ds_list[i]; 55 if (ds != NULL) 56 nfs4_pnfs_ds_put(ds); 57 } 58 kfree(dsaddr->stripe_indices); 59 kfree_rcu(dsaddr, id_node.rcu); 60 } 61 62 /* Decode opaque device data and return the result */ 63 struct nfs4_file_layout_dsaddr * 64 nfs4_fl_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev, 65 gfp_t gfp_flags) 66 { 67 int i; 68 u32 cnt, num; 69 u8 *indexp; 70 __be32 *p; 71 u8 *stripe_indices; 72 u8 max_stripe_index; 73 struct nfs4_file_layout_dsaddr *dsaddr = NULL; 74 struct xdr_stream stream; 75 struct xdr_buf buf; 76 struct folio *scratch; 77 struct list_head dsaddrs; 78 struct nfs4_pnfs_ds_addr *da; 79 struct net *net = server->nfs_client->cl_net; 80 81 /* set up xdr stream */ 82 scratch = folio_alloc(gfp_flags, 0); 83 if (!scratch) 84 goto out_err; 85 86 xdr_init_decode_pages(&stream, &buf, pdev->pages, pdev->pglen); 87 xdr_set_scratch_folio(&stream, scratch); 88 89 /* Get the stripe count (number of stripe index) */ 90 p = xdr_inline_decode(&stream, 4); 91 if (unlikely(!p)) 92 goto out_err_free_scratch; 93 94 cnt = be32_to_cpup(p); 95 dprintk("%s stripe count %d\n", __func__, cnt); 96 if (cnt > NFS4_PNFS_MAX_STRIPE_CNT) { 97 printk(KERN_WARNING "NFS: %s: stripe count %d greater than " 98 "supported maximum %d\n", __func__, 99 cnt, NFS4_PNFS_MAX_STRIPE_CNT); 100 goto out_err_free_scratch; 101 } 102 103 /* read stripe indices */ 104 stripe_indices = kcalloc(cnt, sizeof(u8), gfp_flags); 105 if (!stripe_indices) 106 goto out_err_free_scratch; 107 108 p = xdr_inline_decode(&stream, cnt << 2); 109 if (unlikely(!p)) 110 goto out_err_free_stripe_indices; 111 112 indexp = &stripe_indices[0]; 113 max_stripe_index = 0; 114 for (i = 0; i < cnt; i++) { 115 *indexp = be32_to_cpup(p++); 116 max_stripe_index = max(max_stripe_index, *indexp); 117 indexp++; 118 } 119 120 /* Check the multipath list count */ 121 p = xdr_inline_decode(&stream, 4); 122 if (unlikely(!p)) 123 goto out_err_free_stripe_indices; 124 125 num = be32_to_cpup(p); 126 dprintk("%s ds_num %u\n", __func__, num); 127 if (num > NFS4_PNFS_MAX_MULTI_CNT) { 128 printk(KERN_WARNING "NFS: %s: multipath count %d greater than " 129 "supported maximum %d\n", __func__, 130 num, NFS4_PNFS_MAX_MULTI_CNT); 131 goto out_err_free_stripe_indices; 132 } 133 134 /* validate stripe indices are all < num */ 135 if (max_stripe_index >= num) { 136 printk(KERN_WARNING "NFS: %s: stripe index %u >= num ds %u\n", 137 __func__, max_stripe_index, num); 138 goto out_err_free_stripe_indices; 139 } 140 141 dsaddr = kzalloc_flex(*dsaddr, ds_list, num, gfp_flags); 142 if (!dsaddr) 143 goto out_err_free_stripe_indices; 144 145 dsaddr->stripe_count = cnt; 146 dsaddr->stripe_indices = stripe_indices; 147 stripe_indices = NULL; 148 dsaddr->ds_num = num; 149 nfs4_init_deviceid_node(&dsaddr->id_node, server, &pdev->dev_id); 150 151 INIT_LIST_HEAD(&dsaddrs); 152 153 for (i = 0; i < dsaddr->ds_num; i++) { 154 int j; 155 u32 mp_count; 156 157 p = xdr_inline_decode(&stream, 4); 158 if (unlikely(!p)) 159 goto out_err_free_deviceid; 160 161 mp_count = be32_to_cpup(p); /* multipath count */ 162 for (j = 0; j < mp_count; j++) { 163 da = nfs4_decode_mp_ds_addr(net, &stream, gfp_flags); 164 if (da) 165 list_add_tail(&da->da_node, &dsaddrs); 166 } 167 if (list_empty(&dsaddrs)) { 168 dprintk("%s: no suitable DS addresses found\n", 169 __func__); 170 goto out_err_free_deviceid; 171 } 172 173 dsaddr->ds_list[i] = nfs4_pnfs_ds_add(net, &dsaddrs, 4, 174 gfp_flags); 175 if (!dsaddr->ds_list[i]) 176 goto out_err_drain_dsaddrs; 177 trace_fl_getdevinfo(server, &pdev->dev_id, dsaddr->ds_list[i]->ds_remotestr); 178 179 /* If DS was already in cache, free ds addrs */ 180 while (!list_empty(&dsaddrs)) { 181 da = list_first_entry(&dsaddrs, 182 struct nfs4_pnfs_ds_addr, 183 da_node); 184 list_del_init(&da->da_node); 185 kfree(da->da_remotestr); 186 kfree(da); 187 } 188 } 189 190 folio_put(scratch); 191 return dsaddr; 192 193 out_err_drain_dsaddrs: 194 while (!list_empty(&dsaddrs)) { 195 da = list_first_entry(&dsaddrs, struct nfs4_pnfs_ds_addr, 196 da_node); 197 list_del_init(&da->da_node); 198 kfree(da->da_remotestr); 199 kfree(da); 200 } 201 out_err_free_deviceid: 202 nfs4_fl_free_deviceid(dsaddr); 203 /* stripe_indicies was part of dsaddr */ 204 goto out_err_free_scratch; 205 out_err_free_stripe_indices: 206 kfree(stripe_indices); 207 out_err_free_scratch: 208 folio_put(scratch); 209 out_err: 210 dprintk("%s ERROR: returning NULL\n", __func__); 211 return NULL; 212 } 213 214 void 215 nfs4_fl_put_deviceid(struct nfs4_file_layout_dsaddr *dsaddr) 216 { 217 nfs4_put_deviceid_node(&dsaddr->id_node); 218 } 219 220 /* 221 * Want res = (offset - layout->pattern_offset)/ layout->stripe_unit 222 * Then: ((res + fsi) % dsaddr->stripe_count) 223 */ 224 u32 225 nfs4_fl_calc_j_index(struct pnfs_layout_segment *lseg, loff_t offset) 226 { 227 struct nfs4_filelayout_segment *flseg = FILELAYOUT_LSEG(lseg); 228 u64 tmp; 229 230 tmp = offset - flseg->pattern_offset; 231 do_div(tmp, flseg->stripe_unit); 232 tmp += flseg->first_stripe_index; 233 return do_div(tmp, flseg->dsaddr->stripe_count); 234 } 235 236 u32 237 nfs4_fl_calc_ds_index(struct pnfs_layout_segment *lseg, u32 j) 238 { 239 return FILELAYOUT_LSEG(lseg)->dsaddr->stripe_indices[j]; 240 } 241 242 struct nfs_fh * 243 nfs4_fl_select_ds_fh(struct pnfs_layout_segment *lseg, u32 j) 244 { 245 struct nfs4_filelayout_segment *flseg = FILELAYOUT_LSEG(lseg); 246 u32 i; 247 248 if (flseg->stripe_type == STRIPE_SPARSE) { 249 if (flseg->num_fh == 1) 250 i = 0; 251 else if (flseg->num_fh == 0) 252 /* Use the MDS OPEN fh set in nfs_read_rpcsetup */ 253 return NULL; 254 else 255 i = nfs4_fl_calc_ds_index(lseg, j); 256 } else 257 i = j; 258 return flseg->fh_array[i]; 259 } 260 261 /* Upon return, either ds is connected, or ds is NULL */ 262 struct nfs4_pnfs_ds * 263 nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx) 264 { 265 struct nfs4_file_layout_dsaddr *dsaddr = FILELAYOUT_LSEG(lseg)->dsaddr; 266 struct nfs4_pnfs_ds *ds = dsaddr->ds_list[ds_idx]; 267 struct nfs4_deviceid_node *devid = FILELAYOUT_DEVID_NODE(lseg); 268 struct nfs4_pnfs_ds *ret = ds; 269 struct nfs_server *s = NFS_SERVER(lseg->pls_layout->plh_inode); 270 int status; 271 272 if (ds == NULL) { 273 printk(KERN_ERR "NFS: %s: No data server for offset index %d\n", 274 __func__, ds_idx); 275 pnfs_generic_mark_devid_invalid(devid); 276 goto out; 277 } 278 smp_rmb(); 279 if (ds->ds_clp) 280 goto out_test_devid; 281 282 status = nfs4_pnfs_ds_connect(s, ds, devid, dataserver_timeo, 283 dataserver_retrans, 4, 284 s->nfs_client->cl_minorversion, true); 285 if (status) { 286 nfs4_mark_deviceid_unavailable(devid); 287 ret = NULL; 288 goto out; 289 } 290 291 out_test_devid: 292 if (ret->ds_clp == NULL || 293 filelayout_test_devid_unavailable(devid)) 294 ret = NULL; 295 out: 296 return ret; 297 } 298 299 module_param(dataserver_retrans, uint, 0644); 300 MODULE_PARM_DESC(dataserver_retrans, "The number of times the NFSv4.1 client " 301 "retries a request before it attempts further " 302 " recovery action."); 303 module_param(dataserver_timeo, uint, 0644); 304 MODULE_PARM_DESC(dataserver_timeo, "The time (in tenths of a second) the " 305 "NFSv4.1 client waits for a response from a " 306 " data server before it retries an NFS request."); 307