Whamcloud - gitweb
b=18857
[fs/lustre-release.git] / lustre / llite / namei.c
index 1bd7c2c..5795c40 100644 (file)
@@ -41,6 +41,8 @@
 #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
 
@@ -123,22 +125,28 @@ struct inode *ll_iget(struct super_block *sb, ino_t hash,
         if (inode) {
                 lli = ll_i2info(inode);
                 if (inode->i_state & I_NEW) {
+                        int rc;
+
                         ll_read_inode2(inode, md);
-                        unlock_new_inode(inode);
-                } else {
-                        if (!(inode->i_state & (I_FREEING | I_CLEAR)))
+                        rc = cl_inode_init(inode, md);
+                        if (rc != 0) {
+                                md->lsm = NULL;
+                                make_bad_inode(inode);
+                                unlock_new_inode(inode);
+                                iput(inode);
+                                inode = ERR_PTR(rc);
+                        } else
+                                unlock_new_inode(inode);
+                } else if (!(inode->i_state & (I_FREEING | I_CLEAR)))
                                 ll_update_inode(inode, md);
-                }
-                CDEBUG(D_VFSTRACE, "got inode: %lu/%u(%p) for "DFID"\n",
-                       inode->i_ino, inode->i_generation, inode,
-                       PFID(&lli->lli_fid));
+                CDEBUG(D_VFSTRACE, "got inode: %p for "DFID"\n",
+                       inode, PFID(&md->body->fid1));
         }
-
         RETURN(inode);
 }
 
 static void ll_drop_negative_dentry(struct inode *dir)
-{ 
+{
         struct dentry *dentry, *tmp_alias, *tmp_subdir;
 
         spin_lock(&ll_lookup_lock);
@@ -336,7 +344,7 @@ static 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);
         spin_lock(&dcache_lock);
         list_for_each(tmp, &inode->i_dentry) {
@@ -374,6 +382,7 @@ static struct dentry *ll_find_alias(struct inode *inode, struct dentry *de)
                 dentry->d_flags &= ~DCACHE_LUSTRE_INVALID;
 #endif
                 unlock_dentry(dentry);
+                ll_dops_init(dentry, 0);
                 d_rehash_cond(dentry, 0); /* avoid taking dcache_lock inside */
                 spin_unlock(&dcache_lock);
                 spin_unlock(&ll_lookup_lock);
@@ -391,6 +400,7 @@ static struct dentry *ll_find_alias(struct inode *inode, struct dentry *de)
                 dget_locked(last_discon);
                 spin_unlock(&dcache_lock);
                 spin_unlock(&ll_lookup_lock);
+                ll_dops_init(last_discon, 1);
                 d_rehash(de);
                 d_move(last_discon, de);
                 iput(inode);
@@ -405,34 +415,6 @@ static struct dentry *ll_find_alias(struct inode *inode, struct dentry *de)
         return de;
 }
 
-static inline void ll_dop_init(struct dentry *de, int *set)
-{
-        lock_dentry(de);
-        if (likely(de->d_op != &ll_d_ops)) {
-                de->d_op = &ll_init_d_ops;
-                *set = 1;
-        }
-        unlock_dentry(de);
-}
-
-static inline void ll_dop_fini(struct dentry *de, int succ)
-{
-        lock_dentry(de);
-        if (likely(de->d_op == &ll_init_d_ops)) {
-                if (succ)
-                        de->d_op = &ll_d_ops;
-                else
-                        de->d_op = &ll_fini_d_ops;
-                unlock_dentry(de);
-                smp_wmb();
-                ll_d_wakeup(de);
-        } else {
-                if (succ)
-                        de->d_op = &ll_d_ops;
-                unlock_dentry(de);
-        }
-}
-
 int ll_lookup_it_finish(struct ptlrpc_request *request,
                      struct lookup_intent *it, void *data)
 {
@@ -441,22 +423,17 @@ int ll_lookup_it_finish(struct ptlrpc_request *request,
         struct inode *parent = icbd->icbd_parent;
         struct ll_sb_info *sbi = ll_i2sbi(parent);
         struct inode *inode = NULL;
-        int set = 0, rc;
+        int rc;
         ENTRY;
 
-        ll_dop_init(*de, &set);
-
         /* NB 1 request reference will be taken away by ll_intent_lock()
          * when I return */
         if (!it_disposition(it, DISP_LOOKUP_NEG)) {
                 struct dentry *save = *de;
 
                 rc = ll_prep_inode(&inode, request, (*de)->d_sb);
-                if (rc) {
-                        if (set)
-                                ll_dop_fini(*de, 0);
+                if (rc)
                         RETURN(rc);
-                }
 
                 CDEBUG(D_DLMTRACE, "setting l_data to inode %p (%lu/%u)\n",
                        inode, inode->i_ino, inode->i_generation);
@@ -469,19 +446,30 @@ int ll_lookup_it_finish(struct ptlrpc_request *request,
                    2.4 and
                    vfs_getattr_it->ll_getattr()->ll_inode_revalidate_it() in 2.6
                    Everybody else who needs correct file size would call
-                   ll_glimpse_size or some equivalent themselves anyway.
+                   cl_glimpse_size or some equivalent themselves anyway.
                    Also see bug 7198. */
 
+                ll_dops_init(*de, 1);
                 *de = ll_find_alias(inode, *de);
-                if (set && *de != save)
-                        ll_dop_fini(save, 0);
+                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;
+                        }
+                }
         } else {
+                ll_dops_init(*de, 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)) {
                         spin_lock(&dcache_lock);
-                        ll_d_add(*de, inode);
+                        ll_d_add(*de, NULL);
                         spin_unlock(&dcache_lock);
                 } else {
                         (*de)->d_inode = NULL;
@@ -495,10 +483,6 @@ int ll_lookup_it_finish(struct ptlrpc_request *request,
                 }
         }
 
-        ll_set_dd(*de);
-
-        ll_dop_fini(*de, 1);
-
         RETURN(0);
 }
 
@@ -511,7 +495,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;
+        int rc, first = 0;
         ENTRY;
 
         if (dentry->d_name.len > ll_i2sbi(parent)->ll_namelen)
@@ -536,10 +520,10 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry,
         }
 
         if (it->it_op == IT_GETATTR) {
-                rc = ll_statahead_enter(parent, &dentry, 1);
-                if (rc >= 0) {
-                        ll_statahead_exit(dentry, rc);
-                        if (rc == 1)
+                first = ll_statahead_enter(parent, &dentry, 1);
+                if (first >= 0) {
+                        ll_statahead_exit(dentry, first);
+                        if (first == 1)
                                 RETURN(retval = dentry);
                 }
         }
@@ -573,6 +557,9 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry,
                 GOTO(out, retval = ERR_PTR(rc));
         }
 
+        if (first == -EEXIST)
+                ll_statahead_mark(dentry);
+
         if ((it->it_op & IT_OPEN) && dentry->d_inode &&
             !S_ISREG(dentry->d_inode->i_mode) &&
             !S_ISDIR(dentry->d_inode->i_mode)) {
@@ -675,19 +662,23 @@ static struct dentry *ll_lookup_nd(struct inode *parent, struct dentry *dentry,
                                                        (struct ptlrpc_request *)
                                                           it->d.lustre.it_data);
                                 } else {
-                                        struct file *filp;
-                                        nd->intent.open.file->private_data = it;
-                                        filp =lookup_instantiate_filp(nd,dentry,
-                                                                      NULL);
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17))
 /* 2.6.1[456] have a bug in open_namei() that forgets to check
  * nd->intent.open.file for error, so we need to return it as lookup's result
  * instead */
+                                        struct file *filp;
+                                        nd->intent.open.file->private_data = it;
+                                        filp =lookup_instantiate_filp(nd,dentry,
+                                                                      NULL);
                                         if (IS_ERR(filp)) {
                                                 if (de)
                                                         dput(de);
                                                 de = (struct dentry *) filp;
                                         }
+#else
+                                        nd->intent.open.file->private_data = it;
+                                        (void)lookup_instantiate_filp(nd,dentry,
+                                                                      NULL);
 #endif
 
                                 }
@@ -719,6 +710,42 @@ static struct dentry *ll_lookup_nd(struct inode *parent, struct dentry *dentry,
 }
 #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,
                                     int namelen, const void *data, int datalen,
@@ -740,7 +767,7 @@ static struct inode *ll_create_node(struct inode *dir, const char *name,
         if (rc)
                 GOTO(out, inode = ERR_PTR(rc));
 
-        LASSERT(list_empty(&inode->i_dentry));
+        ll_validate_new_inode(inode);
 
         /* We asked for a lock on the directory, but were granted a
          * lock on the inode.  Since we finally have an inode pointer,
@@ -790,6 +817,8 @@ static int ll_create_it(struct inode *dir, struct dentry *dentry, int mode,
                 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
@@ -847,7 +876,7 @@ static int ll_new_node(struct inode *dir, struct qstr *name,
 
         err = md_create(sbi->ll_md_exp, op_data, tgt, tgt_len, mode,
                         current->fsuid, current->fsgid,
-                        current->cap_effective, rdev, &request);
+                        cfs_curproc_cap_pack(), rdev, &request);
         ll_finish_md_op_data(op_data);
         if (err)
                 GOTO(err_exit, err);
@@ -1017,7 +1046,7 @@ static void ll_get_child_fid(struct inode * dir, struct qstr *name,
                              struct lu_fid *fid)
 {
         struct dentry *parent, *child;
-        
+
         parent = list_entry(dir->i_dentry.next, struct dentry, d_alias);
         child = d_lookup(parent, name);
         if (child) {
@@ -1034,7 +1063,7 @@ static int ll_rmdir_generic(struct inode *dir, struct dentry *dparent,
         struct md_op_data *op_data;
         int rc;
         ENTRY;
-        
+
         CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s,dir=%lu/%u(%p)\n",
                name->len, name->name, dir->i_ino, dir->i_generation, dir);
 
@@ -1062,6 +1091,7 @@ int ll_objects_destroy(struct ptlrpc_request *request, struct inode *dir)
         struct lov_stripe_md *lsm = NULL;
         struct obd_trans_info oti = { 0 };
         struct obdo *oa;
+        struct obd_capa *oc = NULL;
         int rc;
         ENTRY;
 
@@ -1105,7 +1135,7 @@ int ll_objects_destroy(struct ptlrpc_request *request, struct inode *dir)
 
         if (body->valid & OBD_MD_FLCOOKIE) {
                 oa->o_valid |= OBD_MD_FLCOOKIE;
-                oti.oti_logcookies = 
+                oti.oti_logcookies =
                         req_capsule_server_sized_get(&request->rq_pill,
                                                      &RMF_LOGCOOKIES,
                                                    sizeof(struct llog_cookie) *
@@ -1116,7 +1146,14 @@ int ll_objects_destroy(struct ptlrpc_request *request, struct inode *dir)
                 }
         }
 
-        rc = obd_destroy(ll_i2dtexp(dir), oa, lsm, &oti, ll_i2mdexp(dir));
+        if (body->valid & OBD_MD_FLOSSCAPA) {
+                rc = md_unpack_capa(ll_i2mdexp(dir), request, &RMF_CAPA2, &oc);
+                if (rc)
+                        GOTO(out_free_memmd, rc);
+        }
+
+        rc = obd_destroy(ll_i2dtexp(dir), oa, lsm, &oti, ll_i2mdexp(dir), oc);
+        capa_put(oc);
         OBDO_FREE(oa);
         if (rc)
                 CERROR("obd destroy objid "LPX64" error %d\n",