Whamcloud - gitweb
b=17187
authorkalpak <kalpak>
Tue, 3 Feb 2009 19:17:29 +0000 (19:17 +0000)
committerkalpak <kalpak>
Tue, 3 Feb 2009 19:17:29 +0000 (19:17 +0000)
i=nikita
i=nathan

open file using fid

lustre/ChangeLog
lustre/fid/fid_lib.c
lustre/fld/fld_handler.c
lustre/include/lustre/lustre_idl.h
lustre/include/lustre_fid.h
lustre/mdd/mdd_device.c
lustre/mdd/mdd_internal.h
lustre/mdd/mdd_object.c
lustre/tests/sanity.sh

index 171283c..8a7efd9 100644 (file)
@@ -1948,6 +1948,12 @@ Details    : While using HA for Lustre servers with Linux RAID, it is possible
              written. Also while reading the MMP block, we should read it from
              disk and not the cached one.
 
+Severity   : enhancement
+Bugzilla   : 17187
+Description: open file using fid
+Details    : A file can be opened using just its fid, like
+            <mntpt>/.lustre/fid/SEQ:OID:VER - this is needed for HSM and replication
+
 --------------------------------------------------------------------------------
 
 2007-08-10         Cluster File Systems, Inc. <info@clusterfs.com>
index 76e779a..ab6422c 100644 (file)
@@ -70,6 +70,7 @@
  *
  * The first 0x400 sequences of normal FID are reserved for special purpose.
  * FID_SEQ_START + 1 is for local file id generation.
+ * FID_SEQ_START + 2 is for .lustre directory and its objects
  */
 const struct lu_seq_range LUSTRE_SEQ_SPACE_RANGE = {
         FID_SEQ_START + 0x400ULL,
@@ -89,3 +90,15 @@ const struct lu_fid LUSTRE_BFL_FID = { .f_seq = 0x0000000000000003,
                                        .f_oid = 0x0000000000000001,
                                        .f_ver = 0x0000000000000000 };
 EXPORT_SYMBOL(LUSTRE_BFL_FID);
+
+/** Special fid for ".lustre" directory */
+const struct lu_fid LU_DOT_LUSTRE_FID = { .f_seq = LU_DOT_LUSTRE_SEQ,
+                                          .f_oid = 0x0000000000000001,
+                                          .f_ver = 0x0000000000000000 };
+EXPORT_SYMBOL(LU_DOT_LUSTRE_FID);
+
+/** Special fid for "fid" special object in .lustre */
+const struct lu_fid LU_OBF_FID = { .f_seq = LU_DOT_LUSTRE_SEQ,
+                                   .f_oid = 0x0000000000000002,
+                                   .f_ver = 0x0000000000000000 };
+EXPORT_SYMBOL(LU_OBF_FID);
index 2b6ab12..5092ac1 100644 (file)
@@ -67,6 +67,7 @@
 #include <lustre_fid.h>
 #include <lustre_req_layout.h>
 #include "fld_internal.h"
+#include <lustre_fid.h>
 
 #ifdef __KERNEL__
 
@@ -466,6 +467,7 @@ int fld_server_init(struct lu_server_fld *fld, struct dt_device *dt,
                     int mds_node_id)
 {
         int cache_size, cache_threshold;
+        struct lu_seq_range range;
         int rc;
         ENTRY;
 
@@ -499,6 +501,13 @@ int fld_server_init(struct lu_server_fld *fld, struct dt_device *dt,
                 GOTO(out, rc);
 
         fld->lsf_control_exp = NULL;
+
+        /* Insert reserved sequence number of ".lustre" into fld cache. */
+        range.lsr_start = LU_DOT_LUSTRE_SEQ;
+        range.lsr_end = LU_DOT_LUSTRE_SEQ + 1;
+        range.lsr_mdt = 0;
+        fld_cache_insert(fld->lsf_cache, &range);
+
         EXIT;
 out:
         if (rc)
index 19f63d5..76327b2 100644 (file)
@@ -372,6 +372,7 @@ static inline __u32 lu_igif_gen(const struct lu_fid *fid)
 }
 
 #define DFID "["LPX64":0x%x:0x%x]"
+#define SFID "0x%llx:0x%x:0x%x"
 
 #define PFID(fid)     \
         fid_seq(fid), \
index 7c8085f..921b423 100644 (file)
@@ -57,6 +57,8 @@ struct lu_context;
 extern const struct lu_seq_range LUSTRE_SEQ_SPACE_RANGE;
 extern const struct lu_seq_range LUSTRE_SEQ_ZERO_RANGE;
 extern const struct lu_fid LUSTRE_BFL_FID;
+extern const struct lu_fid LU_OBF_FID;
+extern const struct lu_fid LU_DOT_LUSTRE_FID;
 
 enum {
         /*
@@ -82,6 +84,9 @@ enum {
 /** special fid seq: used for local object create. */
 #define FID_SEQ_LOCAL_FILE      (FID_SEQ_START + 1)
 
+/** special fid seq: used for .lustre objects. */
+#define LU_DOT_LUSTRE_SEQ       (FID_SEQ_START + 0x02ULL)
+
 /** special OID for local objects */
 enum {
         /** \see osd_oi_index_create */
index e9bfcfc..07924a0 100644 (file)
 #include <lustre/lustre_idl.h>
 #include <lustre_disk.h>      /* for changelogs */
 #include <lustre_param.h>
+#include <lustre_fid.h>
 
 #include "mdd_internal.h"
 
 const struct md_device_operations mdd_ops;
+static struct lu_device_type mdd_device_type;
 
 static const char mdd_root_dir_name[] = "ROOT";
+static const char mdd_obf_dir_name[] = "fid";
+static const char mdd_dot_lustre_name[] = ".lustre";
 
 static int mdd_device_init(const struct lu_env *env, struct lu_device *d,
                            const char *name, struct lu_device *next)
@@ -112,6 +116,8 @@ static void mdd_device_shutdown(const struct lu_env *env,
         ENTRY;
         mdd_changelog_fini(env, m);
         dt_txn_callback_del(m->mdd_child, &m->mdd_txn_cb);
+        mdd_object_put(env, m->mdd_dot_lustre_objs.mdd_obf);
+        mdd_object_put(env, m->mdd_dot_lustre);
         if (m->mdd_obd_dev)
                 mdd_fini_obd(env, m, cfg);
         orph_index_fini(env, m);
@@ -300,6 +306,369 @@ int mdd_changelog_write_header(struct mdd_device *mdd, int markerflags)
         RETURN(rc);
 }
 
+/**
+ * Create ".lustre" directory.
+ */
+static int create_dot_lustre_dir(const struct lu_env *env, struct mdd_device *m)
+{
+        struct lu_fid *fid = &mdd_env_info(env)->mti_fid;
+        struct md_object *mdo;
+        int rc;
+
+        memcpy(fid, &LU_DOT_LUSTRE_FID, sizeof(struct lu_fid));
+        mdo = llo_store_create_index(env, &m->mdd_md_dev, m->mdd_child,
+                                     mdd_root_dir_name, mdd_dot_lustre_name,
+                                     fid, &dt_directory_features);
+        /* .lustre dir may be already present */
+        if (IS_ERR(mdo) && PTR_ERR(mdo) != -EEXIST) {
+                rc = PTR_ERR(mdo);
+                CERROR("creating obj [%s] fid = "DFID" rc = %d\n",
+                        mdd_dot_lustre_name, PFID(fid), rc);
+                RETURN(rc);
+        }
+
+        return 0;
+}
+
+static int dot_lustre_attr_get(const struct lu_env *env, struct md_object *obj,
+                               struct md_attr *ma)
+{
+        struct mdd_object *mdd_obj = md2mdd_obj(obj);
+
+        return mdd_attr_get_internal_locked(env, mdd_obj, ma);
+}
+
+static int dot_lustre_attr_set(const struct lu_env *env, struct md_object *obj,
+                               const struct md_attr *ma)
+{
+        return -EPERM;
+}
+
+static int dot_lustre_xattr_get(const struct lu_env *env,
+                                struct md_object *obj, struct lu_buf *buf,
+                                const char *name)
+{
+        return 0;
+}
+
+/**
+ * Direct access to the ".lustre" directory is not allowed.
+ */
+static int dot_lustre_mdd_open(const struct lu_env *env, struct md_object *obj,
+                               int flags)
+{
+        return -EPERM;
+}
+
+static int dot_lustre_path(const struct lu_env *env, struct md_object *obj,
+                           char *path, int pathlen, __u64 recno, int *linkno)
+{
+        return -ENOSYS;
+}
+
+static struct md_object_operations mdd_dot_lustre_obj_ops = {
+        .moo_attr_get   = dot_lustre_attr_get,
+        .moo_attr_set   = dot_lustre_attr_set,
+        .moo_xattr_get  = dot_lustre_xattr_get,
+        .moo_open       = dot_lustre_mdd_open,
+        .moo_path       = dot_lustre_path
+};
+
+static int dot_lustre_lookup(const struct lu_env *env, struct md_object *p,
+                             const struct lu_name *lname, struct lu_fid *f,
+                             struct md_op_spec *spec)
+{
+        if (strcmp(lname->ln_name, mdd_obf_dir_name) == 0)
+                *f = LU_OBF_FID;
+        else
+                return -ENOENT;
+
+        return 0;
+}
+
+static int dot_lustre_create(const struct lu_env *env, struct md_object *pobj,
+                             const struct lu_name *lname,
+                             struct md_object *child, struct md_op_spec *spec,
+                             struct md_attr* ma)
+{
+        return -EPERM;
+}
+
+static int dot_lustre_rename(const struct lu_env *env,
+                             struct md_object *src_pobj,
+                             struct md_object *tgt_pobj,
+                             const struct lu_fid *lf,
+                             const struct lu_name *lsname,
+                             struct md_object *tobj,
+                             const struct lu_name *ltname, struct md_attr *ma)
+{
+        return -EPERM;
+}
+
+static int dot_lustre_link(const struct lu_env *env, struct md_object *tgt_obj,
+                           struct md_object *src_obj,
+                           const struct lu_name *lname, struct md_attr *ma)
+{
+        return -EPERM;
+}
+
+static int dot_lustre_unlink(const struct lu_env *env, struct md_object *pobj,
+                             struct md_object *cobj, const struct lu_name *lname,
+                             struct md_attr *ma)
+{
+        return -EPERM;
+}
+
+static struct md_dir_operations mdd_dot_lustre_dir_ops = {
+        .mdo_lookup = dot_lustre_lookup,
+        .mdo_create = dot_lustre_create,
+        .mdo_rename = dot_lustre_rename,
+        .mdo_link   = dot_lustre_link,
+        .mdo_unlink = dot_lustre_unlink,
+};
+
+static int obf_attr_get(const struct lu_env *env, struct md_object *obj,
+                        struct md_attr *ma)
+{
+        int rc = 0;
+
+        if (ma->ma_need & MA_INODE) {
+                struct mdd_device *mdd = mdo2mdd(obj);
+
+                /* "fid" is a virtual object and hence does not have any "real"
+                 * attributes. So we reuse attributes of .lustre for "fid" dir */
+                ma->ma_need |= MA_INODE;
+                rc = dot_lustre_attr_get(env, &mdd->mdd_dot_lustre->mod_obj, ma);
+                if (rc)
+                        return rc;
+                ma->ma_valid |= MA_INODE;
+        }
+
+        /* "fid" directory does not have any striping information. */
+        if (ma->ma_need & MA_LOV) {
+                struct mdd_object *mdd_obj = md2mdd_obj(obj);
+
+                if (ma->ma_valid & MA_LOV)
+                        return 0;
+
+                if (!(S_ISREG(mdd_object_type(mdd_obj)) ||
+                      S_ISDIR(mdd_object_type(mdd_obj))))
+                        return 0;
+
+                if (ma->ma_need & MA_LOV_DEF) {
+                        rc = mdd_get_default_md(mdd_obj, ma->ma_lmm,
+                                        &ma->ma_lmm_size);
+                        if (rc > 0) {
+                                ma->ma_valid |= MA_LOV;
+                                rc = 0;
+                        }
+                }
+        }
+
+        return rc;
+}
+
+static int obf_attr_set(const struct lu_env *env, struct md_object *obj,
+                        const struct md_attr *ma)
+{
+        return -EPERM;
+}
+
+static int obf_xattr_get(const struct lu_env *env,
+                         struct md_object *obj, struct lu_buf *buf,
+                         const char *name)
+{
+        return 0;
+}
+
+static int obf_mdd_open(const struct lu_env *env, struct md_object *obj,
+                        int flags)
+{
+        struct mdd_object *mdd_obj = md2mdd_obj(obj);
+
+        mdd_write_lock(env, mdd_obj, MOR_TGT_CHILD);
+        mdd_obj->mod_count++;
+        mdd_write_unlock(env, mdd_obj);
+
+        return 0;
+}
+
+static int obf_mdd_close(const struct lu_env *env, struct md_object *obj,
+                         struct md_attr *ma)
+{
+        struct mdd_object *mdd_obj = md2mdd_obj(obj);
+
+        mdd_write_lock(env, mdd_obj, MOR_TGT_CHILD);
+        mdd_obj->mod_count--;
+        mdd_write_unlock(env, mdd_obj);
+
+        return 0;
+}
+
+/** Nothing to list in "fid" directory */
+static int obf_mdd_readpage(const struct lu_env *env, struct md_object *obj,
+                            const struct lu_rdpg *rdpg)
+{
+        return -EPERM;
+}
+
+static int obf_path(const struct lu_env *env, struct md_object *obj,
+                    char *path, int pathlen, __u64 recno, int *linkno)
+{
+        return -ENOSYS;
+}
+
+static struct md_object_operations mdd_obf_obj_ops = {
+        .moo_attr_get   = obf_attr_get,
+        .moo_attr_set   = obf_attr_set,
+        .moo_xattr_get  = obf_xattr_get,
+        .moo_open       = obf_mdd_open,
+        .moo_close      = obf_mdd_close,
+        .moo_readpage   = obf_mdd_readpage,
+        .moo_path       = obf_path
+};
+
+/**
+ * Lookup method for "fid" object. Only filenames with correct SEQ:OID format
+ * are valid. We also check if object with passed fid exists or not.
+ */
+static int obf_lookup(const struct lu_env *env, struct md_object *p,
+                      const struct lu_name *lname, struct lu_fid *f,
+                      struct md_op_spec *spec)
+{
+        char *name = (char *)lname->ln_name;
+        struct mdd_device *mdd = mdo2mdd(p);
+        struct mdd_object *child;
+        int rc = 0;
+
+        while (*name == '[')
+                name++;
+
+        sscanf(name, SFID, &(f->f_seq), &(f->f_oid),
+               &(f->f_ver));
+        if (!fid_is_sane(f)) {
+                CWARN("bad FID format [%s], should be "DFID"\n", lname->ln_name,
+                      (__u64)1, 2, 0);
+                GOTO(out, rc = -EINVAL);
+        }
+
+        /* Check if object with this fid exists */
+        child = mdd_object_find(env, mdd, f);
+        if (child == NULL)
+                GOTO(out, rc = 0);
+        if (IS_ERR(child))
+                GOTO(out, rc = PTR_ERR(child));
+
+        if (mdd_object_exists(child) == 0)
+                rc = -ENOENT;
+
+        mdd_object_put(env, child);
+
+out:
+        return rc;
+}
+
+static int obf_create(const struct lu_env *env, struct md_object *pobj,
+                      const struct lu_name *lname, struct md_object *child,
+                      struct md_op_spec *spec, struct md_attr* ma)
+{
+        return -EPERM;
+}
+
+static int obf_rename(const struct lu_env *env,
+                      struct md_object *src_pobj, struct md_object *tgt_pobj,
+                      const struct lu_fid *lf, const struct lu_name *lsname,
+                      struct md_object *tobj, const struct lu_name *ltname,
+                      struct md_attr *ma)
+{
+        return -EPERM;
+}
+
+static int obf_link(const struct lu_env *env, struct md_object *tgt_obj,
+                    struct md_object *src_obj, const struct lu_name *lname,
+                    struct md_attr *ma)
+{
+        return -EPERM;
+}
+
+static int obf_unlink(const struct lu_env *env, struct md_object *pobj,
+                      struct md_object *cobj, const struct lu_name *lname,
+                      struct md_attr *ma)
+{
+        return -EPERM;
+}
+
+static struct md_dir_operations mdd_obf_dir_ops = {
+        .mdo_lookup = obf_lookup,
+        .mdo_create = obf_create,
+        .mdo_rename = obf_rename,
+        .mdo_link   = obf_link,
+        .mdo_unlink = obf_unlink
+};
+
+/**
+ * Create special in-memory "fid" object for open-by-fid.
+ */
+static int mdd_obf_setup(const struct lu_env *env, struct mdd_device *m)
+{
+        struct mdd_object *mdd_obf;
+        struct lu_object *obf_lu_obj;
+        int rc = 0;
+
+        m->mdd_dot_lustre_objs.mdd_obf = mdd_object_find(env, m,
+                                                         &LU_OBF_FID);
+        if (m->mdd_dot_lustre_objs.mdd_obf == NULL ||
+            IS_ERR(m->mdd_dot_lustre_objs.mdd_obf))
+                GOTO(out, rc = -ENOENT);
+
+        mdd_obf = m->mdd_dot_lustre_objs.mdd_obf;
+        mdd_obf->mod_obj.mo_dir_ops = &mdd_obf_dir_ops;
+        mdd_obf->mod_obj.mo_ops = &mdd_obf_obj_ops;
+        /* Don't allow objects to be created in "fid" dir */
+        mdd_obf->mod_flags |= IMMUTE_OBJ;
+
+        obf_lu_obj = mdd2lu_obj(mdd_obf);
+        obf_lu_obj->lo_header->loh_attr |= (LOHA_EXISTS | S_IFDIR);
+
+out:
+        return rc;
+}
+
+/** Setup ".lustre" directory object */
+static int mdd_dot_lustre_setup(const struct lu_env *env, struct mdd_device *m)
+{
+        struct dt_object *dt_dot_lustre;
+        struct lu_fid *fid = &mdd_env_info(env)->mti_fid;
+        int rc;
+
+        rc = create_dot_lustre_dir(env, m);
+        if (rc)
+                return rc;
+
+        dt_dot_lustre = dt_store_open(env, m->mdd_child, mdd_root_dir_name,
+                                      mdd_dot_lustre_name, fid);
+        if (IS_ERR(dt_dot_lustre)) {
+                rc = PTR_ERR(dt_dot_lustre);
+                GOTO(out, rc);
+        }
+
+        /* references are released in mdd_device_shutdown() */
+        m->mdd_dot_lustre = lu2mdd_obj(lu_object_locate(dt_dot_lustre->do_lu.lo_header,
+                                                        &mdd_device_type));
+
+        lu_object_put(env, &dt_dot_lustre->do_lu);
+
+        m->mdd_dot_lustre->mod_obj.mo_dir_ops = &mdd_dot_lustre_dir_ops;
+        m->mdd_dot_lustre->mod_obj.mo_ops = &mdd_dot_lustre_obj_ops;
+
+        rc = mdd_obf_setup(env, m);
+        if (rc)
+                CERROR("Error initializing \"fid\" object - %d.\n", rc);
+
+out:
+        RETURN(rc);
+}
+
 static int mdd_process_config(const struct lu_env *env,
                               struct lu_device *d, struct lustre_cfg *cfg)
 {
@@ -435,8 +804,17 @@ static int mdd_prepare(const struct lu_env *env,
                 LASSERT(root != NULL);
                 lu_object_put(env, &root->do_lu);
                 rc = orph_index_init(env, mdd);
-        } else
+        } else {
                 rc = PTR_ERR(root);
+        }
+        if (rc)
+                GOTO(out, rc);
+
+        rc = mdd_dot_lustre_setup(env, mdd);
+        if (rc) {
+                CERROR("Error(%d) initializing .lustre objects\n", rc);
+                GOTO(out, rc);
+        }
 
 out:
         RETURN(rc);
index c855f80..0d66a68 100644 (file)
@@ -110,6 +110,11 @@ struct mdd_changelog {
         __u64                            mc_starttime;
 };
 
+/** Objects in .lustre dir */
+struct mdd_dot_lustre_objs {
+        struct mdd_object *mdd_obf;
+};
+
 struct mdd_device {
         struct md_device                 mdd_md_dev;
         struct dt_device                *mdd_child;
@@ -123,6 +128,8 @@ struct mdd_device {
         struct mdd_txn_op_descr          mdd_tod[MDD_TXN_LAST_OP];
         struct mdd_changelog             mdd_cl;
         unsigned long                    mdd_atime_diff;
+        struct mdd_object               *mdd_dot_lustre;
+        struct mdd_dot_lustre_objs       mdd_dot_lustre_objs;
 };
 
 enum mod_flags {
@@ -362,6 +369,8 @@ extern const struct lu_device_operations mdd_lu_ops;
 struct mdd_object *mdd_object_find(const struct lu_env *env,
                                    struct mdd_device *d,
                                    const struct lu_fid *f);
+int mdd_get_default_md(struct mdd_object *mdd_obj, struct lov_mds_md *lmm,
+                       int *size);
 
 /* mdd_quota.c*/
 #ifdef HAVE_QUOTA_SUPPORT
index 0cf918a..9d0dbc1 100644 (file)
@@ -582,8 +582,8 @@ int mdd_iattr_get(const struct lu_env *env, struct mdd_object *mdd_obj,
         RETURN(rc);
 }
 
-static int mdd_get_default_md(struct mdd_object *mdd_obj,
-                struct lov_mds_md *lmm, int *size)
+int mdd_get_default_md(struct mdd_object *mdd_obj, struct lov_mds_md *lmm,
+                       int *size)
 {
         struct lov_desc *ldesc;
         struct mdd_device *mdd = mdo2mdd(&mdd_obj->mod_obj);
index 348fe13..568620d 100644 (file)
@@ -5948,6 +5948,19 @@ err17935 () {
     fi
 }
 
+test_154() {
+       cp /etc/hosts $DIR/$tfile
+
+       fid=`$LFS path2fid $DIR/$tfile`
+       rc=$?
+       [ $rc -ne 0 ] && error "error: could not get fid for $DIR/$tfile."
+
+       diff $DIR/$tfile $DIR/.lustre/fid/$fid || error "open by fid failed: did not find expected data in file."
+
+       echo "Opening a file by FID succeeded"
+}
+run_test 154 "Opening a file by FID"
+
 #Changelogs
 test_160() {
     remote_mds && skip "remote MDS" && return