Whamcloud - gitweb
LU-2446 build: Update Whamcloud copyright messages for Intel
[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) 2012, Intel Corporation.
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 #include "osd_oi.h"
59
60 struct osd_compat_objid_seq {
61         /* protects on-fly initialization */
62         struct semaphore        dir_init_sem;
63         /* file storing last created objid */
64         struct osd_inode_id    last_id;
65         struct dentry         *groot; /* O/<seq> */
66         struct dentry        **dirs;  /* O/<seq>/d0-dXX */
67 };
68
69 #define MAX_OBJID_GROUP (FID_SEQ_ECHO + 1)
70
71 struct osd_compat_objid {
72         int                          subdir_count;
73         struct dentry               *root;
74         struct osd_inode_id          last_rcvd_id;
75         struct osd_inode_id          last_seq_id;
76         struct osd_compat_objid_seq  groups[MAX_OBJID_GROUP];
77 };
78
79 static void osd_push_ctxt(const struct osd_device *dev,
80                           struct lvfs_run_ctxt *newctxt,
81                           struct lvfs_run_ctxt *save)
82 {
83         OBD_SET_CTXT_MAGIC(newctxt);
84         newctxt->pwdmnt = dev->od_mnt;
85         newctxt->pwd = dev->od_mnt->mnt_root;
86         newctxt->fs = get_ds();
87
88         push_ctxt(save, newctxt, NULL);
89 }
90
91 void osd_compat_seq_fini(struct osd_device *osd, int seq)
92 {
93         struct osd_compat_objid_seq *grp;
94         struct osd_compat_objid     *map = osd->od_ost_map;
95         int                          i;
96
97         ENTRY;
98
99         grp = &map->groups[seq];
100         if (grp->groot ==NULL)
101                 RETURN_EXIT;
102         LASSERT(grp->dirs);
103
104         for (i = 0; i < map->subdir_count; i++) {
105                 if (grp->dirs[i] == NULL)
106                         break;
107                 dput(grp->dirs[i]);
108         }
109
110         OBD_FREE(grp->dirs, sizeof(struct dentry *) * map->subdir_count);
111         dput(grp->groot);
112         EXIT;
113 }
114
115 int osd_compat_seq_init(struct osd_device *osd, int seq)
116 {
117         struct osd_compat_objid_seq *grp;
118         struct osd_compat_objid     *map;
119         struct dentry               *d;
120         int                          rc = 0;
121         char                         name[32];
122         int                          i;
123         ENTRY;
124
125         map = osd->od_ost_map;
126         LASSERT(map);
127         LASSERT(map->root);
128         grp = &map->groups[seq];
129
130         if (grp->groot != NULL)
131                 RETURN(0);
132
133         down(&grp->dir_init_sem);
134
135         sprintf(name, "%d", seq);
136         d = simple_mkdir(map->root, osd->od_mnt, name, 0755, 1);
137         if (IS_ERR(d)) {
138                 rc = PTR_ERR(d);
139                 GOTO(out, rc);
140         } else if (d->d_inode == NULL) {
141                 rc = -EFAULT;
142                 dput(d);
143                 GOTO(out, rc);
144         }
145
146         LASSERT(grp->dirs == NULL);
147         OBD_ALLOC(grp->dirs, sizeof(d) * map->subdir_count);
148         if (grp->dirs == NULL) {
149                 dput(d);
150                 GOTO(out, rc = -ENOMEM);
151         }
152
153         grp->groot = d;
154         for (i = 0; i < map->subdir_count; i++) {
155                 sprintf(name, "d%d", i);
156                 d = simple_mkdir(grp->groot, osd->od_mnt, name, 0755, 1);
157                 if (IS_ERR(d)) {
158                         rc = PTR_ERR(d);
159                         break;
160                 } else if (d->d_inode == NULL) {
161                         rc = -EFAULT;
162                         dput(d);
163                         break;
164                 }
165
166                 grp->dirs[i] = d;
167         }
168
169         if (rc)
170                 osd_compat_seq_fini(osd, seq);
171 out:
172         up(&grp->dir_init_sem);
173         RETURN(rc);
174 }
175
176 int osd_last_rcvd_subdir_count(struct osd_device *osd)
177 {
178         struct lr_server_data lsd;
179         struct dentry        *dlast;
180         loff_t                off;
181         int                   rc = 0;
182         int                   count = FILTER_SUBDIR_COUNT;
183
184         ENTRY;
185
186         dlast = ll_lookup_one_len(LAST_RCVD, osd_sb(osd)->s_root,
187                                   strlen(LAST_RCVD));
188         if (IS_ERR(dlast))
189                 return PTR_ERR(dlast);
190         else if (dlast->d_inode == NULL)
191                 goto out;
192
193         off = 0;
194         rc = osd_ldiskfs_read(dlast->d_inode, &lsd, sizeof(lsd), &off);
195         if (rc == sizeof(lsd)) {
196                 CDEBUG(D_INFO, "read last_rcvd header, uuid = %s, "
197                        "subdir count = %d\n", lsd.lsd_uuid,
198                        lsd.lsd_subdir_count);
199                 if (le16_to_cpu(lsd.lsd_subdir_count) > 0)
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                 dput(dlast);
206                 return rc;
207         }
208 out:
209         dput(dlast);
210         LASSERT(count > 0);
211         return count;
212 }
213
214 void osd_compat_fini(struct osd_device *dev)
215 {
216         int i;
217
218         ENTRY;
219
220         if (dev->od_ost_map == NULL)
221                 RETURN_EXIT;
222
223         for (i = 0; i < MAX_OBJID_GROUP; i++)
224                 osd_compat_seq_fini(dev, i);
225
226         dput(dev->od_ost_map->root);
227         OBD_FREE_PTR(dev->od_ost_map);
228         dev->od_ost_map = NULL;
229
230         EXIT;
231 }
232
233 /*
234  * directory structure on legacy OST:
235  *
236  * O/<seq>/d0-31/<objid>
237  * O/<seq>/LAST_ID
238  * last_rcvd
239  * LAST_GROUP
240  * CONFIGS
241  *
242  */
243 int osd_compat_init(struct osd_device *dev)
244 {
245         struct lvfs_run_ctxt  new;
246         struct lvfs_run_ctxt  save;
247         struct dentry        *rootd = osd_sb(dev)->s_root;
248         struct dentry        *d;
249         int                   rc;
250         int                   i;
251
252         ENTRY;
253
254         OBD_ALLOC_PTR(dev->od_ost_map);
255         if (dev->od_ost_map == NULL)
256                 RETURN(-ENOMEM);
257
258         /* to get subdir count from last_rcvd */
259         rc = osd_last_rcvd_subdir_count(dev);
260         if (rc < 0) {
261                 OBD_FREE_PTR(dev->od_ost_map);
262                 RETURN(rc);
263         }
264
265         dev->od_ost_map->subdir_count = rc;
266         rc = 0;
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                 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         ll_vfs_dq_init(dir);
318         mutex_lock(&dir->i_mutex);
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         mutex_unlock(&dir->i_mutex);
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         osd_id_to_inode(inode, id);
348         inode->i_mode = S_IFREG; /* for type in ldiskfs dir entry */
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         ll_vfs_dq_init(dir->d_inode);
358         mutex_lock(&dir->d_inode->i_mutex);
359         rc = osd_ldiskfs_add_entry(oh->ot_handle, child, inode, NULL);
360         mutex_unlock(&dir->d_inode->i_mutex);
361
362         RETURN(rc);
363 }
364
365 int osd_compat_objid_lookup(struct osd_thread_info *info,
366                             struct osd_device *dev, const struct lu_fid *fid,
367                             struct osd_inode_id *id)
368 {
369         struct osd_compat_objid    *map;
370         struct dentry              *d;
371         struct dentry              *d_seq;
372         struct ost_id              *ostid = &info->oti_ostid;
373         int                         dirn;
374         char                        name[32];
375         struct ldiskfs_dir_entry_2 *de;
376         struct buffer_head         *bh;
377         struct inode               *dir;
378         struct inode               *inode;
379         ENTRY;
380
381         /* on the very first lookup we find and open directories */
382
383         map = dev->od_ost_map;
384         LASSERT(map);
385         LASSERT(map->root);
386
387         fid_ostid_pack(fid, ostid);
388         LASSERT(ostid->oi_seq < MAX_OBJID_GROUP);
389         LASSERT(map->subdir_count > 0);
390         LASSERT(map->groups[ostid->oi_seq].groot);
391
392         dirn = ostid->oi_id & (map->subdir_count - 1);
393         d = map->groups[ostid->oi_seq].dirs[dirn];
394         LASSERT(d);
395
396         sprintf(name, "%llu", ostid->oi_id);
397         d_seq = &info->oti_child_dentry;
398         d_seq->d_parent = d;
399         d_seq->d_name.hash = 0;
400         d_seq->d_name.name = name;
401         /* XXX: we can use rc from sprintf() instead of strlen() */
402         d_seq->d_name.len = strlen(name);
403
404         dir = d->d_inode;
405         mutex_lock(&dir->i_mutex);
406         bh = osd_ldiskfs_find_entry(dir, d_seq, &de, NULL);
407         mutex_unlock(&dir->i_mutex);
408
409         if (bh == NULL)
410                 RETURN(-ENOENT);
411
412         osd_id_gen(id, le32_to_cpu(de->inode), OSD_OII_NOGEN);
413         brelse(bh);
414
415         inode = osd_iget(info, dev, id);
416         if (IS_ERR(inode))
417                 RETURN(PTR_ERR(inode));
418
419         iput(inode);
420         RETURN(0);
421 }
422
423 int osd_compat_objid_insert(struct osd_thread_info *info,
424                             struct osd_device *osd,
425                             const struct lu_fid *fid,
426                             const struct osd_inode_id *id,
427                             struct thandle *th)
428 {
429         struct osd_compat_objid *map;
430         struct dentry           *d;
431         struct ost_id           *ostid = &info->oti_ostid;
432         int                      dirn, rc = 0;
433         char                     name[32];
434         ENTRY;
435
436         map = osd->od_ost_map;
437         LASSERT(map);
438         LASSERT(map->root);
439         LASSERT(map->subdir_count > 0);
440         LASSERT(map->groups[ostid->oi_seq].groot);
441
442         /* map fid to group:objid */
443         fid_ostid_pack(fid, ostid);
444         dirn = ostid->oi_id & (map->subdir_count - 1);
445         d = map->groups[ostid->oi_seq].dirs[dirn];
446         LASSERT(d);
447
448         sprintf(name, "%llu", ostid->oi_id);
449         rc = osd_compat_add_entry(info, osd, d, name, id, th);
450
451         RETURN(rc);
452 }
453
454 int osd_compat_objid_delete(struct osd_thread_info *info,
455                             struct osd_device *osd,
456                             const struct lu_fid *fid, struct thandle *th)
457 {
458         struct osd_compat_objid *map;
459         struct dentry           *d;
460         struct ost_id           *ostid = &info->oti_ostid;
461         int                      dirn, rc = 0;
462         char                     name[32];
463         ENTRY;
464
465         map = osd->od_ost_map;
466         LASSERT(map);
467         LASSERT(map->root);
468         LASSERT(map->subdir_count > 0);
469         LASSERT(map->groups[ostid->oi_seq].groot);
470
471         /* map fid to group:objid */
472         fid_ostid_pack(fid, ostid);
473         dirn = ostid->oi_id & (map->subdir_count - 1);
474         d = map->groups[ostid->oi_seq].dirs[dirn];
475         LASSERT(d);
476
477         sprintf(name, "%llu", ostid->oi_id);
478         rc = osd_compat_del_entry(info, osd, d, name, th);
479
480         RETURN(rc);
481 }
482
483 struct named_oid {
484         unsigned long  oid;
485         char          *name;
486 };
487
488 static const struct named_oid oids[] = {
489         { FLD_INDEX_OID,        "fld" },
490         { FID_SEQ_CTL_OID,      "seq_ctl" },
491         { FID_SEQ_SRV_OID,      "seq_srv" },
492         { MDD_ROOT_INDEX_OID,   "" /* "ROOT" */ },
493         { MDD_ORPHAN_OID,       "" /* "PENDING" */ },
494         { MDD_LOV_OBJ_OID,      LOV_OBJID },
495         { MDD_CAPA_KEYS_OID,    "" /* CAPA_KEYS */ },
496         { MDT_LAST_RECV_OID,    LAST_RCVD },
497         { LFSCK_BOOKMARK_OID,   "" /* "lfsck_bookmark" */ },
498         { OTABLE_IT_OID,        "" /* "otable iterator" */},
499         { OFD_LAST_RECV_OID,    LAST_RCVD },
500         { OFD_LAST_GROUP_OID,   "LAST_GROUP" },
501         { LLOG_CATALOGS_OID,    "CATALOGS" },
502         { MGS_CONFIGS_OID,      "" /* MOUNT_CONFIGS_DIR */ },
503         { OFD_HEALTH_CHECK_OID, HEALTH_CHECK },
504         { 0,                    NULL }
505 };
506
507 static char *oid2name(const unsigned long oid)
508 {
509         int i = 0;
510
511         while (oids[i].oid) {
512                 if (oids[i].oid == oid)
513                         return oids[i].name;
514                 i++;
515         }
516         return NULL;
517 }
518
519 int osd_compat_spec_insert(struct osd_thread_info *info,
520                            struct osd_device *osd, const struct lu_fid *fid,
521                            const struct osd_inode_id *id, struct thandle *th)
522 {
523         struct osd_compat_objid *map = osd->od_ost_map;
524         struct dentry           *root = osd_sb(osd)->s_root;
525         char                    *name;
526         int                      rc = 0;
527         int                      seq;
528         ENTRY;
529
530         if (fid_oid(fid) >= OFD_GROUP0_LAST_OID &&
531             fid_oid(fid) < OFD_GROUP4K_LAST_OID) {
532                 /* on creation of LAST_ID we create O/<group> hierarchy */
533                 LASSERT(map);
534                 seq = fid_oid(fid) - OFD_GROUP0_LAST_OID;
535                 LASSERT(seq < MAX_OBJID_GROUP);
536                 LASSERT(map->groups[seq].groot);
537                 rc = osd_compat_add_entry(info, osd, map->groups[seq].groot,
538                                           "LAST_ID", id, th);
539         } else {
540                 name = oid2name(fid_oid(fid));
541                 if (name == NULL)
542                         CWARN("UNKNOWN COMPAT FID "DFID"\n", PFID(fid));
543                 else if (name[0])
544                         rc = osd_compat_add_entry(info, osd, root, name, id,
545                                                   th);
546         }
547
548         RETURN(rc);
549 }
550
551 int osd_compat_spec_lookup(struct osd_thread_info *info,
552                            struct osd_device *osd, const struct lu_fid *fid,
553                            struct osd_inode_id *id)
554 {
555         struct dentry   *root;
556         struct dentry *dentry;
557         struct inode  *inode;
558         char          *name;
559         int            rc = -ENOENT;
560         ENTRY;
561
562         if (fid_oid(fid) >= OFD_GROUP0_LAST_OID &&
563             fid_oid(fid) < OFD_GROUP4K_LAST_OID) {
564                 struct osd_compat_objid *map = osd->od_ost_map;
565                 int                      seq;
566
567                 LASSERT(map);
568                 seq = fid_oid(fid) - OFD_GROUP0_LAST_OID;
569                 LASSERT(seq < MAX_OBJID_GROUP);
570                 LASSERT(map->groups[seq].groot);
571                 root = map->groups[seq].groot;
572                 name = "LAST_ID";
573         } else {
574                 root = osd_sb(osd)->s_root;
575                 name = oid2name(fid_oid(fid));
576                 if (name == NULL || strlen(name) == 0)
577                         RETURN(-ENOENT);
578         }
579
580         dentry = ll_lookup_one_len(name, root, strlen(name));
581         if (!IS_ERR(dentry)) {
582                 inode = dentry->d_inode;
583                 if (inode) {
584                         if (is_bad_inode(inode)) {
585                                 rc = -EIO;
586                         } else {
587                                 osd_id_gen(id, inode->i_ino,
588                                            inode->i_generation);
589                                 rc = 0;
590                         }
591                 }
592                 /* if dentry is accessible after osd_compat_spec_insert it
593                  * will still contain NULL inode, so don't keep it in cache */
594                 d_invalidate(dentry);
595                 dput(dentry);
596         }
597
598         RETURN(rc);
599 }