X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lustre%2Fllite%2Ffile.c;h=3db09e11980593421d2ed08796edccce2fd4c4d0;hb=ea58c4cfb0fc255befbbb7754bd4ed71704a2a2c;hp=d7c1e9e35029e58be47de8ad13fafd2b94a1a786;hpb=6d296587441d80588340200903027ac4231922cd;p=fs%2Flustre-release.git diff --git a/lustre/llite/file.c b/lustre/llite/file.c index d7c1e9e..3db09e1 100644 --- a/lustre/llite/file.c +++ b/lustre/llite/file.c @@ -58,6 +58,12 @@ struct split_param { __u16 sp_mirror_id; }; +struct pcc_param { + __u64 pa_data_version; + __u32 pa_archive_id; + __u32 pa_layout_gen; +}; + static int ll_put_grouplock(struct inode *inode, struct file *file, unsigned long arg); @@ -73,6 +79,7 @@ static struct ll_file_data *ll_file_data_get(void) return NULL; fd->fd_write_failed = false; + pcc_file_init(&fd->fd_pcc_file); return fd; } @@ -156,6 +163,7 @@ static int ll_close_inode_openhandle(struct inode *inode, op_data->op_attr_blocks += ((struct inode *)data)->i_blocks; op_data->op_attr.ia_valid |= ATTR_SIZE; op_data->op_xvalid |= OP_XVALID_BLOCKS; + /* fallthrough */ case MDS_CLOSE_LAYOUT_SPLIT: case MDS_CLOSE_LAYOUT_SWAP: { struct split_param *sp = data; @@ -190,6 +198,17 @@ static int ll_close_inode_openhandle(struct inode *inode, break; } + case MDS_PCC_ATTACH: { + struct pcc_param *param = data; + + LASSERT(data != NULL); + op_data->op_bias |= MDS_HSM_RELEASE | MDS_PCC_ATTACH; + op_data->op_archive_id = param->pa_archive_id; + op_data->op_data_version = param->pa_data_version; + op_data->op_lease_handle = och->och_lease_handle; + break; + } + case MDS_HSM_RELEASE: LASSERT(data != NULL); op_data->op_bias |= MDS_HSM_RELEASE; @@ -220,6 +239,12 @@ static int ll_close_inode_openhandle(struct inode *inode, body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY); if (!(body->mbo_valid & OBD_MD_CLOSE_INTENT_EXECED)) rc = -EBUSY; + + if (bias & MDS_PCC_ATTACH) { + struct pcc_param *param = data; + + param->pa_layout_gen = body->mbo_layout_gen; + } } ll_finish_md_op_data(op_data); @@ -329,7 +354,9 @@ static int ll_md_close(struct inode *inode, struct file *file) } mutex_unlock(&lli->lli_och_mutex); - if (!md_lock_match(ll_i2mdexp(inode), flags, ll_inode2fid(inode), + /* LU-4398: do not cache write open lock if the file has exec bit */ + if ((lockmode == LCK_CW && inode->i_mode & S_IXUGO) || + !md_lock_match(ll_i2mdexp(inode), flags, ll_inode2fid(inode), LDLM_IBITS, &policy, lockmode, &lockh)) rc = ll_md_real_close(inode, fd->fd_omode); @@ -347,19 +374,19 @@ out: */ int ll_file_release(struct inode *inode, struct file *file) { - struct ll_file_data *fd; - struct ll_sb_info *sbi = ll_i2sbi(inode); - struct ll_inode_info *lli = ll_i2info(inode); - int rc; - ENTRY; + struct ll_file_data *fd; + struct ll_sb_info *sbi = ll_i2sbi(inode); + struct ll_inode_info *lli = ll_i2info(inode); + ktime_t kstart = ktime_get(); + int rc; + + ENTRY; CDEBUG(D_VFSTRACE, "VFS Op:inode="DFID"(%p)\n", PFID(ll_inode2fid(inode)), inode); - if (inode->i_sb->s_root != file_dentry(file)) - ll_stats_ops_tally(sbi, LPROC_LL_RELEASE, 1); - fd = LUSTRE_FPRIVATE(file); - LASSERT(fd != NULL); + fd = LUSTRE_FPRIVATE(file); + LASSERT(fd != NULL); /* The last ref on @file, maybe not the the owner pid of statahead, * because parent and child process can share the same file handle. */ @@ -369,9 +396,11 @@ int ll_file_release(struct inode *inode, struct file *file) if (inode->i_sb->s_root == file_dentry(file)) { LUSTRE_FPRIVATE(file) = NULL; ll_file_data_put(fd); - RETURN(0); + GOTO(out, rc = 0); } + pcc_file_release(inode, file); + if (!S_ISDIR(inode->i_mode)) { if (lli->lli_clob != NULL) lov_read_and_clear_async_rc(lli->lli_clob); @@ -383,6 +412,10 @@ int ll_file_release(struct inode *inode, struct file *file) if (CFS_FAIL_TIMEOUT_MS(OBD_FAIL_PTLRPC_DUMP_LOG, cfs_fail_val)) libcfs_debug_dumplog(); +out: + if (!rc && inode->i_sb->s_root != file_dentry(file)) + ll_stats_ops_tally(sbi, LPROC_LL_RELEASE, + ktime_us_delta(ktime_get(), kstart)); RETURN(rc); } @@ -412,6 +445,7 @@ void ll_dom_finish_open(struct inode *inode, struct ptlrpc_request *req, struct address_space *mapping = inode->i_mapping; struct page *vmpage; struct niobuf_remote *rnb; + struct mdt_body *body; char *data; unsigned long index, start; struct niobuf_local lnb; @@ -437,18 +471,19 @@ void ll_dom_finish_open(struct inode *inode, struct ptlrpc_request *req, if (rnb->rnb_offset % PAGE_SIZE) RETURN_EXIT; - /* Server returns whole file or just file tail if it fills in - * reply buffer, in both cases total size should be inode size. + /* Server returns whole file or just file tail if it fills in reply + * buffer, in both cases total size should be equal to the file size. */ - if (rnb->rnb_offset + rnb->rnb_len < i_size_read(inode)) { - CERROR("%s: server returns off/len %llu/%u < i_size %llu\n", + body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY); + if (rnb->rnb_offset + rnb->rnb_len != body->mbo_dom_size) { + CERROR("%s: server returns off/len %llu/%u but size %llu\n", ll_i2sbi(inode)->ll_fsname, rnb->rnb_offset, - rnb->rnb_len, i_size_read(inode)); + rnb->rnb_len, body->mbo_dom_size); RETURN_EXIT; } - CDEBUG(D_INFO, "Get data along with open at %llu len %i, i_size %llu\n", - rnb->rnb_offset, rnb->rnb_len, i_size_read(inode)); + CDEBUG(D_INFO, "Get data along with open at %llu len %i, size %llu\n", + rnb->rnb_offset, rnb->rnb_len, body->mbo_dom_size); data = (char *)rnb + sizeof(*rnb); @@ -662,6 +697,7 @@ int ll_file_open(struct inode *inode, struct file *file) struct obd_client_handle **och_p = NULL; __u64 *och_usecount = NULL; struct ll_file_data *fd; + ktime_t kstart = ktime_get(); int rc = 0; ENTRY; @@ -813,6 +849,11 @@ restart: if (rc) GOTO(out_och_free, rc); } + + rc = pcc_file_open(inode, file); + if (rc) + GOTO(out_och_free, rc); + mutex_unlock(&lli->lli_och_mutex); fd = NULL; @@ -837,11 +878,13 @@ out_och_free: out_openerr: if (lli->lli_opendir_key == fd) ll_deauthorize_statahead(inode, fd); + if (fd != NULL) ll_file_data_put(fd); - } else { - ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_OPEN, 1); - } + } else { + ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_OPEN, + ktime_us_delta(ktime_get(), kstart)); + } out_nofiledata: if (it && it_disposition(it, DISP_ENQ_OPEN_REF)) { @@ -849,7 +892,7 @@ out_nofiledata: it_clear_disposition(it, DISP_ENQ_OPEN_REF); } - return rc; + return rc; } static int ll_md_blocking_lease_ast(struct ldlm_lock *lock, @@ -1029,7 +1072,9 @@ ll_lease_open(struct inode *inode, struct file *file, fmode_t fmode, GOTO(out_release_it, rc); LASSERT(it_disposition(&it, DISP_ENQ_OPEN_REF)); - ll_och_fill(sbi->ll_md_exp, &it, och); + rc = ll_och_fill(sbi->ll_md_exp, &it, och); + if (rc) + GOTO(out_release_it, rc); if (!it_disposition(&it, DISP_OPEN_LEASE)) /* old server? */ GOTO(out_close, rc = -EOPNOTSUPP); @@ -1338,13 +1383,14 @@ static bool file_is_noatime(const struct file *file) if ((mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode)) return true; - if ((inode->i_sb->s_flags & MS_NODIRATIME) && S_ISDIR(inode->i_mode)) + if ((inode->i_sb->s_flags & SB_NODIRATIME) && S_ISDIR(inode->i_mode)) return true; return false; } -static void ll_io_init(struct cl_io *io, struct file *file, enum cl_io_type iot) +void ll_io_init(struct cl_io *io, struct file *file, enum cl_io_type iot, + struct vvp_io_args *args) { struct inode *inode = file_inode(file); struct ll_file_data *fd = LUSTRE_FPRIVATE(file); @@ -1357,7 +1403,13 @@ static void ll_io_init(struct cl_io *io, struct file *file, enum cl_io_type iot) io->u.ci_wr.wr_sync = !!(file->f_flags & O_SYNC || file->f_flags & O_DIRECT || IS_SYNC(inode)); +#ifdef HAVE_GENERIC_WRITE_SYNC_2ARGS + io->u.ci_wr.wr_sync |= !!(args && + args->via_io_subtype == IO_NORMAL && + args->u.normal.via_iocb->ki_flags & IOCB_DSYNC); +#endif } + io->ci_obj = ll_i2info(inode)->lli_clob; io->ci_lockreq = CILR_MAYBE; if (ll_file_nolock(file)) { @@ -1367,6 +1419,7 @@ static void ll_io_init(struct cl_io *io, struct file *file, enum cl_io_type iot) io->ci_lockreq = CILR_MANDATORY; } io->ci_noatime = file_is_noatime(file); + io->ci_async_readahead = false; /* FLR: only use non-delay I/O for read as there is only one * avaliable mirror for write. */ @@ -1430,7 +1483,7 @@ ll_file_io_generic(const struct lu_env *env, struct vvp_io_args *args, restart: io = vvp_env_thread_io(env); - ll_io_init(io, file, iot); + ll_io_init(io, file, iot, args); io->ci_ndelay_tried = retried; if (cl_io_rw_init(env, io, iot, *ppos, count) == 0) { @@ -1601,7 +1654,7 @@ ll_do_fast_read(struct kiocb *iocb, struct iov_iter *iter) if (result > 0) { ll_heat_add(file_inode(iocb->ki_filp), CIT_READ, result); ll_stats_ops_tally(ll_i2sbi(file_inode(iocb->ki_filp)), - LPROC_LL_READ_BYTES, result); + LPROC_LL_READ_BYTES, result); } return result; @@ -1614,11 +1667,32 @@ static ssize_t ll_file_read_iter(struct kiocb *iocb, struct iov_iter *to) { struct lu_env *env; struct vvp_io_args *args; + struct file *file = iocb->ki_filp; ssize_t result; ssize_t rc2; __u16 refcheck; + ktime_t kstart = ktime_get(); + bool cached; + + if (!iov_iter_count(to)) + return 0; + + /** + * Currently when PCC read failed, we do not fall back to the + * normal read path, just return the error. + * The resaon is that: for RW-PCC, the file data may be modified + * in the PCC and inconsistent with the data on OSTs (or file + * data has been removed from the Lustre file system), at this + * time, fallback to the normal read path may read the wrong + * data. + * TODO: for RO-PCC (readonly PCC), fall back to normal read + * path: read data from data copy on OSTs. + */ + result = pcc_file_read_iter(iocb, to, &cached); + if (cached) + GOTO(out, result); - ll_ras_enter(iocb->ki_filp); + ll_ras_enter(file); result = ll_do_fast_read(iocb, to); if (result < 0 || iov_iter_count(to) == 0) @@ -1632,7 +1706,7 @@ static ssize_t ll_file_read_iter(struct kiocb *iocb, struct iov_iter *to) args->u.normal.via_iter = to; args->u.normal.via_iocb = iocb; - rc2 = ll_file_io_generic(env, args, iocb->ki_filp, CIT_READ, + rc2 = ll_file_io_generic(env, args, file, CIT_READ, &iocb->ki_pos, iov_iter_count(to)); if (rc2 > 0) result += rc2; @@ -1641,6 +1715,14 @@ static ssize_t ll_file_read_iter(struct kiocb *iocb, struct iov_iter *to) cl_env_put(env, &refcheck); out: + if (result > 0) { + ll_rw_stats_tally(ll_i2sbi(file_inode(file)), current->pid, + LUSTRE_FPRIVATE(file), iocb->ki_pos, result, + READ); + ll_stats_ops_tally(ll_i2sbi(file_inode(file)), LPROC_LL_READ, + ktime_us_delta(ktime_get(), kstart)); + } + return result; } @@ -1711,17 +1793,38 @@ static ssize_t ll_file_write_iter(struct kiocb *iocb, struct iov_iter *from) struct vvp_io_args *args; struct lu_env *env; ssize_t rc_tiny = 0, rc_normal; + struct file *file = iocb->ki_filp; __u16 refcheck; + bool cached; + ktime_t kstart = ktime_get(); + int result; ENTRY; + if (!iov_iter_count(from)) + GOTO(out, rc_normal = 0); + + /** + * When PCC write failed, we usually do not fall back to the normal + * write path, just return the error. But there is a special case when + * returned error code is -ENOSPC due to running out of space on PCC HSM + * bakcend. At this time, it will fall back to normal I/O path and + * retry the I/O. As the file is in HSM released state, it will restore + * the file data to OSTs first and redo the write again. And the + * restore process will revoke the layout lock and detach the file + * from PCC cache automatically. + */ + result = pcc_file_write_iter(iocb, from, &cached); + if (cached && result != -ENOSPC && result != -EDQUOT) + GOTO(out, rc_normal = result); + /* NB: we can't do direct IO for tiny writes because they use the page * cache, we can't do sync writes because tiny writes can't flush * pages, and we can't do append writes because we can't guarantee the * required DLM locks are held to protect file size. */ - if (ll_sbi_has_tiny_write(ll_i2sbi(file_inode(iocb->ki_filp))) && - !(iocb->ki_filp->f_flags & (O_DIRECT | O_SYNC | O_APPEND))) + if (ll_sbi_has_tiny_write(ll_i2sbi(file_inode(file))) && + !(file->f_flags & (O_DIRECT | O_SYNC | O_APPEND))) rc_tiny = ll_do_tiny_write(iocb, from); /* In case of error, go on and try normal write - Only stop if tiny @@ -1738,8 +1841,8 @@ static ssize_t ll_file_write_iter(struct kiocb *iocb, struct iov_iter *from) args->u.normal.via_iter = from; args->u.normal.via_iocb = iocb; - rc_normal = ll_file_io_generic(env, args, iocb->ki_filp, CIT_WRITE, - &iocb->ki_pos, iov_iter_count(from)); + rc_normal = ll_file_io_generic(env, args, file, CIT_WRITE, + &iocb->ki_pos, iov_iter_count(from)); /* On success, combine bytes written. */ if (rc_tiny >= 0 && rc_normal > 0) @@ -1752,6 +1855,14 @@ static ssize_t ll_file_write_iter(struct kiocb *iocb, struct iov_iter *from) cl_env_put(env, &refcheck); out: + if (rc_normal > 0) { + ll_rw_stats_tally(ll_i2sbi(file_inode(file)), current->pid, + LUSTRE_FPRIVATE(file), iocb->ki_pos, + rc_normal, WRITE); + ll_stats_ops_tally(ll_i2sbi(file_inode(file)), LPROC_LL_WRITE, + ktime_us_delta(ktime_get(), kstart)); + } + RETURN(rc_normal); } @@ -1799,6 +1910,9 @@ static ssize_t ll_file_aio_read(struct kiocb *iocb, const struct iovec *iov, if (result) RETURN(result); + if (!iov_count) + RETURN(0); + # ifdef HAVE_IOV_ITER_INIT_DIRECTION iov_iter_init(&to, READ, iov, nr_segs, iov_count); # else /* !HAVE_IOV_ITER_INIT_DIRECTION */ @@ -1816,8 +1930,12 @@ static ssize_t ll_file_read(struct file *file, char __user *buf, size_t count, struct iovec iov = { .iov_base = buf, .iov_len = count }; struct kiocb kiocb; ssize_t result; + ENTRY; + if (!count) + RETURN(0); + init_sync_kiocb(&kiocb, file); kiocb.ki_pos = *ppos; #ifdef HAVE_KIOCB_KI_LEFT @@ -1848,6 +1966,9 @@ static ssize_t ll_file_aio_write(struct kiocb *iocb, const struct iovec *iov, if (result) RETURN(result); + if (!iov_count) + RETURN(0); + # ifdef HAVE_IOV_ITER_INIT_DIRECTION iov_iter_init(&from, WRITE, iov, nr_segs, iov_count); # else /* !HAVE_IOV_ITER_INIT_DIRECTION */ @@ -1869,6 +1990,9 @@ static ssize_t ll_file_write(struct file *file, const char __user *buf, ENTRY; + if (!count) + RETURN(0); + init_sync_kiocb(&kiocb, file); kiocb.ki_pos = *ppos; #ifdef HAVE_KIOCB_KI_LEFT @@ -1891,15 +2015,22 @@ static ssize_t ll_file_splice_read(struct file *in_file, loff_t *ppos, struct pipe_inode_info *pipe, size_t count, unsigned int flags) { - struct lu_env *env; - struct vvp_io_args *args; - ssize_t result; - __u16 refcheck; + struct lu_env *env; + struct vvp_io_args *args; + ssize_t result; + __u16 refcheck; + bool cached; + ENTRY; + result = pcc_file_splice_read(in_file, ppos, pipe, + count, flags, &cached); + if (cached) + RETURN(result); + ll_ras_enter(in_file); - env = cl_env_get(&refcheck); + env = cl_env_get(&refcheck); if (IS_ERR(env)) RETURN(PTR_ERR(env)); @@ -1909,6 +2040,11 @@ static ssize_t ll_file_splice_read(struct file *in_file, loff_t *ppos, result = ll_file_io_generic(env, args, in_file, CIT_READ, ppos, count); cl_env_put(env, &refcheck); + + if (result > 0) + ll_rw_stats_tally(ll_i2sbi(file_inode(in_file)), current->pid, + LUSTRE_FPRIVATE(in_file), *ppos, result, + READ); RETURN(result); } @@ -1922,6 +2058,12 @@ int ll_lov_setstripe_ea_info(struct inode *inode, struct dentry *dentry, int rc; ENTRY; + if ((__swab32(lum->lmm_magic) & le32_to_cpu(LOV_MAGIC_MASK)) == + le32_to_cpu(LOV_MAGIC_MAGIC)) { + /* this code will only exist for big-endian systems */ + lustre_swab_lov_user_md(lum, 0); + } + ll_inode_size_lock(inode); rc = ll_intent_file_open(dentry, lum, lum_size, &oit); if (rc < 0) @@ -1985,13 +2127,14 @@ int ll_lov_getstripe_ea_info(struct inode *inode, const char *filename, lmm->lmm_magic != cpu_to_le32(LOV_MAGIC_FOREIGN)) GOTO(out, rc = -EPROTO); - /* - * This is coming from the MDS, so is probably in - * little endian. We convert it to host endian before - * passing it to userspace. - */ - if (LOV_MAGIC != cpu_to_le32(LOV_MAGIC)) { - int stripe_count; + /* + * This is coming from the MDS, so is probably in + * little endian. We convert it to host endian before + * passing it to userspace. + */ + if ((lmm->lmm_magic & __swab32(LOV_MAGIC_MAGIC)) == + __swab32(LOV_MAGIC_MAGIC)) { + int stripe_count = 0; if (lmm->lmm_magic == cpu_to_le32(LOV_MAGIC_V1) || lmm->lmm_magic == cpu_to_le32(LOV_MAGIC_V3)) { @@ -2001,36 +2144,19 @@ int ll_lov_getstripe_ea_info(struct inode *inode, const char *filename, stripe_count = 0; } - /* if function called for directory - we should - * avoid swab not existent lsm objects */ - if (lmm->lmm_magic == cpu_to_le32(LOV_MAGIC_V1)) { - lustre_swab_lov_user_md_v1( - (struct lov_user_md_v1 *)lmm); - if (S_ISREG(body->mbo_mode)) - lustre_swab_lov_user_md_objects( - ((struct lov_user_md_v1 *)lmm)->lmm_objects, - stripe_count); - } else if (lmm->lmm_magic == cpu_to_le32(LOV_MAGIC_V3)) { - lustre_swab_lov_user_md_v3( - (struct lov_user_md_v3 *)lmm); - if (S_ISREG(body->mbo_mode)) - lustre_swab_lov_user_md_objects( - ((struct lov_user_md_v3 *)lmm)->lmm_objects, - stripe_count); - } else if (lmm->lmm_magic == - cpu_to_le32(LOV_MAGIC_COMP_V1)) { - lustre_swab_lov_comp_md_v1( - (struct lov_comp_md_v1 *)lmm); - } else if (lmm->lmm_magic == - cpu_to_le32(LOV_MAGIC_FOREIGN)) { - struct lov_foreign_md *lfm; - - lfm = (struct lov_foreign_md *)lmm; - __swab32s(&lfm->lfm_magic); - __swab32s(&lfm->lfm_length); - __swab32s(&lfm->lfm_type); - __swab32s(&lfm->lfm_flags); - } + lustre_swab_lov_user_md((struct lov_user_md *)lmm, 0); + + /* if function called for directory - we should + * avoid swab not existent lsm objects */ + if (lmm->lmm_magic == LOV_MAGIC_V1 && S_ISREG(body->mbo_mode)) + lustre_swab_lov_user_md_objects( + ((struct lov_user_md_v1 *)lmm)->lmm_objects, + stripe_count); + else if (lmm->lmm_magic == LOV_MAGIC_V3 && + S_ISREG(body->mbo_mode)) + lustre_swab_lov_user_md_objects( + ((struct lov_user_md_v3 *)lmm)->lmm_objects, + stripe_count); } out: @@ -2117,10 +2243,11 @@ static int ll_lov_setstripe(struct inode *inode, struct file *file, cl_lov_delay_create_clear(&file->f_flags); out: - OBD_FREE(klum, lum_size); + OBD_FREE_LARGE(klum, lum_size); RETURN(rc); } + static int ll_get_grouplock(struct inode *inode, struct file *file, unsigned long arg) { @@ -2136,18 +2263,28 @@ ll_get_grouplock(struct inode *inode, struct file *file, unsigned long arg) RETURN(-EINVAL); } - if (ll_file_nolock(file)) - RETURN(-EOPNOTSUPP); + if (ll_file_nolock(file)) + RETURN(-EOPNOTSUPP); +retry: + if (file->f_flags & O_NONBLOCK) { + if (!mutex_trylock(&lli->lli_group_mutex)) + RETURN(-EAGAIN); + } else + mutex_lock(&lli->lli_group_mutex); - spin_lock(&lli->lli_lock); if (fd->fd_flags & LL_FILE_GROUP_LOCKED) { CWARN("group lock already existed with gid %lu\n", fd->fd_grouplock.lg_gid); - spin_unlock(&lli->lli_lock); - RETURN(-EINVAL); + GOTO(out, rc = -EINVAL); + } + if (arg != lli->lli_group_gid && lli->lli_group_users != 0) { + if (file->f_flags & O_NONBLOCK) + GOTO(out, rc = -EAGAIN); + mutex_unlock(&lli->lli_group_mutex); + wait_var_event(&lli->lli_group_users, !lli->lli_group_users); + GOTO(retry, rc = 0); } LASSERT(fd->fd_grouplock.lg_lock == NULL); - spin_unlock(&lli->lli_lock); /** * XXX: group lock needs to protect all OST objects while PFL @@ -2167,7 +2304,7 @@ ll_get_grouplock(struct inode *inode, struct file *file, unsigned long arg) env = cl_env_get(&refcheck); if (IS_ERR(env)) - RETURN(PTR_ERR(env)); + GOTO(out, rc = PTR_ERR(env)); rc = cl_object_layout_get(env, obj, &cl); if (!rc && cl.cl_is_composite) @@ -2176,28 +2313,26 @@ ll_get_grouplock(struct inode *inode, struct file *file, unsigned long arg) cl_env_put(env, &refcheck); if (rc) - RETURN(rc); + GOTO(out, rc); } rc = cl_get_grouplock(ll_i2info(inode)->lli_clob, arg, (file->f_flags & O_NONBLOCK), &grouplock); - if (rc) - RETURN(rc); - spin_lock(&lli->lli_lock); - if (fd->fd_flags & LL_FILE_GROUP_LOCKED) { - spin_unlock(&lli->lli_lock); - CERROR("another thread just won the race\n"); - cl_put_grouplock(&grouplock); - RETURN(-EINVAL); - } + if (rc) + GOTO(out, rc); fd->fd_flags |= LL_FILE_GROUP_LOCKED; fd->fd_grouplock = grouplock; - spin_unlock(&lli->lli_lock); + if (lli->lli_group_users == 0) + lli->lli_group_gid = grouplock.lg_gid; + lli->lli_group_users++; CDEBUG(D_INFO, "group lock %lu obtained\n", arg); - RETURN(0); +out: + mutex_unlock(&lli->lli_group_mutex); + + RETURN(rc); } static int ll_put_grouplock(struct inode *inode, struct file *file, @@ -2206,32 +2341,40 @@ static int ll_put_grouplock(struct inode *inode, struct file *file, struct ll_inode_info *lli = ll_i2info(inode); struct ll_file_data *fd = LUSTRE_FPRIVATE(file); struct ll_grouplock grouplock; + int rc; ENTRY; - spin_lock(&lli->lli_lock); + mutex_lock(&lli->lli_group_mutex); if (!(fd->fd_flags & LL_FILE_GROUP_LOCKED)) { - spin_unlock(&lli->lli_lock); - CWARN("no group lock held\n"); - RETURN(-EINVAL); - } + CWARN("no group lock held\n"); + GOTO(out, rc = -EINVAL); + } LASSERT(fd->fd_grouplock.lg_lock != NULL); if (fd->fd_grouplock.lg_gid != arg) { CWARN("group lock %lu doesn't match current id %lu\n", arg, fd->fd_grouplock.lg_gid); - spin_unlock(&lli->lli_lock); - RETURN(-EINVAL); + GOTO(out, rc = -EINVAL); } grouplock = fd->fd_grouplock; memset(&fd->fd_grouplock, 0, sizeof(fd->fd_grouplock)); fd->fd_flags &= ~LL_FILE_GROUP_LOCKED; - spin_unlock(&lli->lli_lock); cl_put_grouplock(&grouplock); + + lli->lli_group_users--; + if (lli->lli_group_users == 0) { + lli->lli_group_gid = 0; + wake_up_var(&lli->lli_group_users); + } CDEBUG(D_INFO, "group lock %lu released\n", arg); - RETURN(0); + GOTO(out, rc = 0); +out: + mutex_unlock(&lli->lli_group_mutex); + + RETURN(rc); } /** @@ -2266,7 +2409,9 @@ int ll_release_openhandle(struct dentry *dentry, struct lookup_intent *it) if (!och) GOTO(out, rc = -ENOMEM); - ll_och_fill(ll_i2sbi(inode)->ll_md_exp, it, och); + rc = ll_och_fill(ll_i2sbi(inode)->ll_md_exp, it, och); + if (rc) + GOTO(out, rc); rc = ll_close_inode_openhandle(inode, och, 0, NULL); out: @@ -2912,6 +3057,7 @@ static int ll_ladvise_sanity(struct inode *inode, ladvise_names[advice], rc); GOTO(out, rc); } + /* fallthrough */ case LU_LADVISE_WILLREAD: case LU_LADVISE_DONTNEED: default: @@ -3105,13 +3251,16 @@ static long ll_file_unlock_lease(struct file *file, struct ll_ioc_lease *ioc, struct ll_inode_info *lli = ll_i2info(inode); struct obd_client_handle *och = NULL; struct split_param sp; - bool lease_broken; + struct pcc_param param; + bool lease_broken = false; fmode_t fmode = 0; enum mds_op_bias bias = 0; struct file *layout_file = NULL; void *data = NULL; size_t data_size = 0; - long rc; + bool attached = false; + long rc, rc2 = 0; + ENTRY; mutex_lock(&lli->lli_och_mutex); @@ -3122,22 +3271,22 @@ static long ll_file_unlock_lease(struct file *file, struct ll_ioc_lease *ioc, mutex_unlock(&lli->lli_och_mutex); if (och == NULL) - GOTO(out, rc = -ENOLCK); + RETURN(-ENOLCK); fmode = och->och_flags; switch (ioc->lil_flags) { case LL_LEASE_RESYNC_DONE: if (ioc->lil_count > IOC_IDS_MAX) - GOTO(out, rc = -EINVAL); + GOTO(out_lease_close, rc = -EINVAL); data_size = offsetof(typeof(*ioc), lil_ids[ioc->lil_count]); OBD_ALLOC(data, data_size); if (!data) - GOTO(out, rc = -ENOMEM); + GOTO(out_lease_close, rc = -ENOMEM); if (copy_from_user(data, (void __user *)arg, data_size)) - GOTO(out, rc = -EFAULT); + GOTO(out_lease_close, rc = -EFAULT); bias = MDS_CLOSE_RESYNC_DONE; break; @@ -3145,19 +3294,19 @@ static long ll_file_unlock_lease(struct file *file, struct ll_ioc_lease *ioc, int fd; if (ioc->lil_count != 1) - GOTO(out, rc = -EINVAL); + GOTO(out_lease_close, rc = -EINVAL); arg += sizeof(*ioc); if (copy_from_user(&fd, (void __user *)arg, sizeof(__u32))) - GOTO(out, rc = -EFAULT); + GOTO(out_lease_close, rc = -EFAULT); layout_file = fget(fd); if (!layout_file) - GOTO(out, rc = -EBADF); + GOTO(out_lease_close, rc = -EBADF); if ((file->f_flags & O_ACCMODE) == O_RDONLY || (layout_file->f_flags & O_ACCMODE) == O_RDONLY) - GOTO(out, rc = -EPERM); + GOTO(out_lease_close, rc = -EPERM); data = file_inode(layout_file); bias = MDS_CLOSE_LAYOUT_MERGE; @@ -3168,20 +3317,20 @@ static long ll_file_unlock_lease(struct file *file, struct ll_ioc_lease *ioc, int mirror_id; if (ioc->lil_count != 2) - GOTO(out, rc = -EINVAL); + GOTO(out_lease_close, rc = -EINVAL); arg += sizeof(*ioc); if (copy_from_user(&fdv, (void __user *)arg, sizeof(__u32))) - GOTO(out, rc = -EFAULT); + GOTO(out_lease_close, rc = -EFAULT); arg += sizeof(__u32); if (copy_from_user(&mirror_id, (void __user *)arg, sizeof(__u32))) - GOTO(out, rc = -EFAULT); + GOTO(out_lease_close, rc = -EFAULT); layout_file = fget(fdv); if (!layout_file) - GOTO(out, rc = -EBADF); + GOTO(out_lease_close, rc = -EBADF); sp.sp_inode = file_inode(layout_file); sp.sp_mirror_id = (__u16)mirror_id; @@ -3189,11 +3338,35 @@ static long ll_file_unlock_lease(struct file *file, struct ll_ioc_lease *ioc, bias = MDS_CLOSE_LAYOUT_SPLIT; break; } + case LL_LEASE_PCC_ATTACH: + if (ioc->lil_count != 1) + RETURN(-EINVAL); + + arg += sizeof(*ioc); + if (copy_from_user(¶m.pa_archive_id, (void __user *)arg, + sizeof(__u32))) + GOTO(out_lease_close, rc2 = -EFAULT); + + rc2 = pcc_readwrite_attach(file, inode, param.pa_archive_id); + if (rc2) + GOTO(out_lease_close, rc2); + + attached = true; + /* Grab latest data version */ + rc2 = ll_data_version(inode, ¶m.pa_data_version, + LL_DV_WR_FLUSH); + if (rc2) + GOTO(out_lease_close, rc2); + + data = ¶m; + bias = MDS_PCC_ATTACH; + break; default: /* without close intent */ break; } +out_lease_close: rc = ll_lease_close_intent(och, inode, &lease_broken, bias, data); if (rc < 0) GOTO(out, rc); @@ -3217,6 +3390,14 @@ out: if (layout_file) fput(layout_file); break; + case LL_LEASE_PCC_ATTACH: + if (!rc) + rc = rc2; + rc = pcc_readwrite_attach_fini(file, inode, + param.pa_layout_gen, + lease_broken, rc, + attached); + break; } if (!rc) @@ -3740,6 +3921,52 @@ out_ladvise: rc = ll_heat_set(inode, flags); RETURN(rc); } + case LL_IOC_PCC_DETACH: { + struct lu_pcc_detach *detach; + + OBD_ALLOC_PTR(detach); + if (detach == NULL) + RETURN(-ENOMEM); + + if (copy_from_user(detach, + (const struct lu_pcc_detach __user *)arg, + sizeof(*detach))) + GOTO(out_detach_free, rc = -EFAULT); + + if (!S_ISREG(inode->i_mode)) + GOTO(out_detach_free, rc = -EINVAL); + + if (!inode_owner_or_capable(inode)) + GOTO(out_detach_free, rc = -EPERM); + + rc = pcc_ioctl_detach(inode, detach->pccd_opt); +out_detach_free: + OBD_FREE_PTR(detach); + RETURN(rc); + } + case LL_IOC_PCC_STATE: { + struct lu_pcc_state __user *ustate = + (struct lu_pcc_state __user *)arg; + struct lu_pcc_state *state; + + OBD_ALLOC_PTR(state); + if (state == NULL) + RETURN(-ENOMEM); + + if (copy_from_user(state, ustate, sizeof(*state))) + GOTO(out_state, rc = -EFAULT); + + rc = pcc_ioctl_state(file, inode, state); + if (rc) + GOTO(out_state, rc); + + if (copy_to_user(ustate, state, sizeof(*state))) + GOTO(out_state, rc = -EFAULT); + +out_state: + OBD_FREE_PTR(state); + RETURN(rc); + } default: RETURN(obd_iocontrol(cmd, ll_i2dtexp(inode), 0, NULL, (void __user *)arg)); @@ -3817,6 +4044,7 @@ static loff_t ll_file_seek(struct file *file, loff_t offset, int origin) { struct inode *inode = file_inode(file); loff_t retval, eof = 0; + ktime_t kstart = ktime_get(); ENTRY; retval = offset + ((origin == SEEK_END) ? i_size_read(inode) : @@ -3824,7 +4052,6 @@ static loff_t ll_file_seek(struct file *file, loff_t offset, int origin) CDEBUG(D_VFSTRACE, "VFS Op:inode="DFID"(%p), to=%llu=%#llx(%d)\n", PFID(ll_inode2fid(inode)), inode, retval, retval, origin); - ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_LLSEEK, 1); if (origin == SEEK_END || origin == SEEK_HOLE || origin == SEEK_DATA) { retval = ll_glimpse_size(inode); @@ -3834,7 +4061,10 @@ static loff_t ll_file_seek(struct file *file, loff_t offset, int origin) } retval = ll_generic_file_llseek_size(file, offset, origin, - ll_file_maxbytes(inode), eof); + ll_file_maxbytes(inode), eof); + if (retval >= 0) + ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_LLSEEK, + ktime_us_delta(ktime_get(), kstart)); RETURN(retval); } @@ -3918,40 +4148,25 @@ int cl_sync_file_range(struct inode *inode, loff_t start, loff_t end, * file_dentry() as is done otherwise. */ -#ifdef HAVE_FILE_FSYNC_4ARGS int ll_fsync(struct file *file, loff_t start, loff_t end, int datasync) { struct dentry *dentry = file_dentry(file); -#elif defined(HAVE_FILE_FSYNC_2ARGS) -int ll_fsync(struct file *file, int datasync) -{ - struct dentry *dentry = file_dentry(file); - loff_t start = 0; - loff_t end = LLONG_MAX; -#else -int ll_fsync(struct file *file, struct dentry *dentry, int datasync) -{ - loff_t start = 0; - loff_t end = LLONG_MAX; -#endif struct inode *inode = dentry->d_inode; struct ll_inode_info *lli = ll_i2info(inode); struct ptlrpc_request *req; + ktime_t kstart = ktime_get(); int rc, err; + ENTRY; - CDEBUG(D_VFSTRACE, "VFS Op:inode="DFID"(%p)\n", - PFID(ll_inode2fid(inode)), inode); - ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_FSYNC, 1); + CDEBUG(D_VFSTRACE, "VFS Op:inode="DFID"(%p), start %lld, end %lld," + "datasync %d\n", + PFID(ll_inode2fid(inode)), inode, start, end, datasync); -#ifdef HAVE_FILE_FSYNC_4ARGS - rc = filemap_write_and_wait_range(inode->i_mapping, start, end); - inode_lock(inode); -#else /* fsync's caller has already called _fdata{sync,write}, we want * that IO to finish before calling the osc and mdc sync methods */ - rc = filemap_fdatawait(inode->i_mapping); -#endif + rc = filemap_write_and_wait_range(inode->i_mapping, start, end); + inode_lock(inode); /* catch async errors that were recorded back when async writeback * failed for pages in this mapping. */ @@ -3975,8 +4190,15 @@ int ll_fsync(struct file *file, struct dentry *dentry, int datasync) if (S_ISREG(inode->i_mode)) { struct ll_file_data *fd = LUSTRE_FPRIVATE(file); + bool cached; - err = cl_sync_file_range(inode, start, end, CL_FSYNC_ALL, 0); + /* Sync metadata on MDT first, and then sync the cached data + * on PCC. + */ + err = pcc_fsync(file, start, end, datasync, &cached); + if (!cached) + err = cl_sync_file_range(inode, start, end, + CL_FSYNC_ALL, 0); if (rc == 0 && err < 0) rc = err; if (rc < 0) @@ -3985,9 +4207,11 @@ int ll_fsync(struct file *file, struct dentry *dentry, int datasync) fd->fd_write_failed = false; } -#ifdef HAVE_FILE_FSYNC_4ARGS inode_unlock(inode); -#endif + + if (!rc) + ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_FSYNC, + ktime_us_delta(ktime_get(), kstart)); RETURN(rc); } @@ -4005,6 +4229,7 @@ ll_file_flock(struct file *file, int cmd, struct file_lock *file_lock) struct lustre_handle lockh = { 0 }; union ldlm_policy_data flock = { { 0 } }; int fl_type = file_lock->fl_type; + ktime_t kstart = ktime_get(); __u64 flags = 0; int rc; int rc2 = 0; @@ -4013,23 +4238,22 @@ ll_file_flock(struct file *file, int cmd, struct file_lock *file_lock) CDEBUG(D_VFSTRACE, "VFS Op:inode="DFID" file_lock=%p\n", PFID(ll_inode2fid(inode)), file_lock); - ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_FLOCK, 1); - - if (file_lock->fl_flags & FL_FLOCK) { - LASSERT((cmd == F_SETLKW) || (cmd == F_SETLK)); - /* flocks are whole-file locks */ - flock.l_flock.end = OFFSET_MAX; - /* For flocks owner is determined by the local file desctiptor*/ - flock.l_flock.owner = (unsigned long)file_lock->fl_file; - } else if (file_lock->fl_flags & FL_POSIX) { - flock.l_flock.owner = (unsigned long)file_lock->fl_owner; - flock.l_flock.start = file_lock->fl_start; - flock.l_flock.end = file_lock->fl_end; - } else { - RETURN(-EINVAL); - } - flock.l_flock.pid = file_lock->fl_pid; + if (file_lock->fl_flags & FL_FLOCK) { + LASSERT((cmd == F_SETLKW) || (cmd == F_SETLK)); + /* flocks are whole-file locks */ + flock.l_flock.end = OFFSET_MAX; + /* For flocks owner is determined by the local file desctiptor*/ + flock.l_flock.owner = (unsigned long)file_lock->fl_file; + } else if (file_lock->fl_flags & FL_POSIX) { + flock.l_flock.owner = (unsigned long)file_lock->fl_owner; + flock.l_flock.start = file_lock->fl_start; + flock.l_flock.end = file_lock->fl_end; + } else { + RETURN(-EINVAL); + } + flock.l_flock.pid = file_lock->fl_pid; +#if defined(HAVE_LM_COMPARE_OWNER) || defined(lm_compare_owner) /* Somewhat ugly workaround for svc lockd. * lockd installs custom fl_lmops->lm_compare_owner that checks * for the fl_owner to be the same (which it always is on local node @@ -4039,6 +4263,7 @@ ll_file_flock(struct file *file, int cmd, struct file_lock *file_lock) * pointer space for current->files are not intersecting */ if (file_lock->fl_lmops && file_lock->fl_lmops->lm_compare_owner) flock.l_flock.owner = (unsigned long)file_lock->fl_pid; +#endif switch (fl_type) { case F_RDLCK: @@ -4131,7 +4356,10 @@ ll_file_flock(struct file *file, int cmd, struct file_lock *file_lock) ll_finish_md_op_data(op_data); - RETURN(rc); + if (!rc) + ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_FLOCK, + ktime_us_delta(ktime_get(), kstart)); + RETURN(rc); } int ll_get_fid_by_name(struct inode *parent, const char *name, @@ -4321,9 +4549,20 @@ out_iput: static int ll_file_noflock(struct file *file, int cmd, struct file_lock *file_lock) { - ENTRY; + struct ll_file_data *fd = LUSTRE_FPRIVATE(file); + ENTRY; - RETURN(-ENOSYS); + /* + * In order to avoid flood of warning messages, only print one message + * for one file. And the entire message rate on the client is limited + * by CDEBUG_LIMIT too. + */ + if (!(fd->fd_flags & LL_FILE_FLOCK_WARNING)) { + fd->fd_flags |= LL_FILE_FLOCK_WARNING; + CDEBUG_LIMIT(D_TTY | D_CONSOLE, + "flock disabled, mount with '-o [local]flock' to enable\r\n"); + } + RETURN(-ENOSYS); } /** @@ -4355,7 +4594,7 @@ int ll_have_md_lock(struct inode *inode, __u64 *bits, enum ldlm_mode l_req_mode) ldlm_lockname[mode]); flags = LDLM_FL_BLOCK_GRANTED | LDLM_FL_CBPENDING | LDLM_FL_TEST_LOCK; - for (i = 0; i <= MDS_INODELOCK_MAXSHIFT && *bits != 0; i++) { + for (i = 0; i < MDS_INODELOCK_NUMBITS && *bits != 0; i++) { policy.l_inodebits.bits = *bits & (1 << i); if (policy.l_inodebits.bits == 0) continue; @@ -4460,9 +4699,9 @@ static int ll_inode_revalidate(struct dentry *dentry, enum ldlm_intent_flags op) * here to preserve get_cwd functionality on 2.6. * Bug 10503 */ if (!dentry->d_inode->i_nlink) { - ll_lock_dcache(inode); + spin_lock(&inode->i_lock); d_lustre_invalidate(dentry, 0); - ll_unlock_dcache(inode); + spin_unlock(&inode->i_lock); } ll_lookup_finish_locks(&oit, dentry); @@ -4501,39 +4740,25 @@ static int ll_merge_md_attr(struct inode *inode) RETURN(0); } -static inline dev_t ll_compat_encode_dev(dev_t dev) -{ - /* The compat_sys_*stat*() syscalls will fail unless the - * device majors and minors are both less than 256. Note that - * the value returned here will be passed through - * old_encode_dev() in cp_compat_stat(). And so we are not - * trying to return a valid compat (u16) device number, just - * one that will pass the old_valid_dev() check. */ - - return MKDEV(MAJOR(dev) & 0xff, MINOR(dev) & 0xff); -} - -#ifdef HAVE_INODEOPS_ENHANCED_GETATTR -int ll_getattr(const struct path *path, struct kstat *stat, - u32 request_mask, unsigned int flags) +int ll_getattr_dentry(struct dentry *de, struct kstat *stat) { - struct dentry *de = path->dentry; -#else -int ll_getattr(struct vfsmount *mnt, struct dentry *de, struct kstat *stat) -{ -#endif struct inode *inode = de->d_inode; struct ll_sb_info *sbi = ll_i2sbi(inode); struct ll_inode_info *lli = ll_i2info(inode); + ktime_t kstart = ktime_get(); int rc; - ll_stats_ops_tally(sbi, LPROC_LL_GETATTR, 1); - rc = ll_inode_revalidate(de, IT_GETATTR); if (rc < 0) RETURN(rc); if (S_ISREG(inode->i_mode)) { + bool cached; + + rc = pcc_inode_getattr(inode, &cached); + if (cached && rc < 0) + RETURN(rc); + /* In case of restore, the MDT has the right size and has * already send it back without granting the layout lock, * inode is up-to-date so glimpse is useless. @@ -4541,7 +4766,7 @@ int ll_getattr(struct vfsmount *mnt, struct dentry *de, struct kstat *stat) * restore the MDT holds the layout lock so the glimpse will * block up to the end of restore (getattr will block) */ - if (!ll_file_test_flag(lli, LLIF_FILE_RESTORING)) { + if (!cached && !ll_file_test_flag(lli, LLIF_FILE_RESTORING)) { rc = ll_glimpse_size(inode); if (rc < 0) RETURN(rc); @@ -4583,7 +4808,22 @@ int ll_getattr(struct vfsmount *mnt, struct dentry *de, struct kstat *stat) stat->size = i_size_read(inode); stat->blocks = inode->i_blocks; - return 0; + ll_stats_ops_tally(sbi, LPROC_LL_GETATTR, + ktime_us_delta(ktime_get(), kstart)); + + return 0; +} + +#ifdef HAVE_INODEOPS_ENHANCED_GETATTR +int ll_getattr(const struct path *path, struct kstat *stat, + u32 request_mask, unsigned int flags) +{ + struct dentry *de = path->dentry; +#else +int ll_getattr(struct vfsmount *mnt, struct dentry *de, struct kstat *stat) +{ +#endif + return ll_getattr_dentry(de, stat); } static int ll_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, @@ -4639,7 +4879,7 @@ struct posix_acl *ll_get_acl(struct inode *inode, int type) } #ifdef HAVE_IOP_SET_ACL -#ifdef CONFIG_FS_POSIX_ACL +#ifdef CONFIG_LUSTRE_FS_POSIX_ACL int ll_set_acl(struct inode *inode, struct posix_acl *acl, int type) { struct ll_sb_info *sbi = ll_i2sbi(inode); @@ -4695,50 +4935,10 @@ out: set_cached_acl(inode, type, acl); RETURN(rc); } -#endif /* CONFIG_FS_POSIX_ACL */ +#endif /* CONFIG_LUSTRE_FS_POSIX_ACL */ #endif /* HAVE_IOP_SET_ACL */ -#ifndef HAVE_GENERIC_PERMISSION_2ARGS -static int -# ifdef HAVE_GENERIC_PERMISSION_4ARGS -ll_check_acl(struct inode *inode, int mask, unsigned int flags) -# else -ll_check_acl(struct inode *inode, int mask) -# endif -{ -# ifdef CONFIG_FS_POSIX_ACL - struct posix_acl *acl; - int rc; - ENTRY; - -# ifdef HAVE_GENERIC_PERMISSION_4ARGS - if (flags & IPERM_FLAG_RCU) - return -ECHILD; -# endif - acl = ll_get_acl(inode, ACL_TYPE_ACCESS); - - if (!acl) - RETURN(-EAGAIN); - - rc = posix_acl_permission(inode, acl, mask); - posix_acl_release(acl); - - RETURN(rc); -# else /* !CONFIG_FS_POSIX_ACL */ - return -EAGAIN; -# endif /* CONFIG_FS_POSIX_ACL */ -} -#endif /* HAVE_GENERIC_PERMISSION_2ARGS */ - -#ifdef HAVE_GENERIC_PERMISSION_4ARGS -int ll_inode_permission(struct inode *inode, int mask, unsigned int flags) -#else -# ifdef HAVE_INODE_PERMISION_2ARGS int ll_inode_permission(struct inode *inode, int mask) -# else -int ll_inode_permission(struct inode *inode, int mask, struct nameidata *nd) -# endif -#endif { int rc = 0; struct ll_sb_info *sbi; @@ -4747,15 +4947,11 @@ int ll_inode_permission(struct inode *inode, int mask, struct nameidata *nd) const struct cred *old_cred = NULL; cfs_cap_t cap; bool squash_id = false; + ktime_t kstart = ktime_get(); ENTRY; -#ifdef MAY_NOT_BLOCK if (mask & MAY_NOT_BLOCK) return -ECHILD; -#elif defined(HAVE_GENERIC_PERMISSION_4ARGS) - if (flags & IPERM_FLAG_RCU) - return -ECHILD; -#endif /* as root inode are NOT getting validated in lookup operation, * need to do it before permission check. */ @@ -4797,14 +4993,17 @@ int ll_inode_permission(struct inode *inode, int mask, struct nameidata *nd) old_cred = override_creds(cred); } - ll_stats_ops_tally(sbi, LPROC_LL_INODE_PERM, 1); - rc = ll_generic_permission(inode, mask, flags, ll_check_acl); + rc = generic_permission(inode, mask); /* restore current process's credentials and FS capability */ if (squash_id) { revert_creds(old_cred); put_cred(cred); } + if (!rc) + ll_stats_ops_tally(sbi, LPROC_LL_INODE_PERM, + ktime_us_delta(ktime_get(), kstart)); + RETURN(rc); } @@ -5199,7 +5398,8 @@ int ll_layout_refresh(struct inode *inode, __u32 *gen) /* mostly layout lock is caching on the local side, so try to * match it before grabbing layout lock mutex. */ mode = ll_take_md_lock(inode, MDS_INODELOCK_LAYOUT, &lockh, 0, - LCK_CR | LCK_CW | LCK_PR | LCK_PW); + LCK_CR | LCK_CW | LCK_PR | + LCK_PW | LCK_EX); if (mode != 0) { /* hit cached lock */ rc = ll_layout_lock_set(&lockh, mode, inode); if (rc == -EAGAIN)