* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2013, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
{
struct ll_file_data *fd;
- OBD_SLAB_ALLOC_PTR_GFP(fd, ll_file_data_slab, CFS_ALLOC_IO);
+ OBD_SLAB_ALLOC_PTR_GFP(fd, ll_file_data_slab, __GFP_IO);
+ if (fd == NULL)
+ return NULL;
+
fd->fd_write_failed = false;
+
return fd;
}
{
ENTRY;
- op_data->op_attr.ia_valid = ATTR_MODE | ATTR_ATIME_SET |
- ATTR_MTIME_SET | ATTR_CTIME_SET;
+ op_data->op_attr.ia_valid = ATTR_MODE | ATTR_ATIME | ATTR_ATIME_SET |
+ ATTR_MTIME | ATTR_MTIME_SET |
+ ATTR_CTIME | ATTR_CTIME_SET;
if (!(och->och_flags & FMODE_WRITE))
goto out;
}
}
-static int ll_och_fill(struct obd_export *md_exp, struct ll_inode_info *lli,
- struct lookup_intent *it, struct obd_client_handle *och)
+static int ll_och_fill(struct obd_export *md_exp, struct lookup_intent *it,
+ struct obd_client_handle *och)
{
- struct ptlrpc_request *req = it->d.lustre.it_data;
- struct mdt_body *body;
-
- LASSERT(och);
+ struct ptlrpc_request *req = it->d.lustre.it_data;
+ struct mdt_body *body;
- body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY);
- LASSERT(body != NULL); /* reply already checked out */
-
- memcpy(&och->och_fh, &body->handle, sizeof(body->handle));
- och->och_magic = OBD_CLIENT_HANDLE_MAGIC;
- och->och_fid = lli->lli_fid;
- och->och_flags = it->it_flags;
- ll_ioepoch_open(lli, body->ioepoch);
+ body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY);
+ och->och_fh = body->handle;
+ och->och_fid = body->fid1;
+ och->och_magic = OBD_CLIENT_HANDLE_MAGIC;
+ och->och_flags = it->it_flags;
- return md_set_open_replay_data(md_exp, och, req);
+ return md_set_open_replay_data(md_exp, och, req);
}
int ll_local_open(struct file *file, struct lookup_intent *it,
struct mdt_body *body;
int rc;
- rc = ll_och_fill(ll_i2sbi(inode)->ll_md_exp, lli, it, och);
- if (rc)
- RETURN(rc);
+ rc = ll_och_fill(ll_i2sbi(inode)->ll_md_exp, it, och);
+ if (rc != 0)
+ RETURN(rc);
- body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY);
- if ((it->it_flags & FMODE_WRITE) &&
- (body->valid & OBD_MD_FLSIZE))
- CDEBUG(D_INODE, "Epoch "LPU64" opened on "DFID"\n",
- lli->lli_ioepoch, PFID(&lli->lli_fid));
- }
+ body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY);
+ ll_ioepoch_open(lli, body->ioepoch);
+ }
+
+ LUSTRE_FPRIVATE(file) = fd;
+ ll_readahead_init(inode, &fd->fd_ras);
+ fd->fd_omode = it->it_flags;
- LUSTRE_FPRIVATE(file) = fd;
- ll_readahead_init(inode, &fd->fd_ras);
- fd->fd_omode = it->it_flags;
- RETURN(0);
+ RETURN(0);
}
/* Open a file, and (for the very first open) create objects on the OSTs at
it = file->private_data; /* XXX: compat macro */
file->private_data = NULL; /* prevent ll_local_open assertion */
- fd = ll_file_data_get();
- if (fd == NULL)
- GOTO(out_och_free, rc = -ENOMEM);
+ fd = ll_file_data_get();
+ if (fd == NULL)
+ GOTO(out_openerr, rc = -ENOMEM);
- fd->fd_file = file;
- if (S_ISDIR(inode->i_mode)) {
+ fd->fd_file = file;
+ if (S_ISDIR(inode->i_mode)) {
spin_lock(&lli->lli_sa_lock);
if (lli->lli_opendir_key == NULL && lli->lli_sai == NULL &&
lli->lli_opendir_pid == 0) {
opendir_set = 1;
}
spin_unlock(&lli->lli_sa_lock);
- }
+ }
if (inode->i_sb->s_root == file->f_dentry) {
LUSTRE_FPRIVATE(file) = fd;
oinfo.oi_md = lsm;
oinfo.oi_oa = obdo;
- oinfo.oi_oa->o_id = lsm->lsm_object_id;
- oinfo.oi_oa->o_seq = lsm->lsm_object_seq;
+ oinfo.oi_oa->o_oi = lsm->lsm_oi;
oinfo.oi_oa->o_mode = S_IFREG;
oinfo.oi_oa->o_ioepoch = ioepoch;
oinfo.oi_oa->o_valid = OBD_MD_FLID | OBD_MD_FLTYPE |
capa, obdo, ioepoch, sync);
capa_put(capa);
if (rc == 0) {
+ struct ost_id *oi = lsm ? &lsm->lsm_oi : &obdo->o_oi;
+
obdo_refresh_inode(inode, obdo, obdo->o_valid);
- CDEBUG(D_INODE,
- "objid "LPX64" size %llu, blocks %llu, blksize %lu\n",
- lsm ? lsm->lsm_object_id : 0, i_size_read(inode),
+ CDEBUG(D_INODE, "objid "DOSTID" size %llu, blocks %llu,"
+ " blksize %lu\n", POSTID(oi), i_size_read(inode),
(unsigned long long)inode->i_blocks,
(unsigned long)ll_inode_blksize(inode));
}
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 && io->ci_need_restart) {
+ if ((result == 0 || result == -ENODATA) && io->ci_need_restart) {
CDEBUG(D_VFSTRACE, "Restart %s on %s from %lld, count:%zd\n",
iot == CIT_READ ? "read" : "write",
file->f_dentry->d_name.name, *ppos, count);
- LASSERTF(io->u.ci_rw.crw_count == count, "%zd != %zd\n",
- io->u.ci_rw.crw_count, count);
+ LASSERTF(io->ci_nob == 0, "%zd", io->ci_nob);
goto restart;
}
}
#endif
-
-#ifdef HAVE_KERNEL_SENDFILE
-/*
- * Send file content (through pagecache) somewhere with helper
- */
-static ssize_t ll_file_sendfile(struct file *in_file, loff_t *ppos,size_t count,
- read_actor_t actor, void *target)
-{
- struct lu_env *env;
- struct vvp_io_args *args;
- ssize_t result;
- int refcheck;
- ENTRY;
-
- env = cl_env_get(&refcheck);
- if (IS_ERR(env))
- RETURN(PTR_ERR(env));
-
- args = vvp_env_args(env, IO_SENDFILE);
- args->u.sendfile.via_target = target;
- args->u.sendfile.via_actor = actor;
-
- result = ll_file_io_generic(env, args, in_file, CIT_READ, ppos, count);
- cl_env_put(env, &refcheck);
- RETURN(result);
-}
-#endif
-
-#ifdef HAVE_KERNEL_SPLICE_READ
/*
* Send file content (through pagecache) somewhere with helper
*/
cl_env_put(env, &refcheck);
RETURN(result);
}
-#endif
-static int ll_lov_recreate(struct inode *inode, obd_id id, obd_seq seq,
+static int ll_lov_recreate(struct inode *inode, struct ost_id *oi,
obd_count ost_idx)
{
struct obd_export *exp = ll_i2dtexp(inode);
RETURN(-ENOMEM);
lsm = ccc_inode_lsm_get(inode);
- if (lsm == NULL)
+ if (!lsm_has_objects(lsm))
GOTO(out, rc = -ENOENT);
lsm_size = sizeof(*lsm) + (sizeof(struct lov_oinfo) *
if (lsm2 == NULL)
GOTO(out, rc = -ENOMEM);
- oa->o_id = id;
- oa->o_seq = seq;
+ oa->o_oi = *oi;
oa->o_nlink = ost_idx;
oa->o_flags |= OBD_FL_RECREATE_OBJS;
oa->o_valid = OBD_MD_FLID | OBD_MD_FLFLAGS | OBD_MD_FLGROUP;
static int ll_lov_recreate_obj(struct inode *inode, unsigned long arg)
{
struct ll_recreate_obj ucreat;
+ struct ost_id oi;
ENTRY;
if (!cfs_capable(CFS_CAP_SYS_ADMIN))
sizeof(ucreat)))
RETURN(-EFAULT);
- RETURN(ll_lov_recreate(inode, ucreat.lrc_id, 0,
- ucreat.lrc_ost_idx));
+ ostid_set_seq_mdt0(&oi);
+ ostid_set_id(&oi, ucreat.lrc_id);
+ RETURN(ll_lov_recreate(inode, &oi, ucreat.lrc_ost_idx));
}
static int ll_lov_recreate_fid(struct inode *inode, unsigned long arg)
{
struct lu_fid fid;
- obd_id id;
+ struct ost_id oi;
obd_count ost_idx;
ENTRY;
if (copy_from_user(&fid, (struct lu_fid *)arg, sizeof(fid)))
RETURN(-EFAULT);
- id = fid_oid(&fid) | ((fid_seq(&fid) & 0xffff) << 32);
+ fid_to_ostid(&fid, &oi);
ost_idx = (fid_seq(&fid) >> 16) & 0xffff;
- RETURN(ll_lov_recreate(inode, id, 0, ost_idx));
+ RETURN(ll_lov_recreate(inode, &oi, ost_idx));
}
int ll_lov_setstripe_ea_info(struct inode *inode, struct file *file,
* passing it to userspace.
*/
if (LOV_MAGIC != cpu_to_le32(LOV_MAGIC)) {
+ int stripe_count;
+
+ stripe_count = le16_to_cpu(lmm->lmm_stripe_count);
+ if (le32_to_cpu(lmm->lmm_pattern) & LOV_PATTERN_F_RELEASED)
+ stripe_count = 0;
+
/* if function called for directory - we should
* avoid swab not existent lsm objects */
if (lmm->lmm_magic == cpu_to_le32(LOV_MAGIC_V1)) {
if (S_ISREG(body->mode))
lustre_swab_lov_user_md_objects(
((struct lov_user_md_v1 *)lmm)->lmm_objects,
- ((struct lov_user_md_v1 *)lmm)->lmm_stripe_count);
+ stripe_count);
} else if (lmm->lmm_magic == cpu_to_le32(LOV_MAGIC_V3)) {
lustre_swab_lov_user_md_v3((struct lov_user_md_v3 *)lmm);
if (S_ISREG(body->mode))
lustre_swab_lov_user_md_objects(
((struct lov_user_md_v3 *)lmm)->lmm_objects,
- ((struct lov_user_md_v3 *)lmm)->lmm_stripe_count);
+ stripe_count);
}
}
if (!och)
GOTO(out, rc = -ENOMEM);
- ll_och_fill(ll_i2sbi(inode)->ll_md_exp,
- ll_i2info(inode), it, och);
+ ll_och_fill(ll_i2sbi(inode)->ll_md_exp, it, och);
rc = ll_close_inode_openhandle(ll_i2sbi(inode)->ll_md_exp,
inode, och);
!(fiemap->fm_flags & FIEMAP_FLAG_DEVICE_ORDER))
GOTO(out, rc = -EOPNOTSUPP);
- fm_key.oa.o_id = lsm->lsm_object_id;
- fm_key.oa.o_seq = lsm->lsm_object_seq;
+ fm_key.oa.o_oi = lsm->lsm_oi;
fm_key.oa.o_valid = OBD_MD_FLID | OBD_MD_FLGROUP;
obdo_from_inode(&fm_key.oa, inode, OBD_MD_FLSIZE);
rc = obd_iocontrol(OBD_IOC_FID2PATH, exp, outsize, gfout, NULL);
if (rc)
GOTO(gf_free, rc);
+
if (copy_to_user(arg, gfout, outsize))
rc = -EFAULT;
/* If no stripe, we consider version is 0. */
lsm = ccc_inode_lsm_get(inode);
- if (lsm == NULL) {
+ if (!lsm_has_objects(lsm)) {
*data_version = 0;
CDEBUG(D_INODE, "No object for inode\n");
- RETURN(0);
+ GOTO(out, rc = 0);
}
OBD_ALLOC_PTR(obdo);
- if (obdo == NULL) {
- ccc_inode_lsm_put(inode, lsm);
- RETURN(-ENOMEM);
- }
+ if (obdo == NULL)
+ GOTO(out, rc = -ENOMEM);
rc = ll_lsm_getattr(lsm, sbi->ll_dt_exp, NULL, obdo, 0, extent_lock);
- if (!rc) {
+ if (rc == 0) {
if (!(obdo->o_valid & OBD_MD_FLDATAVERSION))
rc = -EOPNOTSUPP;
else
}
OBD_FREE_PTR(obdo);
+ EXIT;
+out:
ccc_inode_lsm_put(inode, lsm);
-
RETURN(rc);
}
-static int ll_swap_layout(struct file *file, struct file *file2,
- struct lustre_swap_layouts *lsl)
+struct ll_swap_stack {
+ struct iattr ia1, ia2;
+ __u64 dv1, dv2;
+ struct inode *inode1, *inode2;
+ bool check_dv1, check_dv2;
+};
+
+static int ll_swap_layouts(struct file *file1, struct file *file2,
+ struct lustre_swap_layouts *lsl)
{
- struct mdc_swap_layouts msl = { .msl_flags = lsl->sl_flags };
- struct md_op_data *op_data;
- struct inode *inode = file->f_dentry->d_inode;
- struct inode *inode2 = file2->f_dentry->d_inode;
- __u32 gid;
- int rc;
+ struct mdc_swap_layouts msl;
+ struct md_op_data *op_data;
+ __u32 gid;
+ __u64 dv;
+ struct ll_swap_stack *llss = NULL;
+ int rc;
- if (!S_ISREG(inode2->i_mode))
- RETURN(-EINVAL);
+ OBD_ALLOC_PTR(llss);
+ if (llss == NULL)
+ RETURN(-ENOMEM);
- if (inode_permission(inode, MAY_WRITE) ||
- inode_permission(inode2, MAY_WRITE))
- RETURN(-EPERM);
+ 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);
+
+ 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);
+
+ /* we use 2 bool because it is easier to swap than 2 bits */
+ if (lsl->sl_flags & SWAP_LAYOUTS_CHECK_DV1)
+ llss->check_dv1 = true;
+
+ if (lsl->sl_flags & SWAP_LAYOUTS_CHECK_DV2)
+ llss->check_dv2 = true;
- if (inode2->i_sb != inode->i_sb)
- RETURN(-EXDEV);
+ /* we cannot use lsl->sl_dvX directly because we may swap them */
+ llss->dv1 = lsl->sl_dv1;
+ llss->dv2 = lsl->sl_dv2;
- rc = lu_fid_cmp(ll_inode2fid(inode), ll_inode2fid(inode2));
+ rc = lu_fid_cmp(ll_inode2fid(llss->inode1), ll_inode2fid(llss->inode2));
if (rc == 0) /* same file, done! */
- RETURN(0);
+ GOTO(free, rc = 0);
if (rc < 0) { /* sequentialize it */
- swap(inode, inode2);
- swap(file, file2);
+ swap(llss->inode1, llss->inode2);
+ swap(file1, file2);
+ swap(llss->dv1, llss->dv2);
+ swap(llss->check_dv1, llss->check_dv2);
}
gid = lsl->sl_gid;
if (gid != 0) { /* application asks to flush dirty cache */
- rc = ll_get_grouplock(inode, file, gid);
+ rc = ll_get_grouplock(llss->inode1, file1, gid);
if (rc < 0)
- RETURN(rc);
+ GOTO(free, rc);
- rc = ll_get_grouplock(inode2, file2, gid);
+ rc = ll_get_grouplock(llss->inode2, file2, gid);
if (rc < 0) {
- ll_put_grouplock(inode, file, gid);
- RETURN(rc);
+ ll_put_grouplock(llss->inode1, file1, gid);
+ GOTO(free, rc);
}
}
+ /* 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) {
+ rc = ll_data_version(llss->inode1, &dv, 0);
+ if (rc)
+ GOTO(putgl, rc);
+ if (dv != llss->dv1)
+ GOTO(putgl, rc = -EAGAIN);
+ }
+
+ if (llss->check_dv2) {
+ rc = ll_data_version(llss->inode2, &dv, 0);
+ if (rc)
+ GOTO(putgl, rc);
+ if (dv != llss->dv2)
+ GOTO(putgl, rc = -EAGAIN);
+ }
+
/* struct md_op_data is used to send the swap args to the mdt
* only flags is missing, so we use struct mdc_swap_layouts
* through the md_op_data->op_data */
+ /* flags from user space have to be converted before they are send to
+ * server, no flag is sent today, they are only used on the client */
+ msl.msl_flags = 0;
rc = -ENOMEM;
- op_data = ll_prep_md_op_data(NULL, inode, inode2, NULL, 0, 0,
- LUSTRE_OPC_ANY, &msl);
- if (op_data != NULL) {
- rc = obd_iocontrol(LL_IOC_LOV_SWAP_LAYOUTS, ll_i2mdexp(inode),
- sizeof(*op_data), op_data, NULL);
- ll_finish_md_op_data(op_data);
- }
+ op_data = ll_prep_md_op_data(NULL, llss->inode1, llss->inode2, NULL, 0,
+ 0, LUSTRE_OPC_ANY, &msl);
+ if (IS_ERR(op_data))
+ GOTO(free, rc = PTR_ERR(op_data));
+ rc = obd_iocontrol(LL_IOC_LOV_SWAP_LAYOUTS, ll_i2mdexp(llss->inode1),
+ sizeof(*op_data), op_data, NULL);
+ ll_finish_md_op_data(op_data);
+
+putgl:
if (gid != 0) {
- ll_put_grouplock(inode2, file2, gid);
- ll_put_grouplock(inode, file, gid);
+ 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);
}
struct file *file2;
struct lustre_swap_layouts lsl;
- if (cfs_copy_from_user(&lsl, (char *)arg,
+ if (copy_from_user(&lsl, (char *)arg,
sizeof(struct lustre_swap_layouts)))
RETURN(-EFAULT);
rc = -EPERM;
if ((file2->f_flags & O_ACCMODE) != 0) /* O_WRONLY or O_RDWR */
- rc = ll_swap_layout(file, file2, &lsl);
+ rc = ll_swap_layouts(file, file2, &lsl);
fput(file2);
RETURN(rc);
}
op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL, 0, 0,
LUSTRE_OPC_ANY, hus);
- if (op_data == NULL) {
+ if (IS_ERR(op_data)) {
OBD_FREE_PTR(hus);
- RETURN(-ENOMEM);
+ RETURN(PTR_ERR(op_data));
}
rc = obd_iocontrol(cmd, ll_i2mdexp(inode), sizeof(*op_data),
op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL, 0, 0,
LUSTRE_OPC_ANY, hss);
- if (op_data == NULL) {
+ if (IS_ERR(op_data)) {
OBD_FREE_PTR(hss);
- RETURN(-ENOMEM);
+ RETURN(PTR_ERR(op_data));
}
rc = obd_iocontrol(cmd, ll_i2mdexp(inode), sizeof(*op_data),
op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL, 0, 0,
LUSTRE_OPC_ANY, hca);
- if (op_data == NULL) {
+ if (IS_ERR(op_data)) {
OBD_FREE_PTR(hca);
- RETURN(-ENOMEM);
+ RETURN(PTR_ERR(op_data));
}
rc = obd_iocontrol(cmd, ll_i2mdexp(inode), sizeof(*op_data),
op_data, NULL);
- if (cfs_copy_to_user((char *)arg, hca, sizeof(*hca)))
+ if (copy_to_user((char *)arg, hca, sizeof(*hca)))
rc = -EFAULT;
ll_finish_md_op_data(op_data);
* Return how many pages have been written.
*/
int cl_sync_file_range(struct inode *inode, loff_t start, loff_t end,
- enum cl_fsync_mode mode)
+ enum cl_fsync_mode mode, int ignore_layout)
{
struct cl_env_nest nest;
struct lu_env *env;
io = ccc_env_thread_io(env);
io->ci_obj = cl_i2info(inode)->lli_clob;
- io->ci_ignore_layout = 1;
+ io->ci_ignore_layout = ignore_layout;
/* initialize parameters for sync */
fio = &io->u.ci_fsync;
RETURN(result);
}
+/*
+ * When dentry is provided (the 'else' case), *file->f_dentry may be
+ * null and dentry must be used directly rather than pulled from
+ * *file->f_dentry as is done otherwise.
+ */
+
#ifdef HAVE_FILE_FSYNC_4ARGS
-int ll_fsync(struct file *file, loff_t start, loff_t end, int data)
+int ll_fsync(struct file *file, loff_t start, loff_t end, int datasync)
+{
+ struct dentry *dentry = file->f_dentry;
#elif defined(HAVE_FILE_FSYNC_2ARGS)
-int ll_fsync(struct file *file, int data)
+int ll_fsync(struct file *file, int datasync)
+{
+ struct dentry *dentry = file->f_dentry;
#else
-int ll_fsync(struct file *file, struct dentry *dentry, int data)
-#endif
+int ll_fsync(struct file *file, struct dentry *dentry, int datasync)
{
- struct inode *inode = file->f_dentry->d_inode;
+#endif
+ struct inode *inode = dentry->d_inode;
struct ll_inode_info *lli = ll_i2info(inode);
struct ptlrpc_request *req;
struct obd_capa *oc;
if (!err)
ptlrpc_req_finished(req);
- if (data) {
+ if (datasync && S_ISREG(inode->i_mode)) {
struct ll_file_data *fd = LUSTRE_FPRIVATE(file);
err = cl_sync_file_range(inode, 0, OBD_OBJECT_EOF,
- CL_FSYNC_ALL);
+ CL_FSYNC_ALL, 0);
if (rc == 0 && err < 0)
rc = err;
if (rc < 0)
int ll_file_flock(struct file *file, int cmd, struct file_lock *file_lock)
{
- struct inode *inode = file->f_dentry->d_inode;
- struct ll_sb_info *sbi = ll_i2sbi(inode);
- struct ldlm_enqueue_info einfo = { .ei_type = LDLM_FLOCK,
- .ei_cb_cp =ldlm_flock_completion_ast,
- .ei_cbdata = file_lock };
- struct md_op_data *op_data;
- struct lustre_handle lockh = {0};
- ldlm_policy_data_t flock = {{0}};
- int flags = 0;
- int rc;
+ struct inode *inode = file->f_dentry->d_inode;
+ struct ll_sb_info *sbi = ll_i2sbi(inode);
+ struct ldlm_enqueue_info einfo = {
+ .ei_type = LDLM_FLOCK,
+ .ei_cb_cp = ldlm_flock_completion_ast,
+ .ei_cbdata = file_lock,
+ };
+ struct md_op_data *op_data;
+ struct lustre_handle lockh = {0};
+ ldlm_policy_data_t flock = {{0}};
+ int flags = 0;
+ int rc;
int rc2 = 0;
- ENTRY;
+ ENTRY;
CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu file_lock=%p\n",
inode->i_ino, file_lock);
CDEBUG(D_INFO, "trying to match res "DFID" mode %s\n", PFID(fid),
ldlm_lockname[mode]);
- flags = LDLM_FL_BLOCK_GRANTED | LDLM_FL_CBPENDING | LDLM_FL_TEST_LOCK;
- for (i = 0; i < MDS_INODELOCK_MAXSHIFT && *bits != 0; i++) {
- policy.l_inodebits.bits = *bits & (1 << i);
- if (policy.l_inodebits.bits == 0)
- continue;
+ flags = LDLM_FL_BLOCK_GRANTED | LDLM_FL_CBPENDING | LDLM_FL_TEST_LOCK;
+ for (i = 0; i <= MDS_INODELOCK_MAXSHIFT && *bits != 0; i++) {
+ policy.l_inodebits.bits = *bits & (1 << i);
+ if (policy.l_inodebits.bits == 0)
+ continue;
if (md_lock_match(ll_i2mdexp(inode), flags, fid, LDLM_IBITS,
&policy, mode, &lockh)) {
here to preserve get_cwd functionality on 2.6.
Bug 10503 */
if (!dentry->d_inode->i_nlink)
- d_lustre_invalidate(dentry);
+ d_lustre_invalidate(dentry, 0);
ll_lookup_finish_locks(&oit, dentry);
} else if (!ll_have_md_lock(dentry->d_inode, &ibits, LCK_MINMODE)) {
}
int ll_inode_revalidate_it(struct dentry *dentry, struct lookup_intent *it,
- __u64 ibits)
+ __u64 ibits)
{
- struct inode *inode = dentry->d_inode;
- int rc;
- ENTRY;
+ struct inode *inode = dentry->d_inode;
+ int rc;
+ ENTRY;
- rc = __ll_inode_revalidate_it(dentry, it, ibits);
+ rc = __ll_inode_revalidate_it(dentry, it, ibits);
if (rc != 0)
RETURN(rc);
LTIME_S(inode->i_mtime) = ll_i2info(inode)->lli_lvb.lvb_mtime;
LTIME_S(inode->i_ctime) = ll_i2info(inode)->lli_lvb.lvb_ctime;
} else {
- rc = ll_glimpse_size(inode);
+ /* In case of restore, the MDT has the right size and has
+ * already send it back without granting the layout lock,
+ * inode is up-to-date so glimpse is useless.
+ * Also to glimpse we need the layout, in case of a running
+ * 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))
+ rc = ll_glimpse_size(inode);
}
- RETURN(rc);
+ RETURN(rc);
}
int ll_getattr_it(struct vfsmount *mnt, struct dentry *de,
.release = ll_file_release,
.mmap = ll_file_mmap,
.llseek = ll_file_seek,
-#ifdef HAVE_KERNEL_SENDFILE
- .sendfile = ll_file_sendfile,
-#endif
-#ifdef HAVE_KERNEL_SPLICE_READ
.splice_read = ll_file_splice_read,
-#endif
.fsync = ll_fsync,
.flush = ll_flush
};
.release = ll_file_release,
.mmap = ll_file_mmap,
.llseek = ll_file_seek,
-#ifdef HAVE_KERNEL_SENDFILE
- .sendfile = ll_file_sendfile,
-#endif
-#ifdef HAVE_KERNEL_SPLICE_READ
.splice_read = ll_file_splice_read,
-#endif
.fsync = ll_fsync,
.flush = ll_flush,
.flock = ll_file_flock,
.release = ll_file_release,
.mmap = ll_file_mmap,
.llseek = ll_file_seek,
-#ifdef HAVE_KERNEL_SENDFILE
- .sendfile = ll_file_sendfile,
-#endif
-#ifdef HAVE_KERNEL_SPLICE_READ
.splice_read = ll_file_splice_read,
-#endif
.fsync = ll_fsync,
.flush = ll_flush,
.flock = ll_file_noflock,
RETURN(result);
}
+/* Fetch layout from MDT with getxattr request, if it's not ready yet */
+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;
+ void *lmm;
+ int lmmsize;
+ int rc;
+ ENTRY;
+
+ CDEBUG(D_INODE, DFID" LVB_READY=%d l_lvb_data=%p l_lvb_len=%d\n",
+ PFID(ll_inode2fid(inode)), !!(lock->l_flags & LDLM_FL_LVB_READY),
+ lock->l_lvb_data, lock->l_lvb_len);
+
+ if ((lock->l_lvb_data != NULL) && (lock->l_flags & LDLM_FL_LVB_READY))
+ RETURN(0);
+
+ /* if layout lock was granted right away, the layout is returned
+ * within DLM_LVB of dlm reply; otherwise if the lock was ever
+ * 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_max_mdsize(sbi, &lmmsize);
+ if (rc == 0)
+ rc = md_getxattr(sbi->ll_md_exp, ll_inode2fid(inode), oc,
+ OBD_MD_FLXATTR, XATTR_NAME_LOV, NULL, 0,
+ lmmsize, 0, &req);
+ capa_put(oc);
+ if (rc < 0)
+ RETURN(rc);
+
+ body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY);
+ if (body == NULL || body->eadatasize > lmmsize)
+ GOTO(out, rc = -EPROTO);
+
+ lmmsize = body->eadatasize;
+ if (lmmsize == 0) /* empty layout */
+ GOTO(out, rc = 0);
+
+ lmm = req_capsule_server_sized_get(&req->rq_pill, &RMF_EADATA, lmmsize);
+ if (lmm == NULL)
+ GOTO(out, rc = -EFAULT);
+
+ OBD_ALLOC_LARGE(lvbdata, lmmsize);
+ if (lvbdata == NULL)
+ GOTO(out, rc = -ENOMEM);
+
+ 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;
+ unlock_res_and_lock(lock);
+
+ EXIT;
+
+out:
+ ptlrpc_req_finished(req);
+ return rc;
+}
+
/**
* Apply the layout to the inode. Layout lock is held and will be released
* in this function.
struct cl_object_conf conf;
int rc = 0;
bool lvb_ready;
+ bool wait_layout = false;
ENTRY;
LASSERT(lustre_handle_is_used(lockh));
LASSERT(ldlm_has_layout(lock));
LDLM_DEBUG(lock, "File %p/"DFID" being reconfigured: %d.\n",
- inode, PFID(&lli->lli_fid), reconf);
+ inode, PFID(&lli->lli_fid), reconf);
+
+ /* in case this is a caching lock and reinstate with new inode */
+ md_set_lock_data(sbi->ll_md_exp, &lockh->cookie, inode, NULL);
lock_res_and_lock(lock);
lvb_ready = !!(lock->l_flags & LDLM_FL_LVB_READY);
unlock_res_and_lock(lock);
/* 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) {
- LDLM_LOCK_PUT(lock);
+ if (lvb_ready || !reconf) {
rc = -ENODATA;
if (lvb_ready) {
/* layout_gen must be valid if layout lock is not
*gen = lli->lli_layout_gen;
rc = 0;
}
- ldlm_lock_decref(lockh, mode);
- RETURN(rc);
+ GOTO(out, rc);
}
+ rc = ll_layout_fetch(inode, lock);
+ if (rc < 0)
+ GOTO(out, rc);
+
/* for layout lock, lmm is returned 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()
PFID(&lli->lli_fid), rc);
}
}
- if (rc < 0) {
- LDLM_LOCK_PUT(lock);
- ldlm_lock_decref(lockh, mode);
- RETURN(rc);
- }
+ if (rc < 0)
+ GOTO(out, rc);
/* set layout to file. Unlikely this will fail as old layout was
* surely eliminated */
conf.coc_lock = lock;
conf.u.coc_md = &md;
rc = ll_layout_conf(inode, &conf);
- LDLM_LOCK_PUT(lock);
-
- ldlm_lock_decref(lockh, mode);
if (md.lsm != NULL)
obd_free_memmd(sbi->ll_dt_exp, &md.lsm);
+ /* refresh layout failed, need to wait */
+ wait_layout = rc == -EBUSY;
+ EXIT;
+
+out:
+ LDLM_LOCK_PUT(lock);
+ ldlm_lock_decref(lockh, mode);
+
/* wait for IO to complete if it's still being used. */
- if (rc == -EBUSY) {
+ if (wait_layout) {
CDEBUG(D_INODE, "%s: %p/"DFID" wait for layout reconf.\n",
ll_get_fsname(inode->i_sb, NULL, 0),
inode, PFID(&lli->lli_fid));
CDEBUG(D_INODE, "file: "DFID" waiting layout return: %d.\n",
PFID(&lli->lli_fid), rc);
}
-
RETURN(rc);
}
struct lookup_intent it;
struct lustre_handle lockh;
ldlm_mode_t mode;
- struct ldlm_enqueue_info einfo = { .ei_type = LDLM_IBITS,
- .ei_mode = LCK_CR,
- .ei_cb_bl = ll_md_blocking_ast,
- .ei_cb_cp = ldlm_completion_ast,
- .ei_cbdata = NULL };
+ struct ldlm_enqueue_info einfo = {
+ .ei_type = LDLM_IBITS,
+ .ei_mode = LCK_CR,
+ .ei_cb_bl = ll_md_blocking_ast,
+ .ei_cb_cp = ldlm_completion_ast,
+ };
int rc;
ENTRY;
- *gen = LL_LAYOUT_GEN_NONE;
+ *gen = lli->lli_layout_gen;
if (!(sbi->ll_flags & LL_SBI_LAYOUT_LOCK))
RETURN(0);
ll_finish_md_op_data(op_data);
- md_set_lock_data(sbi->ll_md_exp, &it.d.lustre.it_lock_handle, inode, NULL);
-
mode = it.d.lustre.it_lock_mode;
it.d.lustre.it_lock_mode = 0;
ll_intent_drop_lock(&it);
RETURN(rc);
}
+
+/**
+ * This function send a restore request to the MDT
+ */
+int ll_layout_restore(struct inode *inode)
+{
+ struct hsm_user_request *hur;
+ int len, rc;
+ ENTRY;
+
+ len = sizeof(struct hsm_user_request) +
+ sizeof(struct hsm_user_item);
+ OBD_ALLOC(hur, len);
+ if (hur == NULL)
+ RETURN(-ENOMEM);
+
+ hur->hur_request.hr_action = HUA_RESTORE;
+ hur->hur_request.hr_archive_id = 0;
+ hur->hur_request.hr_flags = 0;
+ memcpy(&hur->hur_user_item[0].hui_fid, &ll_i2info(inode)->lli_fid,
+ sizeof(hur->hur_user_item[0].hui_fid));
+ hur->hur_user_item[0].hui_extent.length = -1;
+ hur->hur_request.hr_itemcount = 1;
+ rc = obd_iocontrol(LL_IOC_HSM_REQUEST, cl_i2sbi(inode)->ll_md_exp,
+ len, hur, NULL);
+ OBD_FREE(hur, len);
+ RETURN(rc);
+}
+