]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - fs/nfs/nfs4filelayout.c
NFSv4.1: filelayout i/o helpers
[mirror_ubuntu-artful-kernel.git] / fs / nfs / nfs4filelayout.c
CommitLineData
7ab672ce
DH
1/*
2 * Module for the pnfs nfs4 file layout driver.
3 * Defines all I/O and Policy interface operations, plus code
4 * to register itself with the pNFS client.
5 *
6 * Copyright (c) 2002
7 * The Regents of the University of Michigan
8 * All Rights Reserved
9 *
10 * Dean Hildebrand <dhildebz@umich.edu>
11 *
12 * Permission is granted to use, copy, create derivative works, and
13 * redistribute this software and such derivative works for any purpose,
14 * so long as the name of the University of Michigan is not used in
15 * any advertising or publicity pertaining to the use or distribution
16 * of this software without specific, written prior authorization. If
17 * the above copyright notice or any other identification of the
18 * University of Michigan is included in any copy of any portion of
19 * this software, then the disclaimer below must also be included.
20 *
21 * This software is provided as is, without representation or warranty
22 * of any kind either express or implied, including without limitation
23 * the implied warranties of merchantability, fitness for a particular
24 * purpose, or noninfringement. The Regents of the University of
25 * Michigan shall not be liable for any damages, including special,
26 * indirect, incidental, or consequential damages, with respect to any
27 * claim arising out of or in connection with the use of the software,
28 * even if it has been or is hereafter advised of the possibility of
29 * such damages.
30 */
31
32#include <linux/nfs_fs.h>
16b374ca
AA
33
34#include "internal.h"
35#include "nfs4filelayout.h"
7ab672ce
DH
36
37#define NFSDBG_FACILITY NFSDBG_PNFS_LD
38
39MODULE_LICENSE("GPL");
40MODULE_AUTHOR("Dean Hildebrand <dhildebz@umich.edu>");
41MODULE_DESCRIPTION("The NFSv4 file layout driver");
42
1c787096
TM
43static int
44filelayout_set_layoutdriver(struct nfs_server *nfss)
7ab672ce 45{
16b374ca
AA
46 int status = pnfs_alloc_init_deviceid_cache(nfss->nfs_client,
47 nfs4_fl_free_deviceid_callback);
48 if (status) {
49 printk(KERN_WARNING "%s: deviceid cache could not be "
50 "initialized\n", __func__);
51 return status;
52 }
53 dprintk("%s: deviceid cache has been initialized successfully\n",
54 __func__);
7ab672ce
DH
55 return 0;
56}
57
1c787096
TM
58/* Clear out the layout by destroying its device list */
59static int
60filelayout_clear_layoutdriver(struct nfs_server *nfss)
7ab672ce
DH
61{
62 dprintk("--> %s\n", __func__);
63
16b374ca
AA
64 if (nfss->nfs_client->cl_devid_cache)
65 pnfs_put_deviceid_cache(nfss->nfs_client);
7ab672ce
DH
66 return 0;
67}
68
cfe7f412
FI
69static loff_t
70filelayout_get_dense_offset(struct nfs4_filelayout_segment *flseg,
71 loff_t offset)
72{
73 u32 stripe_width = flseg->stripe_unit * flseg->dsaddr->stripe_count;
74 u64 tmp;
75
76 offset -= flseg->pattern_offset;
77 tmp = offset;
78 do_div(tmp, stripe_width);
79
80 return tmp * flseg->stripe_unit + do_div(offset, flseg->stripe_unit);
81}
82
83/* This function is used by the layout driver to calculate the
84 * offset of the file on the dserver based on whether the
85 * layout type is STRIPE_DENSE or STRIPE_SPARSE
86 */
87static loff_t
88filelayout_get_dserver_offset(struct pnfs_layout_segment *lseg, loff_t offset)
89{
90 struct nfs4_filelayout_segment *flseg = FILELAYOUT_LSEG(lseg);
91
92 switch (flseg->stripe_type) {
93 case STRIPE_SPARSE:
94 return offset;
95
96 case STRIPE_DENSE:
97 return filelayout_get_dense_offset(flseg, offset);
98 }
99
100 BUG();
101}
102
16b374ca
AA
103/*
104 * filelayout_check_layout()
105 *
106 * Make sure layout segment parameters are sane WRT the device.
107 * At this point no generic layer initialization of the lseg has occurred,
108 * and nothing has been added to the layout_hdr cache.
109 *
110 */
111static int
112filelayout_check_layout(struct pnfs_layout_hdr *lo,
113 struct nfs4_filelayout_segment *fl,
114 struct nfs4_layoutget_res *lgr,
115 struct nfs4_deviceid *id)
116{
117 struct nfs4_file_layout_dsaddr *dsaddr;
118 int status = -EINVAL;
b7edfaa1 119 struct nfs_server *nfss = NFS_SERVER(lo->plh_inode);
16b374ca
AA
120
121 dprintk("--> %s\n", __func__);
122
123 if (fl->pattern_offset > lgr->range.offset) {
124 dprintk("%s pattern_offset %lld to large\n",
125 __func__, fl->pattern_offset);
126 goto out;
127 }
128
129 if (fl->stripe_unit % PAGE_SIZE) {
130 dprintk("%s Stripe unit (%u) not page aligned\n",
131 __func__, fl->stripe_unit);
132 goto out;
133 }
134
135 /* find and reference the deviceid */
136 dsaddr = nfs4_fl_find_get_deviceid(nfss->nfs_client, id);
137 if (dsaddr == NULL) {
b7edfaa1 138 dsaddr = get_device_info(lo->plh_inode, id);
16b374ca
AA
139 if (dsaddr == NULL)
140 goto out;
141 }
142 fl->dsaddr = dsaddr;
143
144 if (fl->first_stripe_index < 0 ||
145 fl->first_stripe_index >= dsaddr->stripe_count) {
146 dprintk("%s Bad first_stripe_index %d\n",
147 __func__, fl->first_stripe_index);
148 goto out_put;
149 }
150
151 if ((fl->stripe_type == STRIPE_SPARSE &&
152 fl->num_fh > 1 && fl->num_fh != dsaddr->ds_num) ||
153 (fl->stripe_type == STRIPE_DENSE &&
154 fl->num_fh != dsaddr->stripe_count)) {
155 dprintk("%s num_fh %u not valid for given packing\n",
156 __func__, fl->num_fh);
157 goto out_put;
158 }
159
160 if (fl->stripe_unit % nfss->rsize || fl->stripe_unit % nfss->wsize) {
161 dprintk("%s Stripe unit (%u) not aligned with rsize %u "
162 "wsize %u\n", __func__, fl->stripe_unit, nfss->rsize,
163 nfss->wsize);
164 }
165
166 status = 0;
167out:
168 dprintk("--> %s returns %d\n", __func__, status);
169 return status;
170out_put:
171 pnfs_put_deviceid(nfss->nfs_client->cl_devid_cache, &dsaddr->deviceid);
172 goto out;
173}
174
175static void filelayout_free_fh_array(struct nfs4_filelayout_segment *fl)
176{
177 int i;
178
179 for (i = 0; i < fl->num_fh; i++) {
180 if (!fl->fh_array[i])
181 break;
182 kfree(fl->fh_array[i]);
183 }
184 kfree(fl->fh_array);
185 fl->fh_array = NULL;
186}
187
188static void
189_filelayout_free_lseg(struct nfs4_filelayout_segment *fl)
190{
191 filelayout_free_fh_array(fl);
192 kfree(fl);
193}
194
195static int
196filelayout_decode_layout(struct pnfs_layout_hdr *flo,
197 struct nfs4_filelayout_segment *fl,
198 struct nfs4_layoutget_res *lgr,
199 struct nfs4_deviceid *id)
200{
201 uint32_t *p = (uint32_t *)lgr->layout.buf;
202 uint32_t nfl_util;
203 int i;
204
205 dprintk("%s: set_layout_map Begin\n", __func__);
206
207 memcpy(id, p, sizeof(*id));
208 p += XDR_QUADLEN(NFS4_DEVICEID4_SIZE);
209 print_deviceid(id);
210
211 nfl_util = be32_to_cpup(p++);
212 if (nfl_util & NFL4_UFLG_COMMIT_THRU_MDS)
213 fl->commit_through_mds = 1;
214 if (nfl_util & NFL4_UFLG_DENSE)
215 fl->stripe_type = STRIPE_DENSE;
216 else
217 fl->stripe_type = STRIPE_SPARSE;
218 fl->stripe_unit = nfl_util & ~NFL4_UFLG_MASK;
219
220 fl->first_stripe_index = be32_to_cpup(p++);
221 p = xdr_decode_hyper(p, &fl->pattern_offset);
222 fl->num_fh = be32_to_cpup(p++);
223
224 dprintk("%s: nfl_util 0x%X num_fh %u fsi %u po %llu\n",
225 __func__, nfl_util, fl->num_fh, fl->first_stripe_index,
226 fl->pattern_offset);
227
228 fl->fh_array = kzalloc(fl->num_fh * sizeof(struct nfs_fh *),
229 GFP_KERNEL);
230 if (!fl->fh_array)
231 return -ENOMEM;
232
233 for (i = 0; i < fl->num_fh; i++) {
234 /* Do we want to use a mempool here? */
235 fl->fh_array[i] = kmalloc(sizeof(struct nfs_fh), GFP_KERNEL);
236 if (!fl->fh_array[i]) {
237 filelayout_free_fh_array(fl);
238 return -ENOMEM;
239 }
240 fl->fh_array[i]->size = be32_to_cpup(p++);
241 if (sizeof(struct nfs_fh) < fl->fh_array[i]->size) {
242 printk(KERN_ERR "Too big fh %d received %d\n",
243 i, fl->fh_array[i]->size);
244 filelayout_free_fh_array(fl);
245 return -EIO;
246 }
247 memcpy(fl->fh_array[i]->data, p, fl->fh_array[i]->size);
248 p += XDR_QUADLEN(fl->fh_array[i]->size);
249 dprintk("DEBUG: %s: fh len %d\n", __func__,
250 fl->fh_array[i]->size);
251 }
252
253 return 0;
254}
255
256static struct pnfs_layout_segment *
257filelayout_alloc_lseg(struct pnfs_layout_hdr *layoutid,
258 struct nfs4_layoutget_res *lgr)
259{
260 struct nfs4_filelayout_segment *fl;
261 int rc;
262 struct nfs4_deviceid id;
263
264 dprintk("--> %s\n", __func__);
265 fl = kzalloc(sizeof(*fl), GFP_KERNEL);
266 if (!fl)
267 return NULL;
268
269 rc = filelayout_decode_layout(layoutid, fl, lgr, &id);
270 if (rc != 0 || filelayout_check_layout(layoutid, fl, lgr, &id)) {
271 _filelayout_free_lseg(fl);
272 return NULL;
273 }
274 return &fl->generic_hdr;
275}
276
277static void
278filelayout_free_lseg(struct pnfs_layout_segment *lseg)
279{
b7edfaa1 280 struct nfs_server *nfss = NFS_SERVER(lseg->pls_layout->plh_inode);
16b374ca
AA
281 struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg);
282
283 dprintk("--> %s\n", __func__);
284 pnfs_put_deviceid(nfss->nfs_client->cl_devid_cache,
285 &fl->dsaddr->deviceid);
286 _filelayout_free_lseg(fl);
287}
288
94ad1c80
FI
289/*
290 * filelayout_pg_test(). Called by nfs_can_coalesce_requests()
291 *
292 * return 1 : coalesce page
293 * return 0 : don't coalesce page
294 */
295int
296filelayout_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev,
297 struct nfs_page *req)
298{
299 u64 p_stripe, r_stripe;
300 u32 stripe_unit;
301
302 if (!pgio->pg_lseg)
303 return 1;
304 p_stripe = (u64)prev->wb_index << PAGE_CACHE_SHIFT;
305 r_stripe = (u64)req->wb_index << PAGE_CACHE_SHIFT;
306 stripe_unit = FILELAYOUT_LSEG(pgio->pg_lseg)->stripe_unit;
307
308 do_div(p_stripe, stripe_unit);
309 do_div(r_stripe, stripe_unit);
310
311 return (p_stripe == r_stripe);
312}
313
7ab672ce
DH
314static struct pnfs_layoutdriver_type filelayout_type = {
315 .id = LAYOUT_NFSV4_1_FILES,
316 .name = "LAYOUT_NFSV4_1_FILES",
317 .owner = THIS_MODULE,
1c787096
TM
318 .set_layoutdriver = filelayout_set_layoutdriver,
319 .clear_layoutdriver = filelayout_clear_layoutdriver,
16b374ca
AA
320 .alloc_lseg = filelayout_alloc_lseg,
321 .free_lseg = filelayout_free_lseg,
94ad1c80 322 .pg_test = filelayout_pg_test,
7ab672ce
DH
323};
324
325static int __init nfs4filelayout_init(void)
326{
327 printk(KERN_INFO "%s: NFSv4 File Layout Driver Registering...\n",
328 __func__);
329 return pnfs_register_layoutdriver(&filelayout_type);
330}
331
332static void __exit nfs4filelayout_exit(void)
333{
334 printk(KERN_INFO "%s: NFSv4 File Layout Driver Unregistering...\n",
335 __func__);
336 pnfs_unregister_layoutdriver(&filelayout_type);
337}
338
339module_init(nfs4filelayout_init);
340module_exit(nfs4filelayout_exit);