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, }; -- To unsubscribe from this list: send the line "unsubscribe linux-nfs" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html