Whamcloud - gitweb
Merge b_md into HEAD
[fs/lustre-release.git] / lustre / lov / lov_pack.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  Copyright (C) 2002, 2003 Cluster File Systems, Inc.
5  *   Author: Andreas Dilger <adilger@clusterfs.com>
6  *
7  *   This file is part of Lustre, http://www.lustre.org.
8  *
9  *   Lustre is free software; you can redistribute it and/or
10  *   modify it under the terms of version 2 of the GNU General Public
11  *   License as published by the Free Software Foundation.
12  *
13  *   Lustre is distributed in the hope that it will be useful,
14  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *   GNU General Public License for more details.
17  *
18  *   You should have received a copy of the GNU General Public License
19  *   along with Lustre; if not, write to the Free Software
20  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  *
22  * (Un)packing of OST/MDS requests
23  *
24  */
25
26 #define DEBUG_SUBSYSTEM S_LLITE
27
28 #include <linux/lustre_net.h>
29 #include <linux/obd.h>
30 #include <linux/obd_lov.h>
31 #include <linux/obd_class.h>
32 #include <linux/obd_support.h>
33
34 /* lov_packdesc() is in mds/mds_lov.c */
35 void lov_unpackdesc(struct lov_desc *ld)
36 {
37         ld->ld_tgt_count = NTOH__u32(ld->ld_tgt_count);
38         ld->ld_default_stripe_count = HTON__u32(ld->ld_default_stripe_count);
39         ld->ld_default_stripe_size = HTON__u32(ld->ld_default_stripe_size);
40         ld->ld_pattern = HTON__u32(ld->ld_pattern);
41 }
42
43 void lov_dump_lmm(int level, struct lov_mds_md *lmm)
44 {
45         struct lov_object_id *loi;
46         int idx;
47
48         CDEBUG(level, "objid "LPX64", magic %#08x, ost_count %u\n",
49                lmm->lmm_object_id, lmm->lmm_magic, lmm->lmm_ost_count);
50         CDEBUG(level,"stripe_size %u, stripe_count %u, stripe_offset %u\n",
51                lmm->lmm_stripe_size, lmm->lmm_stripe_count,
52                lmm->lmm_stripe_offset);
53         for (idx = 0, loi = lmm->lmm_objects; idx < lmm->lmm_ost_count;
54              idx++, loi++)
55                 CDEBUG(level, "ost idx %u subobj "LPX64"\n", idx,
56                        loi->l_object_id);
57 }
58
59 #define LMM_ASSERT(test)                                                \
60 do {                                                                    \
61         if (!(test)) lov_dump_lmm(D_ERROR, lmm);                        \
62         LASSERT(test); /* so we know what assertion failed */           \
63 } while(0)
64
65 /* Pack LOV object metadata for shipment to the MDS.
66  *
67  * XXX In the future, this will be enhanced to get the EA size from the
68  *     underlying OSC device(s) to get their EA sizes so we can stack
69  *     LOVs properly.  For now lov_mds_md_size() just assumes one obd_id
70  *     per stripe.
71  */
72 int lov_packmd(struct lustre_handle *conn, struct lov_mds_md **lmmp,
73                struct lov_stripe_md *lsm)
74 {
75         struct obd_device *obd = class_conn2obd(conn);
76         struct lov_obd *lov = &obd->u.lov;
77         struct lov_oinfo *loi;
78         struct lov_mds_md *lmm;
79         int ost_count = lov->desc.ld_tgt_count;
80         int stripe_count = ost_count;
81         int lmm_size;
82         int i;
83         ENTRY;
84
85         if (lsm) {
86                 int i, max = 0;
87                 if (lsm->lsm_magic != LOV_MAGIC) {
88                         CERROR("bad mem LOV MAGIC: %#010x != %#010x\n",
89                                lsm->lsm_magic, LOV_MAGIC);
90                         RETURN(-EINVAL);
91                 }
92                 stripe_count = lsm->lsm_stripe_count;
93
94                 for (i = 0,loi = lsm->lsm_oinfo; i < stripe_count; i++,loi++) {
95                         if (loi->loi_ost_idx > max)
96                                 max = loi->loi_ost_idx;
97                 }
98                 ost_count = max + 1;
99         }
100
101         /* XXX LOV STACKING call into osc for sizes */
102         lmm_size = lov_mds_md_size(ost_count);
103
104         if (!lmmp)
105                 RETURN(lmm_size);
106
107         if (*lmmp && !lsm) {
108                 /* endianness */
109                 ost_count = ((*lmmp)->lmm_ost_count);
110                 OBD_FREE(*lmmp, lov_mds_md_size(ost_count));
111                 *lmmp = NULL;
112                 RETURN(0);
113         }
114
115         if (!*lmmp) {
116                 OBD_ALLOC(*lmmp, lmm_size);
117                 if (!*lmmp)
118                         RETURN(-ENOMEM);
119         }
120
121         lmm = *lmmp;
122
123         lmm->lmm_stripe_count = (stripe_count);
124         if (!lsm)
125                 RETURN(lmm_size);
126
127         /* XXX endianness */
128         lmm->lmm_magic = (lsm->lsm_magic);
129         lmm->lmm_object_id = (lsm->lsm_object_id);
130         LASSERT(lsm->lsm_object_id);
131         lmm->lmm_stripe_size = (lsm->lsm_stripe_size);
132         lmm->lmm_stripe_offset = (lsm->lsm_stripe_offset);
133         lmm->lmm_ost_count = (ost_count);
134
135         /* Only fill in the object ids which we are actually using.
136          * Assumes lmm_objects is otherwise zero-filled. */
137         for (i = 0, loi = lsm->lsm_oinfo; i < stripe_count; i++, loi++) {
138                 /* XXX call down to osc_packmd() to do the packing */
139                 LASSERT(loi->loi_id);
140                 lmm->lmm_objects[loi->loi_ost_idx].l_object_id = (loi->loi_id);
141         }
142
143         RETURN(lmm_size);
144 }
145
146 static int lov_get_stripecnt(struct lov_obd *lov, int stripe_count)
147 {
148         if (!stripe_count)
149                 stripe_count = lov->desc.ld_default_stripe_count;
150         if (!stripe_count || stripe_count > lov->desc.ld_active_tgt_count)
151                 stripe_count = lov->desc.ld_active_tgt_count;
152
153         return stripe_count;
154 }
155
156 int lov_unpackmd(struct lustre_handle *conn, struct lov_stripe_md **lsmp,
157                  struct lov_mds_md *lmm)
158 {
159         struct obd_device *obd = class_conn2obd(conn);
160         struct lov_obd *lov = &obd->u.lov;
161         struct lov_stripe_md *lsm;
162         struct lov_oinfo *loi;
163         int ost_count;
164         int ost_offset = 0;
165         int stripe_count;
166         int lsm_size;
167         int i;
168         ENTRY;
169
170         if (lmm) {
171                 /* endianness */
172                 if (lmm->lmm_magic != LOV_MAGIC) {
173                         CERROR("bad wire LOV MAGIC: %#08x != %#08x\n",
174                                lmm->lmm_magic, LOV_MAGIC);
175                         RETURN(-EINVAL);
176                 }
177                 stripe_count = (lmm->lmm_stripe_count);
178                 LASSERT(stripe_count);
179         } else
180                 stripe_count = lov_get_stripecnt(lov, 0);
181
182         /* XXX LOV STACKING call into osc for sizes */
183         lsm_size = lov_stripe_md_size(stripe_count);
184
185         if (!lsmp)
186                 RETURN(lsm_size);
187
188         if (*lsmp && !lmm) {
189                 stripe_count = (*lsmp)->lsm_stripe_count;
190                 OBD_FREE(*lsmp, lov_stripe_md_size(stripe_count));
191                 *lsmp = NULL;
192                 RETURN(0);
193         }
194
195         if (!*lsmp) {
196                 OBD_ALLOC(*lsmp, lsm_size);
197                 if (!*lsmp)
198                         RETURN(-ENOMEM);
199         }
200
201         lsm = *lsmp;
202
203         lsm->lsm_stripe_count = stripe_count;
204         if (!lmm)
205                 RETURN(lsm_size);
206
207         /* XXX endianness */
208         ost_offset = lsm->lsm_stripe_offset = (lmm->lmm_stripe_offset);
209         lsm->lsm_magic = (lmm->lmm_magic);
210         lsm->lsm_object_id = (lmm->lmm_object_id);
211         lsm->lsm_stripe_size = (lmm->lmm_stripe_size);
212
213         ost_count = (lmm->lmm_ost_count);
214
215         LMM_ASSERT(lsm->lsm_object_id);
216         LMM_ASSERT(ost_count);
217
218         for (i = 0, loi = lsm->lsm_oinfo; i < ost_count; i++, ost_offset++) {
219                 ost_offset %= ost_count;
220
221                 if (!lmm->lmm_objects[ost_offset].l_object_id)
222                         continue;
223
224                 LMM_ASSERT(loi - lsm->lsm_oinfo < stripe_count);
225                 /* XXX LOV STACKING call down to osc_unpackmd() */
226                 loi->loi_id = (lmm->lmm_objects[ost_offset].l_object_id);
227                 loi->loi_ost_idx = ost_offset;
228                 loi++;
229         }
230         LMM_ASSERT(loi - lsm->lsm_oinfo > 0);
231         LMM_ASSERT(loi - lsm->lsm_oinfo == stripe_count);
232
233         RETURN(lsm_size);
234 }
235
236 /* Configure object striping information on a new file.
237  *
238  * @lmmu is a pointer to a user struct with one or more of the fields set to
239  * indicate the application preference: lmm_stripe_count, lmm_stripe_size,
240  * lmm_stripe_offset, and lmm_stripe_pattern.  lmm_magic must be LOV_MAGIC.
241  * @lsmp is a pointer to an in-core stripe MD that needs to be filled in.
242  */
243 int lov_setstripe(struct lustre_handle *conn, struct lov_stripe_md **lsmp,
244                   struct lov_mds_md *lmmu)
245 {
246         struct obd_device *obd = class_conn2obd(conn);
247         struct lov_obd *lov = &obd->u.lov;
248         struct lov_mds_md lmm;
249         struct lov_stripe_md *lsm;
250         int stripe_count;
251         int rc;
252         ENTRY;
253
254         rc = copy_from_user(&lmm, lmmu, sizeof(lmm));
255         if (rc)
256                 RETURN(-EFAULT);
257
258         if (lmm.lmm_magic != LOV_MAGIC) {
259                 CERROR("bad wire LOV MAGIC: %#08x != %#08x\n",
260                        lmm.lmm_magic, LOV_MAGIC);
261                 RETURN(-EINVAL);
262         }
263         if (lmm.lmm_stripe_count > lov->desc.ld_tgt_count) {
264                 CERROR("stripe count %u more than OST count %d\n",
265                        lmm.lmm_stripe_count, lov->desc.ld_tgt_count);
266                 RETURN(-EINVAL);
267         }
268         if (lmm.lmm_stripe_offset >= lov->desc.ld_tgt_count &&
269             lmm.lmm_stripe_offset != 0xffffffff) {
270                 CERROR("stripe offset %u more than max OST index %d\n",
271                        lmm.lmm_stripe_offset, lov->desc.ld_tgt_count);
272                 RETURN(-EINVAL);
273         }
274         if (lmm.lmm_stripe_size & (PAGE_SIZE - 1)) {
275                 CERROR("stripe size %u not multiple of %lu\n",
276                        lmm.lmm_stripe_size, PAGE_SIZE);
277                 RETURN(-EINVAL);
278         }
279         if ((__u64)lmm.lmm_stripe_size * lmm.lmm_stripe_count > ~0UL) {
280                 CERROR("stripe width %ux%u > %lu on 32-bit system\n",
281                        lmm.lmm_stripe_size, (int)lmm.lmm_stripe_count, ~0UL);
282                 RETURN(-EINVAL);
283         }
284
285         stripe_count = lov_get_stripecnt(lov, lmm.lmm_stripe_count);
286
287         /* XXX LOV STACKING call into osc for sizes */
288         OBD_ALLOC(lsm, lov_stripe_md_size(stripe_count));
289         if (!lsm)
290                 RETURN(-ENOMEM);
291
292         lsm->lsm_magic = LOV_MAGIC;
293         lsm->lsm_stripe_count = stripe_count;
294         lsm->lsm_stripe_offset = lmm.lmm_stripe_offset;
295         lsm->lsm_stripe_size = lmm.lmm_stripe_size;
296
297         *lsmp = lsm;
298
299         RETURN(rc);
300 }
301
302 /* Retrieve object striping information.
303  *
304  * @lmmu is a pointer to an in-core struct with lmm_ost_count indicating
305  * the maximum number of OST indices which will fit in the user buffer.
306  * lmm_magic must be LOV_MAGIC.
307  */
308 int lov_getstripe(struct lustre_handle *conn, struct lov_stripe_md *lsm,
309                   struct lov_mds_md *lmmu)
310 {
311         struct obd_device *obd = class_conn2obd(conn);
312         struct lov_obd *lov = &obd->u.lov;
313         struct lov_mds_md lmm, *lmmk = NULL;
314         int ost_count, rc, lmm_size;
315         ENTRY;
316
317         if (!lsm)
318                 RETURN(-ENODATA);
319
320         rc = copy_from_user(&lmm, lmmu, sizeof(lmm));
321         if (rc)
322                 RETURN(-EFAULT);
323
324         if (lmm.lmm_magic != LOV_MAGIC)
325                 RETURN(-EINVAL);
326
327         ost_count = lov->desc.ld_tgt_count;
328
329         /* XXX we _could_ check if indices > user lmm_ost_count are zero */
330         if (lmm.lmm_ost_count < ost_count)
331                 RETURN(-EOVERFLOW);
332
333         rc = lov_packmd(conn, &lmmk, lsm);
334         if (rc < 0)
335                 RETURN(rc);
336
337         lmm_size = rc;
338         rc = 0;
339
340         if (lmm_size && copy_to_user(lmmu, lmmk, lmm_size))
341                 rc = -EFAULT;
342
343         obd_free_wiremd(conn, &lmmk);
344
345         RETURN(rc);
346 }