X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=blobdiff_plain;f=lustre%2Fllite%2Fllite_lib.c;h=09aa53cff431102131d1cc762016976ce9e5475b;hp=135e77f4ee39994e8e0481c560ea095466cb074c;hb=0c6776db8cce84fd623c76a18df93759f2fcaed4;hpb=3000a83dcd3c201f383c0507d33e7861fc695997 diff --git a/lustre/llite/llite_lib.c b/lustre/llite/llite_lib.c index 135e77f..09aa53c 100644 --- a/lustre/llite/llite_lib.c +++ b/lustre/llite/llite_lib.c @@ -41,12 +41,12 @@ #define DEBUG_SUBSYSTEM S_LLITE #include +#include #include #include #include #include -#include #include #include #include @@ -93,13 +93,13 @@ static struct ll_sb_info *ll_init_sbi(void) /* initialize ll_cache data */ atomic_set(&sbi->ll_cache.ccc_users, 0); sbi->ll_cache.ccc_lru_max = lru_page_max; - atomic_set(&sbi->ll_cache.ccc_lru_left, lru_page_max); + atomic_long_set(&sbi->ll_cache.ccc_lru_left, lru_page_max); spin_lock_init(&sbi->ll_cache.ccc_lru_lock); INIT_LIST_HEAD(&sbi->ll_cache.ccc_lru); /* turn unstable check off by default as it impacts performance */ sbi->ll_cache.ccc_unstable_check = 0; - atomic_set(&sbi->ll_cache.ccc_unstable_nr, 0); + atomic_long_set(&sbi->ll_cache.ccc_unstable_nr, 0); init_waitqueue_head(&sbi->ll_cache.ccc_unstable_waitq); sbi->ll_ra_info.ra_max_pages_per_file = min(pages / 32, @@ -138,6 +138,7 @@ static struct ll_sb_info *ll_init_sbi(void) 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; @@ -772,22 +773,27 @@ static void client_common_put_super(struct super_block *sb) void ll_kill_super(struct super_block *sb) { - struct ll_sb_info *sbi; - - ENTRY; + struct ll_sb_info *sbi; + ENTRY; /* not init sb ?*/ - if (!(sb->s_flags & MS_ACTIVE)) - return; + if (!(sb->s_flags & MS_ACTIVE)) + return; - sbi = ll_s2sbi(sb); - /* we need restore s_dev from changed for clustred NFS before put_super - * because new kernels have cached s_dev and change sb->s_dev in - * put_super not affected real removing devices */ + sbi = ll_s2sbi(sb); + /* we need restore s_dev from changed for clustred NFS before put_super + * because new kernels have cached s_dev and change sb->s_dev in + * put_super not affected real removing devices */ 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) + schedule_timeout_and_set_state(TASK_UNINTERRUPTIBLE, + msecs_to_jiffies(MSEC_PER_SEC >> 3)); } + EXIT; } @@ -843,30 +849,11 @@ static int ll_options(char *options, int *flags) *flags &= ~tmp; goto next; } -#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 6, 52, 0) - tmp = ll_set_opt("acl", s1, LL_SBI_ACL); + tmp = ll_set_opt("remote_client", s1, LL_SBI_RMT_CLIENT); if (tmp) { - /* Ignore deprecated mount option. The client will - * always try to mount with ACL support, whether this - * is used depends on whether server supports it. */ - LCONSOLE_ERROR_MSG(0x152, "Ignoring deprecated " - "mount option 'acl'.\n"); - goto next; - } - tmp = ll_set_opt("noacl", s1, LL_SBI_ACL); - if (tmp) { - LCONSOLE_ERROR_MSG(0x152, "Ignoring deprecated " - "mount option 'noacl'.\n"); + *flags |= tmp; goto next; } -#else -#warning "{no}acl options have been deprecated since 1.8, please remove them" -#endif - tmp = ll_set_opt("remote_client", s1, LL_SBI_RMT_CLIENT); - if (tmp) { - *flags |= tmp; - goto next; - } tmp = ll_set_opt("user_fid2path", s1, LL_SBI_USER_FID2PATH); if (tmp) { *flags |= tmp; @@ -983,11 +970,12 @@ 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; } 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); @@ -1110,7 +1098,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; + long ccc_count; + int next, force = 1, rc = 0; ENTRY; CDEBUG(D_VFSTRACE, "VFS Op: sb %p - %s\n", sb, profilenm); @@ -1133,13 +1122,13 @@ void ll_put_super(struct super_block *sb) if (force == 0) { 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) == 0, + atomic_long_read(&sbi->ll_cache.ccc_unstable_nr) == 0, &lwi); } - ccc_count = atomic_read(&sbi->ll_cache.ccc_unstable_nr); + ccc_count = atomic_long_read(&sbi->ll_cache.ccc_unstable_nr); if (force == 0 && rc != -EINTR) - LASSERTF(ccc_count == 0, "count: %i\n", ccc_count); + LASSERTF(ccc_count == 0, "count: %li\n", ccc_count); /* We need to set force before the lov_disconnect in @@ -1488,8 +1477,8 @@ void ll_clear_inode(struct inode *inode) EXIT; } -int ll_md_setattr(struct dentry *dentry, struct md_op_data *op_data, - struct md_open_data **mod) +static int ll_md_setattr(struct dentry *dentry, struct md_op_data *op_data, + struct md_open_data **mod) { struct lustre_md md; struct inode *inode = dentry->d_inode; @@ -1969,7 +1958,7 @@ int ll_update_inode(struct inode *inode, struct lustre_md *md) 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_lvb.lvb_atime = body->mbo_atime; + lli->lli_atime = body->mbo_atime; } if (body->mbo_valid & OBD_MD_FLMTIME) { @@ -1979,13 +1968,13 @@ int ll_update_inode(struct inode *inode, struct lustre_md *md) LTIME_S(inode->i_mtime), body->mbo_mtime); LTIME_S(inode->i_mtime) = body->mbo_mtime; } - lli->lli_lvb.lvb_mtime = body->mbo_mtime; + 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_lvb.lvb_ctime = body->mbo_ctime; + lli->lli_ctime = body->mbo_ctime; } if (body->mbo_valid & OBD_MD_FLMODE) @@ -2157,24 +2146,15 @@ void ll_delete_inode(struct inode *inode) ENTRY; if (S_ISREG(inode->i_mode) && lli->lli_clob != NULL) - /* discard all dirty pages before truncating them, required by - * osc_extent implementation at LU-1030. */ - cl_sync_file_range(inode, 0, OBD_OBJECT_EOF, - CL_FSYNC_DISCARD, 1); - - truncate_inode_pages(&inode->i_data, 0); - - /* 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 " - "https://jira.hpdd.intel.com/browse/LU-118\n", - PFID(ll_inode2fid(inode)), inode, - inode->i_data.nrpages); - } - /* Workaround end */ + /* It is last chance to write out dirty pages, + * otherwise we may lose data while umount */ + cl_sync_file_range(inode, 0, OBD_OBJECT_EOF, CL_FSYNC_LOCAL, 1); + + truncate_inode_pages_final(&inode->i_data); + + LASSERTF(inode->i_data.nrpages == 0, "inode="DFID"(%p) nrpages=%lu, " + "see https://jira.hpdd.intel.com/browse/LU-118\n", + PFID(ll_inode2fid(inode)), inode, inode->i_data.nrpages); #ifdef HAVE_SBOPS_EVICT_INODE ll_clear_inode(inode); @@ -2219,22 +2199,22 @@ int ll_iocontrol(struct inode *inode, struct file *file, ptlrpc_req_finished(req); - RETURN(put_user(flags, (int *)arg)); + RETURN(put_user(flags, (int __user *)arg)); } case FSFILT_IOC_SETFLAGS: { struct lov_stripe_md *lsm; struct obd_info oinfo = { { { 0 } } }; struct md_op_data *op_data; - if (get_user(flags, (int *)arg)) - RETURN(-EFAULT); + if (get_user(flags, (int __user *)arg)) + RETURN(-EFAULT); op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL, 0, 0, LUSTRE_OPC_ANY, NULL); if (IS_ERR(op_data)) RETURN(PTR_ERR(op_data)); - ((struct ll_iattr *)&op_data->op_attr)->ia_attr_flags = flags; + op_data->op_attr_flags = flags; op_data->op_attr.ia_valid |= ATTR_ATTR_FLAG; rc = md_setattr(sbi->ll_md_exp, op_data, NULL, 0, NULL, 0, &req, NULL); @@ -2456,14 +2436,14 @@ out: RETURN(rc); } -int ll_obd_statfs(struct inode *inode, void *arg) +int ll_obd_statfs(struct inode *inode, void __user *arg) { struct ll_sb_info *sbi = NULL; struct obd_export *exp; char *buf = NULL; struct obd_ioctl_data *data = NULL; __u32 type; - __u32 flags; + __u32 __user flags; /* not user, but obd_iocontrol is abused */ int len = 0, rc; if (!inode || !(sbi = ll_i2sbi(inode))) @@ -2521,8 +2501,8 @@ int ll_process_config(struct lustre_cfg *lcfg) /* Note we have not called client_common_fill_super yet, so proc fns must be able to handle that! */ - rc = class_process_proc_seq_param(PARAM_LLITE, lprocfs_llite_obd_vars, - lcfg, sb); + rc = class_process_proc_param(PARAM_LLITE, lprocfs_llite_obd_vars, + lcfg, sb); if (rc > 0) rc = 0; return rc; @@ -2530,9 +2510,9 @@ 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) + struct inode *i1, struct inode *i2, + const char *name, size_t namelen, + __u32 mode, __u32 opc, void *data) { LASSERT(i1 != NULL); @@ -2663,7 +2643,7 @@ int ll_get_obd_name(struct inode *inode, unsigned int cmd, unsigned long arg) if (!obd) RETURN(-ENOENT); - if (copy_to_user((void *)arg, obd->obd_name, + if (copy_to_user((void __user *)arg, obd->obd_name, strlen(obd->obd_name) + 1)) RETURN(-EFAULT); @@ -2745,6 +2725,32 @@ void ll_dirty_page_discard_warn(struct page *page, int ioret) 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; + ENTRY; + + if (copy_from_user(&lum, md, sizeof(lum))) + RETURN(-EFAULT); + + lum_size = ll_lov_user_md_size(&lum); + if (lum_size < 0) + RETURN(lum_size); + + OBD_ALLOC(*kbuf, lum_size); + if (*kbuf == NULL) + RETURN(-ENOMEM); + + if (copy_from_user(*kbuf, md, lum_size) != 0) { + OBD_FREE(*kbuf, lum_size); + RETURN(-EFAULT); + } + + RETURN(lum_size); +} + /* * Compute llite root squash state after a change of root squash * configuration setting or add/remove of a lnet nid @@ -2781,4 +2787,130 @@ void ll_compute_rootsquash_state(struct ll_sb_info *sbi) 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] gpout - Destination structure to fill with linkno, + * parent FID and entry name + * \param[in] size - Size of the gp_name buffer in gpout + * + * \retval 0 on success + * \retval Appropriate negative error code on failure + */ +static int ll_linkea_decode(struct linkea_data *ldata, unsigned int linkno, + struct getparent *gpout, size_t name_size) +{ + unsigned int idx; + struct lu_name ln; + int rc; + ENTRY; + + 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); + idx = 0; + while (ldata->ld_lee != NULL) { + linkea_entry_unpack(ldata->ld_lee, &ldata->ld_reclen, &ln, + &gpout->gp_fid); + if (idx == linkno) + break; + + linkea_next_entry(ldata); + idx++; + } + + if (idx < linkno) + RETURN(-ENODATA); + + if (ln.ln_namelen >= name_size) + RETURN(-EOVERFLOW); + + gpout->gp_linkno = linkno; + strlcpy(gpout->gp_name, ln.ln_name, name_size); + 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 dentry *dentry = file->f_dentry; + struct inode *inode = file->f_dentry->d_inode; + struct linkea_data *ldata; + struct lu_buf buf = LU_BUF_NULL; + struct getparent *gpout; + __u32 linkno; + __u32 name_size; + size_t out_size; + int rc; + + ENTRY; + + if (!cfs_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); + + OBD_ALLOC(ldata, sizeof(*ldata)); + if (ldata == NULL) + RETURN(-ENOMEM); + rc = linkea_data_new(ldata, &buf); + if (rc < 0) + GOTO(ldata_free, rc); + + out_size = sizeof(*gpout) + name_size; + OBD_ALLOC(gpout, out_size); + if (gpout == NULL) + GOTO(lb_free, rc = -ENOMEM); + + if (copy_from_user(gpout, arg, sizeof(*gpout))) + GOTO(gp_free, rc = -EFAULT); + + rc = ll_getxattr(dentry, XATTR_NAME_LINK, buf.lb_buf, buf.lb_len); + if (rc < 0) + GOTO(gp_free, rc); + + rc = ll_linkea_decode(ldata, linkno, gpout, name_size); + if (rc < 0) + GOTO(gp_free, rc); + + if (copy_to_user(arg, gpout, out_size)) + GOTO(gp_free, rc = -EFAULT); + +gp_free: + OBD_FREE(gpout, out_size); +lb_free: + lu_buf_free(&buf); +ldata_free: + OBD_FREE(ldata, sizeof(*ldata)); + + RETURN(rc); +}