Whamcloud - gitweb
LU-2240 osd: change FID of /ROOT on zfs
authorwangdi <di.wang@whamcloud.com>
Sun, 29 Dec 2013 08:08:07 +0000 (00:08 -0800)
committerOleg Drokin <oleg.drokin@intel.com>
Fri, 15 Mar 2013 20:28:22 +0000 (16:28 -0400)
Pre-production 2.4 code used FID_SEQ_LOCAL_FILE for /ROOT. With
ldiskfs that FID turns into IGIF which is mapped to MDT0 permanently.
With ZFS original local sequence, was used which makes existing setup
incompatibile with DNE. The intention of the patch is to fix this on
existing ZFS setups and replace FID with one from special FID_SEQ_ROOT
sequence which is mapped to MDT0 as well. For simplicity this is done
in few steps:

 - osd-zfs replaces direntry for /ROOT with the new FID and fixes OI
   so that the new FID is mapped to the same dnode
 - MDD finds all objects listed in /ROOT and updates linkEA properly
 - MDD removes ./.. which may be on disk for pre-production setups
 - finally MDD resets LMA on /ROOT with the new FID, which is later
   used to recognize already converted filesystems (or ones created
   with correct FID from the beginning) and skip this conversion code

Signed-off-by: Alex Zhuravlev <alexey.zhuravlev@intel.com>
Signed-off-by: Di Wang <di.wang@intel.com>
Change-Id: I03062c6909146f9a3aed72f41c0708f9ef92bb82
Reviewed-on: http://review.whamcloud.com/5249
Reviewed-by: Andreas Dilger <andreas.dilger@intel.com>
Tested-by: Hudson
Tested-by: Maloo <whamcloud.maloo@gmail.com>
Reviewed-by: Prakash Surya <surya1@llnl.gov>
lustre/fld/fld_index.c
lustre/include/lustre_fld.h
lustre/mdd/Makefile.in
lustre/mdd/mdd_compat.c [new file with mode: 0644]
lustre/mdd/mdd_device.c
lustre/mdd/mdd_dir.c
lustre/mdd/mdd_internal.h
lustre/osd-zfs/osd_handler.c
lustre/osd-zfs/osd_internal.h
lustre/osd-zfs/osd_oi.c

index f8bbfba..cbe8300 100644 (file)
@@ -262,9 +262,9 @@ int fld_index_lookup(const struct lu_env *env, struct lu_server_fld *fld,
         RETURN(rc);
 }
 
-static int fld_insert_entry(const struct lu_env *env,
-                           struct lu_server_fld *fld,
-                           const struct lu_seq_range *range)
+int fld_insert_entry(const struct lu_env *env,
+                    struct lu_server_fld *fld,
+                    const struct lu_seq_range *range)
 {
        struct thandle *th;
        int rc;
@@ -293,6 +293,7 @@ out:
        dt_trans_stop(env, lu2dt_dev(fld->lsf_obj->do_lu.lo_dev), th);
        RETURN(rc);
 }
+EXPORT_SYMBOL(fld_insert_entry);
 
 static int fld_insert_special_entries(const struct lu_env *env,
                                      struct lu_server_fld *fld)
index 853793d..8e329c8 100644 (file)
@@ -163,6 +163,10 @@ int fld_server_create(const struct lu_env *env,
                      struct lu_seq_range *add_range,
                      struct thandle *th);
 
+int fld_insert_entry(const struct lu_env *env,
+                    struct lu_server_fld *fld,
+                    const struct lu_seq_range *range);
+
 int fld_server_lookup(const struct lu_env *env, struct lu_server_fld *fld,
                      seqno_t seq, struct lu_seq_range *range);
 
index 59e191d..62f9606 100644 (file)
@@ -1,7 +1,7 @@
 MODULES := mdd
 mdd-objs := mdd_object.o mdd_lov.o mdd_orphans.o mdd_lproc.o mdd_dir.o
 mdd-objs += mdd_device.o mdd_trans.o mdd_permission.o mdd_lock.o
-mdd-objs += mdd_lfsck.o
+mdd-objs += mdd_lfsck.o mdd_compat.o
 
 EXTRA_PRE_CFLAGS := -I@LINUX@/fs -I@LDISKFS_DIR@ -I@LDISKFS_DIR@/ldiskfs
 
diff --git a/lustre/mdd/mdd_compat.c b/lustre/mdd/mdd_compat.c
new file mode 100644 (file)
index 0000000..fe1eb49
--- /dev/null
@@ -0,0 +1,392 @@
+/*
+ * GPL HEADER START
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 only,
+ * as published by the Free Software Foundation.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License version 2 for more details.  A copy is
+ * included in the COPYING file that accompanied this code.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * GPL HEADER END
+ */
+/*
+ * Copyright (c) 2012, Intel Corporation.
+ */
+#define DEBUG_SUBSYSTEM S_MDS
+
+#include <lustre/lustre_idl.h>
+#include <lustre_fid.h>
+#include <obd_support.h>
+
+#include "mdd_internal.h"
+
+/*
+ * To enable DNE functionality we need FID of /ROOT directory
+ * (which is / as seen by the clients) to belong to MDT0 and
+ * not to FID_SEQ_LOCAL_FILE or some other local sequence,
+ * which can be used by any node, so can't be part of FLDB.
+ *
+ * Pre-production code was using FID_SEQ_LOCAL_FILE for /ROOT
+ * making few existing setups incompatibile with DNE. This
+ * applies to ZFS-based setups only as ldiskfs-based setups
+ * are still using IGIF to identify /ROOT.
+ *
+ * The intention of this code is to fix on-disk state to use
+ * FID_SEQ_ROOT for /ROOT:
+ *  - "." and ".." references in /ROOT itself and it`s subdirectories
+ *  - LinkEA in all the objects listed in /ROOT
+ *
+ * Given only ZFS is affected where "." and ".." are not stored, we need to:
+ *  - delete "." and ".." from /ROOT and its subdirectories
+ *  - rename references in LinkEA in all the objects listed in /ROOT
+ *
+ * This code is subject for removal in 2.5
+ */
+static int mdd_convert_remove_dots(const struct lu_env *env,
+                                  struct mdd_device *mdd,
+                                  struct mdd_object *o)
+{
+       struct thandle          *th = NULL;
+       const struct dt_key     *dot = (const struct dt_key *)".";
+       const struct dt_key     *dotdot = (const struct dt_key *)"..";
+       int                      rc;
+
+       if (dt_try_as_dir(env, mdd_object_child(o)) == 0)
+               RETURN(-ENOTDIR);
+
+       /* remove "."/".." and do not insert them back - not stored in ZFS */
+       th = dt_trans_create(env, mdd->mdd_child);
+       if (IS_ERR(th))
+               RETURN(PTR_ERR(th));
+       rc = dt_declare_delete(env, mdd_object_child(o), dot, th);
+       if (rc)
+               GOTO(out, rc);
+       rc = dt_declare_delete(env, mdd_object_child(o), dotdot, th);
+       if (rc)
+               GOTO(out, rc);
+       rc = dt_trans_start_local(env, mdd->mdd_child, th);
+       if (rc)
+               GOTO(out, rc);
+       /* ignore non-existing "."/".." - we stored them on disk for
+        * pre-production systems, but this is not how regular ZFS works */
+       rc = dt_delete(env, mdd_object_child(o), dot, th, BYPASS_CAPA);
+       if (rc == -ENOENT)
+               rc = 0;
+       if (rc)
+               GOTO(out, rc);
+       rc = dt_delete(env, mdd_object_child(o), dotdot, th, BYPASS_CAPA);
+       if (rc == -ENOENT)
+               rc = 0;
+       if (rc)
+               GOTO(out, rc);
+
+out:
+       if (th)
+               dt_trans_stop(env, mdd->mdd_child, th);
+       RETURN(rc);
+}
+
+static int mdd_convert_linkea(const struct lu_env *env,
+                             struct mdd_device *mdd,
+                             struct mdd_object *o,
+                             const struct lu_name *name)
+{
+       struct thandle  *th = NULL;
+       struct lu_fid    oldfid;
+       int              rc;
+       ENTRY;
+
+       th = dt_trans_create(env, mdd->mdd_child);
+       rc = mdd_declare_links_add(env, o, th);
+       if (rc)
+               GOTO(out, rc);
+       rc = dt_trans_start_local(env, mdd->mdd_child, th);
+       if (rc)
+               GOTO(out, rc);
+
+       oldfid.f_seq = FID_SEQ_LOCAL_FILE;
+       oldfid.f_oid = MDD_ROOT_INDEX_OID;
+       oldfid.f_ver = 0;
+       rc = mdd_links_rename(env, o, &oldfid, name, &mdd->mdd_root_fid,
+                             name, th, 0, 1);
+       if (rc == -ENOENT || rc == -EEXIST)
+               rc = 0;
+
+out:
+       if (th)
+               dt_trans_stop(env, mdd->mdd_child, th);
+       RETURN(rc);
+}
+
+static int mdd_convert_object(const struct lu_env *env,
+                             struct mdd_device *mdd,
+                             const struct lu_fid *fid,
+                             const struct lu_name *name)
+{
+       struct mdd_object       *o;
+       struct lu_attr          *la = &mdd_env_info(env)->mti_la;
+       int                      rc;
+       ENTRY;
+
+       o = mdd_object_find(env, mdd, fid);
+       if (IS_ERR(o)) {
+               CERROR("%s: can't access the object: rc = %d\n",
+                      mdd2obd_dev(mdd)->obd_name, (int)PTR_ERR(o));
+               RETURN(PTR_ERR(o));
+       }
+
+       rc = mdo_attr_get(env, o, la, BYPASS_CAPA);
+       if (rc)
+               GOTO(out, rc);
+
+       if (S_ISDIR(la->la_mode)) {
+               /* remove "." and ".." if a directory */
+               rc = mdd_convert_remove_dots(env, mdd, o);
+               if (rc)
+                       GOTO(out, rc);
+       }
+
+       /* update linkEA */
+       rc = mdd_convert_linkea(env, mdd, o, name);
+       if (rc)
+               CERROR("%s: can't convert: rc = %d\n",
+                      mdd2obd_dev(mdd)->obd_name, rc);
+
+out:
+       mdd_object_put(env, o);
+       RETURN(0);
+}
+
+static int mdd_convert_lma(const struct lu_env *env, struct mdd_device *mdd,
+                          struct mdd_object *o)
+{
+       struct lustre_mdt_attrs *lma;
+       struct thandle          *th = NULL;
+       struct lu_fid            fid;
+       struct lu_buf            buf;
+       int                      rc;
+       ENTRY;
+
+       lu_root_fid(&fid);
+
+       lma = (struct lustre_mdt_attrs *)&mdd_env_info(env)->mti_xattr_buf;
+       lustre_lma_init(lma, &fid);
+       lustre_lma_swab(lma);
+       buf.lb_buf = lma;
+       buf.lb_len = sizeof(*lma);
+
+       th = dt_trans_create(env, mdd->mdd_child);
+       if (IS_ERR(th))
+               RETURN(PTR_ERR(th));
+       rc = mdo_declare_xattr_set(env, o, &buf, XATTR_NAME_LMA, 0, th);
+       if (rc)
+               GOTO(out, rc);
+       rc = dt_trans_start_local(env, mdd->mdd_child, th);
+       if (rc)
+               GOTO(out, rc);
+       rc = mdo_xattr_set(env, o, &buf, XATTR_NAME_LMA, 0, th, BYPASS_CAPA);
+out:
+       if (th)
+               dt_trans_stop(env, mdd->mdd_child, th);
+       RETURN(rc);
+}
+
+static int mdd_fix_children(const struct lu_env *env,
+                           struct mdd_device *mdd,
+                           struct dt_object *o)
+{
+       struct mdd_thread_info *info = mdd_env_info(env);
+       const struct dt_it_ops *iops;
+       struct lu_name          name;
+       struct dt_it           *it;
+       struct lu_dirent       *ent;
+       int                     rc;
+       ENTRY;
+
+       /* scan /ROOT and update all ".." and linkEAs */
+       ent = (struct lu_dirent *)&info->mti_xattr_buf;
+       iops = &o->do_index_ops->dio_it;
+
+       it = iops->init(env, o, LUDA_64BITHASH, BYPASS_CAPA);
+       if (IS_ERR(it)) {
+               rc = PTR_ERR(it);
+               CERROR("%s: can't initialize the iterator: rc = %d\n",
+                      mdd2obd_dev(mdd)->obd_name, rc);
+               GOTO(out, rc);
+       }
+
+       rc = iops->load(env, it, 0);
+       if (rc <= 0)
+               GOTO(out_put, rc);
+
+       do {
+               rc = iops->key_size(env, it);
+               if (rc == 0)
+                       goto next;
+
+               /* calculate max space required for lu_dirent */
+               rc = lu_dirent_calc_size(rc, 0);
+               LASSERT(rc <= sizeof(info->mti_xattr_buf));
+
+               rc = iops->rec(env, it, (struct dt_rec *)ent, LUDA_TYPE);
+               if (rc == 0) {
+                       CDEBUG(D_OTHER, "convert %*s -> "DFID"\n",
+                              ent->lde_namelen, ent->lde_name,
+                              PFID(&ent->lde_fid));
+                       name.ln_namelen = ent->lde_namelen;
+                       name.ln_name = ent->lde_name;
+                       rc = mdd_convert_object(env, mdd, &ent->lde_fid, &name);
+                       if (rc) {
+                               CERROR("%s: can't convert "DFID": rc = %d\n",
+                                      mdd2obd_dev(mdd)->obd_name,
+                                      PFID(&ent->lde_fid), rc);
+                               break;
+                       }
+               }
+
+next:
+               rc = iops->next(env, it);
+       } while (rc == 0);
+       if (rc > 0)
+               rc = 0;
+
+out_put:
+       iops->put(env, it);
+       iops->fini(env, it);
+out:
+       RETURN(rc);
+}
+
+static int mdd_fill_fldb(const struct lu_env *env, struct mdd_device *mdd)
+{
+       struct seq_server_site *ss = mdd_seq_site(mdd);
+       struct lu_seq_range range;
+       int     rc;
+
+       LASSERT(ss->ss_server_seq != NULL);
+       LASSERT(ss->ss_server_fld != NULL);
+
+       if (ss->ss_server_seq->lss_space.lsr_end == 0)
+               return 0;
+
+       memcpy(&range, &ss->ss_server_seq->lss_space, sizeof(range));
+
+       /* Pre-existing ZFS does not insert any entries to FLDB, we need
+        * to insert it to FLDB during convertion */
+       range.lsr_start = FID_SEQ_NORMAL;
+       range.lsr_flags = LU_SEQ_RANGE_MDT;
+
+       mutex_lock(&ss->ss_server_fld->lsf_lock);
+       rc = fld_insert_entry(env, ss->ss_server_fld, &range);
+       mutex_unlock(&ss->ss_server_fld->lsf_lock);
+
+       LCONSOLE_INFO("%s: insert missing range "DRANGE"\n",
+                     mdd2obd_dev(mdd)->obd_name, PRANGE(&range));
+       return rc;
+}
+int mdd_compat_fixes(const struct lu_env *env, struct mdd_device *mdd)
+{
+       struct mdd_thread_info  *info = mdd_env_info(env);
+       struct mdd_object       *root;
+       struct dt_object        *o;
+       struct lustre_mdt_attrs *lma;
+       struct lu_buf            buf;
+       int                      rc;
+       ENTRY;
+
+       /* IGIF FIDS are valid for old 1.8 and 2.[123] ROOT and are kept.
+        * Normal FIDs used by Xyratex 1.8->2.1 upgrade tool are also kept. */
+       if (fid_is_igif(&mdd->mdd_root_fid) || fid_is_norm(&mdd->mdd_root_fid))
+               RETURN(0);
+
+       /*
+        * FID is supposed to be FID_SEQ_ROOT for:
+        *  - new ldiskfs fs
+        *  - new ZFS fs
+        *  - old ZFS fs, by now processed with osd_convert_root_to_new_seq()
+        */
+       if (fid_seq(&mdd->mdd_root_fid) != FID_SEQ_ROOT) {
+               CERROR("%s: wrong FID "DFID" is used for /ROOT\n",
+                      mdd2obd_dev(mdd)->obd_name,
+                      PFID(&mdd->mdd_root_fid));
+               RETURN(-EINVAL);
+       }
+
+       root = mdd_object_find(env, mdd, &mdd->mdd_root_fid);
+       if (IS_ERR(root))
+               RETURN(PTR_ERR(root));
+       o = mdd_object_child(root);
+
+       CDEBUG(D_OTHER, "/ROOT = "DFID"\n", PFID(&mdd->mdd_root_fid));
+
+       if (dt_try_as_dir(env, o) == 0) {
+               CERROR("%s: not a directory\n", mdd2obd_dev(mdd)->obd_name);
+               GOTO(out, rc = -ENOTDIR);
+       }
+
+       lma = (struct lustre_mdt_attrs *)&info->mti_xattr_buf;
+       CLASSERT(sizeof(info->mti_xattr_buf) >= LMA_OLD_SIZE);
+       buf.lb_len = LMA_OLD_SIZE;
+       buf.lb_buf = lma;
+       rc = mdo_xattr_get(env, root, &buf, XATTR_NAME_LMA, BYPASS_CAPA);
+       if (rc < 0 && rc != -ENODATA) {
+               CERROR("%s: can't fetch LMA: rc = %d\n",
+                      mdd2obd_dev(mdd)->obd_name, rc);
+               GOTO(out, rc);
+       }
+
+       lustre_lma_swab(lma);
+       if (lu_fid_eq(&lma->lma_self_fid, &mdd->mdd_root_fid)) {
+               /* /ROOT has been converted already
+                * or was correct from the beginning */
+               CDEBUG(D_OTHER, "%s: converted already\n",
+                      mdd2obd_dev(mdd)->obd_name);
+               GOTO(out, rc = 0);
+       }
+
+       /* this is supposed to happen only on pre-production ZFS backend */
+       if (strcmp(mdd->mdd_bottom->dd_lu_dev.ld_type->ldt_name,
+                  LUSTRE_OSD_ZFS_NAME) != 0) {
+               CERROR("%s: "DFID" is used on ldiskfs?!\n",
+                      mdd2obd_dev(mdd)->obd_name, PFID(&mdd->mdd_root_fid));
+               RETURN(-ENOTSUPP);
+       }
+
+       LCONSOLE_INFO("%s: FID of /ROOT has been changed. "
+                     "Please remount the clients.\n",
+                     mdd2obd_dev(mdd)->obd_name);
+
+       /* Fill FLDB first */
+       rc = mdd_fill_fldb(env, mdd);
+       if (rc)
+               GOTO(out, rc);
+
+       /* remove ./.. from /ROOT */
+       rc = mdd_convert_remove_dots(env, mdd, root);
+       if (rc)
+               GOTO(out, rc);
+
+       /* go over the directory, fix all the objects */
+       rc = mdd_fix_children(env, mdd, o);
+       if (rc)
+               GOTO(out, rc);
+
+       /* Update LMA on /ROOT.  Done for simplicity in MDD, not in osd-zfs.
+        * Correct LMA will imply the whole directory has been coverted
+        * successfully, otherwise it will be retried on next mount. */
+       rc = mdd_convert_lma(env, mdd, root);
+
+out:
+       mdd_object_put(env, root);
+       RETURN(rc);
+}
index 06db993..55f2069 100644 (file)
@@ -1235,6 +1235,11 @@ static int mdd_prepare(const struct lu_env *env,
                               mdd2obd_dev(mdd)->obd_name, rc);
                        GOTO(out, rc);
                }
+
+               rc = mdd_compat_fixes(env, mdd);
+               if (rc)
+                       GOTO(out, rc);
+
        }
 
        rc = orph_index_init(env, mdd);
index c383d4f..9f5b6f3 100644 (file)
@@ -70,14 +70,6 @@ static inline int mdd_links_del(const struct lu_env *env,
                                const struct lu_fid *pfid,
                                const struct lu_name *lname,
                                struct thandle *handle);
-static int mdd_links_rename(const struct lu_env *env,
-                           struct mdd_object *mdd_obj,
-                           const struct lu_fid *oldpfid,
-                           const struct lu_name *oldlname,
-                           const struct lu_fid *newpfid,
-                           const struct lu_name *newlname,
-                           struct thandle *handle,
-                           int first, int check);
 
 static int
 __mdd_lookup_locked(const struct lu_env *env, struct md_object *pobj,
@@ -2537,7 +2529,7 @@ int mdd_links_read(const struct lu_env *env, struct mdd_object *mdd_obj,
                ldata->ml_buf = mdd_buf_alloc(env, rc);
                if (ldata->ml_buf->lb_buf == NULL)
                        return -ENOMEM;
-               rc = mdo_xattr_get(env, mdd_obj, ldata->ml_buf,
+               rc = mdo_xattr_get(env, mdd_obj, &LU_BUF_NULL,
                                   XATTR_NAME_LINK, capa);
        }
        if (rc < 0)
@@ -2779,14 +2771,14 @@ static int __mdd_links_del(const struct lu_env *env,
        return 0;
 }
 
-static int mdd_links_rename(const struct lu_env *env,
-                           struct mdd_object *mdd_obj,
-                           const struct lu_fid *oldpfid,
-                           const struct lu_name *oldlname,
-                           const struct lu_fid *newpfid,
-                           const struct lu_name *newlname,
-                           struct thandle *handle,
-                           int first, int check)
+int mdd_links_rename(const struct lu_env *env,
+                    struct mdd_object *mdd_obj,
+                    const struct lu_fid *oldpfid,
+                    const struct lu_name *oldlname,
+                    const struct lu_fid *newpfid,
+                    const struct lu_name *newlname,
+                    struct thandle *handle,
+                    int first, int check)
 {
        struct mdd_link_data ldata = { 0 };
        int updated = 0;
index d72737d..9739ab2 100644 (file)
@@ -101,7 +101,7 @@ struct mdd_device {
        struct obd_export               *mdd_child_exp;
         struct dt_device                *mdd_child;
        struct dt_device                *mdd_bottom;
-        struct lu_fid                    mdd_root_fid;
+       struct lu_fid                    mdd_root_fid; /* /ROOT */
        struct lu_fid                    mdd_local_root_fid;
         struct dt_device_param           mdd_dt_conf;
         struct dt_object                *mdd_orphans; /* PENDING directory */
@@ -331,6 +331,14 @@ struct lu_buf *mdd_links_get(const struct lu_env *env,
                              struct mdd_object *mdd_obj);
 void mdd_lee_unpack(const struct link_ea_entry *lee, int *reclen,
                     struct lu_name *lname, struct lu_fid *pfid);
+int mdd_links_rename(const struct lu_env *env,
+                    struct mdd_object *mdd_obj,
+                    const struct lu_fid *oldpfid,
+                    const struct lu_name *oldlname,
+                    const struct lu_fid *newpfid,
+                    const struct lu_name *newlname,
+                    struct thandle *handle,
+                    int first, int check);
 
 /* mdd_lov.c */
 int mdd_declare_unlink_log(const struct lu_env *env, struct mdd_object *obj,
@@ -479,6 +487,9 @@ int mdd_permission(const struct lu_env *env,
 int mdd_capa_get(const struct lu_env *env, struct md_object *obj,
                  struct lustre_capa *capa, int renewal);
 
+/* mdd_prepare.c */
+int mdd_compat_fixes(const struct lu_env *env, struct mdd_device *mdd);
+
 static inline int lu_device_is_mdd(struct lu_device *d)
 {
         return ergo(d != NULL && d->ld_ops != NULL, d->ld_ops == &mdd_lu_ops);
index 8a03298..22928c4 100644 (file)
@@ -569,6 +569,10 @@ static int osd_mount(const struct lu_env *env,
        if (rc)
                GOTO(err, rc);
 
+       rc = osd_convert_root_to_new_seq(env, o);
+       if (rc)
+               GOTO(err, rc);
+
        /* Use our own ZAP for inode accounting by default, this can be changed
         * via procfs to estimate the inode usage from the block usage */
        o->od_quota_iused_est = 0;
index 55759c3..ab89fa4 100644 (file)
@@ -421,6 +421,8 @@ int osd_fid_lookup(const struct lu_env *env,
 uint64_t osd_get_name_n_idx(const struct lu_env *env, struct osd_device *osd,
                            const struct lu_fid *fid, char *buf);
 int osd_options_init(void);
+int osd_convert_root_to_new_seq(const struct lu_env *env,
+                               struct osd_device *o);
 
 /* osd_index.c */
 int osd_index_try(const struct lu_env *env, struct dt_object *dt,
index c6fffbf..427bde0 100644 (file)
@@ -684,6 +684,107 @@ osd_oi_init_compat(const struct lu_env *env, struct osd_device *o)
        RETURN(rc);
 }
 
+static char *root2convert = "ROOT";
+/*
+ * due to DNE requirements we have to change sequence of /ROOT object
+ * so that it doesn't belong to the local sequence FID_SEQ_LOCAL_FILE
+ * but a normal sequence living on MDS#0
+ * this is the sole purpose of this function.
+ *
+ * This is only needed for pre-production 2.4 ZFS filesystems, and
+ * can be removed in the future.
+ */
+int osd_convert_root_to_new_seq(const struct lu_env *env,
+                                       struct osd_device *o)
+{
+       struct luz_direntry *lze = &osd_oti_get(env)->oti_zde;
+       char                *buf = osd_oti_get(env)->oti_str;
+       struct lu_fid        newfid;
+       uint64_t             zapid;
+       dmu_tx_t            *tx = NULL;
+       int                  rc;
+       ENTRY;
+
+       /* ignore OSTs */
+       if (strstr(o->od_svname, "MDT") == NULL)
+               RETURN(0);
+
+       /* lookup /ROOT */
+       rc = -zap_lookup(o->od_objset.os, o->od_root, root2convert, 8,
+                        sizeof(*lze) / 8, (void *)lze);
+       /* doesn't exist or let actual user to handle the error */
+       if (rc)
+               RETURN(0);
+
+       CDEBUG(D_OTHER, "%s: /ROOT -> "DFID" -> "LPU64"\n", o->od_svname,
+              PFID(&lze->lzd_fid), (long long int) lze->lzd_reg.zde_dnode);
+
+       /* already right one? */
+       if (fid_seq(&lze->lzd_fid) == FID_SEQ_ROOT)
+               return 0;
+
+       tx = dmu_tx_create(o->od_objset.os);
+       if (tx == NULL)
+               return -ENOMEM;
+
+       dmu_tx_hold_bonus(tx, o->od_root);
+
+       /* declare delete/insert of the name */
+       dmu_tx_hold_zap(tx, o->od_root, TRUE, root2convert);
+       dmu_tx_hold_zap(tx, o->od_root, FALSE, root2convert);
+
+       /* declare that we'll remove object from fid-dnode mapping */
+       zapid = osd_get_name_n_idx(env, o, &lze->lzd_fid, buf);
+       dmu_tx_hold_bonus(tx, zapid);
+       dmu_tx_hold_zap(tx, zapid, FALSE, buf);
+
+       /* declare that we'll add object to fid-dnode mapping */
+       newfid.f_seq = FID_SEQ_ROOT;
+       newfid.f_oid = 1;
+       newfid.f_ver = 0;
+       zapid = osd_get_name_n_idx(env, o, &newfid, buf);
+       dmu_tx_hold_bonus(tx, zapid);
+       dmu_tx_hold_zap(tx, zapid, TRUE, buf);
+
+       rc = -dmu_tx_assign(tx, TXG_WAIT);
+       if (rc)
+               GOTO(err, rc);
+
+       rc = -zap_remove(o->od_objset.os, o->od_root, root2convert, tx);
+       if (rc)
+               GOTO(err, rc);
+
+       /* remove from OI */
+       zapid = osd_get_name_n_idx(env, o, &lze->lzd_fid, buf);
+       rc = -zap_remove(o->od_objset.os, zapid, buf, tx);
+       if (rc)
+               GOTO(err, rc);
+
+       lze->lzd_fid = newfid;
+       rc = -zap_add(o->od_objset.os, o->od_root, root2convert,
+                     8, sizeof(*lze) / 8, (void *)lze, tx);
+       if (rc)
+               GOTO(err, rc);
+
+       /* add to OI with the new fid */
+       zapid = osd_get_name_n_idx(env, o, &newfid, buf);
+       rc = -zap_add(o->od_objset.os, zapid, buf, 8, 1, &lze->lzd_reg, tx);
+       if (rc)
+               GOTO(err, rc);
+
+
+       /* LMA will be updated in mdd_compat_fixes */
+       dmu_tx_commit(tx);
+
+       RETURN(rc);
+
+err:
+       if (tx)
+               dmu_tx_abort(tx);
+       CERROR("%s: can't convert to new fid: rc = %d\n", o->od_svname, rc);
+       RETURN(rc);
+}
+
 /**
  * Initialize the OIs by either opening or creating them as needed.
  */