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