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 41static unsigned int dataserver_timeo = NFS4_DEF_DS_TIMEO; 42static unsigned int dataserver_retrans = NFS4_DEF_DS_RETRANS; 43 44void 45nfs4_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 */ 62struct nfs4_file_layout_dsaddr * 63nfs4_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_buffer(&stream, page_address(scratch), PAGE_SIZE); 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(sizeof(*dsaddr) + 140 (sizeof(struct nfs4_pnfs_ds *) * (num - 1)), 141 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(server->nfs_client->cl_net, 164 &stream, gfp_flags); 165 if (da) 166 list_add_tail(&da->da_node, &dsaddrs); 167 } 168 if (list_empty(&dsaddrs)) { 169 dprintk("%s: no suitable DS addresses found\n", 170 __func__); 171 goto out_err_free_deviceid; 172 } 173 174 dsaddr->ds_list[i] = nfs4_pnfs_ds_add(&dsaddrs, gfp_flags); 175 if (!dsaddr->ds_list[i]) 176 goto out_err_drain_dsaddrs; 177 178 /* If DS was already in cache, free ds addrs */ 179 while (!list_empty(&dsaddrs)) { 180 da = list_first_entry(&dsaddrs, 181 struct nfs4_pnfs_ds_addr, 182 da_node); 183 list_del_init(&da->da_node); 184 kfree(da->da_remotestr); 185 kfree(da); 186 } 187 } 188 189 __free_page(scratch); 190 return dsaddr; 191 192out_err_drain_dsaddrs: 193 while (!list_empty(&dsaddrs)) { 194 da = list_first_entry(&dsaddrs, struct nfs4_pnfs_ds_addr, 195 da_node); 196 list_del_init(&da->da_node); 197 kfree(da->da_remotestr); 198 kfree(da); 199 } 200out_err_free_deviceid: 201 nfs4_fl_free_deviceid(dsaddr); 202 /* stripe_indicies was part of dsaddr */ 203 goto out_err_free_scratch; 204out_err_free_stripe_indices: 205 kfree(stripe_indices); 206out_err_free_scratch: 207 __free_page(scratch); 208out_err: 209 dprintk("%s ERROR: returning NULL\n", __func__); 210 return NULL; 211} 212 213void 214nfs4_fl_put_deviceid(struct nfs4_file_layout_dsaddr *dsaddr) 215{ 216 nfs4_put_deviceid_node(&dsaddr->id_node); 217} 218 219/* 220 * Want res = (offset - layout->pattern_offset)/ layout->stripe_unit 221 * Then: ((res + fsi) % dsaddr->stripe_count) 222 */ 223u32 224nfs4_fl_calc_j_index(struct pnfs_layout_segment *lseg, loff_t offset) 225{ 226 struct nfs4_filelayout_segment *flseg = FILELAYOUT_LSEG(lseg); 227 u64 tmp; 228 229 tmp = offset - flseg->pattern_offset; 230 do_div(tmp, flseg->stripe_unit); 231 tmp += flseg->first_stripe_index; 232 return do_div(tmp, flseg->dsaddr->stripe_count); 233} 234 235u32 236nfs4_fl_calc_ds_index(struct pnfs_layout_segment *lseg, u32 j) 237{ 238 return FILELAYOUT_LSEG(lseg)->dsaddr->stripe_indices[j]; 239} 240 241struct nfs_fh * 242nfs4_fl_select_ds_fh(struct pnfs_layout_segment *lseg, u32 j) 243{ 244 struct nfs4_filelayout_segment *flseg = FILELAYOUT_LSEG(lseg); 245 u32 i; 246 247 if (flseg->stripe_type == STRIPE_SPARSE) { 248 if (flseg->num_fh == 1) 249 i = 0; 250 else if (flseg->num_fh == 0) 251 /* Use the MDS OPEN fh set in nfs_read_rpcsetup */ 252 return NULL; 253 else 254 i = nfs4_fl_calc_ds_index(lseg, j); 255 } else 256 i = j; 257 return flseg->fh_array[i]; 258} 259 260/* Upon return, either ds is connected, or ds is NULL */ 261struct nfs4_pnfs_ds * 262nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx) 263{ 264 struct nfs4_file_layout_dsaddr *dsaddr = FILELAYOUT_LSEG(lseg)->dsaddr; 265 struct nfs4_pnfs_ds *ds = dsaddr->ds_list[ds_idx]; 266 struct nfs4_deviceid_node *devid = FILELAYOUT_DEVID_NODE(lseg); 267 struct nfs4_pnfs_ds *ret = ds; 268 struct nfs_server *s = NFS_SERVER(lseg->pls_layout->plh_inode); 269 270 if (ds == NULL) { 271 printk(KERN_ERR "NFS: %s: No data server for offset index %d\n", 272 __func__, ds_idx); 273 pnfs_generic_mark_devid_invalid(devid); 274 goto out; 275 } 276 smp_rmb(); 277 if (ds->ds_clp) 278 goto out_test_devid; 279 280 nfs4_pnfs_ds_connect(s, ds, devid, dataserver_timeo, 281 dataserver_retrans, 4, 282 s->nfs_client->cl_minorversion, 283 s->nfs_client->cl_rpcclient->cl_auth->au_flavor); 284 285out_test_devid: 286 if (filelayout_test_devid_unavailable(devid)) 287 ret = NULL; 288out: 289 return ret; 290} 291 292module_param(dataserver_retrans, uint, 0644); 293MODULE_PARM_DESC(dataserver_retrans, "The number of times the NFSv4.1 client " 294 "retries a request before it attempts further " 295 " recovery action."); 296module_param(dataserver_timeo, uint, 0644); 297MODULE_PARM_DESC(dataserver_timeo, "The time (in tenths of a second) the " 298 "NFSv4.1 client waits for a response from a " 299 " data server before it retries an NFS request."); 300