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);
-
- if (IS_ERR(dchild) || dchild->d_inode == NULL)
+ /*
+ * 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 (is_bad_inode(dchild->d_inode)) {
- CERROR("bad inode returned %lu/%u\n",
- dchild->d_inode->i_ino, dchild->d_inode->i_generation);
+ if (dchild->d_inode && unlikely(is_bad_inode(dchild->d_inode))) {
+ 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);
}
}
/**
- * 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_ios_lookup_one_len(const char *name, struct dentry *base,
- int len)
+struct dentry *osd_lookup_one_len_unlocked(struct osd_device *dev,
+ const char *name,
+ struct dentry *base, int len)
{
- struct dentry *dentry;
-
- dentry = osd_lookup_one_len_unlocked(name, base, len);
- if (IS_ERR(dentry)) {
- int rc = PTR_ERR(dentry);
-
- if (rc != -ENOENT)
- CERROR("Fail to find %.*s in %.*s (%lu/%u): rc = %d\n",
- len, name, base->d_name.len,
- base->d_name.name, base->d_inode->i_ino,
- base->d_inode->i_generation, rc);
-
- return dentry;
- }
+ return osd_lookup_one_len_common(dev, name, base, len, ~OI_LOCKED);
+}
- return dentry;
+/**
+ * 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_lookup_one_len(struct osd_device *dev, const char *name,
+ struct dentry *base, int len)
+{
+ return osd_lookup_one_len_common(dev, name, base, len, OI_LOCKED);
}
/* utility to make a directory */
// 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);
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);
RETURN(-ENOENT);
}
- dentry = osd_lookup_one_len_unlocked(name, root, strlen(name));
+ dentry = osd_lookup_one_len_unlocked(osd, name, root, strlen(name));
if (!IS_ERR(dentry)) {
inode = dentry->d_inode;
if (inode) {