/* * 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 (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. * Use is subject to license terms. * * Copyright (c) 2012, Intel Corporation. */ /* * 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 */ #define DEBUG_SUBSYSTEM S_CLASS #include #include #include #include #include #include /** List head to hold list of objects to be created. */ static cfs_list_t 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_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 = 0; spec->sp_cr_mode = 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 * * \retval rc returns error code for lookup or locate operation * * pointer to object is returned in data (lfh->lfh_pobj) */ 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; 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 = lfh->lfh_pobj; } } 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; if (feat == &dt_directory_features) la->la_mode = S_IFDIR | S_IXUGO; 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 dirname 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 dirname 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. * objects are created in order of registration. */ void llo_local_obj_register(struct lu_local_obj_desc *llod) { mutex_lock(&llo_lock); cfs_list_add_tail(&llod->llod_linkage, &llo_lobj_list); mutex_unlock(&llo_lock); } EXPORT_SYMBOL(llo_local_obj_register); void llo_local_obj_unregister(struct lu_local_obj_desc *llod) { mutex_lock(&llo_lock); cfs_list_del(&llod->llod_linkage); mutex_unlock(&llo_lock); } EXPORT_SYMBOL(llo_local_obj_unregister); /** * 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; const char *dir; int rc = 0; fid = &info->lti_cfid; mutex_lock(&llo_lock); cfs_list_for_each_entry(scan, &llo_lobj_list, llod_linkage) { lu_local_obj_fid(fid, scan->llod_oid); dir = ""; if (scan->llod_dir) dir = scan->llod_dir; if (scan->llod_is_index) mdo = llo_store_create_index(env, md, dt , dir, scan->llod_name, fid, scan->llod_feat); else mdo = llo_store_create(env, md, dt, dir, 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); LASSERT(cfs_list_empty(&llo_lobj_list)); }