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 39 #define NFSDBG_FACILITY NFSDBG_PNFS_LD 40 41 static unsigned int dataserver_timeo = NFS4_DEF_DS_TIMEO; 42 static unsigned int dataserver_retrans = NFS4_DEF_DS_RETRANS; 43 44 void 45 nfs4_fl_free_deviceid(struct nfs4_file_layout_dsaddr *dsaddr) 46 { 47 struct nfs4_pnfs_ds *ds; 48 int i; 49 50 nfs4_print_deviceid(&dsaddr->id_node.deviceid); 51 52 for (i = 0; i < dsaddr->ds_num; i++) { 53 ds = dsaddr->ds_list[i]; 54 if (ds != NULL) 55 nfs4_pnfs_ds_put(ds); 56 } 57 kfree(dsaddr->stripe_indices); 58 kfree_rcu(dsaddr, id_node.rcu); 59 } 60 61 /* Decode opaque device data and return the result */ 62 struct nfs4_file_layout_dsaddr * 63 nfs4_fl_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev, 64 gfp_t gfp_flags) 65 { 66 int i; 67 u32 cnt, num; 68 u8 *indexp; 69 __be32 *p; 70 u8 *stripe_indices; 71 u8 max_stripe_index; 72 struct nfs4_file_layout_dsaddr *dsaddr = NULL; 73 struct xdr_stream stream; 74 struct xdr_buf buf; 75 struct page *scratch; 76 struct list_head dsaddrs; 77 struct nfs4_pnfs_ds_addr *da; 78 79 /* set up xdr stream */ 80 scratch = alloc_page(gfp_flags); 81 if (!scratch) 82 goto out_err; 83 84 xdr_init_decode_pages(&stream, &buf, pdev->pages, pdev->pglen); 85 xdr_set_scratch_page(&stream, scratch); 86 87 /* Get the stripe count (number of stripe index) */ 88 p = xdr_inline_decode(&stream, 4); 89 if (unlikely(!p)) 90 goto out_err_free_scratch; 91 92 cnt = be32_to_cpup(p); 93 dprintk("%s stripe count %d\n", __func__, cnt); 94 if (cnt > NFS4_PNFS_MAX_STRIPE_CNT) { 95 printk(KERN_WARNING "NFS: %s: stripe count %d greater than " 96 "supported maximum %d\n", __func__, 97 cnt, NFS4_PNFS_MAX_STRIPE_CNT); 98 goto out_err_free_scratch; 99 } 100 101 /* read stripe indices */ 102 stripe_indices = kcalloc(cnt, sizeof(u8), gfp_flags); 103 if (!stripe_indices) 104 goto out_err_free_scratch; 105 106 p = xdr_inline_decode(&stream, cnt << 2); 107 if (unlikely(!p)) 108 goto out_err_free_stripe_indices; 109 110 indexp = &stripe_indices[0]; 111 max_stripe_index = 0; 112 for (i = 0; i < cnt; i++) { 113 *indexp = be32_to_cpup(p++); 114 max_stripe_index = max(max_stripe_index, *indexp); 115 indexp++; 116 } 117 118 /* Check the multipath list count */ 119 p = xdr_inline_decode(&stream, 4); 120 if (unlikely(!p)) 121 goto out_err_free_stripe_indices; 122 123 num = be32_to_cpup(p); 124 dprintk("%s ds_num %u\n", __func__, num); 125 if (num > NFS4_PNFS_MAX_MULTI_CNT) { 126 printk(KERN_WARNING "NFS: %s: multipath count %d greater than " 127 "supported maximum %d\n", __func__, 128 num, NFS4_PNFS_MAX_MULTI_CNT); 129 goto out_err_free_stripe_indices; 130 } 131 132 /* validate stripe indices are all < num */ 133 if (max_stripe_index >= num) { 134 printk(KERN_WARNING "NFS: %s: stripe index %u >= num ds %u\n", 135 __func__, max_stripe_index, num); 136 goto out_err_free_stripe_indices; 137 } 138 139 dsaddr = kzalloc(struct_size(dsaddr, ds_list, num), gfp_flags); 140 if (!dsaddr) 141 goto out_err_free_stripe_indices; 142 143 dsaddr->stripe_count = cnt; 144 dsaddr->stripe_indices = stripe_indices; 145 stripe_indices = NULL; 146 dsaddr->ds_num = num; 147 nfs4_init_deviceid_node(&dsaddr->id_node, server, &pdev->dev_id); 148 149 INIT_LIST_HEAD(&dsaddrs); 150 151 for (i = 0; i < dsaddr->ds_num; i++) { 152 int j; 153 u32 mp_count; 154 155 p = xdr_inline_decode(&stream, 4); 156 if (unlikely(!p)) 157 goto out_err_free_deviceid; 158 159 mp_count = be32_to_cpup(p); /* multipath count */ 160 for (j = 0; j < mp_count; j++) { 161 da = nfs4_decode_mp_ds_addr(server->nfs_client->cl_net, 162 &stream, gfp_flags); 163 if (da) 164 list_add_tail(&da->da_node, &dsaddrs); 165 } 166 if (list_empty(&dsaddrs)) { 167 dprintk("%s: no suitable DS addresses found\n", 168 __func__); 169 goto out_err_free_deviceid; 170 } 171 172 dsaddr->ds_list[i] = nfs4_pnfs_ds_add(&dsaddrs, gfp_flags); 173 if (!dsaddr->ds_list[i]) 174 goto out_err_drain_dsaddrs; 175 176 /* If DS was already in cache, free ds addrs */ 177 while (!list_empty(&dsaddrs)) { 178 da = list_first_entry(&dsaddrs, 179 struct nfs4_pnfs_ds_addr, 180 da_node); 181 list_del_init(&da->da_node); 182 kfree(da->da_remotestr); 183 kfree(da); 184 } 185 } 186 187 __free_page(scratch); 188 return dsaddr; 189 190 out_err_drain_dsaddrs: 191 while (!list_empty(&dsaddrs)) { 192 da = list_first_entry(&dsaddrs, struct nfs4_pnfs_ds_addr, 193 da_node); 194 list_del_init(&da->da_node); 195 kfree(da->da_remotestr); 196 kfree(da); 197 } 198 out_err_free_deviceid: 199 nfs4_fl_free_deviceid(dsaddr); 200 /* stripe_indicies was part of dsaddr */ 201 goto out_err_free_scratch; 202 out_err_free_stripe_indices: 203 kfree(stripe_indices); 204 out_err_free_scratch: 205 __free_page(scratch); 206 out_err: 207 dprintk("%s ERROR: returning NULL\n", __func__); 208 return NULL; 209 } 210 211 void 212 nfs4_fl_put_deviceid(struct nfs4_file_layout_dsaddr *dsaddr) 213 { 214 nfs4_put_deviceid_node(&dsaddr->id_node); 215 } 216 217 /* 218 * Want res = (offset - layout->pattern_offset)/ layout->stripe_unit 219 * Then: ((res + fsi) % dsaddr->stripe_count) 220 */ 221 u32 222 nfs4_fl_calc_j_index(struct pnfs_layout_segment *lseg, loff_t offset) 223 { 224 struct nfs4_filelayout_segment *flseg = FILELAYOUT_LSEG(lseg); 225 u64 tmp; 226 227 tmp = offset - flseg->pattern_offset; 228 do_div(tmp, flseg->stripe_unit); 229 tmp += flseg->first_stripe_index; 230 return do_div(tmp, flseg->dsaddr->stripe_count); 231 } 232 233 u32 234 nfs4_fl_calc_ds_index(struct pnfs_layout_segment *lseg, u32 j) 235 { 236 return FILELAYOUT_LSEG(lseg)->dsaddr->stripe_indices[j]; 237 } 238 239 struct nfs_fh * 240 nfs4_fl_select_ds_fh(struct pnfs_layout_segment *lseg, u32 j) 241 { 242 struct nfs4_filelayout_segment *flseg = FILELAYOUT_LSEG(lseg); 243 u32 i; 244 245 if (flseg->stripe_type == STRIPE_SPARSE) { 246 if (flseg->num_fh == 1) 247 i = 0; 248 else if (flseg->num_fh == 0) 249 /* Use the MDS OPEN fh set in nfs_read_rpcsetup */ 250 return NULL; 251 else 252 i = nfs4_fl_calc_ds_index(lseg, j); 253 } else 254 i = j; 255 return flseg->fh_array[i]; 256 } 257 258 /* Upon return, either ds is connected, or ds is NULL */ 259 struct nfs4_pnfs_ds * 260 nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx) 261 { 262 struct nfs4_file_layout_dsaddr *dsaddr = FILELAYOUT_LSEG(lseg)->dsaddr; 263 struct nfs4_pnfs_ds *ds = dsaddr->ds_list[ds_idx]; 264 struct nfs4_deviceid_node *devid = FILELAYOUT_DEVID_NODE(lseg); 265 struct nfs4_pnfs_ds *ret = ds; 266 struct nfs_server *s = NFS_SERVER(lseg->pls_layout->plh_inode); 267 int status; 268 269 if (ds == NULL) { 270 printk(KERN_ERR "NFS: %s: No data server for offset index %d\n", 271 __func__, ds_idx); 272 pnfs_generic_mark_devid_invalid(devid); 273 goto out; 274 } 275 smp_rmb(); 276 if (ds->ds_clp) 277 goto out_test_devid; 278 279 status = nfs4_pnfs_ds_connect(s, ds, devid, dataserver_timeo, 280 dataserver_retrans, 4, 281 s->nfs_client->cl_minorversion); 282 if (status) { 283 nfs4_mark_deviceid_unavailable(devid); 284 ret = NULL; 285 goto out; 286 } 287 288 out_test_devid: 289 if (ret->ds_clp == NULL || 290 filelayout_test_devid_unavailable(devid)) 291 ret = NULL; 292 out: 293 return ret; 294 } 295 296 module_param(dataserver_retrans, uint, 0644); 297 MODULE_PARM_DESC(dataserver_retrans, "The number of times the NFSv4.1 client " 298 "retries a request before it attempts further " 299 " recovery action."); 300 module_param(dataserver_timeo, uint, 0644); 301 MODULE_PARM_DESC(dataserver_timeo, "The time (in tenths of a second) the " 302 "NFSv4.1 client waits for a response from a " 303 " data server before it retries an NFS request."); 304