diff options
Diffstat (limited to 'drivers/staging/lustre/lustre/llite/llite_lib.c')
-rw-r--r-- | drivers/staging/lustre/lustre/llite/llite_lib.c | 715 |
1 files changed, 599 insertions, 116 deletions
diff --git a/drivers/staging/lustre/lustre/llite/llite_lib.c b/drivers/staging/lustre/lustre/llite/llite_lib.c index 546063e728db..6bb41b09172e 100644 --- a/drivers/staging/lustre/lustre/llite/llite_lib.c +++ b/drivers/staging/lustre/lustre/llite/llite_lib.c @@ -41,7 +41,7 @@ #include <linux/types.h> #include <linux/mm.h> -#include "../include/lustre_lite.h" +#include "../include/lustre/lustre_ioctl.h" #include "../include/lustre_ha.h" #include "../include/lustre_dlm.h" #include "../include/lprocfs_status.h" @@ -115,9 +115,16 @@ static struct ll_sb_info *ll_init_sbi(struct super_block *sb) sbi->ll_sa_max = LL_SA_RPC_DEF; atomic_set(&sbi->ll_sa_total, 0); atomic_set(&sbi->ll_sa_wrong, 0); + atomic_set(&sbi->ll_sa_running, 0); atomic_set(&sbi->ll_agl_total, 0); sbi->ll_flags |= LL_SBI_AGL_ENABLED; + /* root squash */ + sbi->ll_squash.rsi_uid = 0; + sbi->ll_squash.rsi_gid = 0; + INIT_LIST_HEAD(&sbi->ll_squash.rsi_nosquash_nids); + init_rwsem(&sbi->ll_squash.rsi_sem); + sbi->ll_sb = sb; return sbi; @@ -128,6 +135,8 @@ static void ll_free_sbi(struct super_block *sb) struct ll_sb_info *sbi = ll_s2sbi(sb); if (sbi->ll_cache) { + if (!list_empty(&sbi->ll_squash.rsi_nosquash_nids)) + cfs_free_nidlist(&sbi->ll_squash.rsi_nosquash_nids); cl_cache_decref(sbi->ll_cache); sbi->ll_cache = NULL; } @@ -180,7 +189,9 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt, OBD_CONNECT_PINGLESS | OBD_CONNECT_MAX_EASIZE | OBD_CONNECT_FLOCK_DEAD | - OBD_CONNECT_DISP_STRIPE; + OBD_CONNECT_DISP_STRIPE | OBD_CONNECT_LFSCK | + OBD_CONNECT_OPEN_BY_FID | + OBD_CONNECT_DIR_STRIPE; if (sbi->ll_flags & LL_SBI_SOM_PREVIEW) data->ocd_connect_flags |= OBD_CONNECT_SOM; @@ -310,9 +321,9 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt, sbi->ll_flags |= LL_SBI_64BIT_HASH; if (data->ocd_connect_flags & OBD_CONNECT_BRW_SIZE) - sbi->ll_md_brw_size = data->ocd_brw_size; + sbi->ll_md_brw_pages = data->ocd_brw_size >> PAGE_SHIFT; else - sbi->ll_md_brw_size = PAGE_SIZE; + sbi->ll_md_brw_pages = 1; if (data->ocd_connect_flags & OBD_CONNECT_LAYOUTLOCK) sbi->ll_flags |= LL_SBI_LAYOUT_LOCK; @@ -418,6 +429,7 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt, CDEBUG(D_SUPER, "rootfid "DFID"\n", PFID(&sbi->ll_root_fid)); sb->s_op = &lustre_super_operations; + sb->s_xattr = ll_xattr_handlers; #if THREAD_SIZE >= 8192 /*b=17630*/ sb->s_export_op = &lustre_export_operations; #endif @@ -462,7 +474,7 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt, md_free_lustre_md(sbi->ll_md_exp, &lmd); ptlrpc_req_finished(request); - if (!(root)) { + if (IS_ERR(root)) { if (lmd.lsm) obd_free_memmd(sbi->ll_dt_exp, &lmd.lsm); #ifdef CONFIG_FS_POSIX_ACL @@ -486,11 +498,21 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt, err = obd_set_info_async(NULL, sbi->ll_dt_exp, sizeof(KEY_CHECKSUM), KEY_CHECKSUM, sizeof(checksum), &checksum, NULL); + if (err) { + CERROR("%s: Set checksum failed: rc = %d\n", + sbi->ll_dt_exp->exp_obd->obd_name, err); + goto out_root; + } cl_sb_init(sb); err = obd_set_info_async(NULL, sbi->ll_dt_exp, sizeof(KEY_CACHE_SET), KEY_CACHE_SET, sizeof(*sbi->ll_cache), sbi->ll_cache, NULL); + if (err) { + CERROR("%s: Set cache_set failed: rc = %d\n", + sbi->ll_dt_exp->exp_obd->obd_name, err); + goto out_root; + } sb->s_root = d_make_root(root); if (!sb->s_root) { @@ -560,6 +582,17 @@ int ll_get_max_mdsize(struct ll_sb_info *sbi, int *lmmsize) return rc; } +/** + * Get the value of the default_easize parameter. + * + * \see client_obd::cl_default_mds_easize + * + * \param[in] sbi superblock info for this filesystem + * \param[out] lmmsize pointer to storage location for value + * + * \retval 0 on success + * \retval negative negated errno on failure + */ int ll_get_default_mdsize(struct ll_sb_info *sbi, int *lmmsize) { int size, rc; @@ -573,6 +606,29 @@ int ll_get_default_mdsize(struct ll_sb_info *sbi, int *lmmsize) return rc; } +/** + * Set the default_easize parameter to the given value. + * + * \see client_obd::cl_default_mds_easize + * + * \param[in] sbi superblock info for this filesystem + * \param[in] lmmsize the size to set + * + * \retval 0 on success + * \retval negative negated errno on failure + */ +int ll_set_default_mdsize(struct ll_sb_info *sbi, int lmmsize) +{ + if (lmmsize < sizeof(struct lov_mds_md) || + lmmsize > OBD_MAX_DEFAULT_EA_SIZE) + return -EINVAL; + + return obd_set_info_async(NULL, sbi->ll_md_exp, + sizeof(KEY_DEFAULT_EASIZE), + KEY_DEFAULT_EASIZE, + sizeof(int), &lmmsize, NULL); +} + static void client_common_put_super(struct super_block *sb) { struct ll_sb_info *sbi = ll_s2sbi(sb); @@ -608,6 +664,12 @@ void ll_kill_super(struct super_block *sb) if (sbi) { sb->s_dev = sbi->ll_sdev_orig; sbi->ll_umounting = 1; + + /* wait running statahead threads to quit */ + while (atomic_read(&sbi->ll_sa_running) > 0) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(msecs_to_jiffies(MSEC_PER_SEC >> 3)); + } } } @@ -647,7 +709,8 @@ static int ll_options(char *options, int *flags) *flags |= tmp; goto next; } - tmp = ll_set_opt("noflock", s1, LL_SBI_FLOCK|LL_SBI_LOCALFLOCK); + tmp = ll_set_opt("noflock", s1, + LL_SBI_FLOCK | LL_SBI_LOCALFLOCK); if (tmp) { *flags &= ~tmp; goto next; @@ -772,11 +835,13 @@ void ll_lli_init(struct ll_inode_info *lli) lli->lli_sai = NULL; spin_lock_init(&lli->lli_sa_lock); lli->lli_opendir_pid = 0; + lli->lli_sa_enabled = 0; + lli->lli_def_stripe_offset = -1; } else { mutex_init(&lli->lli_size_mutex); lli->lli_symlink_name = NULL; init_rwsem(&lli->lli_trunc_sem); - mutex_init(&lli->lli_write_mutex); + range_lock_tree_init(&lli->lli_write_tree); init_rwsem(&lli->lli_glimpse_sem); lli->lli_glimpse_time = 0; INIT_LIST_HEAD(&lli->lli_agl_list); @@ -896,7 +961,8 @@ void ll_put_super(struct super_block *sb) struct lustre_sb_info *lsi = s2lsi(sb); struct ll_sb_info *sbi = ll_s2sbi(sb); char *profilenm = get_profile_name(sb); - int ccc_count, next, force = 1, rc = 0; + int next, force = 1, rc = 0; + long ccc_count; CDEBUG(D_VFSTRACE, "VFS Op: sb %p - %s\n", sb, profilenm); @@ -917,13 +983,13 @@ void ll_put_super(struct super_block *sb) struct l_wait_info lwi = LWI_INTR(LWI_ON_SIGNAL_NOOP, NULL); rc = l_wait_event(sbi->ll_cache->ccc_unstable_waitq, - !atomic_read(&sbi->ll_cache->ccc_unstable_nr), + !atomic_long_read(&sbi->ll_cache->ccc_unstable_nr), &lwi); } - ccc_count = atomic_read(&sbi->ll_cache->ccc_unstable_nr); + ccc_count = atomic_long_read(&sbi->ll_cache->ccc_unstable_nr); if (!force && rc != -EINTR) - LASSERTF(!ccc_count, "count: %i\n", ccc_count); + LASSERTF(!ccc_count, "count: %li\n", ccc_count); /* We need to set force before the lov_disconnect in * lustre_common_put_super, since l_d cleans up osc's as well. @@ -991,6 +1057,206 @@ struct inode *ll_inode_from_resource_lock(struct ldlm_lock *lock) return inode; } +static void ll_dir_clear_lsm_md(struct inode *inode) +{ + struct ll_inode_info *lli = ll_i2info(inode); + + LASSERT(S_ISDIR(inode->i_mode)); + + if (lli->lli_lsm_md) { + lmv_free_memmd(lli->lli_lsm_md); + lli->lli_lsm_md = NULL; + } +} + +static struct inode *ll_iget_anon_dir(struct super_block *sb, + const struct lu_fid *fid, + struct lustre_md *md) +{ + struct ll_sb_info *sbi = ll_s2sbi(sb); + struct mdt_body *body = md->body; + struct inode *inode; + ino_t ino; + + ino = cl_fid_build_ino(fid, sbi->ll_flags & LL_SBI_32BIT_API); + inode = iget_locked(sb, ino); + if (!inode) { + CERROR("%s: failed get simple inode "DFID": rc = -ENOENT\n", + ll_get_fsname(sb, NULL, 0), PFID(fid)); + return ERR_PTR(-ENOENT); + } + + if (inode->i_state & I_NEW) { + struct ll_inode_info *lli = ll_i2info(inode); + struct lmv_stripe_md *lsm = md->lmv; + + inode->i_mode = (inode->i_mode & ~S_IFMT) | + (body->mbo_mode & S_IFMT); + LASSERTF(S_ISDIR(inode->i_mode), "Not slave inode "DFID"\n", + PFID(fid)); + + LTIME_S(inode->i_mtime) = 0; + LTIME_S(inode->i_atime) = 0; + LTIME_S(inode->i_ctime) = 0; + inode->i_rdev = 0; + + inode->i_op = &ll_dir_inode_operations; + inode->i_fop = &ll_dir_operations; + lli->lli_fid = *fid; + ll_lli_init(lli); + + LASSERT(lsm); + /* master object FID */ + lli->lli_pfid = body->mbo_fid1; + CDEBUG(D_INODE, "lli %p slave "DFID" master "DFID"\n", + lli, PFID(fid), PFID(&lli->lli_pfid)); + unlock_new_inode(inode); + } + + return inode; +} + +static int ll_init_lsm_md(struct inode *inode, struct lustre_md *md) +{ + struct lmv_stripe_md *lsm = md->lmv; + struct lu_fid *fid; + int i; + + LASSERT(lsm); + /* + * XXX sigh, this lsm_root initialization should be in + * LMV layer, but it needs ll_iget right now, so we + * put this here right now. + */ + for (i = 0; i < lsm->lsm_md_stripe_count; i++) { + fid = &lsm->lsm_md_oinfo[i].lmo_fid; + LASSERT(!lsm->lsm_md_oinfo[i].lmo_root); + /* Unfortunately ll_iget will call ll_update_inode, + * where the initialization of slave inode is slightly + * different, so it reset lsm_md to NULL to avoid + * initializing lsm for slave inode. + */ + /* For migrating inode, master stripe and master object will + * be same, so we only need assign this inode + */ + if (lsm->lsm_md_hash_type & LMV_HASH_FLAG_MIGRATION && !i) + lsm->lsm_md_oinfo[i].lmo_root = inode; + else + lsm->lsm_md_oinfo[i].lmo_root = + ll_iget_anon_dir(inode->i_sb, fid, md); + if (IS_ERR(lsm->lsm_md_oinfo[i].lmo_root)) { + int rc = PTR_ERR(lsm->lsm_md_oinfo[i].lmo_root); + + lsm->lsm_md_oinfo[i].lmo_root = NULL; + return rc; + } + } + + return 0; +} + +static inline int lli_lsm_md_eq(const struct lmv_stripe_md *lsm_md1, + const struct lmv_stripe_md *lsm_md2) +{ + return lsm_md1->lsm_md_magic == lsm_md2->lsm_md_magic && + lsm_md1->lsm_md_stripe_count == lsm_md2->lsm_md_stripe_count && + lsm_md1->lsm_md_master_mdt_index == + lsm_md2->lsm_md_master_mdt_index && + lsm_md1->lsm_md_hash_type == lsm_md2->lsm_md_hash_type && + lsm_md1->lsm_md_layout_version == + lsm_md2->lsm_md_layout_version && + !strcmp(lsm_md1->lsm_md_pool_name, + lsm_md2->lsm_md_pool_name); +} + +static int ll_update_lsm_md(struct inode *inode, struct lustre_md *md) +{ + struct ll_inode_info *lli = ll_i2info(inode); + struct lmv_stripe_md *lsm = md->lmv; + int rc; + + LASSERT(S_ISDIR(inode->i_mode)); + CDEBUG(D_INODE, "update lsm %p of "DFID"\n", lli->lli_lsm_md, + PFID(ll_inode2fid(inode))); + + /* no striped information from request. */ + if (!lsm) { + if (!lli->lli_lsm_md) { + return 0; + } else if (lli->lli_lsm_md->lsm_md_hash_type & + LMV_HASH_FLAG_MIGRATION) { + /* + * migration is done, the temporay MIGRATE layout has + * been removed + */ + CDEBUG(D_INODE, DFID" finish migration.\n", + PFID(ll_inode2fid(inode))); + lmv_free_memmd(lli->lli_lsm_md); + lli->lli_lsm_md = NULL; + return 0; + } else { + /* + * The lustre_md from req does not include stripeEA, + * see ll_md_setattr + */ + return 0; + } + } + + /* set the directory layout */ + if (!lli->lli_lsm_md) { + rc = ll_init_lsm_md(inode, md); + if (rc) + return rc; + + lli->lli_lsm_md = lsm; + /* + * set lsm_md to NULL, so the following free lustre_md + * will not free this lsm + */ + md->lmv = NULL; + CDEBUG(D_INODE, "Set lsm %p magic %x to "DFID"\n", lsm, + lsm->lsm_md_magic, PFID(ll_inode2fid(inode))); + return 0; + } + + /* Compare the old and new stripe information */ + if (!lsm_md_eq(lli->lli_lsm_md, lsm)) { + struct lmv_stripe_md *old_lsm = lli->lli_lsm_md; + int idx; + + CERROR("%s: inode "DFID"(%p)'s lmv layout mismatch (%p)/(%p) magic:0x%x/0x%x stripe count: %d/%d master_mdt: %d/%d hash_type:0x%x/0x%x layout: 0x%x/0x%x pool:%s/%s\n", + ll_get_fsname(inode->i_sb, NULL, 0), PFID(&lli->lli_fid), + inode, lsm, old_lsm, + lsm->lsm_md_magic, old_lsm->lsm_md_magic, + lsm->lsm_md_stripe_count, + old_lsm->lsm_md_stripe_count, + lsm->lsm_md_master_mdt_index, + old_lsm->lsm_md_master_mdt_index, + lsm->lsm_md_hash_type, old_lsm->lsm_md_hash_type, + lsm->lsm_md_layout_version, + old_lsm->lsm_md_layout_version, + lsm->lsm_md_pool_name, + old_lsm->lsm_md_pool_name); + + for (idx = 0; idx < old_lsm->lsm_md_stripe_count; idx++) { + CERROR("%s: sub FIDs in old lsm idx %d, old: "DFID"\n", + ll_get_fsname(inode->i_sb, NULL, 0), idx, + PFID(&old_lsm->lsm_md_oinfo[idx].lmo_fid)); + } + + for (idx = 0; idx < lsm->lsm_md_stripe_count; idx++) { + CERROR("%s: sub FIDs in new lsm idx %d, new: "DFID"\n", + ll_get_fsname(inode->i_sb, NULL, 0), idx, + PFID(&lsm->lsm_md_oinfo[idx].lmo_fid)); + } + + return -EIO; + } + + return 0; +} + void ll_clear_inode(struct inode *inode) { struct ll_inode_info *lli = ll_i2info(inode); @@ -1031,14 +1297,15 @@ void ll_clear_inode(struct inode *inode) #ifdef CONFIG_FS_POSIX_ACL if (lli->lli_posix_acl) { - LASSERT(atomic_read(&lli->lli_posix_acl->a_refcount) == 1); posix_acl_release(lli->lli_posix_acl); lli->lli_posix_acl = NULL; } #endif lli->lli_inode_magic = LLI_INODE_DEAD; - if (!S_ISDIR(inode->i_mode)) + if (S_ISDIR(inode->i_mode)) + ll_dir_clear_lsm_md(inode); + if (S_ISREG(inode->i_mode) && !is_bad_inode(inode)) LASSERT(list_empty(&lli->lli_agl_list)); /* @@ -1103,10 +1370,10 @@ static int ll_md_setattr(struct dentry *dentry, struct md_op_data *op_data, op_data->op_attr.ia_valid = ia_valid; /* Extract epoch data if obtained. */ - op_data->op_handle = md.body->handle; - op_data->op_ioepoch = md.body->ioepoch; + op_data->op_handle = md.body->mbo_handle; + op_data->op_ioepoch = md.body->mbo_ioepoch; - ll_update_inode(inode, &md); + rc = ll_update_inode(inode, &md); ptlrpc_req_finished(request); return rc; @@ -1138,8 +1405,8 @@ static int ll_setattr_done_writing(struct inode *inode, rc = ll_som_update(inode, op_data); else if (rc) { CERROR("%s: inode "DFID" mdc truncate failed: rc = %d\n", - ll_i2sbi(inode)->ll_md_exp->exp_obd->obd_name, - PFID(ll_inode2fid(inode)), rc); + ll_i2sbi(inode)->ll_md_exp->exp_obd->obd_name, + PFID(ll_inode2fid(inode)), rc); } return rc; } @@ -1331,14 +1598,14 @@ int ll_setattr(struct dentry *de, struct iattr *attr) { int mode = d_inode(de)->i_mode; - if ((attr->ia_valid & (ATTR_CTIME|ATTR_SIZE|ATTR_MODE)) == - (ATTR_CTIME|ATTR_SIZE|ATTR_MODE)) + if ((attr->ia_valid & (ATTR_CTIME | ATTR_SIZE | ATTR_MODE)) == + (ATTR_CTIME | ATTR_SIZE | ATTR_MODE)) attr->ia_valid |= MDS_OPEN_OWNEROVERRIDE; - if (((attr->ia_valid & (ATTR_MODE|ATTR_FORCE|ATTR_SIZE)) == - (ATTR_SIZE|ATTR_MODE)) && + if (((attr->ia_valid & (ATTR_MODE | ATTR_FORCE | ATTR_SIZE)) == + (ATTR_SIZE | ATTR_MODE)) && (((mode & S_ISUID) && !(attr->ia_mode & S_ISUID)) || - (((mode & (S_ISGID|S_IXGRP)) == (S_ISGID|S_IXGRP)) && + (((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) && !(attr->ia_mode & S_ISGID)))) attr->ia_valid |= ATTR_FORCE; @@ -1349,7 +1616,7 @@ int ll_setattr(struct dentry *de, struct iattr *attr) attr->ia_valid |= ATTR_KILL_SUID; if ((attr->ia_valid & ATTR_MODE) && - ((mode & (S_ISGID|S_IXGRP)) == (S_ISGID|S_IXGRP)) && + ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) && !(attr->ia_mode & S_ISGID) && !(attr->ia_valid & ATTR_KILL_SGID)) attr->ia_valid |= ATTR_KILL_SGID; @@ -1465,14 +1732,14 @@ void ll_inode_size_unlock(struct inode *inode) mutex_unlock(&lli->lli_size_mutex); } -void ll_update_inode(struct inode *inode, struct lustre_md *md) +int ll_update_inode(struct inode *inode, struct lustre_md *md) { struct ll_inode_info *lli = ll_i2info(inode); struct mdt_body *body = md->body; struct lov_stripe_md *lsm = md->lsm; struct ll_sb_info *sbi = ll_i2sbi(inode); - LASSERT((lsm != NULL) == ((body->valid & OBD_MD_FLEASIZE) != 0)); + LASSERT((lsm != NULL) == ((body->mbo_valid & OBD_MD_FLEASIZE) != 0)); if (lsm) { if (!lli->lli_has_smd && !(sbi->ll_flags & LL_SBI_LAYOUT_LOCK)) @@ -1483,8 +1750,16 @@ void ll_update_inode(struct inode *inode, struct lustre_md *md) lli->lli_maxbytes = MAX_LFS_FILESIZE; } + if (S_ISDIR(inode->i_mode)) { + int rc; + + rc = ll_update_lsm_md(inode, md); + if (rc) + return rc; + } + #ifdef CONFIG_FS_POSIX_ACL - if (body->valid & OBD_MD_FLACL) { + if (body->mbo_valid & OBD_MD_FLACL) { spin_lock(&lli->lli_lock); if (lli->lli_posix_acl) posix_acl_release(lli->lli_posix_acl); @@ -1492,65 +1767,67 @@ void ll_update_inode(struct inode *inode, struct lustre_md *md) spin_unlock(&lli->lli_lock); } #endif - inode->i_ino = cl_fid_build_ino(&body->fid1, + inode->i_ino = cl_fid_build_ino(&body->mbo_fid1, sbi->ll_flags & LL_SBI_32BIT_API); - inode->i_generation = cl_fid_build_gen(&body->fid1); + inode->i_generation = cl_fid_build_gen(&body->mbo_fid1); - if (body->valid & OBD_MD_FLATIME) { - if (body->atime > LTIME_S(inode->i_atime)) - LTIME_S(inode->i_atime) = body->atime; - lli->lli_atime = body->atime; + if (body->mbo_valid & OBD_MD_FLATIME) { + if (body->mbo_atime > LTIME_S(inode->i_atime)) + LTIME_S(inode->i_atime) = body->mbo_atime; + lli->lli_atime = body->mbo_atime; } - if (body->valid & OBD_MD_FLMTIME) { - if (body->mtime > LTIME_S(inode->i_mtime)) { + if (body->mbo_valid & OBD_MD_FLMTIME) { + if (body->mbo_mtime > LTIME_S(inode->i_mtime)) { CDEBUG(D_INODE, "setting ino %lu mtime from %lu to %llu\n", inode->i_ino, LTIME_S(inode->i_mtime), - body->mtime); - LTIME_S(inode->i_mtime) = body->mtime; + body->mbo_mtime); + LTIME_S(inode->i_mtime) = body->mbo_mtime; } - lli->lli_mtime = body->mtime; - } - if (body->valid & OBD_MD_FLCTIME) { - if (body->ctime > LTIME_S(inode->i_ctime)) - LTIME_S(inode->i_ctime) = body->ctime; - lli->lli_ctime = body->ctime; - } - if (body->valid & OBD_MD_FLMODE) - inode->i_mode = (inode->i_mode & S_IFMT)|(body->mode & ~S_IFMT); - if (body->valid & OBD_MD_FLTYPE) - inode->i_mode = (inode->i_mode & ~S_IFMT)|(body->mode & S_IFMT); + lli->lli_mtime = body->mbo_mtime; + } + if (body->mbo_valid & OBD_MD_FLCTIME) { + if (body->mbo_ctime > LTIME_S(inode->i_ctime)) + LTIME_S(inode->i_ctime) = body->mbo_ctime; + lli->lli_ctime = body->mbo_ctime; + } + if (body->mbo_valid & OBD_MD_FLMODE) + inode->i_mode = (inode->i_mode & S_IFMT) | + (body->mbo_mode & ~S_IFMT); + if (body->mbo_valid & OBD_MD_FLTYPE) + inode->i_mode = (inode->i_mode & ~S_IFMT) | + (body->mbo_mode & S_IFMT); LASSERT(inode->i_mode != 0); if (S_ISREG(inode->i_mode)) inode->i_blkbits = min(PTLRPC_MAX_BRW_BITS + 1, LL_MAX_BLKSIZE_BITS); else inode->i_blkbits = inode->i_sb->s_blocksize_bits; - if (body->valid & OBD_MD_FLUID) - inode->i_uid = make_kuid(&init_user_ns, body->uid); - if (body->valid & OBD_MD_FLGID) - inode->i_gid = make_kgid(&init_user_ns, body->gid); - if (body->valid & OBD_MD_FLFLAGS) - inode->i_flags = ll_ext_to_inode_flags(body->flags); - if (body->valid & OBD_MD_FLNLINK) - set_nlink(inode, body->nlink); - if (body->valid & OBD_MD_FLRDEV) - inode->i_rdev = old_decode_dev(body->rdev); - - if (body->valid & OBD_MD_FLID) { + if (body->mbo_valid & OBD_MD_FLUID) + inode->i_uid = make_kuid(&init_user_ns, body->mbo_uid); + if (body->mbo_valid & OBD_MD_FLGID) + inode->i_gid = make_kgid(&init_user_ns, body->mbo_gid); + if (body->mbo_valid & OBD_MD_FLFLAGS) + inode->i_flags = ll_ext_to_inode_flags(body->mbo_flags); + if (body->mbo_valid & OBD_MD_FLNLINK) + set_nlink(inode, body->mbo_nlink); + if (body->mbo_valid & OBD_MD_FLRDEV) + inode->i_rdev = old_decode_dev(body->mbo_rdev); + + if (body->mbo_valid & OBD_MD_FLID) { /* FID shouldn't be changed! */ if (fid_is_sane(&lli->lli_fid)) { - LASSERTF(lu_fid_eq(&lli->lli_fid, &body->fid1), + LASSERTF(lu_fid_eq(&lli->lli_fid, &body->mbo_fid1), "Trying to change FID "DFID" to the "DFID", inode "DFID"(%p)\n", - PFID(&lli->lli_fid), PFID(&body->fid1), + PFID(&lli->lli_fid), PFID(&body->mbo_fid1), PFID(ll_inode2fid(inode)), inode); } else { - lli->lli_fid = body->fid1; + lli->lli_fid = body->mbo_fid1; } } LASSERT(fid_seq(&lli->lli_fid) != 0); - if (body->valid & OBD_MD_FLSIZE) { + if (body->mbo_valid & OBD_MD_FLSIZE) { if (exp_connect_som(ll_i2mdexp(inode)) && S_ISREG(inode->i_mode)) { struct lustre_handle lockh; @@ -1577,7 +1854,7 @@ void ll_update_inode(struct inode *inode, struct lustre_md *md) /* Use old size assignment to avoid * deadlock bz14138 & bz14326 */ - i_size_write(inode, body->size); + i_size_write(inode, body->mbo_size); spin_lock(&lli->lli_lock); lli->lli_flags |= LLIF_MDS_SIZE_LOCK; spin_unlock(&lli->lli_lock); @@ -1588,26 +1865,29 @@ void ll_update_inode(struct inode *inode, struct lustre_md *md) /* Use old size assignment to avoid * deadlock bz14138 & bz14326 */ - i_size_write(inode, body->size); + i_size_write(inode, body->mbo_size); CDEBUG(D_VFSTRACE, "inode=%lu, updating i_size %llu\n", - inode->i_ino, (unsigned long long)body->size); + inode->i_ino, (unsigned long long)body->mbo_size); } - if (body->valid & OBD_MD_FLBLOCKS) - inode->i_blocks = body->blocks; + if (body->mbo_valid & OBD_MD_FLBLOCKS) + inode->i_blocks = body->mbo_blocks; } - if (body->valid & OBD_MD_TSTATE) { - if (body->t_state & MS_RESTORE) + if (body->mbo_valid & OBD_MD_TSTATE) { + if (body->mbo_t_state & MS_RESTORE) lli->lli_flags |= LLIF_FILE_RESTORING; } + + return 0; } -void ll_read_inode2(struct inode *inode, void *opaque) +int ll_read_inode2(struct inode *inode, void *opaque) { struct lustre_md *md = opaque; struct ll_inode_info *lli = ll_i2info(inode); + int rc; CDEBUG(D_VFSTRACE, "VFS Op:inode="DFID"(%p)\n", PFID(&lli->lli_fid), inode); @@ -1623,7 +1903,9 @@ void ll_read_inode2(struct inode *inode, void *opaque) LTIME_S(inode->i_atime) = 0; LTIME_S(inode->i_ctime) = 0; inode->i_rdev = 0; - ll_update_inode(inode, md); + rc = ll_update_inode(inode, md); + if (rc) + return rc; /* OIDEBUG(inode); */ @@ -1644,6 +1926,8 @@ void ll_read_inode2(struct inode *inode, void *opaque) init_special_inode(inode, inode->i_mode, inode->i_rdev); } + + return 0; } void ll_delete_inode(struct inode *inode) @@ -1655,20 +1939,13 @@ void ll_delete_inode(struct inode *inode) * osc_extent implementation at LU-1030. */ cl_sync_file_range(inode, 0, OBD_OBJECT_EOF, - CL_FSYNC_DISCARD, 1); + CL_FSYNC_LOCAL, 1); truncate_inode_pages_final(&inode->i_data); - /* Workaround for LU-118 */ - if (inode->i_data.nrpages) { - spin_lock_irq(&inode->i_data.tree_lock); - spin_unlock_irq(&inode->i_data.tree_lock); - LASSERTF(inode->i_data.nrpages == 0, - "inode="DFID"(%p) nrpages=%lu, see http://jira.whamcloud.com/browse/LU-118\n", - PFID(ll_inode2fid(inode)), inode, - inode->i_data.nrpages); - } - /* Workaround end */ + LASSERTF(!inode->i_data.nrpages, + "inode=" DFID "(%p) nrpages=%lu, see http://jira.whamcloud.com/browse/LU-118\n", + PFID(ll_inode2fid(inode)), inode, inode->i_data.nrpages); ll_clear_inode(inode); clear_inode(inode); @@ -1704,7 +1981,7 @@ int ll_iocontrol(struct inode *inode, struct file *file, body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY); - flags = body->flags; + flags = body->mbo_flags; ptlrpc_req_finished(req); @@ -1886,9 +2163,9 @@ void ll_open_cleanup(struct super_block *sb, struct ptlrpc_request *open_req) if (!op_data) return; - op_data->op_fid1 = body->fid1; - op_data->op_ioepoch = body->ioepoch; - op_data->op_handle = body->handle; + op_data->op_fid1 = body->mbo_fid1; + op_data->op_ioepoch = body->mbo_ioepoch; + op_data->op_handle = body->mbo_handle; op_data->op_mod_time = get_seconds(); md_close(exp, op_data, NULL, &close_req); ptlrpc_req_finished(close_req); @@ -1910,7 +2187,9 @@ int ll_prep_inode(struct inode **inode, struct ptlrpc_request *req, goto cleanup; if (*inode) { - ll_update_inode(*inode, &md); + rc = ll_update_inode(*inode, &md); + if (rc) + goto out; } else { LASSERT(sb); @@ -1918,18 +2197,18 @@ int ll_prep_inode(struct inode **inode, struct ptlrpc_request *req, * At this point server returns to client's same fid as client * generated for creating. So using ->fid1 is okay here. */ - if (!fid_is_sane(&md.body->fid1)) { + if (!fid_is_sane(&md.body->mbo_fid1)) { CERROR("%s: Fid is insane " DFID "\n", ll_get_fsname(sb, NULL, 0), - PFID(&md.body->fid1)); + PFID(&md.body->mbo_fid1)); rc = -EINVAL; goto out; } - *inode = ll_iget(sb, cl_fid_build_ino(&md.body->fid1, + *inode = ll_iget(sb, cl_fid_build_ino(&md.body->mbo_fid1, sbi->ll_flags & LL_SBI_32BIT_API), &md); - if (!*inode) { + if (IS_ERR(*inode)) { #ifdef CONFIG_FS_POSIX_ACL if (md.posix_acl) { posix_acl_release(md.posix_acl); @@ -2075,11 +2354,20 @@ int ll_process_config(struct lustre_cfg *lcfg) /* this function prepares md_op_data hint for passing ot down to MD stack. */ struct md_op_data *ll_prep_md_op_data(struct md_op_data *op_data, struct inode *i1, struct inode *i2, - const char *name, int namelen, - int mode, __u32 opc, void *data) + const char *name, size_t namelen, + u32 mode, __u32 opc, void *data) { - if (namelen > ll_i2sbi(i1)->ll_namelen) - return ERR_PTR(-ENAMETOOLONG); + if (!name) { + /* Do not reuse namelen for something else. */ + if (namelen) + return ERR_PTR(-EINVAL); + } else { + if (namelen > ll_i2sbi(i1)->ll_namelen) + return ERR_PTR(-ENAMETOOLONG); + + if (!lu_name_is_valid_2(name, namelen)) + return ERR_PTR(-EINVAL); + } if (!op_data) op_data = kzalloc(sizeof(*op_data), GFP_NOFS); @@ -2089,11 +2377,26 @@ struct md_op_data *ll_prep_md_op_data(struct md_op_data *op_data, ll_i2gids(op_data->op_suppgids, i1, i2); op_data->op_fid1 = *ll_inode2fid(i1); + op_data->op_default_stripe_offset = -1; + if (S_ISDIR(i1->i_mode)) { + op_data->op_mea1 = ll_i2info(i1)->lli_lsm_md; + op_data->op_default_stripe_offset = + ll_i2info(i1)->lli_def_stripe_offset; + } - if (i2) + if (i2) { op_data->op_fid2 = *ll_inode2fid(i2); - else + if (S_ISDIR(i2->i_mode)) + op_data->op_mea2 = ll_i2info(i2)->lli_lsm_md; + } else { fid_zero(&op_data->op_fid2); + } + + if (ll_i2sbi(i1)->ll_flags & LL_SBI_64BIT_HASH) + op_data->op_cli_flags |= CLI_HASH64; + + if (ll_need_32bit_api(ll_i2sbi(i1))) + op_data->op_cli_flags |= CLI_API32; op_data->op_name = name; op_data->op_namelen = namelen; @@ -2105,26 +2408,12 @@ struct md_op_data *ll_prep_md_op_data(struct md_op_data *op_data, op_data->op_bias = 0; op_data->op_cli_flags = 0; if ((opc == LUSTRE_OPC_CREATE) && name && - filename_is_volatile(name, namelen, NULL)) + filename_is_volatile(name, namelen, &op_data->op_mds)) op_data->op_bias |= MDS_CREATE_VOLATILE; - op_data->op_opc = opc; - op_data->op_mds = 0; + else + op_data->op_mds = 0; op_data->op_data = data; - /* If the file is being opened after mknod() (normally due to NFS) - * try to use the default stripe data from parent directory for - * allocating OST objects. Try to pass the parent FID to MDS. - */ - if (opc == LUSTRE_OPC_CREATE && i1 == i2 && S_ISREG(i2->i_mode) && - !ll_i2info(i2)->lli_has_smd) { - struct ll_inode_info *lli = ll_i2info(i2); - - spin_lock(&lli->lli_lock); - if (likely(!lli->lli_has_smd && !fid_is_zero(&lli->lli_pfid))) - op_data->op_fid1 = lli->lli_pfid; - spin_unlock(&lli->lli_lock); - } - /* When called by ll_setattr_raw, file is i1. */ if (ll_i2info(i1)->lli_flags & LLIF_DATA_MODIFIED) op_data->op_bias |= MDS_DATA_MODIFIED; @@ -2251,3 +2540,197 @@ void ll_dirty_page_discard_warn(struct page *page, int ioret) if (buf) free_page((unsigned long)buf); } + +ssize_t ll_copy_user_md(const struct lov_user_md __user *md, + struct lov_user_md **kbuf) +{ + struct lov_user_md lum; + ssize_t lum_size; + + if (copy_from_user(&lum, md, sizeof(lum))) { + lum_size = -EFAULT; + goto no_kbuf; + } + + lum_size = ll_lov_user_md_size(&lum); + if (lum_size < 0) + goto no_kbuf; + + *kbuf = kzalloc(lum_size, GFP_NOFS); + if (!*kbuf) { + lum_size = -ENOMEM; + goto no_kbuf; + } + + if (copy_from_user(*kbuf, md, lum_size) != 0) { + kfree(*kbuf); + *kbuf = NULL; + lum_size = -EFAULT; + } +no_kbuf: + return lum_size; +} + +/* + * Compute llite root squash state after a change of root squash + * configuration setting or add/remove of a lnet nid + */ +void ll_compute_rootsquash_state(struct ll_sb_info *sbi) +{ + struct root_squash_info *squash = &sbi->ll_squash; + lnet_process_id_t id; + bool matched; + int i; + + /* Update norootsquash flag */ + down_write(&squash->rsi_sem); + if (list_empty(&squash->rsi_nosquash_nids)) { + sbi->ll_flags &= ~LL_SBI_NOROOTSQUASH; + } else { + /* + * Do not apply root squash as soon as one of our NIDs is + * in the nosquash_nids list + */ + matched = false; + i = 0; + + while (LNetGetId(i++, &id) != -ENOENT) { + if (LNET_NETTYP(LNET_NIDNET(id.nid)) == LOLND) + continue; + if (cfs_match_nid(id.nid, &squash->rsi_nosquash_nids)) { + matched = true; + break; + } + } + if (matched) + sbi->ll_flags |= LL_SBI_NOROOTSQUASH; + else + sbi->ll_flags &= ~LL_SBI_NOROOTSQUASH; + } + up_write(&squash->rsi_sem); +} + +/** + * Parse linkea content to extract information about a given hardlink + * + * \param[in] ldata - Initialized linkea data + * \param[in] linkno - Link identifier + * \param[out] parent_fid - The entry's parent FID + * \param[in] size - Entry name destination buffer + * + * \retval 0 on success + * \retval Appropriate negative error code on failure + */ +static int ll_linkea_decode(struct linkea_data *ldata, unsigned int linkno, + struct lu_fid *parent_fid, struct lu_name *ln) +{ + unsigned int idx; + int rc; + + rc = linkea_init(ldata); + if (rc < 0) + return rc; + + if (linkno >= ldata->ld_leh->leh_reccount) + /* beyond last link */ + return -ENODATA; + + linkea_first_entry(ldata); + for (idx = 0; ldata->ld_lee; idx++) { + linkea_entry_unpack(ldata->ld_lee, &ldata->ld_reclen, ln, + parent_fid); + if (idx == linkno) + break; + + linkea_next_entry(ldata); + } + + if (idx < linkno) + return -ENODATA; + + return 0; +} + +/** + * Get parent FID and name of an identified link. Operation is performed for + * a given link number, letting the caller iterate over linkno to list one or + * all links of an entry. + * + * \param[in] file - File descriptor against which to perform the operation + * \param[in,out] arg - User-filled structure containing the linkno to operate + * on and the available size. It is eventually filled with + * the requested information or left untouched on error + * + * \retval - 0 on success + * \retval - Appropriate negative error code on failure + */ +int ll_getparent(struct file *file, struct getparent __user *arg) +{ + struct inode *inode = file_inode(file); + struct linkea_data *ldata; + struct lu_fid parent_fid; + struct lu_buf buf = { + .lb_buf = NULL, + .lb_len = 0 + }; + struct lu_name ln; + u32 name_size; + u32 linkno; + int rc; + + if (!capable(CFS_CAP_DAC_READ_SEARCH) && + !(ll_i2sbi(inode)->ll_flags & LL_SBI_USER_FID2PATH)) + return -EPERM; + + if (get_user(name_size, &arg->gp_name_size)) + return -EFAULT; + + if (get_user(linkno, &arg->gp_linkno)) + return -EFAULT; + + if (name_size > PATH_MAX) + return -EINVAL; + + ldata = kzalloc(sizeof(*ldata), GFP_NOFS); + if (!ldata) + return -ENOMEM; + + rc = linkea_data_new(ldata, &buf); + if (rc < 0) + goto ldata_free; + + rc = ll_xattr_list(inode, XATTR_NAME_LINK, XATTR_TRUSTED_T, buf.lb_buf, + buf.lb_len, OBD_MD_FLXATTR); + if (rc < 0) + goto lb_free; + + rc = ll_linkea_decode(ldata, linkno, &parent_fid, &ln); + if (rc < 0) + goto lb_free; + + if (ln.ln_namelen >= name_size) { + rc = -EOVERFLOW; + goto lb_free; + } + + if (copy_to_user(&arg->gp_fid, &parent_fid, sizeof(arg->gp_fid))) { + rc = -EFAULT; + goto lb_free; + } + + if (copy_to_user(&arg->gp_name, ln.ln_name, ln.ln_namelen)) { + rc = -EFAULT; + goto lb_free; + } + + if (put_user('\0', arg->gp_name + ln.ln_namelen)) { + rc = -EFAULT; + goto lb_free; + } + +lb_free: + lu_buf_free(&buf); +ldata_free: + kfree(ldata); + return rc; +} |