X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=blobdiff_plain;f=lustre%2Fllite%2Fllite_lib.c;h=c11da6c7c05a242e10a970dbe58b0a89c77ebaf5;hp=cd9f5ae69a20c27c2bba093aeb8f6bc1a99ebcce;hb=7d5d004506650c3739898e70d72c9a86b8aeeb88;hpb=f37e26964a34fc33ec6add792ebb3b6a51797813 diff --git a/lustre/llite/llite_lib.c b/lustre/llite/llite_lib.c index cd9f5ae..c11da6c 100644 --- a/lustre/llite/llite_lib.c +++ b/lustre/llite/llite_lib.c @@ -27,7 +27,6 @@ */ /* * This file is part of Lustre, http://www.lustre.org/ - * Lustre is a trademark of Sun Microsystems, Inc. * * lustre/llite/llite_lib.c * @@ -48,7 +47,7 @@ #include #include #include -#include +#include #ifndef HAVE_CPUS_READ_LOCK #include @@ -128,11 +127,33 @@ static struct ll_sb_info *ll_init_sbi(void) if (sbi->ll_cache == NULL) GOTO(out_destroy_ra, rc = -ENOMEM); - sbi->ll_ra_info.ra_max_pages_per_file = min(pages / 32, - SBI_DEFAULT_READ_AHEAD_MAX); + /* initialize foreign symlink prefix path */ + OBD_ALLOC(sbi->ll_foreign_symlink_prefix, sizeof("/mnt/")); + if (sbi->ll_foreign_symlink_prefix == NULL) + GOTO(out_destroy_ra, rc = -ENOMEM); + memcpy(sbi->ll_foreign_symlink_prefix, "/mnt/", sizeof("/mnt/")); + sbi->ll_foreign_symlink_prefix_size = sizeof("/mnt/"); + + /* initialize foreign symlink upcall path, none by default */ + OBD_ALLOC(sbi->ll_foreign_symlink_upcall, sizeof("none")); + if (sbi->ll_foreign_symlink_upcall == NULL) + GOTO(out_destroy_ra, rc = -ENOMEM); + memcpy(sbi->ll_foreign_symlink_upcall, "none", sizeof("none")); + sbi->ll_foreign_symlink_upcall_items = NULL; + sbi->ll_foreign_symlink_upcall_nb_items = 0; + init_rwsem(&sbi->ll_foreign_symlink_sem); + /* foreign symlink support (LL_SBI_FOREIGN_SYMLINK in ll_flags) + * not enabled by default + */ + + sbi->ll_ra_info.ra_max_pages = + min(pages / 32, SBI_DEFAULT_READ_AHEAD_MAX); + sbi->ll_ra_info.ra_max_pages_per_file = + min(sbi->ll_ra_info.ra_max_pages / 4, + SBI_DEFAULT_READ_AHEAD_PER_FILE_MAX); sbi->ll_ra_info.ra_async_pages_per_file_threshold = sbi->ll_ra_info.ra_max_pages_per_file; - sbi->ll_ra_info.ra_max_pages = sbi->ll_ra_info.ra_max_pages_per_file; + sbi->ll_ra_info.ra_range_pages = SBI_DEFAULT_RA_RANGE_PAGES; sbi->ll_ra_info.ra_max_read_ahead_whole_pages = -1; atomic_set(&sbi->ll_ra_info.ra_async_inflight, 0); @@ -177,8 +198,19 @@ static struct ll_sb_info *ll_init_sbi(void) /* Per-filesystem file heat */ sbi->ll_heat_decay_weight = SBI_DEFAULT_HEAT_DECAY_WEIGHT; sbi->ll_heat_period_second = SBI_DEFAULT_HEAT_PERIOD_SECOND; + + /* Per-fs open heat level before requesting open lock */ + sbi->ll_oc_thrsh_count = SBI_DEFAULT_OPENCACHE_THRESHOLD_COUNT; + sbi->ll_oc_max_ms = SBI_DEFAULT_OPENCACHE_THRESHOLD_MAX_MS; + sbi->ll_oc_thrsh_ms = SBI_DEFAULT_OPENCACHE_THRESHOLD_MS; RETURN(sbi); out_destroy_ra: + if (sbi->ll_foreign_symlink_prefix) + OBD_FREE(sbi->ll_foreign_symlink_prefix, sizeof("/mnt/")); + if (sbi->ll_cache) { + cl_cache_decref(sbi->ll_cache); + sbi->ll_cache = NULL; + } destroy_workqueue(sbi->ll_ra_info.ll_readahead_wq); out_pcc: pcc_super_fini(&sbi->ll_pcc_super); @@ -201,6 +233,32 @@ static void ll_free_sbi(struct super_block *sb) cl_cache_decref(sbi->ll_cache); sbi->ll_cache = NULL; } + if (sbi->ll_foreign_symlink_prefix) { + OBD_FREE(sbi->ll_foreign_symlink_prefix, + sbi->ll_foreign_symlink_prefix_size); + sbi->ll_foreign_symlink_prefix = NULL; + } + if (sbi->ll_foreign_symlink_upcall) { + OBD_FREE(sbi->ll_foreign_symlink_upcall, + strlen(sbi->ll_foreign_symlink_upcall) + + 1); + sbi->ll_foreign_symlink_upcall = NULL; + } + if (sbi->ll_foreign_symlink_upcall_items) { + int i; + int nb_items = sbi->ll_foreign_symlink_upcall_nb_items; + struct ll_foreign_symlink_upcall_item *items = + sbi->ll_foreign_symlink_upcall_items; + + for (i = 0 ; i < nb_items; i++) + if (items[i].type == STRING_TYPE) + OBD_FREE(items[i].string, + items[i].size); + + OBD_FREE_LARGE(items, nb_items * + sizeof(struct ll_foreign_symlink_upcall_item)); + sbi->ll_foreign_symlink_upcall_items = NULL; + } pcc_super_fini(&sbi->ll_pcc_super); OBD_FREE(sbi, sizeof(*sbi)); } @@ -275,7 +333,10 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt) OBD_CONNECT2_LSOM | OBD_CONNECT2_ASYNC_DISCARD | OBD_CONNECT2_PCC | - OBD_CONNECT2_CRUSH; + OBD_CONNECT2_CRUSH | OBD_CONNECT2_LSEEK | + OBD_CONNECT2_GETATTR_PFID | + OBD_CONNECT2_DOM_LVB | + OBD_CONNECT2_REP_MBITS; #ifdef HAVE_LRU_RESIZE_SUPPORT if (sbi->ll_flags & LL_SBI_LRU_RESIZE) @@ -304,13 +365,7 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt) */ sb->s_flags |= SB_NOSEC; #endif - - if (sbi->ll_flags & LL_SBI_FLOCK) - sbi->ll_fop = &ll_file_operations_flock; - else if (sbi->ll_flags & LL_SBI_LOCALFLOCK) - sbi->ll_fop = &ll_file_operations; - else - sbi->ll_fop = &ll_file_operations_noflock; + sbi->ll_fop = ll_select_file_operations(sbi); /* always ping even if server suppress_pings */ if (sbi->ll_flags & LL_SBI_ALWAYS_PING) @@ -473,7 +528,8 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt) OBD_CONNECT_BULK_MBITS | OBD_CONNECT_SHORTIO | OBD_CONNECT_FLAGS2 | OBD_CONNECT_GRANT_SHRINK; data->ocd_connect_flags2 = OBD_CONNECT2_LOCKAHEAD | - OBD_CONNECT2_INC_XID; + OBD_CONNECT2_INC_XID | OBD_CONNECT2_LSEEK | + OBD_CONNECT2_REP_MBITS; if (!OBD_FAIL_CHECK(OBD_FAIL_OSC_CONNECT_GRANT_PARAM)) data->ocd_connect_flags |= OBD_CONNECT_GRANT_PARAM; @@ -692,8 +748,7 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt) RETURN(err); out_root: - if (root) - iput(root); + iput(root); out_lock_cn_cb: obd_fid_fini(sbi->ll_dt_exp->exp_obd); out_dt: @@ -982,6 +1037,58 @@ static int ll_options(char *options, struct ll_sb_info *sbi) #endif goto next; } + tmp = ll_set_opt("foreign_symlink", s1, LL_SBI_FOREIGN_SYMLINK); + if (tmp) { + int prefix_pos = sizeof("foreign_symlink=") - 1; + int equal_pos = sizeof("foreign_symlink=") - 2; + + /* non-default prefix provided ? */ + if (strlen(s1) >= sizeof("foreign_symlink=") && + *(s1 + equal_pos) == '=') { + char *old = sbi->ll_foreign_symlink_prefix; + size_t old_len = + sbi->ll_foreign_symlink_prefix_size; + + /* path must be absolute */ + if (*(s1 + sizeof("foreign_symlink=") + - 1) != '/') { + LCONSOLE_ERROR_MSG(0x152, + "foreign prefix '%s' must be an absolute path\n", + s1 + prefix_pos); + RETURN(-EINVAL); + } + /* last option ? */ + s2 = strchrnul(s1 + prefix_pos, ','); + + if (sbi->ll_foreign_symlink_prefix) { + sbi->ll_foreign_symlink_prefix = NULL; + sbi->ll_foreign_symlink_prefix_size = 0; + } + /* alloc for path length and '\0' */ + OBD_ALLOC(sbi->ll_foreign_symlink_prefix, + s2 - (s1 + prefix_pos) + 1); + if (!sbi->ll_foreign_symlink_prefix) { + /* restore previous */ + sbi->ll_foreign_symlink_prefix = old; + sbi->ll_foreign_symlink_prefix_size = + old_len; + RETURN(-ENOMEM); + } + if (old) + OBD_FREE(old, old_len); + strncpy(sbi->ll_foreign_symlink_prefix, + s1 + prefix_pos, + s2 - (s1 + prefix_pos)); + sbi->ll_foreign_symlink_prefix_size = + s2 - (s1 + prefix_pos) + 1; + } else { + LCONSOLE_ERROR_MSG(0x152, + "invalid %s option\n", s1); + } + /* enable foreign symlink support */ + *flags |= tmp; + goto next; + } LCONSOLE_ERROR_MSG(0x152, "Unknown option '%s', won't mount.\n", s1); RETURN(-EINVAL); @@ -1114,6 +1221,8 @@ int ll_fill_super(struct super_block *sb) CDEBUG(D_VFSTRACE, "VFS Op: cfg_instance %s-%016lx (sb %p)\n", profilenm, cfg_instance, sb); + OBD_RACE(OBD_FAIL_LLITE_RACE_MOUNT); + OBD_ALLOC_PTR(cfg); if (cfg == NULL) GOTO(out_free_cfg, err = -ENOMEM); @@ -1320,8 +1429,6 @@ out_no_sbi: cl_env_cache_purge(~0); - module_put(THIS_MODULE); - EXIT; } /* client_put_super */ @@ -1483,30 +1590,27 @@ static void ll_update_default_lsm_md(struct inode *inode, struct lustre_md *md) } up_write(&lli->lli_lsm_sem); } - } else if (lli->lli_default_lsm_md) { - /* update default lsm if it changes */ + return; + } + + if (lli->lli_default_lsm_md) { + /* do nonthing if default lsm isn't changed */ down_read(&lli->lli_lsm_sem); if (lli->lli_default_lsm_md && - !lsm_md_eq(lli->lli_default_lsm_md, md->default_lmv)) { - up_read(&lli->lli_lsm_sem); - down_write(&lli->lli_lsm_sem); - if (lli->lli_default_lsm_md) - lmv_free_memmd(lli->lli_default_lsm_md); - lli->lli_default_lsm_md = md->default_lmv; - lsm_md_dump(D_INODE, md->default_lmv); - md->default_lmv = NULL; - up_write(&lli->lli_lsm_sem); - } else { + lsm_md_eq(lli->lli_default_lsm_md, md->default_lmv)) { up_read(&lli->lli_lsm_sem); + return; } - } else { - /* init default lsm */ - down_write(&lli->lli_lsm_sem); - lli->lli_default_lsm_md = md->default_lmv; - lsm_md_dump(D_INODE, md->default_lmv); - md->default_lmv = NULL; - up_write(&lli->lli_lsm_sem); + up_read(&lli->lli_lsm_sem); } + + down_write(&lli->lli_lsm_sem); + if (lli->lli_default_lsm_md) + lmv_free_memmd(lli->lli_default_lsm_md); + lli->lli_default_lsm_md = md->default_lmv; + lsm_md_dump(D_INODE, md->default_lmv); + md->default_lmv = NULL; + up_write(&lli->lli_lsm_sem); } static int ll_update_lsm_md(struct inode *inode, struct lustre_md *md) @@ -1591,8 +1695,8 @@ static int ll_update_lsm_md(struct inode *inode, struct lustre_md *md) GOTO(unlock, rc = -ENOMEM); /* validate the lsm */ - rc = md_merge_attr(ll_i2mdexp(inode), &lli->lli_fid, lli->lli_lsm_md, - attr, ll_md_blocking_ast); + rc = md_merge_attr(ll_i2mdexp(inode), lli->lli_lsm_md, attr, + ll_md_blocking_ast); if (!rc) { if (md->body->mbo_valid & OBD_MD_FLNLINK) md->body->mbo_nlink = attr->cat_nlink; @@ -1942,7 +2046,7 @@ int ll_setattr_raw(struct dentry *dentry, struct iattr *attr, /* POSIX: check before ATTR_*TIME_SET set (from inode_change_ok) */ if (attr->ia_valid & TIMES_SET_FLAGS) { if ((!uid_eq(current_fsuid(), inode->i_uid)) && - !cfs_capable(CFS_CAP_FOWNER)) + !capable(CAP_FOWNER)) RETURN(-EPERM); } @@ -1984,7 +2088,7 @@ int ll_setattr_raw(struct dentry *dentry, struct iattr *attr, */ xvalid |= OP_XVALID_OWNEROVERRIDE; op_data->op_bias |= MDS_DATA_MODIFIED; - ll_file_clear_flag(lli, LLIF_DATA_MODIFIED); + clear_bit(LLIF_DATA_MODIFIED, &lli->lli_flags); } if (attr->ia_valid & ATTR_FILE) { @@ -2033,7 +2137,15 @@ int ll_setattr_raw(struct dentry *dentry, struct iattr *attr, attr->ia_valid & ATTR_SIZE) { xvalid |= OP_XVALID_FLAGS; flags = LUSTRE_ENCRYPT_FL; - if (attr->ia_size & ~PAGE_MASK) { + /* Call to ll_io_zero_page is not necessary if + * truncating on PAGE_SIZE boundary, because + * whole pages will be wiped. + * In case of Direct IO, all we need is to set + * new size. + */ + if (attr->ia_size & ~PAGE_MASK && + !(attr->ia_valid & ATTR_FILE && + attr->ia_file->f_flags & O_DIRECT)) { pgoff_t offset = attr->ia_size & (PAGE_SIZE - 1); @@ -2061,7 +2173,7 @@ int ll_setattr_raw(struct dentry *dentry, struct iattr *attr, * LLIF_DATA_MODIFIED is not set(see vvp_io_setattr_fini()). * This way we can save an RPC for common open + trunc * operation. */ - if (ll_file_test_and_clear_flag(lli, LLIF_DATA_MODIFIED)) { + if (test_and_clear_bit(LLIF_DATA_MODIFIED, &lli->lli_flags)) { struct hsm_state_set hss = { .hss_valid = HSS_SETMASK, .hss_setmask = HS_DIRTY, @@ -2193,6 +2305,52 @@ out: RETURN(rc); } +static int ll_statfs_project(struct inode *inode, struct kstatfs *sfs) +{ + struct if_quotactl qctl = { + .qc_cmd = LUSTRE_Q_GETQUOTA, + .qc_type = PRJQUOTA, + .qc_valid = QC_GENERAL, + }; + u64 limit, curblock; + int ret; + + qctl.qc_id = ll_i2info(inode)->lli_projid; + ret = quotactl_ioctl(ll_i2sbi(inode), &qctl); + if (ret) { + /* ignore errors if project ID does not have + * a quota limit or feature unsupported. + */ + if (ret == -ESRCH || ret == -EOPNOTSUPP) + ret = 0; + return ret; + } + + limit = ((qctl.qc_dqblk.dqb_bsoftlimit ? + qctl.qc_dqblk.dqb_bsoftlimit : + qctl.qc_dqblk.dqb_bhardlimit) * 1024) / sfs->f_bsize; + if (limit && sfs->f_blocks > limit) { + curblock = (qctl.qc_dqblk.dqb_curspace + + sfs->f_bsize - 1) / sfs->f_bsize; + sfs->f_blocks = limit; + sfs->f_bfree = sfs->f_bavail = + (sfs->f_blocks > curblock) ? + (sfs->f_blocks - curblock) : 0; + } + + limit = qctl.qc_dqblk.dqb_isoftlimit ? + qctl.qc_dqblk.dqb_isoftlimit : + qctl.qc_dqblk.dqb_ihardlimit; + if (limit && sfs->f_files > limit) { + sfs->f_files = limit; + sfs->f_ffree = (sfs->f_files > + qctl.qc_dqblk.dqb_curinodes) ? + (sfs->f_files - qctl.qc_dqblk.dqb_curinodes) : 0; + } + + return 0; +} + int ll_statfs(struct dentry *de, struct kstatfs *sfs) { struct super_block *sb = de->d_sb; @@ -2229,6 +2387,8 @@ int ll_statfs(struct dentry *de, struct kstatfs *sfs) sfs->f_bavail = osfs.os_bavail; sfs->f_fsid.val[0] = (__u32)fsid; sfs->f_fsid.val[1] = (__u32)(fsid >> 32); + if (ll_i2info(de->d_inode)->lli_projid) + return ll_statfs_project(de->d_inode, sfs); ll_stats_ops_tally(ll_s2sbi(sb), LPROC_LL_STATFS, ktime_us_delta(ktime_get(), kstart)); @@ -2254,15 +2414,15 @@ void ll_inode_size_unlock(struct inode *inode) mutex_unlock(&lli->lli_size_mutex); } -void ll_update_inode_flags(struct inode *inode, int ext_flags) +void ll_update_inode_flags(struct inode *inode, unsigned int ext_flags) { /* do not clear encryption flag */ ext_flags |= ll_inode_to_ext_flags(inode->i_flags) & LUSTRE_ENCRYPT_FL; inode->i_flags = ll_ext_to_inode_flags(ext_flags); if (ext_flags & LUSTRE_PROJINHERIT_FL) - ll_file_set_flag(ll_i2info(inode), LLIF_PROJECT_INHERIT); + set_bit(LLIF_PROJECT_INHERIT, &ll_i2info(inode)->lli_flags); else - ll_file_clear_flag(ll_i2info(inode), LLIF_PROJECT_INHERIT); + clear_bit(LLIF_PROJECT_INHERIT, &ll_i2info(inode)->lli_flags); } int ll_update_inode(struct inode *inode, struct lustre_md *md) @@ -2378,14 +2538,42 @@ int ll_update_inode(struct inode *inode, struct lustre_md *md) * glimpsing updated attrs */ if (body->mbo_t_state & MS_RESTORE) - ll_file_set_flag(lli, LLIF_FILE_RESTORING); + set_bit(LLIF_FILE_RESTORING, &lli->lli_flags); else - ll_file_clear_flag(lli, LLIF_FILE_RESTORING); + clear_bit(LLIF_FILE_RESTORING, &lli->lli_flags); } return 0; } +void ll_truncate_inode_pages_final(struct inode *inode) +{ + struct address_space *mapping = &inode->i_data; + unsigned long nrpages; + unsigned long flags; + + truncate_inode_pages_final(mapping); + + /* Workaround for LU-118: Note nrpages may not be totally updated when + * truncate_inode_pages() returns, as there can be a page in the process + * of deletion (inside __delete_from_page_cache()) in the specified + * range. Thus mapping->nrpages can be non-zero when this function + * returns even after truncation of the whole mapping. Only do this if + * npages isn't already zero. + */ + nrpages = mapping->nrpages; + if (nrpages) { + ll_xa_lock_irqsave(&mapping->i_pages, flags); + nrpages = mapping->nrpages; + ll_xa_unlock_irqrestore(&mapping->i_pages, flags); + } /* Workaround end */ + + LASSERTF(nrpages == 0, "%s: inode="DFID"(%p) nrpages=%lu, " + "see https://jira.whamcloud.com/browse/LU-118\n", + ll_i2sbi(inode)->ll_fsname, + PFID(ll_inode2fid(inode)), inode, nrpages); +} + int ll_read_inode2(struct inode *inode, void *opaque) { struct lustre_md *md = opaque; @@ -2443,10 +2631,6 @@ int ll_read_inode2(struct inode *inode, void *opaque) void ll_delete_inode(struct inode *inode) { struct ll_inode_info *lli = ll_i2info(inode); - struct address_space *mapping = &inode->i_data; - unsigned long nrpages; - unsigned long flags; - ENTRY; if (S_ISREG(inode->i_mode) && lli->lli_clob != NULL) { @@ -2460,27 +2644,8 @@ void ll_delete_inode(struct inode *inode) cl_sync_file_range(inode, 0, OBD_OBJECT_EOF, inode->i_nlink ? CL_FSYNC_LOCAL : CL_FSYNC_DISCARD, 1); } - truncate_inode_pages_final(mapping); - - /* Workaround for LU-118: Note nrpages may not be totally updated when - * truncate_inode_pages() returns, as there can be a page in the process - * of deletion (inside __delete_from_page_cache()) in the specified - * range. Thus mapping->nrpages can be non-zero when this function - * returns even after truncation of the whole mapping. Only do this if - * npages isn't already zero. - */ - nrpages = mapping->nrpages; - if (nrpages) { - ll_xa_lock_irqsave(&mapping->i_pages, flags); - nrpages = mapping->nrpages; - ll_xa_unlock_irqrestore(&mapping->i_pages, flags); - } /* Workaround end */ - - LASSERTF(nrpages == 0, "%s: inode="DFID"(%p) nrpages=%lu, " - "see https://jira.whamcloud.com/browse/LU-118\n", - ll_i2sbi(inode)->ll_fsname, - PFID(ll_inode2fid(inode)), inode, nrpages); + ll_truncate_inode_pages_final(inode); ll_clear_inode(inode); clear_inode(inode); @@ -2808,6 +2973,13 @@ int ll_prep_inode(struct inode **inode, struct ptlrpc_request *req, if (default_lmv_deleted) ll_update_default_lsm_md(*inode, &md); + /* we may want to apply some policy for foreign file/dir */ + if (ll_sbi_has_foreign_symlink(sbi)) { + rc = ll_manage_foreign(*inode, &md); + if (rc < 0) + GOTO(out, rc); + } + GOTO(out, rc = 0); out: @@ -2824,44 +2996,44 @@ out: 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; - int len = 0, rc; - - if (!inode || !(sbi = ll_i2sbi(inode))) - GOTO(out_statfs, rc = -EINVAL); - - rc = obd_ioctl_getdata(&buf, &len, arg); - if (rc) - GOTO(out_statfs, rc); - - data = (void*)buf; - if (!data->ioc_inlbuf1 || !data->ioc_inlbuf2 || - !data->ioc_pbuf1 || !data->ioc_pbuf2) - GOTO(out_statfs, rc = -EINVAL); - - if (data->ioc_inllen1 != sizeof(__u32) || - data->ioc_inllen2 != sizeof(__u32) || - data->ioc_plen1 != sizeof(struct obd_statfs) || - data->ioc_plen2 != sizeof(struct obd_uuid)) - GOTO(out_statfs, rc = -EINVAL); - - memcpy(&type, data->ioc_inlbuf1, sizeof(__u32)); + struct ll_sb_info *sbi = NULL; + struct obd_export *exp; + struct obd_ioctl_data *data = NULL; + __u32 type; + int len = 0, rc; + + if (inode) + sbi = ll_i2sbi(inode); + if (!sbi) + GOTO(out_statfs, rc = -EINVAL); + + rc = obd_ioctl_getdata(&data, &len, arg); + if (rc) + GOTO(out_statfs, rc); + + if (!data->ioc_inlbuf1 || !data->ioc_inlbuf2 || + !data->ioc_pbuf1 || !data->ioc_pbuf2) + GOTO(out_statfs, rc = -EINVAL); + + if (data->ioc_inllen1 != sizeof(__u32) || + data->ioc_inllen2 != sizeof(__u32) || + data->ioc_plen1 != sizeof(struct obd_statfs) || + data->ioc_plen2 != sizeof(struct obd_uuid)) + GOTO(out_statfs, rc = -EINVAL); + + memcpy(&type, data->ioc_inlbuf1, sizeof(__u32)); if (type & LL_STATFS_LMV) - exp = sbi->ll_md_exp; + exp = sbi->ll_md_exp; else if (type & LL_STATFS_LOV) - exp = sbi->ll_dt_exp; - else - GOTO(out_statfs, rc = -ENODEV); + exp = sbi->ll_dt_exp; + else + GOTO(out_statfs, rc = -ENODEV); - rc = obd_iocontrol(IOC_OBD_STATFS, exp, len, buf, NULL); - if (rc) - GOTO(out_statfs, rc); + rc = obd_iocontrol(IOC_OBD_STATFS, exp, len, data, NULL); + if (rc) + GOTO(out_statfs, rc); out_statfs: - OBD_FREE_LARGE(buf, len); + OBD_FREE_LARGE(data, len); return rc; } @@ -2872,12 +3044,12 @@ out_statfs: void ll_unlock_md_op_lsm(struct md_op_data *op_data) { if (op_data->op_mea2_sem) { - up_read(op_data->op_mea2_sem); + up_read_non_owner(op_data->op_mea2_sem); op_data->op_mea2_sem = NULL; } if (op_data->op_mea1_sem) { - up_read(op_data->op_mea1_sem); + up_read_non_owner(op_data->op_mea1_sem); op_data->op_mea1_sem = NULL; } } @@ -2899,7 +3071,9 @@ struct md_op_data *ll_prep_md_op_data(struct md_op_data *op_data, if (namelen > ll_i2sbi(i1)->ll_namelen) return ERR_PTR(-ENAMETOOLONG); - if (!lu_name_is_valid_2(name, namelen)) + /* "/" is not valid name, but it's allowed */ + if (!lu_name_is_valid_2(name, namelen) && + strncmp("/", name, namelen) != 0) return ERR_PTR(-EINVAL); } @@ -2914,7 +3088,7 @@ struct md_op_data *ll_prep_md_op_data(struct md_op_data *op_data, op_data->op_code = opc; if (S_ISDIR(i1->i_mode)) { - down_read(&ll_i2info(i1)->lli_lsm_sem); + down_read_non_owner(&ll_i2info(i1)->lli_lsm_sem); op_data->op_mea1_sem = &ll_i2info(i1)->lli_lsm_sem; op_data->op_mea1 = ll_i2info(i1)->lli_lsm_md; op_data->op_default_mea1 = ll_i2info(i1)->lli_default_lsm_md; @@ -2924,7 +3098,10 @@ struct md_op_data *ll_prep_md_op_data(struct md_op_data *op_data, op_data->op_fid2 = *ll_inode2fid(i2); if (S_ISDIR(i2->i_mode)) { if (i2 != i1) { - down_read(&ll_i2info(i2)->lli_lsm_sem); + /* i2 is typically a child of i1, and MUST be + * further from the root to avoid deadlocks. + */ + down_read_non_owner(&ll_i2info(i2)->lli_lsm_sem); op_data->op_mea2_sem = &ll_i2info(i2)->lli_lsm_sem; } @@ -2960,9 +3137,10 @@ struct md_op_data *ll_prep_md_op_data(struct md_op_data *op_data, void ll_finish_md_op_data(struct md_op_data *op_data) { ll_unlock_md_op_lsm(op_data); - security_release_secctx(op_data->op_file_secctx, - op_data->op_file_secctx_size); - OBD_FREE_PTR(op_data); + ll_security_release_secctx(op_data->op_file_secctx, + op_data->op_file_secctx_size); + llcrypt_free_ctx(op_data->op_file_encctx, op_data->op_file_encctx_size); + OBD_FREE_PTR(op_data); } int ll_show_options(struct seq_file *seq, struct dentry *dentry) @@ -3006,6 +3184,11 @@ int ll_show_options(struct seq_file *seq, struct dentry *dentry) else seq_puts(seq, ",noencrypt"); + if (sbi->ll_flags & LL_SBI_FOREIGN_SYMLINK) { + seq_puts(seq, ",foreign_symlink="); + seq_puts(seq, sbi->ll_foreign_symlink_prefix); + } + RETURN(0); } @@ -3018,7 +3201,7 @@ int ll_get_obd_name(struct inode *inode, unsigned int cmd, unsigned long arg) struct obd_device *obd; ENTRY; - if (cmd == OBD_IOC_GETDTNAME) + if (cmd == OBD_IOC_GETNAME_OLD || cmd == OBD_IOC_GETDTNAME) obd = class_exp2obd(sbi->ll_dt_exp); else if (cmd == OBD_IOC_GETMDNAME) obd = class_exp2obd(sbi->ll_md_exp); @@ -3208,7 +3391,7 @@ int ll_getparent(struct file *file, struct getparent __user *arg) ENTRY; - if (!cfs_capable(CFS_CAP_DAC_READ_SEARCH) && + if (!capable(CAP_DAC_READ_SEARCH) && !(ll_i2sbi(inode)->ll_flags & LL_SBI_USER_FID2PATH)) RETURN(-EPERM);