pnfs-obj: decode layout, alloc/free lseg
[linux-2.6-block.git] / fs / nfs / objlayout / objio_osd.c
1 /*
2  *  pNFS Objects layout implementation over open-osd initiator library
3  *
4  *  Copyright (C) 2009 Panasas Inc. [year of first publication]
5  *  All rights reserved.
6  *
7  *  Benny Halevy <bhalevy@panasas.com>
8  *  Boaz Harrosh <bharrosh@panasas.com>
9  *
10  *  This program is free software; you can redistribute it and/or modify
11  *  it under the terms of the GNU General Public License version 2
12  *  See the file COPYING included with this distribution for more details.
13  *
14  *  Redistribution and use in source and binary forms, with or without
15  *  modification, are permitted provided that the following conditions
16  *  are met:
17  *
18  *  1. Redistributions of source code must retain the above copyright
19  *     notice, this list of conditions and the following disclaimer.
20  *  2. Redistributions in binary form must reproduce the above copyright
21  *     notice, this list of conditions and the following disclaimer in the
22  *     documentation and/or other materials provided with the distribution.
23  *  3. Neither the name of the Panasas company nor the names of its
24  *     contributors may be used to endorse or promote products derived
25  *     from this software without specific prior written permission.
26  *
27  *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
28  *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
29  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
30  *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31  *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
34  *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
35  *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
36  *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
37  *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38  */
39
40 #include <linux/module.h>
41 #include <scsi/osd_initiator.h>
42
43 #include "objlayout.h"
44
45 #define NFSDBG_FACILITY         NFSDBG_PNFS_LD
46
47 #define _LLU(x) ((unsigned long long)x)
48
49 struct caps_buffers {
50         u8 caps_key[OSD_CRYPTO_KEYID_SIZE];
51         u8 creds[OSD_CAP_LEN];
52 };
53
54 struct objio_segment {
55         struct pnfs_layout_segment lseg;
56
57         struct pnfs_osd_object_cred *comps;
58
59         unsigned mirrors_p1;
60         unsigned stripe_unit;
61         unsigned group_width;   /* Data stripe_units without integrity comps */
62         u64 group_depth;
63         unsigned group_count;
64
65         unsigned comps_index;
66         unsigned num_comps;
67         /* variable length */
68         struct objio_dev_ent *ods[];
69 };
70
71 static inline struct objio_segment *
72 OBJIO_LSEG(struct pnfs_layout_segment *lseg)
73 {
74         return container_of(lseg, struct objio_segment, lseg);
75 }
76
77 static int _verify_data_map(struct pnfs_osd_layout *layout)
78 {
79         struct pnfs_osd_data_map *data_map = &layout->olo_map;
80         u64 stripe_length;
81         u32 group_width;
82
83 /* FIXME: Only raid0 for now. if not go through MDS */
84         if (data_map->odm_raid_algorithm != PNFS_OSD_RAID_0) {
85                 printk(KERN_ERR "Only RAID_0 for now\n");
86                 return -ENOTSUPP;
87         }
88         if (0 != (data_map->odm_num_comps % (data_map->odm_mirror_cnt + 1))) {
89                 printk(KERN_ERR "Data Map wrong, num_comps=%u mirrors=%u\n",
90                           data_map->odm_num_comps, data_map->odm_mirror_cnt);
91                 return -EINVAL;
92         }
93
94         if (data_map->odm_group_width)
95                 group_width = data_map->odm_group_width;
96         else
97                 group_width = data_map->odm_num_comps /
98                                                 (data_map->odm_mirror_cnt + 1);
99
100         stripe_length = (u64)data_map->odm_stripe_unit * group_width;
101         if (stripe_length >= (1ULL << 32)) {
102                 printk(KERN_ERR "Total Stripe length(0x%llx)"
103                           " >= 32bit is not supported\n", _LLU(stripe_length));
104                 return -ENOTSUPP;
105         }
106
107         if (0 != (data_map->odm_stripe_unit & ~PAGE_MASK)) {
108                 printk(KERN_ERR "Stripe Unit(0x%llx)"
109                           " must be Multples of PAGE_SIZE(0x%lx)\n",
110                           _LLU(data_map->odm_stripe_unit), PAGE_SIZE);
111                 return -ENOTSUPP;
112         }
113
114         return 0;
115 }
116
117 static void copy_single_comp(struct pnfs_osd_object_cred *cur_comp,
118                              struct pnfs_osd_object_cred *src_comp,
119                              struct caps_buffers *caps_p)
120 {
121         WARN_ON(src_comp->oc_cap_key.cred_len > sizeof(caps_p->caps_key));
122         WARN_ON(src_comp->oc_cap.cred_len > sizeof(caps_p->creds));
123
124         *cur_comp = *src_comp;
125
126         memcpy(caps_p->caps_key, src_comp->oc_cap_key.cred,
127                sizeof(caps_p->caps_key));
128         cur_comp->oc_cap_key.cred = caps_p->caps_key;
129
130         memcpy(caps_p->creds, src_comp->oc_cap.cred,
131                sizeof(caps_p->creds));
132         cur_comp->oc_cap.cred = caps_p->creds;
133 }
134
135 int objio_alloc_lseg(struct pnfs_layout_segment **outp,
136         struct pnfs_layout_hdr *pnfslay,
137         struct pnfs_layout_range *range,
138         struct xdr_stream *xdr,
139         gfp_t gfp_flags)
140 {
141         struct objio_segment *objio_seg;
142         struct pnfs_osd_xdr_decode_layout_iter iter;
143         struct pnfs_osd_layout layout;
144         struct pnfs_osd_object_cred *cur_comp, src_comp;
145         struct caps_buffers *caps_p;
146         int err;
147
148         err = pnfs_osd_xdr_decode_layout_map(&layout, &iter, xdr);
149         if (unlikely(err))
150                 return err;
151
152         err = _verify_data_map(&layout);
153         if (unlikely(err))
154                 return err;
155
156         objio_seg = kzalloc(sizeof(*objio_seg) +
157                             sizeof(objio_seg->ods[0]) * layout.olo_num_comps +
158                             sizeof(*objio_seg->comps) * layout.olo_num_comps +
159                             sizeof(struct caps_buffers) * layout.olo_num_comps,
160                             gfp_flags);
161         if (!objio_seg)
162                 return -ENOMEM;
163
164         objio_seg->comps = (void *)(objio_seg->ods + layout.olo_num_comps);
165         cur_comp = objio_seg->comps;
166         caps_p = (void *)(cur_comp + layout.olo_num_comps);
167         while (pnfs_osd_xdr_decode_layout_comp(&src_comp, &iter, xdr, &err))
168                 copy_single_comp(cur_comp++, &src_comp, caps_p++);
169         if (unlikely(err))
170                 goto err;
171
172         objio_seg->num_comps = layout.olo_num_comps;
173         objio_seg->comps_index = layout.olo_comps_index;
174
175         objio_seg->mirrors_p1 = layout.olo_map.odm_mirror_cnt + 1;
176         objio_seg->stripe_unit = layout.olo_map.odm_stripe_unit;
177         if (layout.olo_map.odm_group_width) {
178                 objio_seg->group_width = layout.olo_map.odm_group_width;
179                 objio_seg->group_depth = layout.olo_map.odm_group_depth;
180                 objio_seg->group_count = layout.olo_map.odm_num_comps /
181                                                 objio_seg->mirrors_p1 /
182                                                 objio_seg->group_width;
183         } else {
184                 objio_seg->group_width = layout.olo_map.odm_num_comps /
185                                                 objio_seg->mirrors_p1;
186                 objio_seg->group_depth = -1;
187                 objio_seg->group_count = 1;
188         }
189
190         *outp = &objio_seg->lseg;
191         return 0;
192
193 err:
194         kfree(objio_seg);
195         dprintk("%s: Error: return %d\n", __func__, err);
196         *outp = NULL;
197         return err;
198 }
199
200 void objio_free_lseg(struct pnfs_layout_segment *lseg)
201 {
202         struct objio_segment *objio_seg = OBJIO_LSEG(lseg);
203
204         kfree(objio_seg);
205 }
206
207
208 static struct pnfs_layoutdriver_type objlayout_type = {
209         .id = LAYOUT_OSD2_OBJECTS,
210         .name = "LAYOUT_OSD2_OBJECTS",
211
212         .alloc_lseg              = objlayout_alloc_lseg,
213         .free_lseg               = objlayout_free_lseg,
214 };
215
216 MODULE_DESCRIPTION("pNFS Layout Driver for OSD2 objects");
217 MODULE_AUTHOR("Benny Halevy <bhalevy@panasas.com>");
218 MODULE_LICENSE("GPL");
219
220 static int __init
221 objlayout_init(void)
222 {
223         int ret = pnfs_register_layoutdriver(&objlayout_type);
224
225         if (ret)
226                 printk(KERN_INFO
227                         "%s: Registering OSD pNFS Layout Driver failed: error=%d\n",
228                         __func__, ret);
229         else
230                 printk(KERN_INFO "%s: Registered OSD pNFS Layout Driver\n",
231                         __func__);
232         return ret;
233 }
234
235 static void __exit
236 objlayout_exit(void)
237 {
238         pnfs_unregister_layoutdriver(&objlayout_type);
239         printk(KERN_INFO "%s: Unregistered OSD pNFS Layout Driver\n",
240                __func__);
241 }
242
243 module_init(objlayout_init);
244 module_exit(objlayout_exit);