* Use is subject to license terms.
*/
/*
+ * Copyright (c) 2011 Whamcloud, Inc.
+ */
+/*
* This file is part of Lustre, http://www.lustre.org/
* Lustre is a trademark of Sun Microsystems, Inc.
*
#define DEBUG_SUBSYSTEM S_LLITE
#include <lustre_dlm.h>
#include <lustre_lite.h>
-#include <lustre_mdc.h>
#include <linux/pagemap.h>
#include <linux/file.h>
#include "llite_internal.h"
rc = ll_md_close(sbi->ll_md_exp, inode, file);
- if (OBD_FAIL_TIMEOUT_MS(OBD_FAIL_PTLRPC_DUMP_LOG, obd_fail_val))
+ if (CFS_FAIL_TIMEOUT_MS(OBD_FAIL_PTLRPC_DUMP_LOG, cfs_fail_val))
libcfs_debug_dumplog();
RETURN(rc);
const int len = file->f_dentry->d_name.len;
struct md_op_data *op_data;
struct ptlrpc_request *req;
+ __u32 opc = LUSTRE_OPC_ANY;
int rc;
ENTRY;
* makes a good candidate for using OPEN lock */
/* If lmmsize & lmm are not 0, we are just setting stripe info
* parameters. No need for the open lock */
- if (!lmm && !lmmsize)
+ if (lmm == NULL && lmmsize == 0) {
itp->it_flags |= MDS_OPEN_LOCK;
+ if (itp->it_flags & FMODE_WRITE)
+ opc = LUSTRE_OPC_CREATE;
+ }
op_data = ll_prep_md_op_data(NULL, parent->d_inode,
file->f_dentry->d_inode, name, len,
- O_RDWR, LUSTRE_OPC_ANY, NULL);
+ O_RDWR, opc, NULL);
if (IS_ERR(op_data))
RETURN(PTR_ERR(op_data));
GOTO(out, rc);
}
+ if (it_disposition(itp, DISP_LOOKUP_NEG))
+ GOTO(out, rc = -ENOENT);
+
if (rc != 0 || it_open_error(DISP_OPEN_OPEN, itp)) {
rc = rc ? rc : it_open_error(DISP_OPEN_OPEN, itp);
CDEBUG(D_VFSTRACE, "lock enqueue: err: %d\n", rc);
rc = ll_prep_inode(&file->f_dentry->d_inode, req, NULL);
if (!rc && itp->d.lustre.it_lock_mode)
- md_set_lock_data(sbi->ll_md_exp,
- &itp->d.lustre.it_lock_handle,
- file->f_dentry->d_inode, NULL);
+ ll_set_lock_data(sbi->ll_md_exp, file->f_dentry->d_inode,
+ itp, NULL);
out:
ptlrpc_req_finished(itp->d.lustre.it_data);
struct lookup_intent *it, oit = { .it_op = IT_OPEN,
.it_flags = file->f_flags };
struct lov_stripe_md *lsm;
- struct ptlrpc_request *req = NULL;
- struct obd_client_handle **och_p;
- __u64 *och_usecount;
+ struct obd_client_handle **och_p = NULL;
+ __u64 *och_usecount = NULL;
struct ll_file_data *fd;
int rc = 0, opendir_set = 0;
ENTRY;
fd = ll_file_data_get();
if (fd == NULL)
- RETURN(-ENOMEM);
+ GOTO(out_och_free, rc = -ENOMEM);
fd->fd_file = file;
if (S_ISDIR(inode->i_mode)) {
cfs_spin_lock(&lli->lli_sa_lock);
- if (lli->lli_opendir_key == NULL && lli->lli_opendir_pid == 0) {
- LASSERT(lli->lli_sai == NULL);
+ if (lli->lli_opendir_key == NULL && lli->lli_opendir_pid == 0 &&
+ lli->lli_sai == NULL) {
lli->lli_opendir_key = fd;
lli->lli_opendir_pid = cfs_curproc_pid();
opendir_set = 1;
* dentry_open after call to open_namei that checks permissions.
* Only nfsd_open call dentry_open directly without checking
* permissions and because of that this code below is safe. */
- if (oit.it_flags & FMODE_WRITE)
+ if (oit.it_flags & (FMODE_WRITE | FMODE_READ))
oit.it_flags |= MDS_OPEN_OWNEROVERRIDE;
/* We do not want O_EXCL here, presumably we opened the file
rc = it_open_error(DISP_OPEN_OPEN, it);
if (rc) {
cfs_up(&lli->lli_och_sem);
- ll_file_data_put(fd);
GOTO(out_openerr, rc);
}
+
ll_release_openhandle(file->f_dentry, it);
lprocfs_counter_incr(ll_i2sbi(inode)->ll_stats,
LPROC_LL_OPEN);
if (rc) {
(*och_usecount)--;
cfs_up(&lli->lli_och_sem);
- ll_file_data_put(fd);
GOTO(out_openerr, rc);
}
} else {
it->it_create_mode |= M_CHECK_STALE;
rc = ll_intent_file_open(file, NULL, 0, it);
it->it_create_mode &= ~M_CHECK_STALE;
- if (rc) {
- ll_file_data_put(fd);
+ if (rc)
GOTO(out_openerr, rc);
- }
- /* Got some error? Release the request */
- if (it->d.lustre.it_status < 0) {
- req = it->d.lustre.it_data;
- ptlrpc_req_finished(req);
- }
goto restart;
}
OBD_ALLOC(*och_p, sizeof (struct obd_client_handle));
- if (!*och_p) {
- ll_file_data_put(fd);
+ if (!*och_p)
GOTO(out_och_free, rc = -ENOMEM);
- }
+
(*och_usecount)++;
- req = it->d.lustre.it_data;
/* md_intent_lock() didn't get a request ref if there was an
* open error, so don't do cleanup on the request here
/* XXX (green): Should not we bail out on any error here, not
* just open error? */
rc = it_open_error(DISP_OPEN_OPEN, it);
- if (rc) {
- ll_file_data_put(fd);
+ if (rc)
GOTO(out_och_free, rc);
- }
+
+ LASSERT(it_disposition(it, DISP_ENQ_OPEN_REF));
ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_OPEN, 1);
rc = ll_local_open(file, it, fd, *och_p);
- if (rc) {
- ll_file_data_put(fd);
+ if (rc)
GOTO(out_och_free, rc);
- }
}
cfs_up(&lli->lli_och_sem);
+ fd = NULL;
/* Must do this outside lli_och_sem lock to prevent deadlock where
different kind of OPEN lock for this same inode gets cancelled
by ldlm_cancel_lru */
if (!S_ISREG(inode->i_mode))
- GOTO(out, rc);
+ GOTO(out_och_free, rc);
ll_capa_open(inode);
if (file->f_flags & O_LOV_DELAY_CREATE ||
!(file->f_mode & FMODE_WRITE)) {
CDEBUG(D_INODE, "object creation was delayed\n");
- GOTO(out, rc);
+ GOTO(out_och_free, rc);
}
}
file->f_flags &= ~O_LOV_DELAY_CREATE;
- GOTO(out, rc);
-out:
- ptlrpc_req_finished(req);
- if (req)
- it_clear_disposition(it, DISP_ENQ_OPEN_REF);
+ GOTO(out_och_free, rc);
+
out_och_free:
+ if (it && it_disposition(it, DISP_ENQ_OPEN_REF)) {
+ ptlrpc_req_finished(it->d.lustre.it_data);
+ it_clear_disposition(it, DISP_ENQ_OPEN_REF);
+ }
+
if (rc) {
- if (*och_p) {
+ if (och_p && *och_p) {
OBD_FREE(*och_p, sizeof (struct obd_client_handle));
*och_p = NULL; /* OBD_FREE writes some magic there */
(*och_usecount)--;
}
cfs_up(&lli->lli_och_sem);
+
out_openerr:
if (opendir_set != 0)
ll_stop_statahead(inode, lli->lli_opendir_key);
+ if (fd != NULL)
+ ll_file_data_put(fd);
}
return rc;
if (rc == 0) {
obdo_refresh_inode(inode, obdo, obdo->o_valid);
CDEBUG(D_INODE,
- "objid "LPX64" size %Lu, blocks %llu, blksize %lu\n",
+ "objid "LPX64" size %llu, blocks %llu, blksize %lu\n",
lli->lli_smd->lsm_object_id, i_size_read(inode),
(unsigned long long)inode->i_blocks,
(unsigned long)ll_inode_blksize(inode));
{
struct inode *inode = file->f_dentry->d_inode;
- memset(io, 0, sizeof *io);
io->u.ci_rw.crw_nonblock = file->f_flags & O_NONBLOCK;
if (write)
io->u.ci_wr.wr_append = !!(file->f_flags & O_APPEND);
ssize_t result;
ENTRY;
- io = &ccc_env_info(env)->cti_io;
+ io = ccc_env_thread_io(env);
ll_io_init(io, file, iot == CIT_WRITE);
if (cl_io_rw_init(env, io, iot, *ppos, count) == 0) {
GOTO(out, result);
out:
cl_io_fini(env, io);
- if (iot == CIT_WRITE)
- lli->lli_write_rc = result < 0 ? : 0;
+
+ 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);
+ lli->lli_write_rc = 0;
+ } else {
+ lli->lli_write_rc = result;
+ }
+ }
+
return result;
}
rc = ll_intent_file_open(file, lum, lum_size, &oit);
if (rc)
GOTO(out, rc);
- if (it_disposition(&oit, DISP_LOOKUP_NEG))
- GOTO(out_req_free, rc = -ENOENT);
rc = oit.d.lustre.it_status;
if (rc < 0)
GOTO(out_req_free, rc);
op_data = ll_prep_md_op_data(NULL, inode, NULL, filename,
strlen(filename), lmmsize,
LUSTRE_OPC_ANY, NULL);
- if (op_data == NULL)
- RETURN(-ENOMEM);
+ if (IS_ERR(op_data))
+ RETURN(PTR_ERR(op_data));
op_data->op_valid = OBD_MD_FLEASIZE | OBD_MD_FLDIREA;
rc = md_getattr_name(sbi->ll_md_exp, op_data, &req);
static int ll_lov_getstripe(struct inode *inode, unsigned long arg)
{
struct lov_stripe_md *lsm = ll_i2info(inode)->lli_smd;
+ int rc = -ENODATA;
+ ENTRY;
- if (!lsm)
- RETURN(-ENODATA);
-
- return obd_iocontrol(LL_IOC_LOV_GETSTRIPE, ll_i2dtexp(inode), 0, lsm,
- (void *)arg);
+ if (lsm != NULL)
+ rc = obd_iocontrol(LL_IOC_LOV_GETSTRIPE, ll_i2dtexp(inode), 0,
+ lsm, (void *)arg);
+ RETURN(rc);
}
int ll_get_grouplock(struct inode *inode, struct file *file, unsigned long arg)
inode, och);
out:
/* this one is in place of ll_file_open */
- if (it_disposition(it, DISP_ENQ_OPEN_REF))
+ if (it_disposition(it, DISP_ENQ_OPEN_REF)) {
ptlrpc_req_finished(it->d.lustre.it_data);
- it_clear_disposition(it, DISP_ENQ_OPEN_REF);
+ it_clear_disposition(it, DISP_ENQ_OPEN_REF);
+ }
RETURN(rc);
}
#endif
struct ll_file_data *fd = LUSTRE_FPRIVATE(file);
int flags;
+
ENTRY;
CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p),cmd=%x\n", inode->i_ino,
}
case OBD_IOC_FID2PATH:
RETURN(ll_fid2path(ll_i2mdexp(inode), (void *)arg));
-
case LL_IOC_GET_MDTIDX: {
int mdtidx;
RETURN(0);
}
+ case OBD_IOC_GETNAME: {
+ struct obd_device *obd =
+ class_exp2obd(ll_i2sbi(inode)->ll_dt_exp);
+ if (!obd)
+ RETURN(-EFAULT);
+ if (cfs_copy_to_user((void *)arg, obd->obd_name,
+ strlen(obd->obd_name) + 1))
+ RETURN(-EFAULT);
+ RETURN(0);
+ }
default: {
int err;
ENTRY;
retval = offset + ((origin == 2) ? i_size_read(inode) :
(origin == 1) ? file->f_pos : 0);
- CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p), to=%Lu=%#Lx(%s)\n",
+ CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p), to=%llu=%#llx(%s)\n",
inode->i_ino, inode->i_generation, inode, retval, retval,
origin == 2 ? "SEEK_END": origin == 1 ? "SEEK_CUR" : "SEEK_SET");
ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_LLSEEK, 1);
}
flock.l_flock.pid = file_lock->fl_pid;
+ /* Somewhat ugly workaround for svc lockd.
+ * lockd installs custom fl_lmops->fl_compare_owner that checks
+ * for the fl_owner to be the same (which it always is on local node
+ * I guess between lockd processes) and then compares pid.
+ * As such we assign pid to the owner field to make it all work,
+ * conflict with normal locks is unlikely since pid space and
+ * pointer space for current->files are not intersecting */
+ if (file_lock->fl_lmops && file_lock->fl_lmops->fl_compare_owner)
+ flock.l_flock.owner = (unsigned long)file_lock->fl_pid;
+
switch (file_lock->fl_type) {
case F_RDLCK:
einfo.ei_mode = LCK_PR;
RETURN(-ENOSYS);
}
-int ll_have_md_lock(struct inode *inode, __u64 bits, ldlm_mode_t l_req_mode)
+/**
+ * test if some locks matching bits and l_req_mode are acquired
+ * - bits can be in different locks
+ * - if found clear the common lock bits in *bits
+ * - the bits not found, are kept in *bits
+ * \param inode [IN]
+ * \param bits [IN] searched lock bits [IN]
+ * \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)
{
struct lustre_handle lockh;
- ldlm_policy_data_t policy = { .l_inodebits = {bits}};
+ 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;
int flags;
+ int i;
ENTRY;
if (!inode)
ldlm_lockname[mode]);
flags = LDLM_FL_BLOCK_GRANTED | LDLM_FL_CBPENDING | LDLM_FL_TEST_LOCK;
- if (md_lock_match(ll_i2mdexp(inode), flags, fid, LDLM_IBITS, &policy,
- mode, &lockh)) {
- RETURN(1);
+ 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)) {
+ struct ldlm_lock *lock;
+
+ lock = ldlm_handle2lock(&lockh);
+ if (lock) {
+ *bits &=
+ ~(lock->l_policy_data.l_inodebits.bits);
+ LDLM_LOCK_PUT(lock);
+ } else {
+ *bits &= ~policy.l_inodebits.bits;
+ }
+ }
}
- RETURN(0);
+ RETURN(*bits == 0);
}
ldlm_mode_t ll_take_md_lock(struct inode *inode, __u64 bits,
}
ll_lookup_finish_locks(&oit, dentry);
- } else if (!ll_have_md_lock(dentry->d_inode, ibits, LCK_MINMODE)) {
+ } else if (!ll_have_md_lock(dentry->d_inode, &ibits, LCK_MINMODE)) {
struct ll_sb_info *sbi = ll_i2sbi(dentry->d_inode);
obd_valid valid = OBD_MD_FLGETATTR;
struct md_op_data *op_data;
op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL,
0, ealen, LUSTRE_OPC_ANY,
NULL);
- if (op_data == NULL)
- RETURN(-ENOMEM);
+ if (IS_ERR(op_data))
+ RETURN(PTR_ERR(op_data));
op_data->op_valid = valid;
/* Once OBD_CONNECT_ATTRFID is not supported, we can't find one
struct lookup_intent *it, struct kstat *stat)
{
struct inode *inode = de->d_inode;
+ struct ll_sb_info *sbi = ll_i2sbi(inode);
struct ll_inode_info *lli = ll_i2info(inode);
int res = 0;
res = ll_inode_revalidate_it(de, it, MDS_INODELOCK_UPDATE |
MDS_INODELOCK_LOOKUP);
- ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_GETATTR, 1);
+ ll_stats_ops_tally(sbi, LPROC_LL_GETATTR, 1);
if (res)
return res;
stat->dev = inode->i_sb->s_dev;
- if (ll_need_32bit_api(ll_i2sbi(inode)))
- stat->ino = cl_fid_build_ino32(&lli->lli_fid);
+ if (ll_need_32bit_api(sbi))
+ stat->ino = cl_fid_build_ino(&lli->lli_fid, 1);
else
stat->ino = inode->i_ino;
-
stat->mode = inode->i_mode;
stat->nlink = inode->i_nlink;
stat->uid = inode->i_uid;
#endif
-static
-int lustre_check_acl(struct inode *inode, int mask)
+static int
+#ifdef HAVE_GENERIC_PERMISSION_4ARGS
+lustre_check_acl(struct inode *inode, int mask, unsigned int flags)
+#else
+lustre_check_acl(struct inode *inode, int mask)
+#endif
{
#ifdef CONFIG_FS_POSIX_ACL
struct ll_inode_info *lli = ll_i2info(inode);
int rc;
ENTRY;
+#ifdef HAVE_GENERIC_PERMISSION_4ARGS
+ if (flags & IPERM_FLAG_RCU)
+ return -ECHILD;
+#endif
cfs_spin_lock(&lli->lli_lock);
acl = posix_acl_dup(lli->lli_posix_acl);
cfs_spin_unlock(&lli->lli_lock);
#endif
}
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10))
-#ifndef HAVE_INODE_PERMISION_2ARGS
-int ll_inode_permission(struct inode *inode, int mask, struct nameidata *nd)
+#ifdef HAVE_GENERIC_PERMISSION_4ARGS
+int ll_inode_permission(struct inode *inode, int mask, unsigned int flags)
#else
+# ifdef HAVE_INODE_PERMISION_2ARGS
int ll_inode_permission(struct inode *inode, int mask)
+# else
+int ll_inode_permission(struct inode *inode, int mask, struct nameidata *nd)
+# endif
#endif
{
int rc = 0;
return lustre_check_remote_perm(inode, mask);
ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_INODE_PERM, 1);
- rc = generic_permission(inode, mask, lustre_check_acl);
+ rc = ll_generic_permission(inode, mask, flags, lustre_check_acl);
RETURN(rc);
}
-#else
-int ll_inode_permission(struct inode *inode, int mask, struct nameidata *nd)
-{
- int mode = inode->i_mode;
- int rc;
-
- CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p), mask %o\n",
- inode->i_ino, inode->i_generation, inode, mask);
-
- if (ll_i2sbi(inode)->ll_flags & LL_SBI_RMT_CLIENT)
- return lustre_check_remote_perm(inode, mask);
-
- ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_INODE_PERM, 1);
-
- if ((mask & MAY_WRITE) && IS_RDONLY(inode) &&
- (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
- return -EROFS;
- if ((mask & MAY_WRITE) && IS_IMMUTABLE(inode))
- return -EACCES;
- if (cfs_curproc_fsuid() == inode->i_uid) {
- mode >>= 6;
- } else if (1) {
- if (((mode >> 3) & mask & S_IRWXO) != mask)
- goto check_groups;
- rc = lustre_check_acl(inode, mask);
- if (rc == -EAGAIN)
- goto check_groups;
- if (rc == -EACCES)
- goto check_capabilities;
- return rc;
- } else {
-check_groups:
- if (cfs_curproc_is_in_groups(inode->i_gid))
- mode >>= 3;
- }
- if ((mode & mask & S_IRWXO) == mask)
- return 0;
-
-check_capabilities:
- if (!(mask & MAY_EXEC) ||
- (inode->i_mode & S_IXUGO) || S_ISDIR(inode->i_mode))
- if (cfs_capable(CFS_CAP_DAC_OVERRIDE))
- return 0;
-
- if (cfs_capable(CFS_CAP_DAC_READ_SEARCH) && ((mask == MAY_READ) ||
- (S_ISDIR(inode->i_mode) && !(mask & MAY_WRITE))))
- return 0;
-
- return -EACCES;
-}
-#endif
#ifdef HAVE_FILE_READV
#define READ_METHOD readv