+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ * 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 LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; If not, see
+ * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ * GPL HEADER END
+ */
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved
+ * Use is subject to license terms.
+ */
+/*
+ * This file is part of Lustre, http://www.lustre.org/
+ * Lustre is a trademark of Sun Microsystems, Inc.
+ *
+ * lustre/obdclass/md_local_object.c
+ *
+ * Lustre Local Object create APIs
+ * 'create on first mount' facility. Files registed under llo module will
+ * be created on first mount.
+ *
+ * Author: Pravin Shelar <pravin.shelar@sun.com>
+ */
+
+#define DEBUG_SUBSYSTEM S_CLASS
+#ifndef EXPORT_SYMTAB
+# define EXPORT_SYMTAB
+#endif
+
+#include <obd_support.h>
+#include <lustre_disk.h>
+#include <lustre_fid.h>
+#include <lu_object.h>
+#include <libcfs/list.h>
+#include <md_object.h>
+
+
+/** List head to hold list of objects to be created. */
+static struct list_head llo_lobj_list;
+
+/** Lock to protect list manipulations */
+static struct mutex llo_lock;
+
+/**
+ * Structure used to maintain state of path parsing.
+ * \see llo_find_entry, llo_store_resolve
+ */
+struct llo_find_hint {
+ struct lu_fid *lfh_cfid;
+ struct md_device *lfh_md;
+ struct md_object *lfh_pobj;
+};
+
+/**
+ * Thread Local storage for this module.
+ */
+struct llo_thread_info {
+ /** buffer to resolve path */
+ char lti_buf[DT_MAX_PATH];
+ /** used for path resolve */
+ struct lu_fid lti_fid;
+ /** used to pass child object fid */
+ struct lu_fid lti_cfid;
+ struct llo_find_hint lti_lfh;
+ struct md_op_spec lti_spc;
+ struct md_attr lti_ma;
+ struct lu_name lti_lname;
+};
+
+LU_KEY_INIT(llod_global, struct llo_thread_info);
+LU_KEY_FINI(llod_global, struct llo_thread_info);
+
+static struct lu_context_key llod_key = {
+ .lct_tags = LCT_MD_THREAD | LCT_DT_THREAD,
+ .lct_init = llod_global_key_init,
+ .lct_fini = llod_global_key_fini
+};
+
+static inline struct llo_thread_info * llo_env_info(const struct lu_env *env)
+{
+ return lu_context_key_get(&env->le_ctx, &llod_key);
+}
+
+/**
+ * Search md object for given fid.
+ */
+static struct md_object *llo_locate(const struct lu_env *env,
+ struct md_device *md,
+ const struct lu_fid *fid)
+{
+ struct lu_object *obj;
+ struct md_object *mdo;
+
+ obj = lu_object_find(env, &md->md_lu_dev, fid, NULL);
+ if (!IS_ERR(obj)) {
+ obj = lu_object_locate(obj->lo_header, md->md_lu_dev.ld_type);
+ LASSERT(obj != NULL);
+ mdo = (struct md_object *) obj;
+ } else
+ mdo = (struct md_object *)obj;
+ return mdo;
+}
+
+/**
+ * Lookup FID for object named \a name in directory \a pobj.
+ */
+static int llo_lookup(const struct lu_env *env,
+ struct md_object *pobj,
+ const char *name,
+ struct lu_fid *fid)
+{
+ struct llo_thread_info *info = llo_env_info(env);
+ struct lu_name *lname = &info->lti_lname;
+ struct md_op_spec *spec = &info->lti_spc;
+
+ spec->sp_feat = NULL;
+ spec->sp_cr_flags = 0;
+ spec->sp_cr_lookup = 1;
+ spec->sp_cr_mode = 0;
+ spec->sp_ck_split = 0;
+
+ lname->ln_name = name;
+ lname->ln_namelen = strlen(name);
+
+ return mdo_lookup(env, pobj, lname, fid, spec);
+}
+
+/**
+ * Function to look up path component, this is passed to parsing
+ * function. \see llo_store_resolve
+ */
+static int llo_find_entry(const struct lu_env *env,
+ const char *name, void *data)
+{
+ struct llo_find_hint *lfh = data;
+ struct md_device *md = lfh->lfh_md;
+ struct lu_fid *fid = lfh->lfh_cfid;
+ struct md_object *obj = lfh->lfh_pobj;
+ int result;
+
+ /* lookup fid for object */
+ result = llo_lookup(env, obj, name, fid);
+ lu_object_put(env, &obj->mo_lu);
+
+ if (result == 0) {
+ /* get md object for fid that we got in lookup */
+ obj = llo_locate(env, md, fid);
+ if (IS_ERR(obj))
+ result = PTR_ERR(obj);
+ }
+
+ lfh->lfh_pobj = obj;
+ return result;
+}
+
+static struct md_object *llo_reg_open(const struct lu_env *env,
+ struct md_device *md,
+ struct md_object *p,
+ const char *name,
+ struct lu_fid *fid)
+{
+ struct md_object *o;
+ int result;
+
+ result = llo_lookup(env, p, name, fid);
+ if (result == 0)
+ o = llo_locate(env, md, fid);
+ else
+ o = ERR_PTR(result);
+
+ return o;
+}
+
+/**
+ * Resolve given \a path, on success function returns
+ * md object for last directory and \a fid points to
+ * its fid.
+ */
+struct md_object *llo_store_resolve(const struct lu_env *env,
+ struct md_device *md,
+ struct dt_device *dt,
+ const char *path,
+ struct lu_fid *fid)
+{
+ struct llo_thread_info *info = llo_env_info(env);
+ struct llo_find_hint *lfh = &info->lti_lfh;
+ char *local = info->lti_buf;
+ struct md_object *obj = lfh->lfh_pobj;
+ int result;
+
+ strncpy(local, path, DT_MAX_PATH);
+ local[DT_MAX_PATH - 1] = '\0';
+
+ lfh->lfh_md = md;
+ lfh->lfh_cfid = fid;
+ /* start path resolution from backend fs root. */
+ result = dt->dd_ops->dt_root_get(env, dt, fid);
+ if (result == 0) {
+ /* get md object for root */
+ obj = llo_locate(env, md, fid);
+ if (!IS_ERR(obj)) {
+ /* start path parser from root md */
+ lfh->lfh_pobj = obj;
+ result = dt_path_parser(env, local, llo_find_entry, lfh);
+ if (result != 0)
+ obj = ERR_PTR(result);
+ }
+ } else {
+ obj = ERR_PTR(result);
+ }
+ return obj;
+}
+EXPORT_SYMBOL(llo_store_resolve);
+
+/**
+ * Returns md object for \a objname in given \a dirname.
+ */
+struct md_object *llo_store_open(const struct lu_env *env,
+ struct md_device *md,
+ struct dt_device *dt,
+ const char *dirname,
+ const char *objname,
+ struct lu_fid *fid)
+{
+ struct md_object *obj;
+ struct md_object *dir;
+
+ /* search md object for parent dir */
+ dir = llo_store_resolve(env, md, dt, dirname, fid);
+ if (!IS_ERR(dir)) {
+ obj = llo_reg_open(env, md, dir, objname, fid);
+ lu_object_put(env, &dir->mo_lu);
+ } else
+ obj = dir;
+
+ return obj;
+}
+EXPORT_SYMBOL(llo_store_open);
+
+static struct md_object *llo_create_obj(const struct lu_env *env,
+ struct md_device *md,
+ struct md_object *dir,
+ const char *objname,
+ const struct lu_fid *fid,
+ const struct dt_index_features *feat)
+{
+ struct llo_thread_info *info = llo_env_info(env);
+ struct md_object *mdo;
+ struct md_attr *ma = &info->lti_ma;
+ struct md_op_spec *spec = &info->lti_spc;
+ struct lu_name *lname = &info->lti_lname;
+ struct lu_attr *la = &ma->ma_attr;
+ int rc;
+
+ mdo = llo_locate(env, md, fid);
+ if (IS_ERR(mdo))
+ return mdo;
+
+ lname->ln_name = objname;
+ lname->ln_namelen = strlen(objname);
+
+ spec->sp_feat = feat;
+ spec->sp_cr_flags = 0;
+ spec->sp_cr_lookup = 1;
+ spec->sp_cr_mode = 0;
+ spec->sp_ck_split = 0;
+
+ if (feat == &dt_directory_features)
+ la->la_mode = S_IFDIR;
+ else
+ la->la_mode = S_IFREG;
+
+ la->la_mode |= S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
+ la->la_uid = la->la_gid = 0;
+ la->la_valid = LA_MODE | LA_UID | LA_GID;
+
+ ma->ma_valid = 0;
+ ma->ma_need = 0;
+
+ rc = mdo_create(env, dir, lname, mdo, spec, ma);
+
+ if (rc) {
+ lu_object_put(env, &mdo->mo_lu);
+ mdo = ERR_PTR(rc);
+ }
+
+ return mdo;
+}
+
+/**
+ * Create md object, object could be diretcory or
+ * special index defined by \a feat in \a directory.
+ *
+ * \param md device
+ * \param dir parent directory
+ * \param objname file name
+ * \param fid object fid
+ * \param feat index features required for directory create
+ */
+
+struct md_object *llo_store_create_index(const struct lu_env *env,
+ struct md_device *md,
+ struct dt_device *dt,
+ const char *dirname,
+ const char *objname,
+ const struct lu_fid *fid,
+ const struct dt_index_features *feat)
+{
+ struct llo_thread_info *info = llo_env_info(env);
+ struct md_object *obj;
+ struct md_object *dir;
+ struct lu_fid *ignore = &info->lti_fid;
+
+ dir = llo_store_resolve(env, md, dt, dirname, ignore);
+ if (!IS_ERR(dir)) {
+ obj = llo_create_obj(env, md, dir, objname, fid, feat);
+ lu_object_put(env, &dir->mo_lu);
+ } else {
+ obj = dir;
+ }
+ return obj;
+}
+
+EXPORT_SYMBOL(llo_store_create_index);
+
+/**
+ * Create md object for regular file in \a directory.
+ *
+ * \param md device
+ * \param dir parent directory
+ * \param objname file name
+ * \param fid object fid.
+ */
+
+struct md_object *llo_store_create(const struct lu_env *env,
+ struct md_device *md,
+ struct dt_device *dt,
+ const char *dirname,
+ const char *objname,
+ const struct lu_fid *fid)
+{
+ return llo_store_create_index(env, md, dt, dirname,
+ objname, fid, NULL);
+}
+
+EXPORT_SYMBOL(llo_store_create);
+
+/**
+ * Register object for 'create on first mount' facility.
+ */
+
+int llo_local_obj_register(struct lu_local_obj_desc *llod)
+{
+ mutex_lock(&llo_lock);
+ list_add(&llod->llod_linkage, &llo_lobj_list);
+ mutex_unlock(&llo_lock);
+
+ return 0;
+}
+
+EXPORT_SYMBOL(llo_local_obj_register);
+
+/**
+ * Created registed objects.
+ */
+
+int llo_local_objects_setup(const struct lu_env *env,
+ struct md_device * md,
+ struct dt_device *dt)
+{
+ struct llo_thread_info *info = llo_env_info(env);
+ struct lu_fid *fid;
+ struct lu_local_obj_desc *scan;
+ struct md_object *mdo;
+ int rc = 0;
+
+ fid = &info->lti_cfid;
+
+ mutex_lock(&llo_lock);
+
+ list_for_each_entry(scan, &llo_lobj_list, llod_linkage) {
+
+ lu_local_obj_fid(fid, scan->llod_oid);
+
+ if (scan->llod_is_index)
+ mdo = llo_store_create_index(env, md, dt ,
+ "", scan->llod_name,
+ fid,
+ scan->llod_feat);
+ else
+ mdo = llo_store_create(env, md, dt,
+ "", scan->llod_name,
+ fid);
+ if (IS_ERR(mdo) && PTR_ERR(mdo) != -EEXIST) {
+ rc = PTR_ERR(mdo);
+ CERROR("creating obj [%s] fid = "DFID" rc = %d\n",
+ scan->llod_name, PFID(fid), rc);
+ goto out;
+ }
+
+ if (!IS_ERR(mdo))
+ lu_object_put(env, &mdo->mo_lu);
+ }
+
+out:
+ mutex_unlock(&llo_lock);
+ return rc;
+}
+
+EXPORT_SYMBOL(llo_local_objects_setup);
+
+int llo_global_init(void)
+{
+ int result;
+
+ CFS_INIT_LIST_HEAD(&llo_lobj_list);
+ mutex_init(&llo_lock);
+
+ LU_CONTEXT_KEY_INIT(&llod_key);
+ result = lu_context_key_register(&llod_key);
+ return result;
+}
+
+void llo_global_fini(void)
+{
+ lu_context_key_degister(&llod_key);
+}