Whamcloud - gitweb
LU-190 opencreate without mode can crash llite
[fs/lustre-release.git] / lustre / llite / namei.c
index acf6593..f9f9bc7 100644 (file)
@@ -26,7 +26,7 @@
  * 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.
  */
 /*
@@ -41,8 +41,6 @@
 #include <linux/quotaops.h>
 #include <linux/highmem.h>
 #include <linux/pagemap.h>
-#include <linux/dcache.h>
-#include <linux/buffer_head.h>
 
 #define DEBUG_SUBSYSTEM S_LLITE
 
@@ -156,7 +154,7 @@ static void ll_drop_negative_dentry(struct inode *dir)
 {
         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,
@@ -177,7 +175,7 @@ restart:
                 }
         }
         spin_unlock(&dcache_lock);
-        spin_unlock(&ll_lookup_lock);
+        cfs_spin_unlock(&ll_lookup_lock);
 }
 
 
@@ -199,22 +197,25 @@ int ll_md_blocking_ast(struct ldlm_lock *lock, struct ldlm_lock_desc *desc,
                 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);
+                /* 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))
+                    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))
+                    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))
+                    ll_have_md_lock(inode, MDS_INODELOCK_OPEN, mode))
                         bits &= ~MDS_INODELOCK_OPEN;
 
                 fid = ll_inode2fid(inode);
@@ -245,8 +246,9 @@ int ll_md_blocking_ast(struct ldlm_lock *lock, struct ldlm_lock_desc *desc,
                         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)) {
@@ -272,7 +274,7 @@ int ll_md_blocking_ast(struct ldlm_lock *lock, struct ldlm_lock_desc *desc,
 
 __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);
@@ -352,7 +354,7 @@ static struct dentry *ll_find_alias(struct inode *inode, struct dentry *de)
         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);
@@ -389,7 +391,7 @@ static struct dentry *ll_find_alias(struct inode *inode, struct dentry *de)
                 ll_dops_init(dentry, 0);
                 d_rehash_cond(dentry, 0); /* avoid taking dcache_lock inside */
                 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,
@@ -406,18 +408,20 @@ static struct dentry *ll_find_alias(struct inode *inode, struct dentry *de)
                 last_discon->d_flags |= DCACHE_LUSTRE_INVALID;
                 unlock_dentry(last_discon);
                 spin_unlock(&dcache_lock);
-                spin_unlock(&ll_lookup_lock);
+                cfs_spin_unlock(&ll_lookup_lock);
                 ll_dops_init(last_discon, 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;
 }
@@ -456,24 +460,19 @@ 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);
                 *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);
                 }
                 /* we have lookup look - unhide dentry */
                 if (bits & MDS_INODELOCK_LOOKUP) {
                         lock_dentry(*de);
-                        (*de)->d_flags &= ~(DCACHE_LUSTRE_INVALID);
+                        (*de)->d_flags &= ~DCACHE_LUSTRE_INVALID;
                         unlock_dentry(*de);
                 }
         } else {
@@ -481,7 +480,7 @@ int ll_lookup_it_finish(struct ptlrpc_request *request,
                 /* 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)) {
+                if (ll_have_md_lock(parent, MDS_INODELOCK_UPDATE, LCK_MINMODE)) {
                         spin_lock(&dcache_lock);
                         ll_d_add(*de, NULL);
                         spin_unlock(&dcache_lock);
@@ -534,7 +533,8 @@ 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));
         }
@@ -563,7 +563,7 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *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);
@@ -597,21 +597,6 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *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)
 {
@@ -625,7 +610,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;
@@ -658,11 +643,16 @@ static struct dentry *ll_lookup_nd(struct inode *parent, struct dentry *dentry,
                         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);
+                                RETURN(NULL);
+                        }
                         it = ll_convert_intent(&nd->intent.open, nd->flags);
                         if (IS_ERR(it))
                                 RETURN((struct dentry *)it);
@@ -728,43 +718,6 @@ static struct dentry *ll_lookup_nd(struct inode *parent, struct dentry *dentry,
 
         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,
@@ -787,7 +740,7 @@ 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,
@@ -833,12 +786,9 @@ static int ll_create_it(struct inode *dir, struct dentry *dentry, int mode,
 
         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
@@ -857,21 +807,15 @@ static void ll_update_times(struct ptlrpc_request *request,
                                                        &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,
@@ -895,7 +839,7 @@ 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)
@@ -910,8 +854,8 @@ static int ll_new_node(struct inode *dir, struct qstr *name,
 
                 d_drop(dchild);
                 d_instantiate(dchild, inode);
-                EXIT;
         }
+        EXIT;
 err_exit:
         ptlrpc_req_finished(request);
 
@@ -928,7 +872,7 @@ static int ll_mknod_generic(struct inode *dir, struct qstr *name, int mode,
                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:
@@ -950,7 +894,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)
 {
@@ -984,17 +927,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)
@@ -1054,7 +986,7 @@ static int ll_mkdir_generic(struct inode *dir, struct qstr *name,
         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);
@@ -1140,16 +1072,12 @@ int ll_objects_destroy(struct ptlrpc_request *request, struct inode *dir)
         }
         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;
 
@@ -1184,6 +1112,10 @@ int ll_objects_destroy(struct ptlrpc_request *request, struct inode *dir)
         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)
 {
@@ -1261,43 +1193,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)
 {
@@ -1346,17 +1241,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,
@@ -1377,9 +1261,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,