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