Whamcloud - gitweb
LU-1406 ofd: OFD to setup device stack on OSD
[fs/lustre-release.git] / lustre / osd-ldiskfs / osd_compat.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21  * CA 95054 USA or visit www.sun.com if you need additional information or
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  *
30  * Copyright (c) 2011, 2012, Whamcloud, Inc.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  *
36  * lustre/osd/osd_compat.c
37  *
38  * on-disk compatibility stuff for OST
39  *
40  * Author: Alex Zhuravlev <bzzz@whamcloud.com>
41  */
42
43 /* LUSTRE_VERSION_CODE */
44 #include <lustre_ver.h>
45 /* prerequisite for linux/xattr.h */
46 #include <linux/types.h>
47 /* prerequisite for linux/xattr.h */
48 #include <linux/fs.h>
49
50 /*
51  * struct OBD_{ALLOC,FREE}*()
52  * OBD_FAIL_CHECK
53  */
54 #include <obd_support.h>
55 #include <lvfs.h>
56
57 #include "osd_internal.h"
58
59 struct osd_compat_objid_seq {
60         /* protects on-fly initialization */
61         cfs_semaphore_t        dir_init_sem;
62         /* file storing last created objid */
63         struct osd_inode_id    last_id;
64         struct dentry         *groot; /* O/<seq> */
65         struct dentry        **dirs;  /* O/<seq>/d0-dXX */
66 };
67
68 #define MAX_OBJID_GROUP (FID_SEQ_ECHO + 1)
69
70 struct osd_compat_objid {
71         int                          subdir_count;
72         struct dentry               *root;
73         struct osd_inode_id          last_rcvd_id;
74         struct osd_inode_id          last_seq_id;
75         struct osd_compat_objid_seq  groups[MAX_OBJID_GROUP];
76 };
77
78 static void osd_push_ctxt(const struct osd_device *dev,
79                           struct lvfs_run_ctxt *newctxt,
80                           struct lvfs_run_ctxt *save)
81 {
82         OBD_SET_CTXT_MAGIC(newctxt);
83         newctxt->pwdmnt = dev->od_mnt;
84         newctxt->pwd = dev->od_mnt->mnt_root;
85         newctxt->fs = get_ds();
86
87         push_ctxt(save, newctxt, NULL);
88 }
89
90 void osd_compat_seq_fini(struct osd_device *osd, int seq)
91 {
92         struct osd_compat_objid_seq *grp;
93         struct osd_compat_objid     *map = osd->od_ost_map;
94         int                          i;
95
96         ENTRY;
97
98         grp = &map->groups[seq];
99         if (grp->groot ==NULL)
100                 RETURN_EXIT;
101         LASSERT(grp->dirs);
102
103         for (i = 0; i < map->subdir_count; i++) {
104                 if (grp->dirs[i] == NULL)
105                         break;
106                 dput(grp->dirs[i]);
107         }
108
109         OBD_FREE(grp->dirs, sizeof(struct dentry *) * map->subdir_count);
110         dput(grp->groot);
111         EXIT;
112 }
113
114 int osd_compat_seq_init(struct osd_device *osd, int seq)
115 {
116         struct osd_compat_objid_seq *grp;
117         struct osd_compat_objid     *map;
118         struct dentry               *d;
119         int                          rc = 0;
120         char                         name[32];
121         int                          i;
122         ENTRY;
123
124         map = osd->od_ost_map;
125         LASSERT(map);
126         LASSERT(map->root);
127         grp = &map->groups[seq];
128
129         if (grp->groot != NULL)
130                 RETURN(0);
131
132         cfs_down(&grp->dir_init_sem);
133
134         sprintf(name, "%d", seq);
135         d = simple_mkdir(map->root, osd->od_mnt, name, 0755, 1);
136         if (IS_ERR(d)) {
137                 rc = PTR_ERR(d);
138                 GOTO(out, rc);
139         } else if (d->d_inode == NULL) {
140                 rc = -EFAULT;
141                 dput(d);
142                 GOTO(out, rc);
143         }
144
145         LASSERT(grp->dirs == NULL);
146         OBD_ALLOC(grp->dirs, sizeof(d) * map->subdir_count);
147         if (grp->dirs == NULL) {
148                 dput(d);
149                 GOTO(out, rc = -ENOMEM);
150         }
151
152         grp->groot = d;
153         for (i = 0; i < map->subdir_count; i++) {
154                 sprintf(name, "d%d", i);
155                 d = simple_mkdir(grp->groot, osd->od_mnt, name, 0755, 1);
156                 if (IS_ERR(d)) {
157                         rc = PTR_ERR(d);
158                         break;
159                 } else if (d->d_inode == NULL) {
160                         rc = -EFAULT;
161                         dput(d);
162                         break;
163                 }
164
165                 grp->dirs[i] = d;
166         }
167
168         if (rc)
169                 osd_compat_seq_fini(osd, seq);
170 out:
171         cfs_up(&grp->dir_init_sem);
172         RETURN(rc);
173 }
174
175 int osd_last_rcvd_subdir_count(struct osd_device *osd)
176 {
177         struct lr_server_data lsd;
178         struct dentry        *dlast;
179         loff_t                off;
180         int                   rc = 0;
181         int                   count = FILTER_SUBDIR_COUNT;
182
183         ENTRY;
184
185         dlast = ll_lookup_one_len(LAST_RCVD, osd_sb(osd)->s_root,
186                                   strlen(LAST_RCVD));
187         if (IS_ERR(dlast))
188                 return PTR_ERR(dlast);
189         else if (dlast->d_inode == NULL)
190                 goto out;
191
192         off = 0;
193         rc = osd_ldiskfs_read(dlast->d_inode, &lsd, sizeof(lsd), &off);
194         if (rc == sizeof(lsd)) {
195                 CDEBUG(D_INFO, "read last_rcvd header, uuid = %s, "
196                        "subdir count = %d\n", lsd.lsd_uuid,
197                        lsd.lsd_subdir_count);
198                 if (le16_to_cpu(lsd.lsd_subdir_count) > 0)
199                         count = le16_to_cpu(lsd.lsd_subdir_count);
200         } else if (rc != 0) {
201                 CERROR("Can't read last_rcvd file, rc = %d\n", rc);
202                 if (rc > 0)
203                         rc = -EFAULT;
204                 dput(dlast);
205                 return rc;
206         } else {
207                 count = FILTER_SUBDIR_COUNT;
208         }
209 out:
210         dput(dlast);
211         LASSERT(count > 0);
212         return rc;
213 }
214
215 void osd_compat_fini(struct osd_device *dev)
216 {
217         int i;
218
219         ENTRY;
220
221         if (dev->od_ost_map == NULL)
222                 RETURN_EXIT;
223
224         for (i = 0; i < MAX_OBJID_GROUP; i++)
225                 osd_compat_seq_fini(dev, i);
226
227         dput(dev->od_ost_map->root);
228         OBD_FREE_PTR(dev->od_ost_map);
229         dev->od_ost_map = NULL;
230
231         EXIT;
232 }
233
234 /*
235  * directory structure on legacy OST:
236  *
237  * O/<seq>/d0-31/<objid>
238  * O/<seq>/LAST_ID
239  * last_rcvd
240  * LAST_GROUP
241  * CONFIGS
242  *
243  */
244 int osd_compat_init(struct osd_device *dev)
245 {
246         struct lvfs_run_ctxt  new;
247         struct lvfs_run_ctxt  save;
248         struct dentry        *rootd = osd_sb(dev)->s_root;
249         struct dentry        *d;
250         int                   rc;
251         int                   i;
252
253         ENTRY;
254
255         OBD_ALLOC_PTR(dev->od_ost_map);
256         if (dev->od_ost_map == NULL)
257                 RETURN(-ENOMEM);
258
259         /* to get subdir count from last_rcvd */
260         rc = osd_last_rcvd_subdir_count(dev);
261         if (rc < 0) {
262                 OBD_FREE_PTR(dev->od_ost_map);
263                 RETURN(rc);
264         }
265
266         dev->od_ost_map->subdir_count = rc;
267         rc = 0;
268
269         LASSERT(dev->od_fsops);
270         osd_push_ctxt(dev, &new, &save);
271
272         d = simple_mkdir(rootd, dev->od_mnt, "O", 0755, 1);
273         pop_ctxt(&save, &new, NULL);
274         if (IS_ERR(d)) {
275                 OBD_FREE_PTR(dev->od_ost_map);
276                 RETURN(PTR_ERR(d));
277         }
278
279         dev->od_ost_map->root = d;
280
281         /* Initialize all groups */
282         for (i = 0; i < MAX_OBJID_GROUP; i++) {
283                 cfs_sema_init(&dev->od_ost_map->groups[i].dir_init_sem, 1);
284                 rc = osd_compat_seq_init(dev, i);
285                 if (rc) {
286                         osd_compat_fini(dev);
287                         break;
288                 }
289         }
290
291         RETURN(rc);
292 }
293
294 int osd_compat_del_entry(struct osd_thread_info *info, struct osd_device *osd,
295                          struct dentry *dird, char *name, struct thandle *th)
296 {
297         struct ldiskfs_dir_entry_2 *de;
298         struct buffer_head         *bh;
299         struct osd_thandle         *oh;
300         struct dentry              *child;
301         struct inode               *dir = dird->d_inode;
302         int                         rc;
303
304         ENTRY;
305
306         oh = container_of(th, struct osd_thandle, ot_super);
307         LASSERT(oh->ot_handle != NULL);
308         LASSERT(oh->ot_handle->h_transaction != NULL);
309
310
311         child = &info->oti_child_dentry;
312         child->d_name.hash = 0;
313         child->d_name.name = name;
314         child->d_name.len = strlen(name);
315         child->d_parent = dird;
316         child->d_inode = NULL;
317
318         LOCK_INODE_MUTEX(dir);
319         rc = -ENOENT;
320         bh = osd_ldiskfs_find_entry(dir, child, &de, NULL);
321         if (bh) {
322                 rc = ldiskfs_delete_entry(oh->ot_handle, dir, de, bh);
323                 brelse(bh);
324         }
325         UNLOCK_INODE_MUTEX(dir);
326
327         RETURN(rc);
328 }
329
330 int osd_compat_add_entry(struct osd_thread_info *info, struct osd_device *osd,
331                          struct dentry *dir, char *name,
332                          const struct osd_inode_id *id, struct thandle *th)
333 {
334         struct osd_thandle *oh;
335         struct dentry *child;
336         struct inode *inode;
337         int rc;
338
339         ENTRY;
340
341         oh = container_of(th, struct osd_thandle, ot_super);
342         LASSERT(oh->ot_handle != NULL);
343         LASSERT(oh->ot_handle->h_transaction != NULL);
344
345         inode = &info->oti_inode;
346         inode->i_sb = osd_sb(osd);
347         inode->i_ino = id->oii_ino;
348         inode->i_generation = id->oii_gen;
349
350         child = &info->oti_child_dentry;
351         child->d_name.hash = 0;
352         child->d_name.name = name;
353         child->d_name.len = strlen(name);
354         child->d_parent = dir;
355         child->d_inode = inode;
356
357         LOCK_INODE_MUTEX(dir->d_inode);
358         rc = osd_ldiskfs_add_entry(oh->ot_handle, child, inode, NULL);
359         UNLOCK_INODE_MUTEX(dir->d_inode);
360
361         RETURN(rc);
362 }
363
364 int osd_compat_objid_lookup(struct osd_thread_info *info,
365                             struct osd_device *dev, const struct lu_fid *fid,
366                             struct osd_inode_id *id)
367 {
368         struct osd_compat_objid    *map;
369         struct dentry              *d;
370         struct dentry              *d_seq;
371         struct ost_id              *ostid = &info->oti_ostid;
372         int                         rc = 0;
373         int                         dirn;
374         char                        name[32];
375         struct ldiskfs_dir_entry_2 *de;
376         struct buffer_head         *bh;
377         struct inode               *dir;
378         ENTRY;
379
380         /* on the very first lookup we find and open directories */
381
382         map = dev->od_ost_map;
383         LASSERT(map);
384         LASSERT(map->root);
385
386         fid_ostid_pack(fid, ostid);
387         LASSERT(ostid->oi_seq < MAX_OBJID_GROUP);
388         LASSERT(map->subdir_count > 0);
389         LASSERT(map->groups[ostid->oi_seq].groot);
390
391         dirn = ostid->oi_id & (map->subdir_count - 1);
392         d = map->groups[ostid->oi_seq].dirs[dirn];
393         LASSERT(d);
394
395         sprintf(name, "%llu", ostid->oi_id);
396         d_seq = &info->oti_child_dentry;
397         d_seq->d_parent = d;
398         d_seq->d_name.hash = 0;
399         d_seq->d_name.name = name;
400         /* XXX: we can use rc from sprintf() instead of strlen() */
401         d_seq->d_name.len = strlen(name);
402
403         dir = d->d_inode;
404         LOCK_INODE_MUTEX(dir);
405         bh = osd_ldiskfs_find_entry(dir, d_seq, &de, NULL);
406         UNLOCK_INODE_MUTEX(dir);
407
408         rc = -ENOENT;
409         if (bh) {
410                 struct inode *inode;
411
412                 id->oii_ino = le32_to_cpu(de->inode);
413                 brelse(bh);
414
415                 id->oii_gen = OSD_OII_NOGEN;
416                 inode = osd_iget(info, dev, id);
417
418                 if (IS_ERR(inode))
419                         GOTO(cleanup, rc = PTR_ERR(inode));
420                 rc = 0;
421                 id->oii_gen = inode->i_generation;
422                 iput(inode);
423         }
424
425 cleanup:
426         RETURN(rc);
427 }
428
429 int osd_compat_objid_insert(struct osd_thread_info *info,
430                             struct osd_device *osd,
431                             const struct lu_fid *fid,
432                             const struct osd_inode_id *id,
433                             struct thandle *th)
434 {
435         struct osd_compat_objid *map;
436         struct dentry           *d;
437         struct ost_id           *ostid = &info->oti_ostid;
438         int                      dirn, rc = 0;
439         char                     name[32];
440         ENTRY;
441
442         map = osd->od_ost_map;
443         LASSERT(map);
444         LASSERT(map->root);
445         LASSERT(map->subdir_count > 0);
446         LASSERT(map->groups[ostid->oi_seq].groot);
447
448         /* map fid to group:objid */
449         fid_ostid_pack(fid, ostid);
450         dirn = ostid->oi_id & (map->subdir_count - 1);
451         d = map->groups[ostid->oi_seq].dirs[dirn];
452         LASSERT(d);
453
454         sprintf(name, "%llu", ostid->oi_id);
455         rc = osd_compat_add_entry(info, osd, d, name, id, th);
456
457         RETURN(rc);
458 }
459
460 int osd_compat_objid_delete(struct osd_thread_info *info,
461                             struct osd_device *osd,
462                             const struct lu_fid *fid, struct thandle *th)
463 {
464         struct osd_compat_objid *map;
465         struct dentry           *d;
466         struct ost_id           *ostid = &info->oti_ostid;
467         int                      dirn, rc = 0;
468         char                     name[32];
469         ENTRY;
470
471         map = osd->od_ost_map;
472         LASSERT(map);
473         LASSERT(map->root);
474         LASSERT(map->subdir_count > 0);
475         LASSERT(map->groups[ostid->oi_seq].groot);
476
477         /* map fid to group:objid */
478         fid_ostid_pack(fid, ostid);
479         dirn = ostid->oi_id & (map->subdir_count - 1);
480         d = map->groups[ostid->oi_seq].dirs[dirn];
481         LASSERT(d);
482
483         sprintf(name, "%llu", ostid->oi_id);
484         rc = osd_compat_del_entry(info, osd, d, name, th);
485
486         RETURN(rc);
487 }
488
489 struct named_oid {
490         unsigned long  oid;
491         char          *name;
492 };
493
494 static const struct named_oid oids[] = {
495         { FLD_INDEX_OID,        "" /* "fld" */ },
496         { FID_SEQ_CTL_OID,      "" /* "seq_ctl" */ },
497         { FID_SEQ_SRV_OID,      "" /* "seq_srv" */ },
498         { MDD_ROOT_INDEX_OID,   "" /* "ROOT" */ },
499         { MDD_ORPHAN_OID,       "" /* "PENDING" */ },
500         { MDD_LOV_OBJ_OID,      "" /* LOV_OBJID */ },
501         { MDD_CAPA_KEYS_OID,    "" /* CAPA_KEYS */ },
502         { MDT_LAST_RECV_OID,    LAST_RCVD },
503         { OFD_LAST_RECV_OID,    "" /* LAST_RCVD */ },
504         { OFD_LAST_GROUP_OID,   "" /* "LAST_GROUP" */ },
505         { LLOG_CATALOGS_OID,    "" /* "CATALOGS" */ },
506         { MGS_CONFIGS_OID,      "" /* MOUNT_CONFIGS_DIR */ },
507         { OFD_HEALTH_CHECK_OID, "" /* HEALTH_CHECK */ },
508         { 0,                    NULL }
509 };
510
511 static char *oid2name(const unsigned long oid)
512 {
513         int i = 0;
514
515         while (oids[i].oid) {
516                 if (oids[i].oid == oid)
517                         return oids[i].name;
518                 i++;
519         }
520         return NULL;
521 }
522
523 int osd_compat_spec_insert(struct osd_thread_info *info,
524                            struct osd_device *osd, const struct lu_fid *fid,
525                            const struct osd_inode_id *id, struct thandle *th)
526 {
527         struct osd_compat_objid *map = osd->od_ost_map;
528         struct dentry           *root = osd_sb(osd)->s_root;
529         char                    *name;
530         int                      rc = 0;
531         int                      seq;
532         ENTRY;
533
534         if (fid_oid(fid) >= OFD_GROUP0_LAST_OID &&
535             fid_oid(fid) < OFD_GROUP4K_LAST_OID) {
536                 /* on creation of LAST_ID we create O/<group> hierarchy */
537                 LASSERT(map);
538                 seq = fid_oid(fid) - OFD_GROUP0_LAST_OID;
539                 LASSERT(seq < MAX_OBJID_GROUP);
540                 LASSERT(map->groups[seq].groot);
541         } else {
542                 name = oid2name(fid_oid(fid));
543                 if (name == NULL)
544                         CWARN("UNKNOWN COMPAT FID "DFID"\n", PFID(fid));
545                 else if (name[0])
546                         rc = osd_compat_add_entry(info, osd, root, name, id,
547                                                   th);
548         }
549
550         RETURN(rc);
551 }
552
553 int osd_compat_spec_lookup(struct osd_thread_info *info,
554                            struct osd_device *osd, const struct lu_fid *fid,
555                            struct osd_inode_id *id)
556 {
557         struct dentry *dentry;
558         char          *name;
559         int            rc = -ERESTART;
560
561         ENTRY;
562
563         name = oid2name(fid_oid(fid));
564         if (name == NULL || strlen(name) == 0)
565                 return -ERESTART;
566
567         dentry = ll_lookup_one_len(name, osd_sb(osd)->s_root, strlen(name));
568         if (!IS_ERR(dentry)) {
569                 if (dentry->d_inode) {
570                         if (is_bad_inode(dentry->d_inode)) {
571                                 rc = -EIO;
572                         } else {
573                                 id->oii_ino = dentry->d_inode->i_ino;
574                                 id->oii_gen = dentry->d_inode->i_generation;
575                                 rc = 0;
576                         }
577                 }
578                 dput(dentry);
579         }
580
581         RETURN(rc);
582 }
583