Whamcloud - gitweb
LU-13124 scrub: check for multiple linked file
[fs/lustre-release.git] / lustre / osd-ldiskfs / osd_compat.c
index fed4238..7c8aee1 100644 (file)
@@ -27,7 +27,6 @@
  */
 /*
  * This file is part of Lustre, http://www.lustre.org/
- * Lustre is a trademark of Sun Microsystems, Inc.
  *
  * lustre/osd/osd_compat.c
  *
@@ -59,38 +58,45 @@ static void osd_push_ctxt(const struct osd_device *dev,
        OBD_SET_CTXT_MAGIC(newctxt);
        newctxt->pwdmnt = dev->od_mnt;
        newctxt->pwd = dev->od_mnt->mnt_root;
-       newctxt->fs = KERNEL_DS;
        newctxt->umask = current_umask();
        newctxt->dt = NULL;
 
        push_ctxt(save, newctxt);
 }
 
-/**
- * osd_lookup_one_len_unlocked
- *
- * @name:      pathname component to lookup
- * @base:      base directory to lookup from
- * @len:       maximum length @len should be interpreted to
- *
- * This should be called without the parent
- * i_mutex held, and will take the i_mutex itself.
- */
-struct dentry *osd_lookup_one_len_unlocked(const char *name,
-                                          struct dentry *base, int len)
+struct dentry *osd_lookup_one_len_common(struct osd_device *dev,
+                                        const char *name,
+                                        struct dentry *base, int len,
+                                        enum oi_check_flags flags)
 {
        struct dentry *dchild;
 
-       inode_lock(base->d_inode);
-       dchild = lookup_one_len(name, base, len);
-       inode_unlock(base->d_inode);
-
+       /*
+        * We can't use inode_is_locked() directly since we can't know
+        * if the current thread context took the lock earlier or if
+        * another thread context took the lock. OI_LOCKED tells us
+        * if the current thread context has already taken the lock.
+        */
+       if (!(flags & OI_LOCKED)) {
+               /* If another thread took this lock already we will
+                * just have to wait until the other thread is done.
+                */
+               inode_lock(base->d_inode);
+               dchild = lookup_one_len(name, base, len);
+               inode_unlock(base->d_inode);
+       } else {
+               /* This thread context already has taken the lock.
+                * Other threads will have to wait until we are done.
+                */
+               dchild = lookup_one_len(name, base, len);
+       }
        if (IS_ERR(dchild))
                return dchild;
 
        if (dchild->d_inode && unlikely(is_bad_inode(dchild->d_inode))) {
-               CERROR("bad inode returned %lu/%u\n",
-                      dchild->d_inode->i_ino, dchild->d_inode->i_generation);
+               CERROR("%s: bad inode returned %lu/%u: rc = -ENOENT\n",
+                      osd_name(dev), dchild->d_inode->i_ino,
+                      dchild->d_inode->i_generation);
                dput(dchild);
                dchild = ERR_PTR(-ENOENT);
        }
@@ -99,16 +105,37 @@ struct dentry *osd_lookup_one_len_unlocked(const char *name,
 }
 
 /**
- * osd_ios_lookup_one_len - lookup single pathname component
+ * osd_lookup_one_len_unlocked
+ *
+ * @dev:       obd device we are searching
+ * @name:      pathname component to lookup
+ * @base:      base directory to lookup from
+ * @len:       maximum length @len should be interpreted to
+ *
+ * Unlike osd_lookup_one_len, this should be called without the parent
+ * i_mutex held, and will take the i_mutex itself.
+ */
+struct dentry *osd_lookup_one_len_unlocked(struct osd_device *dev,
+                                          const char *name,
+                                          struct dentry *base, int len)
+{
+       return osd_lookup_one_len_common(dev, name, base, len, ~OI_LOCKED);
+}
+
+/**
+ * osd_lookup_one_len - lookup single pathname component
  *
+ * @dev:       obd device we are searching
  * @name:      pathname component to lookup
  * @base:      base directory to lookup from
  * @len:       maximum length @len should be interpreted to
+ *
+ * The caller must hold inode lock
  */
-struct dentry *osd_ios_lookup_one_len(const char *name, struct dentry *base,
-                                     int len)
+struct dentry *osd_lookup_one_len(struct osd_device *dev, const char *name,
+                                 struct dentry *base, int len)
 {
-       return osd_lookup_one_len_unlocked(name, base, len);
+       return osd_lookup_one_len_common(dev, name, base, len, OI_LOCKED);
 }
 
 /* utility to make a directory */
@@ -127,7 +154,7 @@ simple_mkdir(const struct lu_env *env, struct osd_device *osd,
 
        // ASSERT_KERNEL_CTXT("kernel doing mkdir outside kernel context\n");
        CDEBUG(D_INODE, "creating directory %.*s\n", (int)strlen(name), name);
-       dchild = osd_lookup_one_len_unlocked(name, dir, strlen(name));
+       dchild = osd_lookup_one_len_unlocked(osd, name, dir, strlen(name));
        if (IS_ERR(dchild))
                RETURN(dchild);
 
@@ -207,7 +234,7 @@ static int osd_last_rcvd_subdir_count(struct osd_device *osd)
 
        ENTRY;
 
-       dlast = osd_lookup_one_len_unlocked(LAST_RCVD, osd_sb(osd)->s_root,
+       dlast = osd_lookup_one_len_unlocked(osd, LAST_RCVD, osd_sb(osd)->s_root,
                                            strlen(LAST_RCVD));
        if (IS_ERR(dlast))
                return PTR_ERR(dlast);
@@ -517,8 +544,8 @@ static void osd_seq_free(struct osd_obj_seq *osd_seq)
                        if (osd_seq->oos_dirs[j])
                                dput(osd_seq->oos_dirs[j]);
                }
-               OBD_FREE(osd_seq->oos_dirs,
-                        sizeof(struct dentry *) * osd_seq->oos_subdir_count);
+               OBD_FREE_PTR_ARRAY(osd_seq->oos_dirs,
+                                  osd_seq->oos_subdir_count);
        }
 
        if (osd_seq->oos_root)
@@ -582,10 +609,8 @@ static int osd_index_backup_dir_init(const struct lu_env *env,
 
 static void osd_index_backup_dir_fini(struct osd_device *dev)
 {
-       if (dev->od_index_backup_inode) {
-               iput(dev->od_index_backup_inode);
-               dev->od_index_backup_inode = NULL;
-       }
+       iput(dev->od_index_backup_inode);
+       dev->od_index_backup_inode = NULL;
 }
 
 int osd_obj_map_init(const struct lu_env *env, struct osd_device *dev)
@@ -801,10 +826,9 @@ out:
        return rc;
 }
 
-static int osd_obj_del_entry(struct osd_thread_info *info,
-                            struct osd_device *osd,
-                            struct dentry *dird, char *name,
-                            handle_t *th)
+int osd_obj_del_entry(struct osd_thread_info *info, struct osd_device *osd,
+                     struct dentry *dird, char *name, int namelen,
+                     handle_t *th)
 {
        struct ldiskfs_dir_entry_2 *de;
        struct buffer_head *bh;
@@ -820,7 +844,7 @@ static int osd_obj_del_entry(struct osd_thread_info *info,
        child = &info->oti_child_dentry;
        child->d_name.hash = 0;
        child->d_name.name = name;
-       child->d_name.len = strlen(name);
+       child->d_name.len = namelen;
        child->d_parent = dird;
        child->d_inode = NULL;
 
@@ -903,15 +927,6 @@ static inline void osd_seq_name(char *seq_name, size_t name_size, u64 seq)
                 fid_seq_is_idif(seq) ? 0 : seq);
 }
 
-static inline void osd_oid_name(char *name, size_t name_size,
-                               const struct lu_fid *fid, u64 id)
-{
-       snprintf(name, name_size,
-                (fid_seq_is_rsvd(fid_seq(fid)) ||
-                 fid_seq_is_mdt0(fid_seq(fid)) ||
-                 fid_seq_is_idif(fid_seq(fid))) ? "%llu" : "%llx", id);
-}
-
 /* external locking is required */
 static int osd_seq_load_locked(struct osd_thread_info *info,
                               struct osd_device *osd,
@@ -943,8 +958,7 @@ static int osd_seq_load_locked(struct osd_thread_info *info,
        osd_seq->oos_root = seq_dir;
 
        LASSERT(osd_seq->oos_dirs == NULL);
-       OBD_ALLOC(osd_seq->oos_dirs,
-                 sizeof(seq_dir) * osd_seq->oos_subdir_count);
+       OBD_ALLOC_PTR_ARRAY(osd_seq->oos_dirs, osd_seq->oos_subdir_count);
        if (osd_seq->oos_dirs == NULL)
                GOTO(out_put, rc = -ENOMEM);
 
@@ -971,8 +985,8 @@ out_free:
                        if (osd_seq->oos_dirs[i] != NULL)
                                dput(osd_seq->oos_dirs[i]);
                }
-               OBD_FREE(osd_seq->oos_dirs,
-                        sizeof(seq_dir) * osd_seq->oos_subdir_count);
+               OBD_FREE_PTR_ARRAY(osd_seq->oos_dirs,
+                                  osd_seq->oos_subdir_count);
 out_put:
                dput(seq_dir);
                osd_seq->oos_root = NULL;
@@ -981,8 +995,8 @@ out_err:
        RETURN(rc);
 }
 
-static struct osd_obj_seq *osd_seq_load(struct osd_thread_info *info,
-                                       struct osd_device *osd, u64 seq)
+struct osd_obj_seq *osd_seq_load(struct osd_thread_info *info,
+                                struct osd_device *osd, u64 seq)
 {
        struct osd_obj_map *map;
        struct osd_obj_seq *osd_seq;
@@ -1176,7 +1190,7 @@ int osd_obj_map_delete(struct osd_thread_info *info, struct osd_device *osd,
        LASSERT(d);
 
        osd_oid_name(name, sizeof(name), fid, ostid_id(ostid));
-       rc = osd_obj_del_entry(info, osd, d, name, th);
+       rc = osd_obj_del_entry(info, osd, d, name, strlen(name), th);
 cleanup:
        RETURN(rc);
 }
@@ -1269,7 +1283,6 @@ int osd_obj_map_recover(struct osd_thread_info *info,
        dquot_initialize(src_parent);
        dquot_initialize(dir);
 
-       inode_lock(src_parent);
        inode_lock(dir);
        bh = osd_ldiskfs_find_entry(dir, &tgt_child->d_name, &de, NULL, NULL);
        if (!IS_ERR(bh)) {
@@ -1294,7 +1307,6 @@ int osd_obj_map_recover(struct osd_thread_info *info,
                 */
                brelse(bh);
                inode_unlock(dir);
-               inode_unlock(src_parent);
                ldiskfs_journal_stop(jh);
 
                rc = -EEXIST;
@@ -1325,7 +1337,6 @@ int osd_obj_map_recover(struct osd_thread_info *info,
 
 unlock:
        inode_unlock(dir);
-       inode_unlock(src_parent);
        ldiskfs_journal_stop(jh);
        return rc;
 }
@@ -1402,7 +1413,8 @@ int osd_obj_spec_insert(struct osd_thread_info *info, struct osd_device *osd,
 }
 
 int osd_obj_spec_lookup(struct osd_thread_info *info, struct osd_device *osd,
-                       const struct lu_fid *fid, struct osd_inode_id *id)
+                       const struct lu_fid *fid, struct osd_inode_id *id,
+                       enum oi_check_flags flags)
 {
        struct dentry *root;
        struct dentry *dentry;
@@ -1427,7 +1439,8 @@ int osd_obj_spec_lookup(struct osd_thread_info *info, struct osd_device *osd,
                        RETURN(-ENOENT);
        }
 
-       dentry = osd_lookup_one_len_unlocked(name, root, strlen(name));
+       dentry = osd_lookup_one_len_common(osd, name, root, strlen(name),
+                                          flags);
        if (!IS_ERR(dentry)) {
                inode = dentry->d_inode;
                if (inode) {