* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2014, Intel Corporation.
+ * Copyright (c) 2011, 2015, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
OBD_SLAB_FREE_PTR(fd, ll_file_data_slab);
}
-void ll_pack_inode2opdata(struct inode *inode, struct md_op_data *op_data,
- struct lustre_handle *fh)
-{
- op_data->op_fid1 = ll_i2info(inode)->lli_fid;
- op_data->op_attr.ia_mode = inode->i_mode;
- op_data->op_attr.ia_atime = inode->i_atime;
- op_data->op_attr.ia_mtime = inode->i_mtime;
- op_data->op_attr.ia_ctime = inode->i_ctime;
- op_data->op_attr.ia_size = i_size_read(inode);
- op_data->op_attr_blocks = inode->i_blocks;
- 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;
-}
-
/**
* Packs all the attributes into @op_data for the CLOSE rpc.
*/
static void ll_prepare_close(struct inode *inode, struct md_op_data *op_data,
struct obd_client_handle *och)
{
- ENTRY;
-
- op_data->op_attr.ia_valid = ATTR_MODE | ATTR_ATIME | ATTR_ATIME_SET |
- ATTR_MTIME | ATTR_MTIME_SET |
- ATTR_CTIME | ATTR_CTIME_SET;
+ ENTRY;
- if (!(och->och_flags & FMODE_WRITE))
- goto out;
+ ll_prep_md_op_data(op_data, inode, NULL, NULL,
+ 0, 0, LUSTRE_OPC_ANY, NULL);
+
+ op_data->op_attr.ia_mode = inode->i_mode;
+ op_data->op_attr.ia_atime = inode->i_atime;
+ op_data->op_attr.ia_mtime = inode->i_mtime;
+ op_data->op_attr.ia_ctime = inode->i_ctime;
+ op_data->op_attr.ia_size = i_size_read(inode);
+ op_data->op_attr.ia_valid |= ATTR_MODE | ATTR_ATIME | ATTR_ATIME_SET |
+ ATTR_MTIME | ATTR_MTIME_SET |
+ ATTR_CTIME | ATTR_CTIME_SET;
+ op_data->op_attr_blocks = inode->i_blocks;
+ op_data->op_attr_flags = ll_inode_to_ext_flags(inode->i_flags);
+ op_data->op_handle = och->och_fh;
- op_data->op_attr.ia_valid |= ATTR_SIZE | ATTR_BLOCKS;
+ if (och->och_flags & FMODE_WRITE &&
+ ll_file_test_and_clear_flag(ll_i2info(inode), LLIF_DATA_MODIFIED))
+ /* For HSM: if inode data has been modified, pack it so that
+ * MDT can set data dirty flag in the archive. */
+ op_data->op_bias |= MDS_DATA_MODIFIED;
-out:
- ll_pack_inode2opdata(inode, op_data, &och->och_fh);
- ll_prep_md_op_data(op_data, inode, NULL, NULL,
- 0, 0, LUSTRE_OPC_ANY, NULL);
- EXIT;
+ EXIT;
}
-static int ll_close_inode_openhandle(struct obd_export *md_exp,
- struct inode *inode,
+/**
+ * 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 inode *inode,
struct obd_client_handle *och,
- const __u64 *data_version)
+ 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 *md_exp = ll_i2mdexp(inode);
+ const struct ll_inode_info *lli = ll_i2info(inode);
+ struct md_op_data *op_data;
+ struct ptlrpc_request *req = NULL;
+ 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 (class_exp2obd(md_exp) == NULL) {
+ CERROR("%s: invalid MDC connection handle closing "DFID"\n",
+ ll_get_fsname(inode->i_sb, NULL, 0),
+ PFID(&lli->lli_fid));
+ 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);
+ /* We leak openhandle and request here on error, but not much to be
+ * done in OOM case since app won't retry close on error either. */
+ if (op_data == NULL)
+ 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;
- rc = md_close(md_exp, op_data, och->och_mod, &req);
- if (rc) {
- CERROR("%s: inode "DFID" mdc close failed: rc = %d\n",
- ll_i2mdexp(inode)->exp_obd->obd_name,
- PFID(ll_inode2fid(inode)), rc);
+ default:
+ LASSERT(data == NULL);
+ break;
}
- /* DATA_MODIFIED flag was successfully sent on close, cancel data
- * modification flag. */
- if (rc == 0 && (op_data->op_bias & MDS_DATA_MODIFIED)) {
- struct ll_inode_info *lli = ll_i2info(inode);
-
- spin_lock(&lli->lli_lock);
- lli->lli_flags &= ~LLIF_DATA_MODIFIED;
- spin_unlock(&lli->lli_lock);
- }
+ rc = md_close(md_exp, op_data, och->och_mod, &req);
+ if (rc != 0 && rc != -EINTR)
+ CERROR("%s: inode "DFID" mdc close failed: rc = %d\n",
+ md_exp->exp_obd->obd_name, PFID(&lli->lli_fid), rc);
- 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);
och->och_fh.cookie = DEAD_HANDLE_MAGIC;
OBD_FREE_PTR(och);
- if (req) /* This is close request */
- ptlrpc_req_finished(req);
- return rc;
+ ptlrpc_req_finished(req); /* This is close request */
+ return rc;
}
int ll_md_real_close(struct inode *inode, fmode_t fmode)
if (och != NULL) {
/* 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);
+ rc = ll_close_inode_openhandle(inode, och, 0, NULL);
}
RETURN(rc);
}
-static int ll_md_close(struct obd_export *md_exp, struct inode *inode,
- struct file *file)
+static int ll_md_close(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;
+ union ldlm_policy_data 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;
+ enum ldlm_mode lockmode;
+ int rc = 0;
+ ENTRY;
/* clear group lock, if present */
if (unlikely(fd->fd_flags & LL_FILE_GROUP_LOCKED))
}
if (fd->fd_och != NULL) {
- rc = ll_close_inode_openhandle(md_exp, inode, fd->fd_och, NULL);
+ rc = ll_close_inode_openhandle(inode, fd->fd_och, 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(ll_i2mdexp(inode), 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);
}
}
#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);
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) {
- LUSTRE_FPRIVATE(file) = NULL;
- ll_file_data_put(fd);
- RETURN(0);
- }
+ if (inode->i_sb->s_root == file->f_path.dentry) {
+ LUSTRE_FPRIVATE(file) = NULL;
+ ll_file_data_put(fd);
+ RETURN(0);
+ }
- if (!S_ISDIR(inode->i_mode)) {
+ if (!S_ISDIR(inode->i_mode)) {
if (lli->lli_clob != NULL)
lov_read_and_clear_async_rc(lli->lli_clob);
- lli->lli_async_rc = 0;
- }
+ lli->lli_async_rc = 0;
+ }
- rc = ll_md_close(sbi->ll_md_exp, inode, file);
+ rc = ll_md_close(inode, file);
- if (CFS_FAIL_TIMEOUT_MS(OBD_FAIL_PTLRPC_DUMP_LOG, cfs_fail_val))
- libcfs_debug_dumplog();
+ if (CFS_FAIL_TIMEOUT_MS(OBD_FAIL_PTLRPC_DUMP_LOG, cfs_fail_val))
+ libcfs_debug_dumplog();
- RETURN(rc);
+ RETURN(rc);
}
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;
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));
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);
}
GOTO(out_openerr, rc);
}
- ll_release_openhandle(file->f_dentry, it);
+ ll_release_openhandle(file->f_path.dentry, it);
}
(*och_usecount)++;
if (!S_ISREG(inode->i_mode))
GOTO(out_och_free, rc);
- ll_capa_open(inode);
-
cl_lov_delay_create_clear(&file->f_flags);
GOTO(out_och_free, rc);
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(inode, och, 0, NULL);
if (rc2 < 0)
CERROR("%s: error closing file "DFID": %d\n",
ll_get_fsname(inode->i_sb, NULL, 0),
}
/**
+ * 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(inode, och, 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.
*/
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(inode, och, 0, NULL);
RETURN(rc);
}
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) {
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);
- }
+ ll_io_init(io, file, iot == CIT_WRITE);
- if (cl_io_rw_init(env, io, iot, *ppos, count) == 0) {
- struct vvp_io *vio = vvp_env_io(env);
+ if (cl_io_rw_init(env, io, iot, *ppos, count) == 0) {
bool range_locked = false;
if (file->f_flags & O_APPEND)
switch (vio->vui_io_subtype) {
case IO_NORMAL:
- vio->vui_iov = args->u.normal.via_iov;
- vio->vui_nrsegs = args->u.normal.via_nrsegs;
- vio->vui_tot_nrsegs = vio->vui_nrsegs;
+ vio->vui_iter = args->u.normal.via_iter;
+#ifndef HAVE_FILE_OPERATIONS_READ_WRITE_ITER
+ vio->vui_tot_nrsegs = vio->vui_iter->nr_segs;
+#endif /* !HAVE_FILE_OPERATIONS_READ_WRITE_ITER */
vio->vui_iocb = args->u.normal.via_iocb;
/* Direct IO reads must also take range lock,
* or multiple reads will try to work on the same pages
!(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;
}
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_iter = vio->vui_iter;
+#ifndef HAVE_FILE_OPERATIONS_READ_WRITE_ITER
+ args->u.normal.via_iter->nr_segs = vio->vui_tot_nrsegs;
+#endif /* !HAVE_FILE_OPERATIONS_READ_WRITE_ITER */
+ }
+ }
+ 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 (result == 0 && rc == 0) {
+ rc = io->ci_result;
+ if (rc < 0)
+ fd->fd_write_failed = true;
+ else
+ fd->fd_write_failed = false;
+ } else if (rc != -ERESTARTSYS) {
fd->fd_write_failed = true;
}
}
+
CDEBUG(D_VFSTRACE, "iot: %d, result: %zd\n", iot, result);
+ return result > 0 ? result : rc;
+}
+
+/*
+ * Read from a file (through the page cache).
+ */
+static ssize_t ll_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
+{
+ struct vvp_io_args *args;
+ struct lu_env *env;
+ ssize_t result;
+ __u16 refcheck;
+
+ env = cl_env_get(&refcheck);
+ if (IS_ERR(env))
+ return PTR_ERR(env);
+
+ args = ll_env_args(env, IO_NORMAL);
+ args->u.normal.via_iter = to;
+ args->u.normal.via_iocb = iocb;
+
+ result = ll_file_io_generic(env, args, iocb->ki_filp, CIT_READ,
+ &iocb->ki_pos, iov_iter_count(to));
+ cl_env_put(env, &refcheck);
return result;
}
+/*
+ * Write to a file (through the page cache).
+ */
+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 result;
+ __u16 refcheck;
+
+ env = cl_env_get(&refcheck);
+ if (IS_ERR(env))
+ return PTR_ERR(env);
+
+ args = ll_env_args(env, IO_NORMAL);
+ args->u.normal.via_iter = from;
+ args->u.normal.via_iocb = iocb;
+
+ result = ll_file_io_generic(env, args, iocb->ki_filp, CIT_WRITE,
+ &iocb->ki_pos, iov_iter_count(from));
+ cl_env_put(env, &refcheck);
+ return result;
+}
+#ifndef HAVE_FILE_OPERATIONS_READ_WRITE_ITER
/*
* XXX: exact copy from kernel code (__generic_file_aio_write_nolock)
*/
static int ll_file_get_iov_count(const struct iovec *iov,
- unsigned long *nr_segs, size_t *count)
+ unsigned long *nr_segs, size_t *count)
{
- size_t cnt = 0;
- unsigned long seg;
+ size_t cnt = 0;
+ unsigned long seg;
- for (seg = 0; seg < *nr_segs; seg++) {
- const struct iovec *iv = &iov[seg];
+ for (seg = 0; seg < *nr_segs; seg++) {
+ const struct iovec *iv = &iov[seg];
- /*
- * If any segment has a negative length, or the cumulative
- * length ever wraps negative then return -EINVAL.
- */
- cnt += iv->iov_len;
- if (unlikely((ssize_t)(cnt|iv->iov_len) < 0))
- return -EINVAL;
- if (access_ok(VERIFY_READ, iv->iov_base, iv->iov_len))
- continue;
- if (seg == 0)
- return -EFAULT;
- *nr_segs = seg;
- cnt -= iv->iov_len; /* This segment is no good */
- break;
- }
- *count = cnt;
- return 0;
+ /*
+ * If any segment has a negative length, or the cumulative
+ * length ever wraps negative then return -EINVAL.
+ */
+ cnt += iv->iov_len;
+ if (unlikely((ssize_t)(cnt|iv->iov_len) < 0))
+ return -EINVAL;
+ if (access_ok(VERIFY_READ, iv->iov_base, iv->iov_len))
+ continue;
+ if (seg == 0)
+ return -EFAULT;
+ *nr_segs = seg;
+ cnt -= iv->iov_len; /* This segment is no good */
+ break;
+ }
+ *count = cnt;
+ return 0;
}
static ssize_t ll_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
- unsigned long nr_segs, loff_t pos)
-{
- struct lu_env *env;
- struct vvp_io_args *args;
- size_t count;
- ssize_t result;
- int refcheck;
- ENTRY;
+ unsigned long nr_segs, loff_t pos)
+{
+ struct iovec *local_iov;
+ struct iov_iter *to;
+ size_t iov_count;
+ ssize_t result;
+ struct lu_env *env = NULL;
+ __u16 refcheck;
+ ENTRY;
- result = ll_file_get_iov_count(iov, &nr_segs, &count);
- if (result)
- RETURN(result);
+ result = ll_file_get_iov_count(iov, &nr_segs, &iov_count);
+ if (result)
+ RETURN(result);
- env = cl_env_get(&refcheck);
- if (IS_ERR(env))
- RETURN(PTR_ERR(env));
+ if (nr_segs == 1) {
- 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;
+ env = cl_env_get(&refcheck);
+ if (IS_ERR(env))
+ RETURN(PTR_ERR(env));
- result = ll_file_io_generic(env, args, iocb->ki_filp, CIT_READ,
- &iocb->ki_pos, count);
- cl_env_put(env, &refcheck);
- RETURN(result);
+ 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)
+ RETURN(-ENOMEM);
+
+ memcpy(local_iov, iov, sizeof(*iov) * nr_segs);
+ }
+
+ OBD_ALLOC_PTR(to);
+ if (to == NULL) {
+ result = -ENOMEM;
+ goto out;
+ }
+# ifdef HAVE_IOV_ITER_INIT_DIRECTION
+ iov_iter_init(to, READ, local_iov, nr_segs, iov_count);
+# else /* !HAVE_IOV_ITER_INIT_DIRECTION */
+ iov_iter_init(to, local_iov, nr_segs, iov_count, 0);
+# endif /* HAVE_IOV_ITER_INIT_DIRECTION */
+
+ result = ll_file_read_iter(iocb, to);
+
+ OBD_FREE_PTR(to);
+out:
+ if (nr_segs == 1)
+ cl_env_put(env, &refcheck);
+ else
+ 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;
+ __u16 refcheck;
ENTRY;
env = cl_env_get(&refcheck);
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);
}
/*
* AIO stuff
*/
static ssize_t ll_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
- unsigned long nr_segs, loff_t pos)
-{
- struct lu_env *env;
- struct vvp_io_args *args;
- size_t count;
- ssize_t result;
- int refcheck;
- ENTRY;
+ unsigned long nr_segs, loff_t pos)
+{
+ struct iovec *local_iov;
+ struct iov_iter *from;
+ size_t iov_count;
+ ssize_t result;
+ struct lu_env *env = NULL;
+ __u16 refcheck;
+ ENTRY;
- result = ll_file_get_iov_count(iov, &nr_segs, &count);
- if (result)
- RETURN(result);
+ result = ll_file_get_iov_count(iov, &nr_segs, &iov_count);
+ if (result)
+ RETURN(result);
- env = cl_env_get(&refcheck);
- if (IS_ERR(env))
- RETURN(PTR_ERR(env));
+ if (nr_segs == 1) {
+ env = cl_env_get(&refcheck);
+ if (IS_ERR(env))
+ RETURN(PTR_ERR(env));
- 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;
+ 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)
+ RETURN(-ENOMEM);
- result = ll_file_io_generic(env, args, iocb->ki_filp, CIT_WRITE,
- &iocb->ki_pos, count);
- cl_env_put(env, &refcheck);
- RETURN(result);
+ memcpy(local_iov, iov, sizeof(*iov) * nr_segs);
+ }
+
+ OBD_ALLOC_PTR(from);
+ if (from == NULL) {
+ result = -ENOMEM;
+ goto out;
+ }
+# ifdef HAVE_IOV_ITER_INIT_DIRECTION
+ iov_iter_init(from, WRITE, local_iov, nr_segs, iov_count);
+# else /* !HAVE_IOV_ITER_INIT_DIRECTION */
+ iov_iter_init(from, local_iov, nr_segs, iov_count, 0);
+# endif /* HAVE_IOV_ITER_INIT_DIRECTION */
+
+ result = ll_file_write_iter(iocb, from);
+
+ OBD_FREE_PTR(from);
+out:
+ if (nr_segs == 1)
+ cl_env_put(env, &refcheck);
+ else
+ 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;
+ __u16 refcheck;
ENTRY;
env = cl_env_get(&refcheck);
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);
}
+#endif /* !HAVE_FILE_OPERATIONS_READ_WRITE_ITER */
/*
* Send file content (through pagecache) somewhere with helper
struct lu_env *env;
struct vvp_io_args *args;
ssize_t result;
- int refcheck;
+ __u16 refcheck;
ENTRY;
env = cl_env_get(&refcheck);
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);
struct lov_user_md __user *lum)
{
struct lu_env *env;
- int refcheck;
+ __u16 refcheck;
int rc;
ENTRY;
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);
+ rc = ll_close_inode_openhandle(inode, och, 0, NULL);
out:
/* this one is in place of ll_file_open */
if (it_disposition(it, DISP_ENQ_OPEN_REF)) {
size_t num_bytes)
{
struct lu_env *env;
- int refcheck;
+ __u16 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 */
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);
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.
*
*/
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;
+ __u16 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);
}
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);
}
/*
/* 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,
+ rc = ll_close_inode_openhandle(inode, och, MDS_HSM_RELEASE,
&data_version);
och = NULL;
}
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,
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)
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);
}
}
- /* 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) {
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);
RETURN(rc);
}
-static int ll_hsm_state_set(struct inode *inode, struct hsm_state_set *hss)
+int ll_hsm_state_set(struct inode *inode, struct hsm_state_set *hss)
{
struct md_op_data *op_data;
int rc;
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;
((fmode & FMODE_WRITE) ? LL_LEASE_WRLCK : 0);
}
+static int ll_file_futimes_3(struct file *file, const struct ll_futimes_3 *lfu)
+{
+ struct inode *inode = file->f_path.dentry->d_inode;
+ struct iattr ia = {
+ .ia_valid = ATTR_ATIME | ATTR_ATIME_SET |
+ ATTR_MTIME | ATTR_MTIME_SET |
+ ATTR_CTIME | ATTR_CTIME_SET,
+ .ia_atime = {
+ .tv_sec = lfu->lfu_atime_sec,
+ .tv_nsec = lfu->lfu_atime_nsec,
+ },
+ .ia_mtime = {
+ .tv_sec = lfu->lfu_mtime_sec,
+ .tv_nsec = lfu->lfu_mtime_nsec,
+ },
+ .ia_ctime = {
+ .tv_sec = lfu->lfu_ctime_sec,
+ .tv_nsec = lfu->lfu_ctime_nsec,
+ },
+ };
+ int rc;
+ ENTRY;
+
+ if (!capable(CAP_SYS_ADMIN))
+ RETURN(-EPERM);
+
+ if (!S_ISREG(inode->i_mode))
+ RETURN(-EINVAL);
+
+ mutex_lock(&inode->i_mutex);
+ rc = ll_setattr_raw(file->f_path.dentry, &ia, false);
+ mutex_unlock(&inode->i_mutex);
+
+ RETURN(rc);
+}
+
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;
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));
OBD_FREE_PTR(hui);
RETURN(rc);
}
+ case LL_IOC_FUTIMES_3: {
+ struct ll_futimes_3 lfu;
+ if (copy_from_user(&lfu,
+ (const struct ll_futimes_3 __user *)arg,
+ sizeof(lfu)))
+ RETURN(-EFAULT);
+
+ RETURN(ll_file_futimes_3(file, &lfu));
+ }
default: {
int err;
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:
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;
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;
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;
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);
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
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;
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)
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,
.ei_cbdata = file_lock,
};
struct md_op_data *op_data;
- struct lustre_handle lockh = {0};
- ldlm_policy_data_t flock = {{0}};
+ struct lustre_handle lockh = { 0 };
+ union ldlm_policy_data flock = { { 0 } };
int fl_type = file_lock->fl_type;
__u64 flags = 0;
int rc;
}
int ll_get_fid_by_name(struct inode *parent, const char *name,
- int namelen, struct lu_fid *fid)
+ int namelen, struct lu_fid *fid,
+ struct inode **inode)
{
struct md_op_data *op_data = NULL;
struct mdt_body *body;
if (IS_ERR(op_data))
RETURN(PTR_ERR(op_data));
- op_data->op_valid = OBD_MD_FLID;
+ op_data->op_valid = OBD_MD_FLID | OBD_MD_FLTYPE;
rc = md_getattr_name(ll_i2sbi(parent)->ll_md_exp, op_data, &req);
ll_finish_md_op_data(op_data);
if (rc < 0)
GOTO(out_req, rc = -EFAULT);
if (fid != NULL)
*fid = body->mbo_fid1;
+
+ if (inode != NULL)
+ rc = ll_prep_inode(inode, req, parent->i_sb, NULL);
out_req:
ptlrpc_req_finished(req);
RETURN(rc);
struct inode *child_inode = NULL;
struct md_op_data *op_data;
struct ptlrpc_request *request = NULL;
+ struct obd_client_handle *och = NULL;
struct qstr qstr;
+ struct mdt_body *body;
int rc;
+ __u64 data_version = 0;
ENTRY;
CDEBUG(D_VFSTRACE, "migrate %s under "DFID" to MDT%04x\n",
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) {
+ if (dchild->d_inode != NULL)
child_inode = igrab(dchild->d_inode);
- if (child_inode != NULL) {
- mutex_lock(&child_inode->i_mutex);
- op_data->op_fid3 = *ll_inode2fid(child_inode);
- ll_invalidate_aliases(child_inode);
- }
- }
dput(dchild);
- } else {
+ }
+
+ if (child_inode == NULL) {
rc = ll_get_fid_by_name(parent, name, namelen,
- &op_data->op_fid3);
+ &op_data->op_fid3, &child_inode);
if (rc != 0)
GOTO(out_free, rc);
}
+ if (child_inode == NULL)
+ GOTO(out_free, rc = -EINVAL);
+
+ mutex_lock(&child_inode->i_mutex);
+ op_data->op_fid3 = *ll_inode2fid(child_inode);
if (!fid_is_sane(&op_data->op_fid3)) {
- CERROR("%s: migrate %s , but fid "DFID" is insane\n",
+ CERROR("%s: migrate %s, but FID "DFID" is insane\n",
ll_get_fsname(parent->i_sb, NULL, 0), name,
PFID(&op_data->op_fid3));
- GOTO(out_free, rc = -EINVAL);
+ GOTO(out_unlock, rc = -EINVAL);
}
rc = ll_get_mdt_idx_by_fid(ll_i2sbi(parent), &op_data->op_fid3);
if (rc < 0)
- GOTO(out_free, rc);
+ GOTO(out_unlock, rc);
if (rc == mdtidx) {
- CDEBUG(D_INFO, "%s:"DFID" is already on MDT%d.\n", name,
+ CDEBUG(D_INFO, "%s: "DFID" is already on MDT%04x\n", name,
PFID(&op_data->op_fid3), mdtidx);
- GOTO(out_free, rc = 0);
+ GOTO(out_unlock, rc = 0);
+ }
+again:
+ if (S_ISREG(child_inode->i_mode)) {
+ och = ll_lease_open(child_inode, NULL, FMODE_WRITE, 0);
+ if (IS_ERR(och)) {
+ rc = PTR_ERR(och);
+ och = NULL;
+ GOTO(out_unlock, rc);
+ }
+
+ rc = ll_data_version(child_inode, &data_version,
+ LL_DV_WR_FLUSH);
+ if (rc != 0)
+ GOTO(out_close, rc);
+
+ op_data->op_handle = och->och_fh;
+ op_data->op_data = och->och_mod;
+ op_data->op_data_version = data_version;
+ op_data->op_lease_handle = och->och_lease_handle;
+ op_data->op_bias |= MDS_RENAME_MIGRATE;
}
op_data->op_mds = mdtidx;
if (rc == 0)
ll_update_times(request, parent);
- ptlrpc_req_finished(request);
- if (rc != 0)
- GOTO(out_free, rc);
+ if (request != NULL) {
+ body = req_capsule_server_get(&request->rq_pill, &RMF_MDT_BODY);
+ if (body == NULL) {
+ ptlrpc_req_finished(request);
+ GOTO(out_close, rc = -EPROTO);
+ }
-out_free:
- if (child_inode != NULL) {
- clear_nlink(child_inode);
- mutex_unlock(&child_inode->i_mutex);
- iput(child_inode);
+ /* If the server does release layout lock, then we cleanup
+ * the client och here, otherwise release it in out_close: */
+ if (och != NULL &&
+ body->mbo_valid & OBD_MD_CLOSE_INTENT_EXECED) {
+ obd_mod_put(och->och_mod);
+ md_clear_open_replay_data(ll_i2sbi(parent)->ll_md_exp,
+ och);
+ och->och_fh.cookie = DEAD_HANDLE_MAGIC;
+ OBD_FREE_PTR(och);
+ och = NULL;
+ }
+ ptlrpc_req_finished(request);
}
+ /* Try again if the file layout has changed. */
+ if (rc == -EAGAIN && S_ISREG(child_inode->i_mode)) {
+ request = NULL;
+ goto again;
+ }
+out_close:
+ if (och != NULL) /* close the file */
+ ll_lease_close(och, child_inode, NULL);
+ if (rc == 0)
+ clear_nlink(child_inode);
+out_unlock:
+ mutex_unlock(&child_inode->i_mutex);
+ iput(child_inode);
+out_free:
ll_finish_md_op_data(op_data);
RETURN(rc);
}
* \param l_req_mode [IN] searched lock mode
* \retval boolean, true iff all bits are found
*/
-int ll_have_md_lock(struct inode *inode, __u64 *bits, ldlm_mode_t l_req_mode)
+int ll_have_md_lock(struct inode *inode, __u64 *bits, enum ldlm_mode l_req_mode)
{
- struct lustre_handle lockh;
- ldlm_policy_data_t policy;
- ldlm_mode_t mode = (l_req_mode == LCK_MINMODE) ?
- (LCK_CR|LCK_CW|LCK_PR|LCK_PW) : l_req_mode;
- struct lu_fid *fid;
+ struct lustre_handle lockh;
+ union ldlm_policy_data policy;
+ enum ldlm_mode mode = (l_req_mode == LCK_MINMODE) ?
+ (LCK_CR | LCK_CW | LCK_PR | LCK_PW) : l_req_mode;
+ struct lu_fid *fid;
__u64 flags;
- int i;
- ENTRY;
+ int i;
+ ENTRY;
if (!inode)
RETURN(0);
RETURN(*bits == 0);
}
-ldlm_mode_t ll_take_md_lock(struct inode *inode, __u64 bits,
- struct lustre_handle *lockh, __u64 flags,
- ldlm_mode_t mode)
+enum ldlm_mode ll_take_md_lock(struct inode *inode, __u64 bits,
+ struct lustre_handle *lockh, __u64 flags,
+ enum ldlm_mode mode)
{
- ldlm_policy_data_t policy = { .l_inodebits = {bits}};
- struct lu_fid *fid;
- ldlm_mode_t rc;
- ENTRY;
+ union ldlm_policy_data policy = { .l_inodebits = { bits } };
+ struct lu_fid *fid;
+ enum ldlm_mode rc;
+ ENTRY;
- fid = &ll_i2info(inode)->lli_fid;
- CDEBUG(D_INFO, "trying to match res "DFID"\n", PFID(fid));
+ fid = &ll_i2info(inode)->lli_fid;
+ CDEBUG(D_INFO, "trying to match res "DFID"\n", PFID(fid));
rc = md_lock_match(ll_i2mdexp(inode), LDLM_FL_BLOCK_GRANTED|flags,
fid, LDLM_IBITS, &policy, mode, lockh);
/* Already unlinked. Just update nlink and return success */
if (rc == -ENOENT) {
clear_nlink(inode);
+ /* If it is striped directory, and there is bad stripe
+ * Let's revalidate the dentry again, instead of returning
+ * error */
+ if (S_ISDIR(inode->i_mode) &&
+ ll_i2info(inode)->lli_lsm_md != NULL)
+ return 0;
+
/* This path cannot be hit for regular files unless in
* case of obscure races, so no need to to validate
* size. */
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) {
* restore the MDT holds the layout lock so the glimpse will
* block up to the end of restore (getattr will block)
*/
- if (!(ll_i2info(inode)->lli_flags & LLIF_FILE_RESTORING))
+ if (!ll_file_test_flag(ll_i2info(inode), LLIF_FILE_RESTORING))
rc = ll_glimpse_size(inode);
}
RETURN(rc);
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;
}
/* -o localflock - only provides locally consistent flock locks */
struct file_operations ll_file_operations = {
- .read = ll_file_read,
- .aio_read = ll_file_aio_read,
- .write = ll_file_write,
- .aio_write = ll_file_aio_write,
- .unlocked_ioctl = ll_file_ioctl,
- .open = ll_file_open,
- .release = ll_file_release,
- .mmap = ll_file_mmap,
- .llseek = ll_file_seek,
- .splice_read = ll_file_splice_read,
- .fsync = ll_fsync,
- .flush = ll_flush
+#ifdef HAVE_FILE_OPERATIONS_READ_WRITE_ITER
+# ifdef HAVE_SYNC_READ_WRITE
+ .read = new_sync_read,
+ .write = new_sync_write,
+# endif
+ .read_iter = ll_file_read_iter,
+ .write_iter = ll_file_write_iter,
+#else /* !HAVE_FILE_OPERATIONS_READ_WRITE_ITER */
+ .read = ll_file_read,
+ .aio_read = ll_file_aio_read,
+ .write = ll_file_write,
+ .aio_write = ll_file_aio_write,
+#endif /* HAVE_FILE_OPERATIONS_READ_WRITE_ITER */
+ .unlocked_ioctl = ll_file_ioctl,
+ .open = ll_file_open,
+ .release = ll_file_release,
+ .mmap = ll_file_mmap,
+ .llseek = ll_file_seek,
+ .splice_read = ll_file_splice_read,
+ .fsync = ll_fsync,
+ .flush = ll_flush
};
struct file_operations ll_file_operations_flock = {
- .read = ll_file_read,
- .aio_read = ll_file_aio_read,
- .write = ll_file_write,
- .aio_write = ll_file_aio_write,
- .unlocked_ioctl = ll_file_ioctl,
- .open = ll_file_open,
- .release = ll_file_release,
- .mmap = ll_file_mmap,
- .llseek = ll_file_seek,
- .splice_read = ll_file_splice_read,
- .fsync = ll_fsync,
- .flush = ll_flush,
- .flock = ll_file_flock,
- .lock = ll_file_flock
+#ifdef HAVE_FILE_OPERATIONS_READ_WRITE_ITER
+# ifdef HAVE_SYNC_READ_WRITE
+ .read = new_sync_read,
+ .write = new_sync_write,
+# endif /* HAVE_SYNC_READ_WRITE */
+ .read_iter = ll_file_read_iter,
+ .write_iter = ll_file_write_iter,
+#else /* !HAVE_FILE_OPERATIONS_READ_WRITE_ITER */
+ .read = ll_file_read,
+ .aio_read = ll_file_aio_read,
+ .write = ll_file_write,
+ .aio_write = ll_file_aio_write,
+#endif /* HAVE_FILE_OPERATIONS_READ_WRITE_ITER */
+ .unlocked_ioctl = ll_file_ioctl,
+ .open = ll_file_open,
+ .release = ll_file_release,
+ .mmap = ll_file_mmap,
+ .llseek = ll_file_seek,
+ .splice_read = ll_file_splice_read,
+ .fsync = ll_fsync,
+ .flush = ll_flush,
+ .flock = ll_file_flock,
+ .lock = ll_file_flock
};
/* These are for -o noflock - to return ENOSYS on flock calls */
struct file_operations ll_file_operations_noflock = {
- .read = ll_file_read,
- .aio_read = ll_file_aio_read,
- .write = ll_file_write,
- .aio_write = ll_file_aio_write,
- .unlocked_ioctl = ll_file_ioctl,
- .open = ll_file_open,
- .release = ll_file_release,
- .mmap = ll_file_mmap,
- .llseek = ll_file_seek,
- .splice_read = ll_file_splice_read,
- .fsync = ll_fsync,
- .flush = ll_flush,
- .flock = ll_file_noflock,
- .lock = ll_file_noflock
+#ifdef HAVE_FILE_OPERATIONS_READ_WRITE_ITER
+# ifdef HAVE_SYNC_READ_WRITE
+ .read = new_sync_read,
+ .write = new_sync_write,
+# endif /* HAVE_SYNC_READ_WRITE */
+ .read_iter = ll_file_read_iter,
+ .write_iter = ll_file_write_iter,
+#else /* !HAVE_FILE_OPERATIONS_READ_WRITE_ITER */
+ .read = ll_file_read,
+ .aio_read = ll_file_aio_read,
+ .write = ll_file_write,
+ .aio_write = ll_file_aio_write,
+#endif /* HAVE_FILE_OPERATIONS_READ_WRITE_ITER */
+ .unlocked_ioctl = ll_file_ioctl,
+ .open = ll_file_open,
+ .release = ll_file_release,
+ .mmap = ll_file_mmap,
+ .llseek = ll_file_seek,
+ .splice_read = ll_file_splice_read,
+ .fsync = ll_fsync,
+ .flush = ll_flush,
+ .flock = ll_file_noflock,
+ .lock = ll_file_noflock
};
struct inode_operations ll_file_inode_operations = {
{
struct ll_sb_info *sbi = ll_i2sbi(inode);
- struct obd_capa *oc;
struct ptlrpc_request *req;
struct mdt_body *body;
void *lvbdata;
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
* 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);
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:
* Apply the layout to the inode. Layout lock is held and will be released
* in this function.
*/
-static int ll_layout_lock_set(struct lustre_handle *lockh, ldlm_mode_t mode,
+static int ll_layout_lock_set(struct lustre_handle *lockh, enum ldlm_mode mode,
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;
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) {
- CERROR("%s: file "DFID" unpackmd error: %d\n",
- ll_get_fsname(inode->i_sb, NULL, 0),
- PFID(&lli->lli_fid), rc);
- GOTO(out, rc);
- }
-
- LASSERTF(md.lsm != NULL, "lvb_data = %p, lvb_len = %u\n",
- lock->l_lvb_data, lock->l_lvb_len);
-
- rc = 0;
- }
-
- /* 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;
struct ll_inode_info *lli = ll_i2info(inode);
struct ll_sb_info *sbi = ll_i2sbi(inode);
struct md_op_data *op_data;
- struct lookup_intent it;
- struct lustre_handle lockh;
- ldlm_mode_t mode;
+ struct lookup_intent it;
+ struct lustre_handle lockh;
+ enum ldlm_mode mode;
struct ldlm_enqueue_info einfo = {
.ei_type = LDLM_IBITS,
.ei_mode = LCK_CR,