summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/ocfs2/cluster/tcp_internal.h5
-rw-r--r--fs/ocfs2/export.c4
-rw-r--r--fs/ocfs2/inode.c10
-rw-r--r--fs/ocfs2/namei.c116
4 files changed, 94 insertions, 41 deletions
diff --git a/fs/ocfs2/cluster/tcp_internal.h b/fs/ocfs2/cluster/tcp_internal.h
index ff9e2e2104c2..da42b515cd1d 100644
--- a/fs/ocfs2/cluster/tcp_internal.h
+++ b/fs/ocfs2/cluster/tcp_internal.h
@@ -44,11 +44,14 @@
* locking semantics of the file system using the protocol. It should
* be somewhere else, I'm sure, but right now it isn't.
*
+ * New in version 3:
+ * - Replace dentry votes with a cluster lock
+ *
* New in version 2:
* - full 64 bit i_size in the metadata lock lvbs
* - introduction of "rw" lock and pushing meta/data locking down
*/
-#define O2NET_PROTOCOL_VERSION 2ULL
+#define O2NET_PROTOCOL_VERSION 3ULL
struct o2net_handshake {
__be64 protocol_version;
__be64 connector_id;
diff --git a/fs/ocfs2/export.c b/fs/ocfs2/export.c
index ec55ab3c1214..ffcd79749e0d 100644
--- a/fs/ocfs2/export.c
+++ b/fs/ocfs2/export.c
@@ -33,6 +33,7 @@
#include "dir.h"
#include "dlmglue.h"
+#include "dcache.h"
#include "export.h"
#include "inode.h"
@@ -77,6 +78,7 @@ static struct dentry *ocfs2_get_dentry(struct super_block *sb, void *vobjp)
mlog_errno(-ENOMEM);
return ERR_PTR(-ENOMEM);
}
+ result->d_op = &ocfs2_dentry_ops;
mlog_exit_ptr(result);
return result;
@@ -127,6 +129,8 @@ static struct dentry *ocfs2_get_parent(struct dentry *child)
parent = ERR_PTR(-ENOMEM);
}
+ parent->d_op = &ocfs2_dentry_ops;
+
bail_unlock:
ocfs2_meta_unlock(dir, 0);
diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c
index 7bcf69154592..66ca7a82b68a 100644
--- a/fs/ocfs2/inode.c
+++ b/fs/ocfs2/inode.c
@@ -1025,12 +1025,10 @@ void ocfs2_drop_inode(struct inode *inode)
/* Testing ip_orphaned_slot here wouldn't work because we may
* not have gotten a delete_inode vote from any other nodes
* yet. */
- if (oi->ip_flags & OCFS2_INODE_MAYBE_ORPHANED) {
- mlog(0, "Inode was orphaned on another node, clearing nlink.\n");
- inode->i_nlink = 0;
- }
-
- generic_drop_inode(inode);
+ if (oi->ip_flags & OCFS2_INODE_MAYBE_ORPHANED)
+ generic_delete_inode(inode);
+ else
+ generic_drop_inode(inode);
mlog_exit_void();
}
diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c
index 0d3e939b1f56..5a942e0123ea 100644
--- a/fs/ocfs2/namei.c
+++ b/fs/ocfs2/namei.c
@@ -199,10 +199,32 @@ static struct dentry *ocfs2_lookup(struct inode *dir, struct dentry *dentry,
spin_unlock(&oi->ip_lock);
bail_add:
-
dentry->d_op = &ocfs2_dentry_ops;
ret = d_splice_alias(inode, dentry);
+ if (inode) {
+ /*
+ * If d_splice_alias() finds a DCACHE_DISCONNECTED
+ * dentry, it will d_move() it on top of ourse. The
+ * return value will indicate this however, so in
+ * those cases, we switch them around for the locking
+ * code.
+ *
+ * NOTE: This dentry already has ->d_op set from
+ * ocfs2_get_parent() and ocfs2_get_dentry()
+ */
+ if (ret)
+ dentry = ret;
+
+ status = ocfs2_dentry_attach_lock(dentry, inode,
+ OCFS2_I(dir)->ip_blkno, 0);
+ if (status) {
+ mlog_errno(status);
+ ret = ERR_PTR(status);
+ goto bail_unlock;
+ }
+ }
+
bail_unlock:
/* Don't drop the cluster lock until *after* the d_add --
* unlink on another node will message us to remove that
@@ -418,6 +440,13 @@ static int ocfs2_mknod(struct inode *dir,
goto leave;
}
+ status = ocfs2_dentry_attach_lock(dentry, inode,
+ OCFS2_I(dir)->ip_blkno, 1);
+ if (status) {
+ mlog_errno(status);
+ goto leave;
+ }
+
insert_inode_hash(inode);
dentry->d_op = &ocfs2_dentry_ops;
d_instantiate(dentry, inode);
@@ -725,6 +754,13 @@ static int ocfs2_link(struct dentry *old_dentry,
goto bail;
}
+ err = ocfs2_dentry_attach_lock(dentry, inode, OCFS2_I(dir)->ip_blkno,
+ 0);
+ if (err) {
+ mlog_errno(err);
+ goto bail;
+ }
+
atomic_inc(&inode->i_count);
dentry->d_op = &ocfs2_dentry_ops;
d_instantiate(dentry, inode);
@@ -743,6 +779,23 @@ bail:
return err;
}
+/*
+ * Takes and drops an exclusive lock on the given dentry. This will
+ * force other nodes to drop it.
+ */
+static int ocfs2_remote_dentry_delete(struct dentry *dentry)
+{
+ int ret;
+
+ ret = ocfs2_dentry_lock(dentry, 1);
+ if (ret)
+ mlog_errno(ret);
+ else
+ ocfs2_dentry_unlock(dentry, 1);
+
+ return ret;
+}
+
static int ocfs2_unlink(struct inode *dir,
struct dentry *dentry)
{
@@ -832,8 +885,7 @@ static int ocfs2_unlink(struct inode *dir,
else
inode->i_nlink--;
- status = ocfs2_request_unlink_vote(inode, dentry,
- (unsigned int) inode->i_nlink);
+ status = ocfs2_remote_dentry_delete(dentry);
if (status < 0) {
/* This vote should succeed under all normal
* circumstances. */
@@ -1019,7 +1071,6 @@ static int ocfs2_rename(struct inode *old_dir,
struct buffer_head *old_inode_de_bh = NULL; // if old_dentry is a dir,
// this is the 1st dirent bh
nlink_t old_dir_nlink = old_dir->i_nlink, new_dir_nlink = new_dir->i_nlink;
- unsigned int links_count;
/* At some point it might be nice to break this function up a
* bit. */
@@ -1093,23 +1144,26 @@ static int ocfs2_rename(struct inode *old_dir,
}
}
- if (S_ISDIR(old_inode->i_mode)) {
- /* Directories actually require metadata updates to
- * the directory info so we can't get away with not
- * doing node locking on it. */
- status = ocfs2_meta_lock(old_inode, handle, NULL, 1);
- if (status < 0) {
- if (status != -ENOENT)
- mlog_errno(status);
- goto bail;
- }
-
- status = ocfs2_request_rename_vote(old_inode, old_dentry);
- if (status < 0) {
+ /*
+ * Though we don't require an inode meta data update if
+ * old_inode is not a directory, we lock anyway here to ensure
+ * the vote thread on other nodes won't have to concurrently
+ * downconvert the inode and the dentry locks.
+ */
+ status = ocfs2_meta_lock(old_inode, handle, NULL, 1);
+ if (status < 0) {
+ if (status != -ENOENT)
mlog_errno(status);
- goto bail;
- }
+ goto bail;
+ }
+
+ status = ocfs2_remote_dentry_delete(old_dentry);
+ if (status < 0) {
+ mlog_errno(status);
+ goto bail;
+ }
+ if (S_ISDIR(old_inode->i_mode)) {
status = -EIO;
old_inode_de_bh = ocfs2_bread(old_inode, 0, &status, 0);
if (!old_inode_de_bh)
@@ -1123,14 +1177,6 @@ static int ocfs2_rename(struct inode *old_dir,
if (!new_inode && new_dir!=old_dir &&
new_dir->i_nlink >= OCFS2_LINK_MAX)
goto bail;
- } else {
- /* Ah, the simple case - we're a file so just send a
- * message. */
- status = ocfs2_request_rename_vote(old_inode, old_dentry);
- if (status < 0) {
- mlog_errno(status);
- goto bail;
- }
}
status = -ENOENT;
@@ -1202,13 +1248,7 @@ static int ocfs2_rename(struct inode *old_dir,
goto bail;
}
- if (S_ISDIR(new_inode->i_mode))
- links_count = 0;
- else
- links_count = (unsigned int) (new_inode->i_nlink - 1);
-
- status = ocfs2_request_unlink_vote(new_inode, new_dentry,
- links_count);
+ status = ocfs2_remote_dentry_delete(new_dentry);
if (status < 0) {
mlog_errno(status);
goto bail;
@@ -1387,6 +1427,7 @@ static int ocfs2_rename(struct inode *old_dir,
}
}
+ ocfs2_dentry_move(old_dentry, new_dentry, old_dir, new_dir);
status = 0;
bail:
if (rename_lock)
@@ -1675,6 +1716,13 @@ static int ocfs2_symlink(struct inode *dir,
goto bail;
}
+ status = ocfs2_dentry_attach_lock(dentry, inode,
+ OCFS2_I(dir)->ip_blkno, 1);
+ if (status) {
+ mlog_errno(status);
+ goto bail;
+ }
+
insert_inode_hash(inode);
dentry->d_op = &ocfs2_dentry_ops;
d_instantiate(dentry, inode);