X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=blobdiff_plain;f=lustre%2Fllite%2Ffile.c;h=8b540681a0a165344a3ca47fbe8d4d343385f43c;hp=1752da18825b8d5f0c7cf44b2f33c08273d63e61;hb=9d3a33b176a1b353603f3a204ae1e818c05226c5;hpb=6eda93c7b5f65324bdc831100a17c0bef1a3c078 diff --git a/lustre/llite/file.c b/lustre/llite/file.c index 1752da1..8b54068 100644 --- a/lustre/llite/file.c +++ b/lustre/llite/file.c @@ -45,6 +45,10 @@ #include #include #include +#include +#ifdef HAVE_UIDGID_HEADER +# include +#endif #include #include @@ -95,7 +99,6 @@ void ll_pack_inode2opdata(struct inode *inode, struct md_op_data *op_data, op_data->op_attr_flags = ll_inode_to_ext_flags(inode->i_flags); if (fh) op_data->op_handle = *fh; - op_data->op_capa1 = ll_mdscapa_get(inode); if (LLIF_DATA_MODIFIED & ll_i2info(inode)->lli_flags) op_data->op_bias |= MDS_DATA_MODIFIED; @@ -125,39 +128,63 @@ out: EXIT; } +/** + * Perform a close, possibly with a bias. + * The meaning of "data" depends on the value of "bias". + * + * If \a bias is MDS_HSM_RELEASE then \a data is a pointer to the data version. + * If \a bias is MDS_CLOSE_LAYOUT_SWAP then \a data is a pointer to the inode to + * swap layouts with. + */ static int ll_close_inode_openhandle(struct obd_export *md_exp, - struct inode *inode, struct obd_client_handle *och, - const __u64 *data_version) + struct inode *inode, + enum mds_op_bias bias, + void *data) { - struct obd_export *exp = ll_i2mdexp(inode); - struct md_op_data *op_data; - struct ptlrpc_request *req = NULL; - struct obd_device *obd = class_exp2obd(exp); - int rc; - ENTRY; + struct obd_export *exp = ll_i2mdexp(inode); + struct md_op_data *op_data; + struct ptlrpc_request *req = NULL; + struct obd_device *obd = class_exp2obd(exp); + int rc; + ENTRY; - if (obd == NULL) { - /* - * XXX: in case of LMV, is this correct to access - * ->exp_handle? - */ - CERROR("Invalid MDC connection handle "LPX64"\n", - ll_i2mdexp(inode)->exp_handle.h_cookie); - GOTO(out, rc = 0); - } + if (obd == NULL) { + /* + * XXX: in case of LMV, is this correct to access + * ->exp_handle? + */ + CERROR("Invalid MDC connection handle "LPX64"\n", + ll_i2mdexp(inode)->exp_handle.h_cookie); + GOTO(out, rc = 0); + } - OBD_ALLOC_PTR(op_data); - if (op_data == NULL) - GOTO(out, rc = -ENOMEM); // XXX We leak openhandle and request here. + OBD_ALLOC_PTR(op_data); + if (op_data == NULL) + /* XXX We leak openhandle and request here. */ + GOTO(out, rc = -ENOMEM); ll_prepare_close(inode, op_data, och); - if (data_version != NULL) { - /* Pass in data_version implies release. */ + switch (bias) { + case MDS_CLOSE_LAYOUT_SWAP: + LASSERT(data != NULL); + op_data->op_bias |= MDS_CLOSE_LAYOUT_SWAP; + op_data->op_data_version = 0; + op_data->op_lease_handle = och->och_lease_handle; + op_data->op_fid2 = *ll_inode2fid(data); + break; + + case MDS_HSM_RELEASE: + LASSERT(data != NULL); op_data->op_bias |= MDS_HSM_RELEASE; - op_data->op_data_version = *data_version; + op_data->op_data_version = *(__u64 *)data; op_data->op_lease_handle = och->och_lease_handle; op_data->op_attr.ia_valid |= ATTR_SIZE | ATTR_BLOCKS; + break; + + default: + LASSERT(data == NULL); + break; } rc = md_close(md_exp, op_data, och->och_mod, &req); @@ -177,15 +204,17 @@ static int ll_close_inode_openhandle(struct obd_export *md_exp, spin_unlock(&lli->lli_lock); } - if (rc == 0 && op_data->op_bias & MDS_HSM_RELEASE) { + if (rc == 0 && + op_data->op_bias & (MDS_HSM_RELEASE | MDS_CLOSE_LAYOUT_SWAP)) { struct mdt_body *body; + body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY); - if (!(body->mbo_valid & OBD_MD_FLRELEASED)) + if (!(body->mbo_valid & OBD_MD_CLOSE_INTENT_EXECED)) rc = -EBUSY; } - ll_finish_md_op_data(op_data); - EXIT; + ll_finish_md_op_data(op_data); + EXIT; out: md_clear_open_replay_data(md_exp, och); @@ -234,7 +263,7 @@ int ll_md_real_close(struct inode *inode, fmode_t fmode) /* There might be a race and this handle may already * be closed. */ rc = ll_close_inode_openhandle(ll_i2sbi(inode)->ll_md_exp, - inode, och, NULL); + och, inode, 0, NULL); } RETURN(rc); @@ -243,10 +272,16 @@ int ll_md_real_close(struct inode *inode, fmode_t fmode) static int ll_md_close(struct obd_export *md_exp, struct inode *inode, struct file *file) { - struct ll_file_data *fd = LUSTRE_FPRIVATE(file); - struct ll_inode_info *lli = ll_i2info(inode); - int rc = 0; - ENTRY; + ldlm_policy_data_t policy = { + .l_inodebits = { MDS_INODELOCK_OPEN }, + }; + __u64 flags = LDLM_FL_BLOCK_GRANTED | LDLM_FL_TEST_LOCK; + struct ll_file_data *fd = LUSTRE_FPRIVATE(file); + struct ll_inode_info *lli = ll_i2info(inode); + struct lustre_handle lockh; + int lockmode; + int rc = 0; + ENTRY; /* clear group lock, if present */ if (unlikely(fd->fd_flags & LL_FILE_GROUP_LOCKED)) @@ -265,52 +300,37 @@ static int ll_md_close(struct obd_export *md_exp, struct inode *inode, } if (fd->fd_och != NULL) { - rc = ll_close_inode_openhandle(md_exp, inode, fd->fd_och, NULL); + rc = ll_close_inode_openhandle(md_exp, fd->fd_och, inode, 0, + NULL); fd->fd_och = NULL; GOTO(out, rc); } /* Let's see if we have good enough OPEN lock on the file and if we can skip talking to MDS */ - if (file->f_dentry->d_inode) { /* Can this ever be false? */ - int lockmode; - __u64 flags = LDLM_FL_BLOCK_GRANTED | LDLM_FL_TEST_LOCK; - struct lustre_handle lockh; - struct inode *inode = file->f_dentry->d_inode; - ldlm_policy_data_t policy = {.l_inodebits={MDS_INODELOCK_OPEN}}; - - mutex_lock(&lli->lli_och_mutex); - if (fd->fd_omode & FMODE_WRITE) { - lockmode = LCK_CW; - LASSERT(lli->lli_open_fd_write_count); - lli->lli_open_fd_write_count--; - } else if (fd->fd_omode & FMODE_EXEC) { - lockmode = LCK_PR; - LASSERT(lli->lli_open_fd_exec_count); - lli->lli_open_fd_exec_count--; - } else { - lockmode = LCK_CR; - LASSERT(lli->lli_open_fd_read_count); - lli->lli_open_fd_read_count--; - } - mutex_unlock(&lli->lli_och_mutex); - - if (!md_lock_match(md_exp, flags, ll_inode2fid(inode), - LDLM_IBITS, &policy, lockmode, - &lockh)) { - rc = ll_md_real_close(file->f_dentry->d_inode, - fd->fd_omode); - } + mutex_lock(&lli->lli_och_mutex); + if (fd->fd_omode & FMODE_WRITE) { + lockmode = LCK_CW; + LASSERT(lli->lli_open_fd_write_count); + lli->lli_open_fd_write_count--; + } else if (fd->fd_omode & FMODE_EXEC) { + lockmode = LCK_PR; + LASSERT(lli->lli_open_fd_exec_count); + lli->lli_open_fd_exec_count--; } else { - CERROR("released file has negative dentry: file = %p, " - "dentry = %p, name = %s\n", - file, file->f_dentry, file->f_dentry->d_name.name); + lockmode = LCK_CR; + LASSERT(lli->lli_open_fd_read_count); + lli->lli_open_fd_read_count--; } + mutex_unlock(&lli->lli_och_mutex); + + if (!md_lock_match(md_exp, flags, ll_inode2fid(inode), + LDLM_IBITS, &policy, lockmode, &lockh)) + rc = ll_md_real_close(inode, fd->fd_omode); out: LUSTRE_FPRIVATE(file) = NULL; ll_file_data_put(fd); - ll_capa_close(inode); RETURN(rc); } @@ -345,7 +365,7 @@ int ll_file_release(struct inode *inode, struct file *file) } #endif - if (inode->i_sb->s_root != file->f_dentry) + if (inode->i_sb->s_root != file->f_path.dentry) ll_stats_ops_tally(sbi, LPROC_LL_RELEASE, 1); fd = LUSTRE_FPRIVATE(file); LASSERT(fd != NULL); @@ -355,7 +375,7 @@ int ll_file_release(struct inode *inode, struct file *file) if (S_ISDIR(inode->i_mode) && lli->lli_opendir_key == fd) ll_deauthorize_statahead(inode, fd); - if (inode->i_sb->s_root == file->f_dentry) { + if (inode->i_sb->s_root == file->f_path.dentry) { LUSTRE_FPRIVATE(file) = NULL; ll_file_data_put(fd); RETURN(0); @@ -378,7 +398,7 @@ int ll_file_release(struct inode *inode, struct file *file) static int ll_intent_file_open(struct file *file, void *lmm, int lmmsize, struct lookup_intent *itp) { - struct dentry *de = file->f_dentry; + struct dentry *de = file->f_path.dentry; struct ll_sb_info *sbi = ll_i2sbi(de->d_inode); struct dentry *parent = de->d_parent; const char *name = NULL; @@ -459,7 +479,7 @@ static int ll_och_fill(struct obd_export *md_exp, struct lookup_intent *it, static int ll_local_open(struct file *file, struct lookup_intent *it, struct ll_file_data *fd, struct obd_client_handle *och) { - struct inode *inode = file->f_dentry->d_inode; + struct inode *inode = file->f_path.dentry->d_inode; ENTRY; LASSERT(!LUSTRE_FPRIVATE(file)); @@ -523,7 +543,7 @@ int ll_file_open(struct inode *inode, struct file *file) if (S_ISDIR(inode->i_mode)) ll_authorize_statahead(inode, fd); - if (inode->i_sb->s_root == file->f_dentry) { + if (inode->i_sb->s_root == file->f_path.dentry) { LUSTRE_FPRIVATE(file) = fd; RETURN(0); } @@ -581,7 +601,7 @@ restart: GOTO(out_openerr, rc); } - ll_release_openhandle(file->f_dentry, it); + ll_release_openhandle(file->f_path.dentry, it); } (*och_usecount)++; @@ -651,14 +671,6 @@ restart: if (!S_ISREG(inode->i_mode)) GOTO(out_och_free, rc); - ll_capa_open(inode); - - if (!lli->lli_has_smd && - (cl_is_lov_delay_create(file->f_flags) || - (file->f_mode & FMODE_WRITE) == 0)) { - CDEBUG(D_INODE, "object creation was delayed\n"); - GOTO(out_och_free, rc); - } cl_lov_delay_create_clear(&file->f_flags); GOTO(out_och_free, rc); @@ -836,7 +848,7 @@ out_close: it.d.lustre.it_lock_mode = 0; och->och_lease_handle.cookie = 0ULL; } - rc2 = ll_close_inode_openhandle(sbi->ll_md_exp, inode, och, NULL); + rc2 = ll_close_inode_openhandle(sbi->ll_md_exp, och, inode, 0, NULL); if (rc2 < 0) CERROR("%s: error closing file "DFID": %d\n", ll_get_fsname(inode->i_sb, NULL, 0), @@ -851,6 +863,68 @@ out: } /** + * Check whether a layout swap can be done between two inodes. + * + * \param[in] inode1 First inode to check + * \param[in] inode2 Second inode to check + * + * \retval 0 on success, layout swap can be performed between both inodes + * \retval negative error code if requirements are not met + */ +static int ll_check_swap_layouts_validity(struct inode *inode1, + struct inode *inode2) +{ + if (!S_ISREG(inode1->i_mode) || !S_ISREG(inode2->i_mode)) + return -EINVAL; + + if (inode_permission(inode1, MAY_WRITE) || + inode_permission(inode2, MAY_WRITE)) + return -EPERM; + + if (inode1->i_sb != inode2->i_sb) + return -EXDEV; + + return 0; +} + +static int ll_swap_layouts_close(struct obd_client_handle *och, + struct inode *inode, struct inode *inode2) +{ + const struct lu_fid *fid1 = ll_inode2fid(inode); + const struct lu_fid *fid2; + int rc; + ENTRY; + + CDEBUG(D_INODE, "%s: biased close of file "DFID"\n", + ll_get_fsname(inode->i_sb, NULL, 0), PFID(fid1)); + + rc = ll_check_swap_layouts_validity(inode, inode2); + if (rc < 0) + GOTO(out_free_och, rc); + + /* We now know that inode2 is a lustre inode */ + fid2 = ll_inode2fid(inode2); + + rc = lu_fid_cmp(fid1, fid2); + if (rc == 0) + GOTO(out_free_och, rc = -EINVAL); + + /* Close the file and swap layouts between inode & inode2. + * NB: lease lock handle is released in mdc_close_layout_swap_pack() + * because we still need it to pack l_remote_handle to MDT. */ + rc = ll_close_inode_openhandle(ll_i2sbi(inode)->ll_md_exp, och, inode, + MDS_CLOSE_LAYOUT_SWAP, inode2); + + och = NULL; /* freed in ll_close_inode_openhandle() */ + +out_free_och: + if (och != NULL) + OBD_FREE_PTR(och); + + RETURN(rc); +} + +/** * Release lease and close the file. * It will check if the lease has ever broken. */ @@ -878,8 +952,9 @@ static int ll_lease_close(struct obd_client_handle *och, struct inode *inode, if (lease_broken != NULL) *lease_broken = cancelled; - rc = ll_close_inode_openhandle(ll_i2sbi(inode)->ll_md_exp, inode, och, - NULL); + rc = ll_close_inode_openhandle(ll_i2sbi(inode)->ll_md_exp, och, inode, + 0, NULL); + RETURN(rc); } @@ -968,7 +1043,7 @@ static bool file_is_noatime(const struct file *file) static void ll_io_init(struct cl_io *io, const struct file *file, int write) { - struct inode *inode = file->f_dentry->d_inode; + struct inode *inode = file->f_path.dentry->d_inode; io->u.ci_rw.crw_nonblock = file->f_flags & O_NONBLOCK; if (write) { @@ -994,37 +1069,25 @@ ll_file_io_generic(const struct lu_env *env, struct vvp_io_args *args, struct file *file, enum cl_io_type iot, loff_t *ppos, size_t count) { - struct inode *inode = file->f_dentry->d_inode; - struct ll_inode_info *lli = ll_i2info(inode); - loff_t end; - struct ll_file_data *fd = LUSTRE_FPRIVATE(file); - struct cl_io *io; - ssize_t result; - struct range_lock range; + struct vvp_io *vio = vvp_env_io(env); + struct inode *inode = file->f_path.dentry->d_inode; + struct ll_inode_info *lli = ll_i2info(inode); + struct ll_file_data *fd = LUSTRE_FPRIVATE(file); + struct cl_io *io; + ssize_t result = 0; + int rc = 0; + struct range_lock range; + ENTRY; CDEBUG(D_VFSTRACE, "file: %s, type: %d ppos: "LPU64", count: %zu\n", - file->f_dentry->d_name.name, iot, *ppos, count); + file->f_path.dentry->d_name.name, iot, *ppos, count); restart: io = vvp_env_thread_io(env); - ll_io_init(io, file, iot == CIT_WRITE); - - /* The maximum Lustre file size is variable, based on the - * OST maximum object size and number of stripes. This - * needs another check in addition to the VFS checks earlier. */ - end = (io->u.ci_wr.wr_append ? i_size_read(inode) : *ppos) + count; - if (end > ll_file_maxbytes(inode)) { - result = -EFBIG; - CDEBUG(D_INODE, "%s: file "DFID" offset %llu > maxbytes "LPU64 - ": rc = %zd\n", ll_get_fsname(inode->i_sb, NULL, 0), - PFID(&lli->lli_fid), end, ll_file_maxbytes(inode), - result); - RETURN(result); - } - - if (cl_io_rw_init(env, io, iot, *ppos, count) == 0) { - struct vvp_io *vio = vvp_env_io(env); + ll_io_init(io, file, iot == CIT_WRITE); + + if (cl_io_rw_init(env, io, iot, *ppos, count) == 0) { bool range_locked = false; if (file->f_flags & O_APPEND) @@ -1041,18 +1104,20 @@ restart: vio->vui_nrsegs = args->u.normal.via_nrsegs; vio->vui_tot_nrsegs = vio->vui_nrsegs; vio->vui_iocb = args->u.normal.via_iocb; - if ((iot == CIT_WRITE) && + /* Direct IO reads must also take range lock, + * or multiple reads will try to work on the same pages + * See LU-6227 for details. */ + if (((iot == CIT_WRITE) || + (iot == CIT_READ && (file->f_flags & O_DIRECT))) && !(vio->vui_fd->fd_flags & LL_FILE_GROUP_LOCKED)) { CDEBUG(D_VFSTRACE, "Range lock "RL_FMT"\n", RL_PARA(&range)); - result = range_lock(&lli->lli_write_tree, - &range); - if (result < 0) - GOTO(out, result); + rc = range_lock(&lli->lli_write_tree, &range); + if (rc < 0) + GOTO(out, rc); range_locked = true; } - down_read(&lli->lli_trunc_sem); break; case IO_SPLICE: vio->u.splice.vui_pipe = args->u.splice.via_pipe; @@ -1064,57 +1129,62 @@ restart: } ll_cl_add(file, env, io); - result = cl_io_loop(env, io); + rc = cl_io_loop(env, io); ll_cl_remove(file, env); - if (args->via_io_subtype == IO_NORMAL) - up_read(&lli->lli_trunc_sem); if (range_locked) { CDEBUG(D_VFSTRACE, "Range unlock "RL_FMT"\n", RL_PARA(&range)); range_unlock(&lli->lli_write_tree, &range); } - } else { - /* cl_io_rw_init() handled IO */ - result = io->ci_result; - } + } else { + /* cl_io_rw_init() handled IO */ + rc = io->ci_result; + } - if (io->ci_nob > 0) { - result = io->ci_nob; - *ppos = io->u.ci_wr.wr.crw_pos; - } - GOTO(out, result); + if (io->ci_nob > 0) { + result += io->ci_nob; + count -= io->ci_nob; + *ppos = io->u.ci_wr.wr.crw_pos; /* for splice */ + + /* prepare IO restart */ + if (count > 0 && args->via_io_subtype == IO_NORMAL) { + args->u.normal.via_iov = vio->vui_iov; + args->u.normal.via_nrsegs = vio->vui_tot_nrsegs; + } + } + GOTO(out, rc); out: - cl_io_fini(env, io); - /* If any bit been read/written (result != 0), we just return - * short read/write instead of restart io. */ - if ((result == 0 || result == -ENODATA) && io->ci_need_restart) { - CDEBUG(D_VFSTRACE, "Restart %s on %s from %lld, count:%zu\n", + cl_io_fini(env, io); + + if ((rc == 0 || rc == -ENODATA) && count > 0 && io->ci_need_restart) { + CDEBUG(D_VFSTRACE, + "%s: restart %s from %lld, count:%zu, result: %zd\n", + file->f_path.dentry->d_name.name, iot == CIT_READ ? "read" : "write", - file->f_dentry->d_name.name, *ppos, count); - LASSERTF(io->ci_nob == 0, "%zd\n", io->ci_nob); + *ppos, count, result); goto restart; } - if (iot == CIT_READ) { - if (result >= 0) - ll_stats_ops_tally(ll_i2sbi(file->f_dentry->d_inode), - LPROC_LL_READ_BYTES, result); - } else if (iot == CIT_WRITE) { - if (result >= 0) { - ll_stats_ops_tally(ll_i2sbi(file->f_dentry->d_inode), - LPROC_LL_WRITE_BYTES, result); + if (iot == CIT_READ) { + if (result > 0) + ll_stats_ops_tally(ll_i2sbi(inode), + LPROC_LL_READ_BYTES, result); + } else if (iot == CIT_WRITE) { + if (result > 0) { + ll_stats_ops_tally(ll_i2sbi(inode), + LPROC_LL_WRITE_BYTES, result); fd->fd_write_failed = false; - } else if (result != -ERESTARTSYS) { + } else if (rc != -ERESTARTSYS) { fd->fd_write_failed = true; } } + CDEBUG(D_VFSTRACE, "iot: %d, result: %zd\n", iot, result); - return result; + return result > 0 ? result : rc; } - /* * XXX: exact copy from kernel code (__generic_file_aio_write_nolock) */ @@ -1147,10 +1217,11 @@ static int ll_file_get_iov_count(const struct iovec *iov, } static ssize_t ll_file_aio_read(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t pos) + unsigned long nr_segs, loff_t pos) { - struct lu_env *env; - struct vvp_io_args *args; + struct lu_env *env; + struct vvp_io_args *args; + struct iovec *local_iov; size_t count; ssize_t result; int refcheck; @@ -1164,22 +1235,40 @@ static ssize_t ll_file_aio_read(struct kiocb *iocb, const struct iovec *iov, if (IS_ERR(env)) RETURN(PTR_ERR(env)); + if (nr_segs == 1) { + local_iov = &ll_env_info(env)->lti_local_iov; + *local_iov = *iov; + } else { + OBD_ALLOC(local_iov, sizeof(*iov) * nr_segs); + if (local_iov == NULL) { + cl_env_put(env, &refcheck); + RETURN(-ENOMEM); + } + + memcpy(local_iov, iov, sizeof(*iov) * nr_segs); + } + args = ll_env_args(env, IO_NORMAL); - args->u.normal.via_iov = (struct iovec *)iov; - args->u.normal.via_nrsegs = nr_segs; - args->u.normal.via_iocb = iocb; + args->u.normal.via_iov = local_iov; + args->u.normal.via_nrsegs = nr_segs; + args->u.normal.via_iocb = iocb; - result = ll_file_io_generic(env, args, iocb->ki_filp, CIT_READ, - &iocb->ki_pos, count); - cl_env_put(env, &refcheck); - RETURN(result); + result = ll_file_io_generic(env, args, iocb->ki_filp, CIT_READ, + &iocb->ki_pos, count); + + cl_env_put(env, &refcheck); + + if (nr_segs > 1) + OBD_FREE(local_iov, sizeof(*iov) * nr_segs); + + RETURN(result); } static ssize_t ll_file_read(struct file *file, char __user *buf, size_t count, - loff_t *ppos) + loff_t *ppos) { - struct lu_env *env; - struct iovec *local_iov; + struct lu_env *env; + struct iovec iov = { .iov_base = buf, .iov_len = count }; struct kiocb *kiocb; ssize_t result; int refcheck; @@ -1189,23 +1278,20 @@ static ssize_t ll_file_read(struct file *file, char __user *buf, size_t count, if (IS_ERR(env)) RETURN(PTR_ERR(env)); - local_iov = &ll_env_info(env)->lti_local_iov; kiocb = &ll_env_info(env)->lti_kiocb; - local_iov->iov_base = (void __user *)buf; - local_iov->iov_len = count; init_sync_kiocb(kiocb, file); kiocb->ki_pos = *ppos; #ifdef HAVE_KIOCB_KI_LEFT - kiocb->ki_left = count; -#else - kiocb->ki_nbytes = count; + kiocb->ki_left = count; +#elif defined(HAVE_KI_NBYTES) + kiocb->ki_nbytes = count; #endif - result = ll_file_aio_read(kiocb, local_iov, 1, kiocb->ki_pos); - *ppos = kiocb->ki_pos; + result = ll_file_aio_read(kiocb, &iov, 1, kiocb->ki_pos); + *ppos = kiocb->ki_pos; - cl_env_put(env, &refcheck); - RETURN(result); + cl_env_put(env, &refcheck); + RETURN(result); } /* @@ -1213,10 +1299,11 @@ static ssize_t ll_file_read(struct file *file, char __user *buf, size_t count, * AIO stuff */ static ssize_t ll_file_aio_write(struct kiocb *iocb, const struct iovec *iov, - unsigned long nr_segs, loff_t pos) + unsigned long nr_segs, loff_t pos) { - struct lu_env *env; - struct vvp_io_args *args; + struct lu_env *env; + struct vvp_io_args *args; + struct iovec *local_iov; size_t count; ssize_t result; int refcheck; @@ -1230,22 +1317,40 @@ static ssize_t ll_file_aio_write(struct kiocb *iocb, const struct iovec *iov, if (IS_ERR(env)) RETURN(PTR_ERR(env)); + if (nr_segs == 1) { + local_iov = &ll_env_info(env)->lti_local_iov; + *local_iov = *iov; + } else { + OBD_ALLOC(local_iov, sizeof(*iov) * nr_segs); + if (local_iov == NULL) { + cl_env_put(env, &refcheck); + RETURN(-ENOMEM); + } + + memcpy(local_iov, iov, sizeof(*iov) * nr_segs); + } + args = ll_env_args(env, IO_NORMAL); - args->u.normal.via_iov = (struct iovec *)iov; - args->u.normal.via_nrsegs = nr_segs; - args->u.normal.via_iocb = iocb; + args->u.normal.via_iov = local_iov; + args->u.normal.via_nrsegs = nr_segs; + args->u.normal.via_iocb = iocb; - result = ll_file_io_generic(env, args, iocb->ki_filp, CIT_WRITE, - &iocb->ki_pos, count); - cl_env_put(env, &refcheck); - RETURN(result); + result = ll_file_io_generic(env, args, iocb->ki_filp, CIT_WRITE, + &iocb->ki_pos, count); + cl_env_put(env, &refcheck); + + if (nr_segs > 1) + OBD_FREE(local_iov, sizeof(*iov) * nr_segs); + + RETURN(result); } static ssize_t ll_file_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { - struct lu_env *env; - struct iovec *local_iov; + struct lu_env *env; + struct iovec iov = { .iov_base = (void __user *)buf, + .iov_len = count }; struct kiocb *kiocb; ssize_t result; int refcheck; @@ -1255,23 +1360,20 @@ static ssize_t ll_file_write(struct file *file, const char __user *buf, if (IS_ERR(env)) RETURN(PTR_ERR(env)); - local_iov = &ll_env_info(env)->lti_local_iov; kiocb = &ll_env_info(env)->lti_kiocb; - local_iov->iov_base = (void __user *)buf; - local_iov->iov_len = count; init_sync_kiocb(kiocb, file); kiocb->ki_pos = *ppos; #ifdef HAVE_KIOCB_KI_LEFT - kiocb->ki_left = count; -#else - kiocb->ki_nbytes = count; + kiocb->ki_left = count; +#elif defined(HAVE_KI_NBYTES) + kiocb->ki_nbytes = count; #endif - result = ll_file_aio_write(kiocb, local_iov, 1, kiocb->ki_pos); - *ppos = kiocb->ki_pos; + result = ll_file_aio_write(kiocb, &iov, 1, kiocb->ki_pos); + *ppos = kiocb->ki_pos; - cl_env_put(env, &refcheck); - RETURN(result); + cl_env_put(env, &refcheck); + RETURN(result); } /* @@ -1304,7 +1406,6 @@ int ll_lov_setstripe_ea_info(struct inode *inode, struct file *file, __u64 flags, struct lov_user_md *lum, int lum_size) { - struct lov_stripe_md *lsm = NULL; struct lookup_intent oit = { .it_op = IT_OPEN, .it_flags = flags | MDS_OPEN_BY_FID, @@ -1312,30 +1413,16 @@ int ll_lov_setstripe_ea_info(struct inode *inode, struct file *file, int rc; ENTRY; - lsm = ccc_inode_lsm_get(inode); - if (lsm != NULL) { - ccc_inode_lsm_put(inode, lsm); - CDEBUG(D_IOCTL, "stripe already exists for inode "DFID"\n", - PFID(ll_inode2fid(inode))); - GOTO(out, rc = -EEXIST); - } - ll_inode_size_lock(inode); rc = ll_intent_file_open(file, lum, lum_size, &oit); if (rc < 0) GOTO(out_unlock, rc); - rc = oit.d.lustre.it_status; - if (rc < 0) - GOTO(out_unlock, rc); - - ll_release_openhandle(file->f_dentry, &oit); + ll_release_openhandle(file->f_path.dentry, &oit); out_unlock: ll_inode_size_unlock(inode); ll_intent_release(&oit); - ccc_inode_lsm_put(inode, lsm); -out: cl_lov_delay_create_clear(&file->f_flags); RETURN(rc); @@ -1616,7 +1703,7 @@ int ll_release_openhandle(struct dentry *dentry, struct lookup_intent *it) ll_och_fill(ll_i2sbi(inode)->ll_md_exp, it, och); rc = ll_close_inode_openhandle(ll_i2sbi(inode)->ll_md_exp, - inode, och, NULL); + och, inode, 0, NULL); out: /* this one is in place of ll_file_open */ if (it_disposition(it, DISP_ENQ_OPEN_REF)) { @@ -1638,7 +1725,7 @@ static int ll_do_fiemap(struct inode *inode, struct fiemap *fiemap, struct lu_env *env; int refcheck; int rc = 0; - struct ll_fiemap_info_key fmkey = { .name = KEY_FIEMAP, }; + struct ll_fiemap_info_key fmkey = { .lfik_name = KEY_FIEMAP, }; ENTRY; /* Checks for fiemap flags */ @@ -1664,17 +1751,17 @@ static int ll_do_fiemap(struct inode *inode, struct fiemap *fiemap, GOTO(out, rc); } - fmkey.oa.o_valid = OBD_MD_FLID | OBD_MD_FLGROUP; - obdo_from_inode(&fmkey.oa, inode, OBD_MD_FLSIZE); - obdo_set_parent_fid(&fmkey.oa, &ll_i2info(inode)->lli_fid); + fmkey.lfik_oa.o_valid = OBD_MD_FLID | OBD_MD_FLGROUP; + obdo_from_inode(&fmkey.lfik_oa, inode, OBD_MD_FLSIZE); + obdo_set_parent_fid(&fmkey.lfik_oa, &ll_i2info(inode)->lli_fid); /* If filesize is 0, then there would be no objects for mapping */ - if (fmkey.oa.o_size == 0) { + if (fmkey.lfik_oa.o_size == 0) { fiemap->fm_mapped_extents = 0; GOTO(out, rc = 0); } - fmkey.fiemap = *fiemap; + fmkey.lfik_fiemap = *fiemap; rc = cl_object_fiemap(env, ll_i2info(inode)->lli_clob, &fmkey, fiemap, &num_bytes); @@ -1726,61 +1813,6 @@ gf_free: RETURN(rc); } -static int ll_ioctl_fiemap(struct inode *inode, struct fiemap __user *arg) -{ - struct fiemap *fiemap; - size_t num_bytes; - size_t ret_bytes; - __u32 extent_count; - int rc = 0; - - /* Get the extent count so we can calculate the size of - * required fiemap buffer */ - if (get_user(extent_count, &arg->fm_extent_count)) - RETURN(-EFAULT); - - if (extent_count >= - (SIZE_MAX - sizeof(*fiemap)) / sizeof(struct ll_fiemap_extent)) - RETURN(-EINVAL); - num_bytes = sizeof(*fiemap) + (extent_count * - sizeof(struct ll_fiemap_extent)); - - OBD_ALLOC_LARGE(fiemap, num_bytes); - if (fiemap == NULL) - RETURN(-ENOMEM); - - /* get the fiemap value */ - if (copy_from_user(fiemap, arg, sizeof(*fiemap))) - GOTO(error, rc = -EFAULT); - - /* If fm_extent_count is non-zero, read the first extent since - * it is used to calculate end_offset and device from previous - * fiemap call. */ - if (extent_count != 0) { - if (copy_from_user(&fiemap->fm_extents[0], - (char __user *)arg + sizeof(*fiemap), - sizeof(struct ll_fiemap_extent))) - GOTO(error, rc = -EFAULT); - } - - rc = ll_do_fiemap(inode, fiemap, num_bytes); - if (rc) - GOTO(error, rc); - - ret_bytes = sizeof(struct fiemap); - - if (extent_count != 0) - ret_bytes += (fiemap->fm_mapped_extents * - sizeof(struct ll_fiemap_extent)); - - if (copy_to_user((void __user *)arg, fiemap, ret_bytes)) - rc = -EFAULT; - -error: - OBD_FREE_LARGE(fiemap, num_bytes); - RETURN(rc); -} - /* * Read the data_version for inode. * @@ -1794,13 +1826,16 @@ error: */ int ll_data_version(struct inode *inode, __u64 *data_version, int flags) { - struct lu_env *env; - int refcheck; - int rc; + struct cl_object *obj = ll_i2info(inode)->lli_clob; + struct lu_env *env; + struct cl_io *io; + int refcheck; + int result; + ENTRY; /* If no file object initialized, we consider its version is 0. */ - if (ll_i2info(inode)->lli_clob == NULL) { + if (obj == NULL) { *data_version = 0; RETURN(0); } @@ -1809,10 +1844,27 @@ int ll_data_version(struct inode *inode, __u64 *data_version, int flags) if (IS_ERR(env)) RETURN(PTR_ERR(env)); - rc = cl_object_data_version(env, ll_i2info(inode)->lli_clob, - data_version, flags); + io = vvp_env_thread_io(env); + io->ci_obj = obj; + io->u.ci_data_version.dv_data_version = 0; + io->u.ci_data_version.dv_flags = flags; + +restart: + if (cl_io_init(env, io, CIT_DATA_VERSION, io->ci_obj) == 0) + result = cl_io_loop(env, io); + else + result = io->ci_result; + + *data_version = io->u.ci_data_version.dv_data_version; + + cl_io_fini(env, io); + + if (unlikely(io->ci_need_restart)) + goto restart; + cl_env_put(env, &refcheck); - RETURN(rc); + + RETURN(result); } /* @@ -1850,8 +1902,8 @@ int ll_hsm_release(struct inode *inode) /* Release the file. * NB: lease lock handle is released in mdc_hsm_release_pack() because * we still need it to pack l_remote_handle to MDT. */ - rc = ll_close_inode_openhandle(ll_i2sbi(inode)->ll_md_exp, inode, och, - &data_version); + rc = ll_close_inode_openhandle(ll_i2sbi(inode)->ll_md_exp, och, inode, + MDS_HSM_RELEASE, &data_version); och = NULL; EXIT; @@ -1863,10 +1915,12 @@ out: } struct ll_swap_stack { - struct iattr ia1, ia2; - __u64 dv1, dv2; - struct inode *inode1, *inode2; - bool check_dv1, check_dv2; + __u64 dv1; + __u64 dv2; + struct inode *inode1; + struct inode *inode2; + bool check_dv1; + bool check_dv2; }; static int ll_swap_layouts(struct file *file1, struct file *file2, @@ -1883,18 +1937,12 @@ static int ll_swap_layouts(struct file *file1, struct file *file2, if (llss == NULL) RETURN(-ENOMEM); - llss->inode1 = file1->f_dentry->d_inode; - llss->inode2 = file2->f_dentry->d_inode; - - if (!S_ISREG(llss->inode2->i_mode)) - GOTO(free, rc = -EINVAL); + llss->inode1 = file1->f_path.dentry->d_inode; + llss->inode2 = file2->f_path.dentry->d_inode; - if (inode_permission(llss->inode1, MAY_WRITE) || - inode_permission(llss->inode2, MAY_WRITE)) - GOTO(free, rc = -EPERM); - - if (llss->inode2->i_sb != llss->inode1->i_sb) - GOTO(free, rc = -EXDEV); + rc = ll_check_swap_layouts_validity(llss->inode1, llss->inode2); + if (rc < 0) + GOTO(free, rc); /* we use 2 bool because it is easier to swap than 2 bits */ if (lsl->sl_flags & SWAP_LAYOUTS_CHECK_DV1) @@ -1909,7 +1957,7 @@ static int ll_swap_layouts(struct file *file1, struct file *file2, rc = lu_fid_cmp(ll_inode2fid(llss->inode1), ll_inode2fid(llss->inode2)); if (rc == 0) /* same file, done! */ - GOTO(free, rc = 0); + GOTO(free, rc); if (rc < 0) { /* sequentialize it */ swap(llss->inode1, llss->inode2); @@ -1931,18 +1979,6 @@ static int ll_swap_layouts(struct file *file1, struct file *file2, } } - /* to be able to restore mtime and atime after swap - * we need to first save them */ - if (lsl->sl_flags & - (SWAP_LAYOUTS_KEEP_MTIME | SWAP_LAYOUTS_KEEP_ATIME)) { - llss->ia1.ia_mtime = llss->inode1->i_mtime; - llss->ia1.ia_atime = llss->inode1->i_atime; - llss->ia1.ia_valid = ATTR_MTIME | ATTR_ATIME; - llss->ia2.ia_mtime = llss->inode2->i_mtime; - llss->ia2.ia_atime = llss->inode2->i_atime; - llss->ia2.ia_valid = ATTR_MTIME | ATTR_ATIME; - } - /* ultimate check, before swaping the layouts we check if * dataversion has changed (if requested) */ if (llss->check_dv1) { @@ -1977,45 +2013,15 @@ static int ll_swap_layouts(struct file *file1, struct file *file2, sizeof(*op_data), op_data, NULL); ll_finish_md_op_data(op_data); + if (rc < 0) + GOTO(putgl, rc); + putgl: if (gid != 0) { ll_put_grouplock(llss->inode2, file2, gid); ll_put_grouplock(llss->inode1, file1, gid); } - /* rc can be set from obd_iocontrol() or from a GOTO(putgl, ...) */ - if (rc != 0) - GOTO(free, rc); - - /* clear useless flags */ - if (!(lsl->sl_flags & SWAP_LAYOUTS_KEEP_MTIME)) { - llss->ia1.ia_valid &= ~ATTR_MTIME; - llss->ia2.ia_valid &= ~ATTR_MTIME; - } - - if (!(lsl->sl_flags & SWAP_LAYOUTS_KEEP_ATIME)) { - llss->ia1.ia_valid &= ~ATTR_ATIME; - llss->ia2.ia_valid &= ~ATTR_ATIME; - } - - /* update time if requested */ - rc = 0; - if (llss->ia2.ia_valid != 0) { - mutex_lock(&llss->inode1->i_mutex); - rc = ll_setattr(file1->f_dentry, &llss->ia2); - mutex_unlock(&llss->inode1->i_mutex); - } - - if (llss->ia1.ia_valid != 0) { - int rc1; - - mutex_lock(&llss->inode2->i_mutex); - rc1 = ll_setattr(file2->f_dentry, &llss->ia1); - mutex_unlock(&llss->inode2->i_mutex); - if (rc == 0) - rc = rc1; - } - free: if (llss != NULL) OBD_FREE_PTR(llss); @@ -2101,7 +2107,7 @@ static int ll_hsm_import(struct inode *inode, struct file *file, mutex_lock(&inode->i_mutex); - rc = ll_setattr_raw(file->f_dentry, attr, true); + rc = ll_setattr_raw(file->f_path.dentry, attr, true); if (rc == -ENODATA) rc = 0; @@ -2126,7 +2132,7 @@ static inline long ll_lease_type_from_fmode(fmode_t fmode) static long ll_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - struct inode *inode = file->f_dentry->d_inode; + struct inode *inode = file->f_path.dentry->d_inode; struct ll_file_data *fd = LUSTRE_FPRIVATE(file); int flags, rc; ENTRY; @@ -2177,24 +2183,46 @@ ll_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg) sizeof(struct lustre_swap_layouts))) RETURN(-EFAULT); - if ((file->f_flags & O_ACCMODE) == 0) /* O_RDONLY */ + if ((file->f_flags & O_ACCMODE) == O_RDONLY) RETURN(-EPERM); file2 = fget(lsl.sl_fd); if (file2 == NULL) RETURN(-EBADF); - rc = -EPERM; - if ((file2->f_flags & O_ACCMODE) != 0) /* O_WRONLY or O_RDWR */ + /* O_WRONLY or O_RDWR */ + if ((file2->f_flags & O_ACCMODE) == O_RDONLY) + GOTO(out, rc = -EPERM); + + if (lsl.sl_flags & SWAP_LAYOUTS_CLOSE) { + struct inode *inode2; + struct ll_inode_info *lli; + struct obd_client_handle *och = NULL; + + if (lsl.sl_flags != SWAP_LAYOUTS_CLOSE) + GOTO(out, rc = -EINVAL); + + lli = ll_i2info(inode); + mutex_lock(&lli->lli_och_mutex); + if (fd->fd_lease_och != NULL) { + och = fd->fd_lease_och; + fd->fd_lease_och = NULL; + } + mutex_unlock(&lli->lli_och_mutex); + if (och == NULL) + GOTO(out, rc = -ENOLCK); + inode2 = file2->f_path.dentry->d_inode; + rc = ll_swap_layouts_close(och, inode, inode2); + } else { rc = ll_swap_layouts(file, file2, &lsl); + } +out: fput(file2); RETURN(rc); } case LL_IOC_LOV_GETSTRIPE: RETURN(ll_file_getstripe(inode, (struct lov_user_md __user *)arg)); - case FSFILT_IOC_FIEMAP: - RETURN(ll_ioctl_fiemap(inode, (struct fiemap __user *)arg)); case FSFILT_IOC_GETFLAGS: case FSFILT_IOC_SETFLAGS: RETURN(ll_iocontrol(inode, file, cmd, arg)); @@ -2466,7 +2494,7 @@ static loff_t generic_file_llseek_size(struct file *file, loff_t offset, int origin, loff_t maxsize, loff_t eof) { - struct inode *inode = file->f_dentry->d_inode; + struct inode *inode = file->f_path.dentry->d_inode; switch (origin) { case SEEK_END: @@ -2515,7 +2543,7 @@ generic_file_llseek_size(struct file *file, loff_t offset, int origin, static loff_t ll_file_seek(struct file *file, loff_t offset, int origin) { - struct inode *inode = file->f_dentry->d_inode; + struct inode *inode = file->f_path.dentry->d_inode; loff_t retval, eof = 0; ENTRY; @@ -2540,7 +2568,7 @@ static loff_t ll_file_seek(struct file *file, loff_t offset, int origin) static int ll_flush(struct file *file, fl_owner_t id) { - struct inode *inode = file->f_dentry->d_inode; + struct inode *inode = file->f_path.dentry->d_inode; struct ll_inode_info *lli = ll_i2info(inode); struct ll_file_data *fd = LUSTRE_FPRIVATE(file); int rc, err; @@ -2576,7 +2604,6 @@ int cl_sync_file_range(struct inode *inode, loff_t start, loff_t end, struct cl_env_nest nest; struct lu_env *env; struct cl_io *io; - struct obd_capa *capa = NULL; struct cl_fsync_io *fio; int result; ENTRY; @@ -2589,15 +2616,12 @@ int cl_sync_file_range(struct inode *inode, loff_t start, loff_t end, if (IS_ERR(env)) RETURN(PTR_ERR(env)); - capa = ll_osscapa_get(inode, CAPA_OPC_OSS_WRITE); - io = vvp_env_thread_io(env); io->ci_obj = ll_i2info(inode)->lli_clob; io->ci_ignore_layout = ignore_layout; /* initialize parameters for sync */ fio = &io->u.ci_fsync; - fio->fi_capa = capa; fio->fi_start = start; fio->fi_end = end; fio->fi_fid = ll_inode2fid(inode); @@ -2613,25 +2637,23 @@ int cl_sync_file_range(struct inode *inode, loff_t start, loff_t end, cl_io_fini(env, io); cl_env_nested_put(&nest, env); - capa_put(capa); - RETURN(result); } /* - * When dentry is provided (the 'else' case), *file->f_dentry may be + * When dentry is provided (the 'else' case), *file->f_path.dentry may be * null and dentry must be used directly rather than pulled from - * *file->f_dentry as is done otherwise. + * *file->f_path.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->f_dentry; + struct dentry *dentry = file->f_path.dentry; #elif defined(HAVE_FILE_FSYNC_2ARGS) int ll_fsync(struct file *file, int datasync) { - struct dentry *dentry = file->f_dentry; + struct dentry *dentry = file->f_path.dentry; loff_t start = 0; loff_t end = LLONG_MAX; #else @@ -2643,7 +2665,6 @@ int ll_fsync(struct file *file, struct dentry *dentry, int datasync) struct inode *inode = dentry->d_inode; struct ll_inode_info *lli = ll_i2info(inode); struct ptlrpc_request *req; - struct obd_capa *oc; int rc, err; ENTRY; @@ -2672,10 +2693,7 @@ int ll_fsync(struct file *file, struct dentry *dentry, int datasync) rc = err; } - oc = ll_mdscapa_get(inode); - err = md_fsync(ll_i2sbi(inode)->ll_md_exp, ll_inode2fid(inode), oc, - &req); - capa_put(oc); + err = md_fsync(ll_i2sbi(inode)->ll_md_exp, ll_inode2fid(inode), &req); if (!rc) rc = err; if (!err) @@ -2702,7 +2720,7 @@ int ll_fsync(struct file *file, struct dentry *dentry, int datasync) static int ll_file_flock(struct file *file, int cmd, struct file_lock *file_lock) { - struct inode *inode = file->f_dentry->d_inode; + struct inode *inode = file->f_path.dentry->d_inode; struct ll_sb_info *sbi = ll_i2sbi(inode); struct ldlm_enqueue_info einfo = { .ei_type = LDLM_FLOCK, @@ -2889,7 +2907,7 @@ int ll_migrate(struct inode *parent, struct file *file, int mdtidx, qstr.hash = full_name_hash(name, namelen); qstr.name = name; qstr.len = namelen; - dchild = d_lookup(file->f_dentry, &qstr); + dchild = d_lookup(file->f_path.dentry, &qstr); if (dchild != NULL) { if (dchild->d_inode != NULL) { child_inode = igrab(dchild->d_inode); @@ -3117,9 +3135,6 @@ static int __ll_inode_revalidate(struct dentry *dentry, __u64 ibits) RETURN(PTR_ERR(op_data)); op_data->op_valid = valid; - /* Once OBD_CONNECT_ATTRFID is not supported, we can't find one - * capa for this inode. Because we only keep capas of dirs - * fresh. */ rc = md_getattr(sbi->ll_md_exp, op_data, &req); ll_finish_md_op_data(op_data); if (rc) { @@ -3231,35 +3246,37 @@ int ll_getattr(struct vfsmount *mnt, struct dentry *de, struct kstat *stat) static int ll_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, __u64 start, __u64 len) { - int rc; - size_t num_bytes; - struct ll_user_fiemap *fiemap; - unsigned int extent_count = fieinfo->fi_extents_max; + int rc; + size_t num_bytes; + struct fiemap *fiemap; + unsigned int extent_count = fieinfo->fi_extents_max; - num_bytes = sizeof(*fiemap) + (extent_count * - sizeof(struct ll_fiemap_extent)); - OBD_ALLOC_LARGE(fiemap, num_bytes); + num_bytes = sizeof(*fiemap) + (extent_count * + sizeof(struct fiemap_extent)); + OBD_ALLOC_LARGE(fiemap, num_bytes); - if (fiemap == NULL) - RETURN(-ENOMEM); + if (fiemap == NULL) + RETURN(-ENOMEM); - fiemap->fm_flags = fieinfo->fi_flags; - fiemap->fm_extent_count = fieinfo->fi_extents_max; - fiemap->fm_start = start; - fiemap->fm_length = len; - if (extent_count > 0) - memcpy(&fiemap->fm_extents[0], fieinfo->fi_extents_start, - sizeof(struct ll_fiemap_extent)); + fiemap->fm_flags = fieinfo->fi_flags; + fiemap->fm_extent_count = fieinfo->fi_extents_max; + fiemap->fm_start = start; + fiemap->fm_length = len; + if (extent_count > 0 && + copy_from_user(&fiemap->fm_extents[0], fieinfo->fi_extents_start, + sizeof(struct fiemap_extent)) != 0) + GOTO(out, rc = -EFAULT); rc = ll_do_fiemap(inode, fiemap, num_bytes); fieinfo->fi_flags = fiemap->fm_flags; fieinfo->fi_extents_mapped = fiemap->fm_mapped_extents; - if (extent_count > 0) - memcpy(fieinfo->fi_extents_start, &fiemap->fm_extents[0], - fiemap->fm_mapped_extents * - sizeof(struct ll_fiemap_extent)); - + if (extent_count > 0 && + copy_to_user(fieinfo->fi_extents_start, &fiemap->fm_extents[0], + fiemap->fm_mapped_extents * + sizeof(struct fiemap_extent)) != 0) + GOTO(out, rc = -EFAULT); +out: OBD_FREE_LARGE(fiemap, num_bytes); return rc; } @@ -3563,48 +3580,53 @@ ll_iocontrol_call(struct inode *inode, struct file *file, int ll_layout_conf(struct inode *inode, const struct cl_object_conf *conf) { struct ll_inode_info *lli = ll_i2info(inode); + struct cl_object *obj = lli->lli_clob; struct cl_env_nest nest; struct lu_env *env; - int result; + int rc; ENTRY; - if (lli->lli_clob == NULL) + if (obj == NULL) RETURN(0); env = cl_env_nested_get(&nest); if (IS_ERR(env)) RETURN(PTR_ERR(env)); - result = cl_conf_set(env, lli->lli_clob, conf); - cl_env_nested_put(&nest, env); + rc = cl_conf_set(env, lli->lli_clob, conf); + if (rc < 0) + GOTO(out, rc); if (conf->coc_opc == OBJECT_CONF_SET) { struct ldlm_lock *lock = conf->coc_lock; + struct cl_layout cl = { + .cl_layout_gen = 0, + }; LASSERT(lock != NULL); LASSERT(ldlm_has_layout(lock)); - if (result == 0) { - struct lustre_md *md = conf->u.coc_md; - __u32 gen = LL_LAYOUT_GEN_EMPTY; - - /* it can only be allowed to match after layout is - * applied to inode otherwise false layout would be - * seen. Applying layout shoud happen before dropping - * the intent lock. */ - ldlm_lock_allow_match(lock); - - lli->lli_has_smd = lsm_has_objects(md->lsm); - if (md->lsm != NULL) - gen = md->lsm->lsm_layout_gen; - - CDEBUG(D_VFSTRACE, - DFID ": layout version change: %u -> %u\n", - PFID(&lli->lli_fid), ll_layout_version_get(lli), - gen); - ll_layout_version_set(lli, gen); - } + + /* it can only be allowed to match after layout is + * applied to inode otherwise false layout would be + * seen. Applying layout shoud happen before dropping + * the intent lock. */ + ldlm_lock_allow_match(lock); + + rc = cl_object_layout_get(env, obj, &cl); + if (rc < 0) + GOTO(out, rc); + + CDEBUG(D_VFSTRACE, + DFID": layout version change: %u -> %u\n", + PFID(&lli->lli_fid), ll_layout_version_get(lli), + cl.cl_layout_gen); + ll_layout_version_set(lli, cl.cl_layout_gen); } - RETURN(result); + +out: + cl_env_nested_put(&nest, env); + + RETURN(rc); } /* Fetch layout from MDT with getxattr request, if it's not ready yet */ @@ -3612,7 +3634,6 @@ static int ll_layout_fetch(struct inode *inode, struct ldlm_lock *lock) { struct ll_sb_info *sbi = ll_i2sbi(inode); - struct obd_capa *oc; struct ptlrpc_request *req; struct mdt_body *body; void *lvbdata; @@ -3625,7 +3646,7 @@ static int ll_layout_fetch(struct inode *inode, struct ldlm_lock *lock) PFID(ll_inode2fid(inode)), ldlm_is_lvb_ready(lock), lock->l_lvb_data, lock->l_lvb_len); - if ((lock->l_lvb_data != NULL) && ldlm_is_lvb_ready(lock)) + if (lock->l_lvb_data != NULL) RETURN(0); /* if layout lock was granted right away, the layout is returned @@ -3633,13 +3654,11 @@ static int ll_layout_fetch(struct inode *inode, struct ldlm_lock *lock) * blocked and then granted via completion ast, we have to fetch * layout here. Please note that we can't use the LVB buffer in * completion AST because it doesn't have a large enough buffer */ - oc = ll_mdscapa_get(inode); rc = ll_get_default_mdsize(sbi, &lmmsize); if (rc == 0) - rc = md_getxattr(sbi->ll_md_exp, ll_inode2fid(inode), oc, + rc = md_getxattr(sbi->ll_md_exp, ll_inode2fid(inode), OBD_MD_FLXATTR, XATTR_NAME_LOV, NULL, 0, lmmsize, 0, &req); - capa_put(oc); if (rc < 0) RETURN(rc); @@ -3661,13 +3680,17 @@ static int ll_layout_fetch(struct inode *inode, struct ldlm_lock *lock) memcpy(lvbdata, lmm, lmmsize); lock_res_and_lock(lock); - if (lock->l_lvb_data != NULL) - OBD_FREE_LARGE(lock->l_lvb_data, lock->l_lvb_len); - - lock->l_lvb_data = lvbdata; - lock->l_lvb_len = lmmsize; + if (unlikely(lock->l_lvb_data == NULL)) { + lock->l_lvb_type = LVB_T_LAYOUT; + lock->l_lvb_data = lvbdata; + lock->l_lvb_len = lmmsize; + lvbdata = NULL; + } unlock_res_and_lock(lock); + if (lvbdata != NULL) + OBD_FREE_LARGE(lvbdata, lmmsize); + EXIT; out: @@ -3680,12 +3703,11 @@ out: * in this function. */ static int ll_layout_lock_set(struct lustre_handle *lockh, ldlm_mode_t mode, - struct inode *inode, __u32 *gen, bool reconf) + struct inode *inode) { struct ll_inode_info *lli = ll_i2info(inode); struct ll_sb_info *sbi = ll_i2sbi(inode); struct ldlm_lock *lock; - struct lustre_md md = { NULL }; struct cl_object_conf conf; int rc = 0; bool lvb_ready; @@ -3698,8 +3720,8 @@ static int ll_layout_lock_set(struct lustre_handle *lockh, ldlm_mode_t mode, LASSERT(lock != NULL); LASSERT(ldlm_has_layout(lock)); - LDLM_DEBUG(lock, "file "DFID"(%p) being reconfigured: %d", - PFID(&lli->lli_fid), inode, reconf); + LDLM_DEBUG(lock, "file "DFID"(%p) being reconfigured", + PFID(&lli->lli_fid), inode); /* in case this is a caching lock and reinstate with new inode */ md_set_lock_data(sbi->ll_md_exp, &lockh->cookie, inode, NULL); @@ -3710,54 +3732,27 @@ static int ll_layout_lock_set(struct lustre_handle *lockh, ldlm_mode_t mode, /* checking lvb_ready is racy but this is okay. The worst case is * that multi processes may configure the file on the same time. */ - if (lvb_ready || !reconf) { - rc = -ENODATA; - if (lvb_ready) { - /* layout_gen must be valid if layout lock is not - * cancelled and stripe has already set */ - *gen = ll_layout_version_get(lli); - rc = 0; - } - GOTO(out, rc); - } + if (lvb_ready) + GOTO(out, rc = 0); rc = ll_layout_fetch(inode, lock); if (rc < 0) GOTO(out, rc); - /* for layout lock, lmm is returned in lock's lvb. + /* for layout lock, lmm is stored in lock's lvb. * lvb_data is immutable if the lock is held so it's safe to access it - * without res lock. See the description in ldlm_lock_decref_internal() - * for the condition to free lvb_data of layout lock */ - if (lock->l_lvb_data != NULL) { - rc = obd_unpackmd(sbi->ll_dt_exp, &md.lsm, - lock->l_lvb_data, lock->l_lvb_len); - if (rc >= 0) { - *gen = LL_LAYOUT_GEN_EMPTY; - if (md.lsm != NULL) - *gen = md.lsm->lsm_layout_gen; - rc = 0; - } else { - CERROR("%s: file "DFID" unpackmd error: %d\n", - ll_get_fsname(inode->i_sb, NULL, 0), - PFID(&lli->lli_fid), rc); - } - } - if (rc < 0) - GOTO(out, rc); - - /* set layout to file. Unlikely this will fail as old layout was + * without res lock. + * + * set layout to file. Unlikely this will fail as old layout was * surely eliminated */ memset(&conf, 0, sizeof conf); conf.coc_opc = OBJECT_CONF_SET; conf.coc_inode = inode; conf.coc_lock = lock; - conf.u.coc_md = &md; + conf.u.coc_layout.lb_buf = lock->l_lvb_data; + conf.u.coc_layout.lb_len = lock->l_lvb_len; rc = ll_layout_conf(inode, &conf); - if (md.lsm != NULL) - obd_free_memmd(sbi->ll_dt_exp, &md.lsm); - /* refresh layout failed, need to wait */ wait_layout = rc == -EBUSY; EXIT; @@ -3786,20 +3781,7 @@ out: RETURN(rc); } -/** - * This function checks if there exists a LAYOUT lock on the client side, - * or enqueues it if it doesn't have one in cache. - * - * This function will not hold layout lock so it may be revoked any time after - * this function returns. Any operations depend on layout should be redone - * in that case. - * - * This function should be called before lov_io_init() to get an uptodate - * layout version, the caller should save the version number and after IO - * is finished, this function should be called again to verify that layout - * is not changed during IO time. - */ -int ll_layout_refresh(struct inode *inode, __u32 *gen) +static int ll_layout_refresh_locked(struct inode *inode) { struct ll_inode_info *lli = ll_i2info(inode); struct ll_sb_info *sbi = ll_i2sbi(inode); @@ -3816,37 +3798,23 @@ int ll_layout_refresh(struct inode *inode, __u32 *gen) int rc; ENTRY; - *gen = ll_layout_version_get(lli); - if (!(sbi->ll_flags & LL_SBI_LAYOUT_LOCK) || *gen != LL_LAYOUT_GEN_NONE) - RETURN(0); - - /* sanity checks */ - LASSERT(fid_is_sane(ll_inode2fid(inode))); - LASSERT(S_ISREG(inode->i_mode)); - - /* take layout lock mutex to enqueue layout lock exclusively. */ - mutex_lock(&lli->lli_layout_mutex); - again: /* 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); if (mode != 0) { /* hit cached lock */ - rc = ll_layout_lock_set(&lockh, mode, inode, gen, true); + rc = ll_layout_lock_set(&lockh, mode, inode); if (rc == -EAGAIN) goto again; - mutex_unlock(&lli->lli_layout_mutex); RETURN(rc); } op_data = ll_prep_md_op_data(NULL, inode, inode, NULL, 0, 0, LUSTRE_OPC_ANY, NULL); - if (IS_ERR(op_data)) { - mutex_unlock(&lli->lli_layout_mutex); + if (IS_ERR(op_data)) RETURN(PTR_ERR(op_data)); - } /* have to enqueue one */ memset(&it, 0, sizeof(it)); @@ -3871,10 +3839,51 @@ again: if (rc == 0) { /* set lock data in case this is a new lock */ ll_set_lock_data(sbi->ll_md_exp, inode, &it, NULL); - rc = ll_layout_lock_set(&lockh, mode, inode, gen, true); + rc = ll_layout_lock_set(&lockh, mode, inode); if (rc == -EAGAIN) goto again; } + + RETURN(rc); +} + +/** + * This function checks if there exists a LAYOUT lock on the client side, + * or enqueues it if it doesn't have one in cache. + * + * This function will not hold layout lock so it may be revoked any time after + * this function returns. Any operations depend on layout should be redone + * in that case. + * + * This function should be called before lov_io_init() to get an uptodate + * layout version, the caller should save the version number and after IO + * is finished, this function should be called again to verify that layout + * is not changed during IO time. + */ +int ll_layout_refresh(struct inode *inode, __u32 *gen) +{ + struct ll_inode_info *lli = ll_i2info(inode); + struct ll_sb_info *sbi = ll_i2sbi(inode); + int rc; + ENTRY; + + *gen = ll_layout_version_get(lli); + if (!(sbi->ll_flags & LL_SBI_LAYOUT_LOCK) || *gen != CL_LAYOUT_GEN_NONE) + RETURN(0); + + /* sanity checks */ + LASSERT(fid_is_sane(ll_inode2fid(inode))); + LASSERT(S_ISREG(inode->i_mode)); + + /* take layout lock mutex to enqueue layout lock exclusively. */ + mutex_lock(&lli->lli_layout_mutex); + + rc = ll_layout_refresh_locked(inode); + if (rc < 0) + GOTO(out, rc); + + *gen = ll_layout_version_get(lli); +out: mutex_unlock(&lli->lli_layout_mutex); RETURN(rc);