* GPL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved
+ * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
+ *
+ * Copyright (c) 2011 Whamcloud, Inc.
+ *
*/
/*
* This file is part of Lustre, http://www.lustre.org/
#include <linux/quotaops.h>
#include <linux/highmem.h>
#include <linux/pagemap.h>
-#include <linux/dcache.h>
-#include <linux/buffer_head.h>
+#include <linux/security.h>
#define DEBUG_SUBSYSTEM S_LLITE
#include <lustre_lite.h>
#include <lustre_dlm.h>
#include <lustre_ver.h>
-#include <lustre_mdc.h>
#include "llite_internal.h"
/*
if (inode) {
if (inode->i_state & I_NEW) {
- int rc;
+ int rc = 0;
ll_read_inode2(inode, md);
- rc = cl_inode_init(inode, md);
+ if (S_ISREG(inode->i_mode) &&
+ ll_i2info(inode)->lli_clob == NULL)
+ rc = cl_inode_init(inode, md);
if (rc != 0) {
md->lsm = NULL;
make_bad_inode(inode);
{
struct dentry *dentry, *tmp_alias, *tmp_subdir;
- spin_lock(&ll_lookup_lock);
+ cfs_spin_lock(&ll_lookup_lock);
spin_lock(&dcache_lock);
restart:
list_for_each_entry_safe(dentry, tmp_alias,
}
}
spin_unlock(&dcache_lock);
- spin_unlock(&ll_lookup_lock);
+ cfs_spin_unlock(&ll_lookup_lock);
}
break;
case LDLM_CB_CANCELING: {
struct inode *inode = ll_inode_from_lock(lock);
+ struct ll_inode_info *lli;
__u64 bits = lock->l_policy_data.l_inodebits.bits;
struct lu_fid *fid;
+ ldlm_mode_t mode = lock->l_req_mode;
/* Invalidate all dentries associated with this inode */
if (inode == NULL)
break;
LASSERT(lock->l_flags & LDLM_FL_CANCELING);
- if ((bits & MDS_INODELOCK_LOOKUP) &&
- ll_have_md_lock(inode, MDS_INODELOCK_LOOKUP))
- bits &= ~MDS_INODELOCK_LOOKUP;
- if ((bits & MDS_INODELOCK_UPDATE) &&
- ll_have_md_lock(inode, MDS_INODELOCK_UPDATE))
- bits &= ~MDS_INODELOCK_UPDATE;
- if ((bits & MDS_INODELOCK_OPEN) &&
- ll_have_md_lock(inode, MDS_INODELOCK_OPEN))
- bits &= ~MDS_INODELOCK_OPEN;
+ /* For OPEN locks we differentiate between lock modes - CR, CW. PR - bug 22891 */
+ if (bits & (MDS_INODELOCK_LOOKUP | MDS_INODELOCK_UPDATE))
+ ll_have_md_lock(inode, &bits, LCK_MINMODE);
+
+ if (bits & MDS_INODELOCK_OPEN)
+ ll_have_md_lock(inode, &bits, mode);
fid = ll_inode2fid(inode);
if (lock->l_resource->lr_name.name[0] != fid_seq(fid) ||
ll_md_real_close(inode, flags);
}
+ lli = ll_i2info(inode);
if (bits & MDS_INODELOCK_UPDATE)
- ll_i2info(inode)->lli_flags &= ~LLIF_MDS_SIZE_LOCK;
+ lli->lli_flags &= ~LLIF_MDS_SIZE_LOCK;
if (S_ISDIR(inode->i_mode) &&
(bits & MDS_INODELOCK_UPDATE)) {
__u32 ll_i2suppgid(struct inode *i)
{
- if (in_group_p(i->i_gid))
+ if (cfs_curproc_is_in_groups(i->i_gid))
return (__u32)i->i_gid;
else
return (__u32)(-1);
if (inode)
list_add(&de->d_alias, &inode->i_dentry);
de->d_inode = inode;
+ /* d_instantiate() replacement code should initialize security
+ * context. */
+ security_d_instantiate(de, inode);
/* d_rehash */
if (!d_unhashed(de)) {
* in ll_revalidate_it. After revaliadate inode will be have hashed aliases
* and it triggers BUG_ON in d_instantiate_unique (bug #10954).
*/
-static struct dentry *ll_find_alias(struct inode *inode, struct dentry *de)
+struct dentry *ll_find_alias(struct inode *inode, struct dentry *de)
{
struct list_head *tmp;
struct dentry *dentry;
struct dentry *last_discon = NULL;
- spin_lock(&ll_lookup_lock);
+ cfs_spin_lock(&ll_lookup_lock);
spin_lock(&dcache_lock);
list_for_each(tmp, &inode->i_dentry) {
dentry = list_entry(tmp, struct dentry, d_alias);
}
if (dentry->d_flags & DCACHE_DISCONNECTED) {
- LASSERT(last_discon == NULL);
+ /* LASSERT(last_discon == NULL); LU-405, bz 20055 */
last_discon = dentry;
continue;
}
continue;
dget_locked(dentry);
- lock_dentry(dentry);
- __d_drop(dentry);
- unlock_dentry(dentry);
- ll_dops_init(dentry, 0);
- d_rehash_cond(dentry, 0); /* avoid taking dcache_lock inside */
+ ll_dops_init(dentry, 0, 1);
+ ll_dentry_rehash(dentry, 1);
spin_unlock(&dcache_lock);
- spin_unlock(&ll_lookup_lock);
+ cfs_spin_unlock(&ll_lookup_lock);
iput(inode);
CDEBUG(D_DENTRY, "alias dentry %.*s (%p) parent %p inode %p "
"refc %d\n", de->d_name.len, de->d_name.name, de,
last_discon->d_flags |= DCACHE_LUSTRE_INVALID;
unlock_dentry(last_discon);
spin_unlock(&dcache_lock);
- spin_unlock(&ll_lookup_lock);
- ll_dops_init(last_discon, 1);
+ cfs_spin_unlock(&ll_lookup_lock);
+ ll_dops_init(last_discon, 1, 1);
d_rehash(de);
d_move(last_discon, de);
iput(inode);
return last_discon;
}
+ lock_dentry(de);
de->d_flags |= DCACHE_LUSTRE_INVALID;
+ unlock_dentry(de);
ll_d_add(de, inode);
spin_unlock(&dcache_lock);
- spin_unlock(&ll_lookup_lock);
+ cfs_spin_unlock(&ll_lookup_lock);
return de;
}
struct it_cb_data *icbd = data;
struct dentry **de = icbd->icbd_childp;
struct inode *parent = icbd->icbd_parent;
- struct ll_sb_info *sbi = ll_i2sbi(parent);
struct inode *inode = NULL;
int rc;
ENTRY;
* when I return */
if (!it_disposition(it, DISP_LOOKUP_NEG)) {
struct dentry *save = *de;
- __u32 bits;
+ __u64 bits = 0;
rc = ll_prep_inode(&inode, request, (*de)->d_sb);
if (rc)
RETURN(rc);
- CDEBUG(D_DLMTRACE, "setting l_data to inode %p (%lu/%u)\n",
- inode, inode->i_ino, inode->i_generation);
- md_set_lock_data(sbi->ll_md_exp,
- &it->d.lustre.it_lock_handle, inode, &bits);
+ ll_set_lock_data(ll_i2sbi(parent)->ll_md_exp, inode, it, &bits);
/* We used to query real size from OSTs here, but actually
this is not needed. For stat() calls size would be updated
Everybody else who needs correct file size would call
cl_glimpse_size or some equivalent themselves anyway.
Also see bug 7198. */
-
- ll_dops_init(*de, 1);
+ ll_dops_init(*de, 1, 1);
*de = ll_find_alias(inode, *de);
if (*de != save) {
struct ll_dentry_data *lld = ll_d2d(*de);
/* just make sure the ll_dentry_data is ready */
- if (unlikely(lld == NULL)) {
- ll_set_dd(*de);
- lld = ll_d2d(*de);
- if (likely(lld != NULL))
- lld->lld_sa_generation = 0;
- }
+ if (unlikely(lld == NULL))
+ ll_dops_init(*de, 1, 1);
}
/* we have lookup look - unhide dentry */
- if (bits & MDS_INODELOCK_LOOKUP) {
- lock_dentry(*de);
- (*de)->d_flags &= ~(DCACHE_LUSTRE_INVALID);
- unlock_dentry(*de);
- }
+ ll_dentry_reset_flags(*de, bits);
} else {
- ll_dops_init(*de, 1);
+ __u64 ibits;
+
+ ll_dops_init(*de, 1, 1);
/* Check that parent has UPDATE lock. If there is none, we
cannot afford to hash this dentry (done by ll_d_add) as it
might get picked up later when UPDATE lock will appear */
- if (ll_have_md_lock(parent, MDS_INODELOCK_UPDATE)) {
+ ibits = MDS_INODELOCK_UPDATE;
+ if (ll_have_md_lock(parent, &ibits, LCK_MINMODE)) {
spin_lock(&dcache_lock);
ll_d_add(*de, NULL);
spin_unlock(&dcache_lock);
struct md_op_data *op_data;
struct it_cb_data icbd;
__u32 opc;
- int rc, first = 0;
+ int rc;
ENTRY;
if (dentry->d_name.len > ll_i2sbi(parent)->ll_namelen)
* not valid, revalidate it here. */
if (parent->i_sb->s_root && (parent->i_sb->s_root->d_inode == parent) &&
(it->it_op & (IT_OPEN | IT_CREAT))) {
- rc = ll_inode_revalidate_it(parent->i_sb->s_root, it);
+ rc = ll_inode_revalidate_it(parent->i_sb->s_root, it,
+ MDS_INODELOCK_LOOKUP);
if (rc)
RETURN(ERR_PTR(rc));
}
if (it->it_op == IT_GETATTR) {
- first = ll_statahead_enter(parent, &dentry, 1);
- if (first >= 0) {
- ll_statahead_exit(parent, dentry, first);
- if (first == 1)
- RETURN(retval = dentry);
+ rc = ll_statahead_enter(parent, &dentry, 0);
+ if (rc == 1) {
+ if (dentry == save)
+ GOTO(out, retval = NULL);
+ GOTO(out, retval = dentry);
}
}
if (IS_ERR(op_data))
RETURN((void *)op_data);
- it->it_create_mode &= ~current->fs->umask;
+ it->it_create_mode &= ~cfs_curproc_umask();
rc = md_intent_lock(ll_i2mdexp(parent), op_data, NULL, 0, it,
lookup_flags, &req, ll_md_blocking_ast, 0);
GOTO(out, retval = ERR_PTR(rc));
}
- if (first == -EEXIST)
- ll_statahead_mark(parent, dentry);
-
if ((it->it_op & IT_OPEN) && dentry->d_inode &&
!S_ISREG(dentry->d_inode->i_mode) &&
!S_ISDIR(dentry->d_inode->i_mode)) {
out:
if (req)
ptlrpc_req_finished(req);
+ if (it->it_op == IT_GETATTR && (retval == NULL || retval == dentry))
+ ll_statahead_mark(parent, dentry);
return retval;
}
-#ifdef HAVE_VFS_INTENT_PATCHES
-static struct dentry *ll_lookup_nd(struct inode *parent, struct dentry *dentry,
- struct nameidata *nd)
-{
- struct dentry *de;
- ENTRY;
-
- if (nd && nd->flags & LOOKUP_LAST && !(nd->flags & LOOKUP_LINK_NOTLAST))
- de = ll_lookup_it(parent, dentry, &nd->intent, nd->flags);
- else
- de = ll_lookup_it(parent, dentry, NULL, 0);
-
- RETURN(de);
-}
-#else
struct lookup_intent *ll_convert_intent(struct open_intent *oit,
int lookup_flags)
{
it->it_op = IT_OPEN;
if (lookup_flags & LOOKUP_CREATE)
it->it_op |= IT_CREAT;
- it->it_create_mode = oit->create_mode;
+ it->it_create_mode = (oit->create_mode & S_IALLUGO) | S_IFREG;
it->it_flags = oit->flags;
} else {
it->it_op = IT_GETATTR;
if (IS_ERR(nd->intent.open.file))
RETURN((struct dentry *)nd->intent.open.file);
#endif
-
if (ll_d2d(dentry) && ll_d2d(dentry)->lld_it) {
it = ll_d2d(dentry)->lld_it;
ll_d2d(dentry)->lld_it = NULL;
} else {
+ if ((nd->flags & LOOKUP_CREATE ) && !(nd->flags & LOOKUP_OPEN)) {
+ /* We are sure this is new dentry, so we need to create
+ our private data and set the dentry ops */
+ ll_dops_init(dentry, 1, 1);
+ RETURN(NULL);
+ }
it = ll_convert_intent(&nd->intent.open, nd->flags);
if (IS_ERR(it))
RETURN((struct dentry *)it);
RETURN(de);
}
-#endif
-
-/**
- * check new allocated inode, new inode shld not have any valid alias
- */
-static void ll_validate_new_inode(struct inode *new)
-{
- struct list_head *lp;
- struct dentry * dentry;
- int need_inval = 0;
- int in_recheck = 0;
-
- if (list_empty(&new->i_dentry))
- return;
-recheck:
- spin_lock(&dcache_lock);
- list_for_each(lp, &new->i_dentry) {
- dentry = list_entry(lp, struct dentry, d_alias);
- if (!d_unhashed(dentry) && !(dentry->d_flags & DCACHE_LUSTRE_INVALID)){
- ll_dump_inode(new);
- if (in_recheck)
- LBUG();
- }
- need_inval = 1;
- }
- spin_unlock(&dcache_lock);
-
- if (need_inval && !in_recheck) {
- /* kill all old inode's data pages */
- truncate_inode_pages(new->i_mapping, 0);
-
- /* invalidate all dirent and recheck inode */
- ll_unhash_aliases(new);
- in_recheck = 1;
- goto recheck;
- }
-}
/* We depend on "mode" being set with the proper file type/umask by now */
static struct inode *ll_create_node(struct inode *dir, const char *name,
if (rc)
GOTO(out, inode = ERR_PTR(rc));
- ll_validate_new_inode(inode);
+ LASSERT(list_empty(&inode->i_dentry));
/* We asked for a lock on the directory, but were granted a
* lock on the inode. Since we finally have an inode pointer,
* stuff it in the lock. */
CDEBUG(D_DLMTRACE, "setting l_ast_data to inode %p (%lu/%u)\n",
inode, inode->i_ino, inode->i_generation);
- md_set_lock_data(sbi->ll_md_exp,
- &it->d.lustre.it_lock_handle, inode, NULL);
+ ll_set_lock_data(sbi->ll_md_exp, inode, it, NULL);
EXIT;
out:
ptlrpc_req_finished(request);
inode = ll_create_node(dir, dentry->d_name.name, dentry->d_name.len,
NULL, 0, mode, 0, it);
- if (IS_ERR(inode)) {
+ if (IS_ERR(inode))
RETURN(PTR_ERR(inode));
- }
- /* it might been set during parent dir revalidation */
- dentry->d_flags &= ~DCACHE_LUSTRE_INVALID;
d_instantiate(dentry, inode);
/* Negative dentry may be unhashed if parent does not have UPDATE lock,
* but some callers, e.g. do_coredump, expect dentry to be hashed after
&RMF_MDT_BODY);
LASSERT(body);
- /* mtime is always updated with ctime, but can be set in past.
- As write and utime(2) may happen within 1 second, and utime's
- mtime has a priority over write's one, so take mtime from mds
- for the same ctimes. */
+ if (body->valid & OBD_MD_FLMTIME &&
+ body->mtime > LTIME_S(inode->i_mtime)) {
+ CDEBUG(D_INODE, "setting ino %lu mtime from %lu to "LPU64"\n",
+ inode->i_ino, LTIME_S(inode->i_mtime), body->mtime);
+ LTIME_S(inode->i_mtime) = body->mtime;
+ }
if (body->valid & OBD_MD_FLCTIME &&
- body->ctime >= LTIME_S(inode->i_ctime)) {
+ body->ctime > LTIME_S(inode->i_ctime))
LTIME_S(inode->i_ctime) = body->ctime;
-
- if (body->valid & OBD_MD_FLMTIME) {
- CDEBUG(D_INODE, "setting ino %lu mtime from %lu "
- "to "LPU64"\n", inode->i_ino,
- LTIME_S(inode->i_mtime), body->mtime);
- LTIME_S(inode->i_mtime) = body->mtime;
- }
- }
}
static int ll_new_node(struct inode *dir, struct qstr *name,
GOTO(err_exit, err = PTR_ERR(op_data));
err = md_create(sbi->ll_md_exp, op_data, tgt, tgt_len, mode,
- current->fsuid, current->fsgid,
+ cfs_curproc_fsuid(), cfs_curproc_fsgid(),
cfs_curproc_cap_pack(), rdev, &request);
ll_finish_md_op_data(op_data);
if (err)
d_drop(dchild);
d_instantiate(dchild, inode);
- EXIT;
}
+ EXIT;
err_exit:
ptlrpc_req_finished(request);
name->len, name->name, dir->i_ino, dir->i_generation, dir,
mode, rdev);
- mode &= ~current->fs->umask;
+ mode &= ~cfs_curproc_umask();
switch (mode & S_IFMT) {
case 0:
RETURN(err);
}
-#ifndef HAVE_VFS_INTENT_PATCHES
static int ll_create_nd(struct inode *dir, struct dentry *dentry,
int mode, struct nameidata *nd)
{
return rc;
}
-#else
-static int ll_create_nd(struct inode *dir, struct dentry *dentry,
- int mode, struct nameidata *nd)
-{
- if (!nd || !nd->intent.d.lustre.it_disposition)
- /* No saved request? Just mknod the file */
- return ll_mknod_generic(dir, &dentry->d_name, mode, 0, dentry);
-
- return ll_create_it(dir, dentry, mode, &nd->intent);
-}
-#endif
static int ll_symlink_generic(struct inode *dir, struct qstr *name,
const char *tgt, struct dentry *dchild)
CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s,dir=%lu/%u(%p)\n",
name->len, name->name, dir->i_ino, dir->i_generation, dir);
- mode = (mode & (S_IRWXUGO|S_ISVTX) & ~current->fs->umask) | S_IFDIR;
+ mode = (mode & (S_IRWXUGO|S_ISVTX) & ~cfs_curproc_umask()) | S_IFDIR;
err = ll_new_node(dir, name, NULL, mode, 0, dchild, LUSTRE_OPC_MKDIR);
RETURN(err);
}
LASSERT(rc >= sizeof(*lsm));
- rc = obd_checkmd(ll_i2dtexp(dir), ll_i2mdexp(dir), lsm);
- if (rc)
- GOTO(out_free_memmd, rc);
-
OBDO_ALLOC(oa);
if (oa == NULL)
GOTO(out_free_memmd, rc = -ENOMEM);
oa->o_id = lsm->lsm_object_id;
- oa->o_gr = lsm->lsm_object_gr;
+ oa->o_seq = lsm->lsm_object_seq;
oa->o_mode = body->mode & S_IFMT;
oa->o_valid = OBD_MD_FLID | OBD_MD_FLTYPE | OBD_MD_FLGROUP;
return rc;
}
+/* ll_unlink_generic() doesn't update the inode with the new link count.
+ * Instead, ll_ddelete() and ll_d_iput() will update it based upon if there
+ * is any lock existing. They will recycle dentries and inodes based upon locks
+ * too. b=20433 */
static int ll_unlink_generic(struct inode *dir, struct dentry *dparent,
struct dentry *dchild, struct qstr *name)
{
RETURN(err);
}
-#ifdef HAVE_VFS_INTENT_PATCHES
-static int ll_mknod_raw(struct nameidata *nd, int mode, dev_t rdev)
-{
- return ll_mknod_generic(nd->dentry->d_inode, &nd->last, mode,rdev,NULL);
-}
-static int ll_rename_raw(struct nameidata *srcnd, struct nameidata *tgtnd)
-{
- return ll_rename_generic(srcnd->dentry->d_inode, srcnd->dentry,
- NULL, &srcnd->last,
- tgtnd->dentry->d_inode, tgtnd->dentry,
- NULL, &tgtnd->last);
-}
-static int ll_link_raw(struct nameidata *srcnd, struct nameidata *tgtnd)
-{
- return ll_link_generic(srcnd->dentry->d_inode, tgtnd->dentry->d_inode,
- &tgtnd->last, NULL);
-}
-static int ll_symlink_raw(struct nameidata *nd, const char *tgt)
-{
- return ll_symlink_generic(nd->dentry->d_inode, &nd->last, tgt, NULL);
-}
-static int ll_rmdir_raw(struct nameidata *nd)
-{
- return ll_rmdir_generic(nd->dentry->d_inode, nd->dentry, NULL,
- &nd->last);
-}
-static int ll_mkdir_raw(struct nameidata *nd, int mode)
-{
- return ll_mkdir_generic(nd->dentry->d_inode, &nd->last, mode, NULL);
-}
-static int ll_unlink_raw(struct nameidata *nd)
-{
- return ll_unlink_generic(nd->dentry->d_inode, nd->dentry, NULL,
- &nd->last);
-}
-#endif
-
static int ll_mknod(struct inode *dir, struct dentry *dchild, int mode,
ll_dev_t rdev)
{
}
struct inode_operations ll_dir_inode_operations = {
-#ifdef HAVE_VFS_INTENT_PATCHES
- .link_raw = ll_link_raw,
- .unlink_raw = ll_unlink_raw,
- .symlink_raw = ll_symlink_raw,
- .mkdir_raw = ll_mkdir_raw,
- .rmdir_raw = ll_rmdir_raw,
- .mknod_raw = ll_mknod_raw,
- .rename_raw = ll_rename_raw,
- .setattr = ll_setattr,
- .setattr_raw = ll_setattr_raw,
-#endif
.mknod = ll_mknod,
.lookup = ll_lookup_nd,
.create = ll_create_nd,
};
struct inode_operations ll_special_inode_operations = {
-#ifdef HAVE_VFS_INTENT_PATCHES
- .setattr_raw = ll_setattr_raw,
-#endif
.setattr = ll_setattr,
.getattr = ll_getattr,
.permission = ll_inode_permission,