[RFC PATCH 2/2] xfs_export_operations.commit_metadata

Ben Myers
2010-02-10T00:33:38Z

Here is the commit_metadata export_operation for xfs. We take two dentries and
force the log up to the larger lsn. It looks to me that in nfsd the child is
always modified after the parent so generally we expect the child's lsn to be
larger. If that's not the case we'll just force the entire thing.

The basic form of this is based upon one of Christoph's suggestions. I'm an
xfs newbie so I'm not very comfortable with it yet. My understanding is that I
need to verify that all of the necessary changes make it into the transations
we're forcing into the log here. I am still looking into that and hopefully
the XFS gurus can continue to provide guidance.
---
fs/xfs/linux-2.6/xfs_export.c | 64 +++++++++++++++++++++++++++++++++++++++++
1 files changed, 64 insertions(+), 0 deletions(-)

diff --git a/fs/xfs/linux-2.6/xfs_export.c b/fs/xfs/linux-2.6/xfs_export.c
index 87b8cbd..af4a214 100644
--- a/fs/xfs/linux-2.6/xfs_export.c
+++ b/fs/xfs/linux-2.6/xfs_export.c
@@ -29,6 +29,7 @@
#include "xfs_vnodeops.h"
#include "xfs_bmap_btree.h"
#include "xfs_inode.h"
+#include "xfs_inode_item.h"

/*
* Note that we only accept fileids which are long enough rather than allow
@@ -215,9 +216,72 @@ xfs_fs_get_parent(
return d_obtain_alias(VFS_I(cip));
}

+STATIC int
+xfs_fs_nfs_commit_metadata(
+ struct dentry *parent,
+ struct dentry *child)
+{
+ struct xfs_inode *p_xip = NULL, *c_xip = NULL;
+ struct xfs_mount *i_mount = NULL;
+ xfs_lsn_t force_lsn = 0;
+ int error = 0;
+
+ if (parent && !child) {
+ p_xip = XFS_I(parent->d_inode);
+ xfs_ilock(p_xip, XFS_ILOCK_SHARED);
+ if (xfs_ipincount(p_xip)) {
+ force_lsn = p_xip->i_itemp->ili_last_lsn;
+ i_mount = p_xip->i_mount;
+ }
+ } else if (child && !parent) {
+ c_xip = XFS_I(child->d_inode);
+ xfs_ilock(c_xip, XFS_ILOCK_SHARED);
+ if (xfs_ipincount(c_xip)) {
+ force_lsn = c_xip->i_itemp->ili_last_lsn;
+ i_mount = c_xip->i_mount;
+ }
+ } else if (parent && child) {
+ p_xip = XFS_I(parent->d_inode);
+ c_xip = XFS_I(child->d_inode);
+ xfs_ilock(p_xip, XFS_ILOCK_SHARED);
+ xfs_ilock(c_xip, XFS_ILOCK_SHARED);
+ if (xfs_ipincount(p_xip)) {
+ force_lsn = p_xip->i_itemp->ili_last_lsn;
+ i_mount = p_xip->i_mount;
+ }
+ if (xfs_ipincount(c_xip)) {
+ /*
+ * AFAICS the child is always modified after the parent
+ * in nfsd so should always have a larger lsn.
+ */
+ if (c_xip->i_itemp->ili_last_lsn > force_lsn) {
+ force_lsn = c_xip->i_itemp->ili_last_lsn;
+ } else {
+ force_lsn = 0; /* whole thing */
+ }
+ i_mount = c_xip->i_mount;
+ }
+ } else {
+ return -EINVAL;
+ }
+
+ if (i_mount) {
+ error = _xfs_log_force(i_mount, force_lsn,
+ XFS_LOG_FORCE | XFS_LOG_SYNC, NULL);
+ }
+
+ if (child)
+ xfs_iunlock(c_xip, XFS_ILOCK_SHARED);
+ if (parent)
+ xfs_iunlock(p_xip, XFS_ILOCK_SHARED);
+
+ return error;
+}
+
const struct export_operations xfs_export_operations = {
.encode_fh = xfs_fs_encode_fh,
.fh_to_dentry = xfs_fs_fh_to_dentry,
.fh_to_parent = xfs_fs_fh_to_parent,
.get_parent = xfs_fs_get_parent,
+ .commit_metadata = xfs_fs_nfs_commit_metadata,
};