Whamcloud - gitweb
LU-857 security: Lustre client tolerates enforced SELinux.
[fs/lustre-release.git] / lustre / llite / namei.c
index b993c0b..e5393a1 100644 (file)
@@ -28,6 +28,9 @@
 /*
  * 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/
@@ -41,6 +44,7 @@
 #include <linux/quotaops.h>
 #include <linux/highmem.h>
 #include <linux/pagemap.h>
+#include <linux/security.h>
 
 #define DEBUG_SUBSYSTEM S_LLITE
 
@@ -49,7 +53,6 @@
 #include <lustre_lite.h>
 #include <lustre_dlm.h>
 #include <lustre_ver.h>
-#include <lustre_mdc.h>
 #include "llite_internal.h"
 
 /*
@@ -130,10 +133,12 @@ struct inode *ll_iget(struct super_block *sb, ino_t hash,
 
         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);
@@ -208,15 +213,11 @@ int ll_md_blocking_ast(struct ldlm_lock *lock, struct ldlm_lock_desc *desc,
 
                 LASSERT(lock->l_flags & LDLM_FL_CANCELING);
                 /* For OPEN locks we differentiate between lock modes - CR, CW. PR - bug 22891 */
-                if ((bits & MDS_INODELOCK_LOOKUP) &&
-                    ll_have_md_lock(inode, MDS_INODELOCK_LOOKUP, LCK_MINMODE))
-                        bits &= ~MDS_INODELOCK_LOOKUP;
-                if ((bits & MDS_INODELOCK_UPDATE) &&
-                    ll_have_md_lock(inode, MDS_INODELOCK_UPDATE, LCK_MINMODE))
-                        bits &= ~MDS_INODELOCK_UPDATE;
-                if ((bits & MDS_INODELOCK_OPEN) &&
-                    ll_have_md_lock(inode, MDS_INODELOCK_OPEN, mode))
-                        bits &= ~MDS_INODELOCK_OPEN;
+                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) ||
@@ -331,6 +332,9 @@ static void ll_d_add(struct dentry *de, struct inode *inode)
         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)) {
@@ -348,7 +352,7 @@ static void ll_d_add(struct dentry *de, struct inode *inode)
  * 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;
@@ -366,7 +370,7 @@ static struct dentry *ll_find_alias(struct inode *inode, struct dentry *de)
                 }
 
                 if (dentry->d_flags & DCACHE_DISCONNECTED) {
-                        LASSERT(last_discon == NULL);
+                        /* LASSERT(last_discon == NULL); LU-405, bz 20055 */
                         last_discon = dentry;
                         continue;
                 }
@@ -385,11 +389,8 @@ static struct dentry *ll_find_alias(struct inode *inode, struct dentry *de)
                         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);
                 cfs_spin_unlock(&ll_lookup_lock);
                 iput(inode);
@@ -409,7 +410,7 @@ static struct dentry *ll_find_alias(struct inode *inode, struct dentry *de)
                 unlock_dentry(last_discon);
                 spin_unlock(&dcache_lock);
                 cfs_spin_unlock(&ll_lookup_lock);
-                ll_dops_init(last_discon, 1);
+                ll_dops_init(last_discon, 1, 1);
                 d_rehash(de);
                 d_move(last_discon, de);
                 iput(inode);
@@ -432,7 +433,6 @@ int ll_lookup_it_finish(struct ptlrpc_request *request,
         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;
@@ -441,16 +441,13 @@ int ll_lookup_it_finish(struct ptlrpc_request *request,
          * 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
@@ -460,27 +457,26 @@ int ll_lookup_it_finish(struct ptlrpc_request *request,
                    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_dops_init(*de, 1);
+                                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, LCK_MINMODE)) {
+                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);
@@ -514,7 +510,7 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry,
         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)
@@ -533,17 +529,18 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry,
          * 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);
                 }
         }
 
@@ -576,9 +573,6 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry,
                 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)) {
@@ -593,24 +587,11 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry,
  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)
 {
@@ -624,7 +605,7 @@ struct lookup_intent *ll_convert_intent(struct open_intent *oit,
                 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;
@@ -664,7 +645,7 @@ static struct dentry *ll_lookup_nd(struct inode *parent, struct dentry *dentry,
                         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);
+                                ll_dops_init(dentry, 1, 1);
                                 RETURN(NULL);
                         }
                         it = ll_convert_intent(&nd->intent.open, nd->flags);
@@ -732,7 +713,6 @@ static struct dentry *ll_lookup_nd(struct inode *parent, struct dentry *dentry,
 
         RETURN(de);
 }
-#endif
 
 /* 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,
@@ -762,8 +742,7 @@ static struct inode *ll_create_node(struct inode *dir, const char *name,
          * 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);
@@ -909,7 +888,6 @@ static int ll_mknod_generic(struct inode *dir, struct qstr *name, int mode,
         RETURN(err);
 }
 
-#ifndef HAVE_VFS_INTENT_PATCHES
 static int ll_create_nd(struct inode *dir, struct dentry *dentry,
                         int mode, struct nameidata *nd)
 {
@@ -943,17 +921,6 @@ out:
 
         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)
@@ -1220,43 +1187,6 @@ static int ll_rename_generic(struct inode *src, struct dentry *src_dparent,
         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)
 {
@@ -1305,17 +1235,6 @@ static int ll_rename(struct inode *old_dir, struct dentry *old_dentry,
 }
 
 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,
@@ -1336,9 +1255,6 @@ struct inode_operations ll_dir_inode_operations = {
 };
 
 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,