Return-Path: linux-nfs-owner@vger.kernel.org Received: from verein.lst.de ([213.95.11.211]:52213 "EHLO newverein.lst.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752850AbbBEN6A (ORCPT ); Thu, 5 Feb 2015 08:58:00 -0500 Date: Thu, 5 Feb 2015 14:57:56 +0100 From: Christoph Hellwig To: Dave Chinner Cc: Christoph Hellwig , "J. Bruce Fields" , Jeff Layton , linux-nfs@vger.kernel.org, linux-fsdevel@vger.kernel.org, xfs@oss.sgi.com Subject: Re: [PATCH 19/20] xfs: implement pNFS export operations Message-ID: <20150205135756.GA6386@lst.de> References: <1421925006-24231-1-git-send-email-hch@lst.de> <1421925006-24231-20-git-send-email-hch@lst.de> <20150205004758.GO4251@dastard> <20150205070858.GA593@lst.de> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii In-Reply-To: <20150205070858.GA593@lst.de> Sender: linux-nfs-owner@vger.kernel.org List-ID: I've updated the patch and pushed out a new pnfsd-for-3.20-4 branch. The changes relative to the old one are below: diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c index 99465ba..48561a0 100644 --- a/fs/xfs/xfs_fsops.c +++ b/fs/xfs/xfs_fsops.c @@ -602,8 +602,12 @@ xfs_growfs_data( if (!mutex_trylock(&mp->m_growlock)) return -EWOULDBLOCK; error = xfs_growfs_data_private(mp, in); - if (!error) - mp->m_generation++; + /* + * Increment the generation unconditionally, the error could be from + * updating the secondary superblocks, in which case the new size + * is live already. + */ + mp->m_generation++; mutex_unlock(&mp->m_growlock); return error; } diff --git a/fs/xfs/xfs_pnfs.c b/fs/xfs/xfs_pnfs.c index ab5ee78..7440b40 100644 --- a/fs/xfs/xfs_pnfs.c +++ b/fs/xfs/xfs_pnfs.c @@ -15,6 +15,7 @@ #include "xfs_error.h" #include "xfs_iomap.h" #include "xfs_shared.h" +#include "xfs_bit.h" #include "xfs_pnfs.h" /* @@ -48,6 +49,10 @@ xfs_break_layouts( return error; } +/* + * Get a uniqueue ID including its location so that the client can identify + * the exported device. + */ int xfs_fs_get_uuid( struct super_block *sb, @@ -57,6 +62,10 @@ xfs_fs_get_uuid( { struct xfs_mount *mp = XFS_M(sb); + printk_once(KERN_NOTICE +"XFS (%s): using experimental pNFS feature, use at your own risk!\n", + mp->m_fsname); + if (*len < sizeof(uuid_t)) return -EINVAL; @@ -75,13 +84,14 @@ xfs_bmbt_to_iomap( struct xfs_mount *mp = ip->i_mount; if (imap->br_startblock == HOLESTARTBLOCK) { - iomap->blkno = -1; + iomap->blkno = IOMAP_NULL_BLOCK; iomap->type = IOMAP_HOLE; } else if (imap->br_startblock == DELAYSTARTBLOCK) { - iomap->blkno = -1; + iomap->blkno = IOMAP_NULL_BLOCK; iomap->type = IOMAP_DELALLOC; } else { - iomap->blkno = xfs_fsb_to_db(ip, imap->br_startblock); + iomap->blkno = + XFS_FSB_TO_DADDR(ip->i_mount, imap->br_startblock); if (imap->br_state == XFS_EXT_UNWRITTEN) iomap->type = IOMAP_UNWRITTEN; else @@ -115,6 +125,12 @@ xfs_fs_map_blocks( if (XFS_FORCED_SHUTDOWN(mp)) return -EIO; + + /* + * We can't export inodes residing on the realtime device. The realtime + * device doesn't have a UUID to identify it, so the client has no way + * to find it. + */ if (XFS_IS_REALTIME_INODE(ip)) return -ENXIO; @@ -190,6 +206,32 @@ out_unlock: } /* + * Ensure the size update falls into a valid allocated block. + */ +static int +xfs_pnfs_validate_isize( + struct xfs_inode *ip, + xfs_off_t isize) +{ + struct xfs_bmbt_irec imap; + int nimaps = 1; + int error = 0; + + xfs_ilock(ip, XFS_ILOCK_SHARED); + error = xfs_bmapi_read(ip, XFS_B_TO_FSBT(ip->i_mount, isize - 1), 1, + &imap, &nimaps, 0); + xfs_iunlock(ip, XFS_ILOCK_SHARED); + if (error) + return error; + + if (imap.br_startblock == HOLESTARTBLOCK || + imap.br_startblock == DELAYSTARTBLOCK || + imap.br_state == XFS_EXT_UNWRITTEN) + return -EIO; + return 0; +} + +/* * Make sure the blocks described by maps are stable on disk. This includes * converting any unwritten extents, flushing the disk cache and updating the * time stamps. @@ -209,6 +251,7 @@ xfs_fs_commit_blocks( struct xfs_inode *ip = XFS_I(inode); struct xfs_mount *mp = ip->i_mount; struct xfs_trans *tp; + bool update_isize = false; int error, i; loff_t size; @@ -217,8 +260,10 @@ xfs_fs_commit_blocks( xfs_ilock(ip, XFS_IOLOCK_EXCL); size = i_size_read(inode); - if ((iattr->ia_valid & ATTR_SIZE) && iattr->ia_size > size) + if ((iattr->ia_valid & ATTR_SIZE) && iattr->ia_size > size) { + update_isize = true; size = iattr->ia_size; + } for (i = 0; i < nr_maps; i++) { u64 start, length, end; @@ -248,6 +293,12 @@ xfs_fs_commit_blocks( goto out_drop_iolock; } + if (update_isize) { + error = xfs_pnfs_validate_isize(ip, size); + if (error) + goto out_drop_iolock; + } + tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_NOT_SIZE); error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ichange, 0, 0); if (error) @@ -258,11 +309,9 @@ xfs_fs_commit_blocks( xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); xfs_setattr_time(ip, iattr); - if (iattr->ia_valid & ATTR_SIZE) { - if (iattr->ia_size > i_size_read(inode)) { - i_size_write(inode, iattr->ia_size); - ip->i_d.di_size = iattr->ia_size; - } + if (update_isize) { + i_size_write(inode, iattr->ia_size); + ip->i_d.di_size = iattr->ia_size; } xfs_trans_set_sync(tp); diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h index ff46bf7..fa05e04 100644 --- a/include/linux/exportfs.h +++ b/include/linux/exportfs.h @@ -187,6 +187,8 @@ struct fid { #define IOMAP_MAPPED 0x03 /* blocks allocated @blkno */ #define IOMAP_UNWRITTEN 0x04 /* blocks allocated @blkno in unwritten state */ +#define IOMAP_NULL_BLOCK -1LL /* blkno is not valid */ + struct iomap { sector_t blkno; /* first sector of mapping */ loff_t offset; /* file offset of mapping, bytes */