From mboxrd@z Thu Jan 1 00:00:00 1970 From: Dave Kleikamp Subject: [RFC] Support for stackable file systems on top of nfs Date: Thu, 10 Nov 2005 11:32:22 -0600 Message-ID: <1131643942.9389.17.camel@kleikamp.austin.ibm.com> Mime-Version: 1.0 Content-Type: text/plain Content-Transfer-Encoding: 7bit Return-path: Received: from e36.co.us.ibm.com ([32.97.110.154]:50573 "EHLO e36.co.us.ibm.com") by vger.kernel.org with ESMTP id S1751103AbVKJRcZ (ORCPT ); Thu, 10 Nov 2005 12:32:25 -0500 Received: from d03relay04.boulder.ibm.com (d03relay04.boulder.ibm.com [9.17.195.106]) by e36.co.us.ibm.com (8.12.11/8.12.11) with ESMTP id jAAHWP5C010312 for ; Thu, 10 Nov 2005 12:32:25 -0500 Received: from d03av01.boulder.ibm.com (d03av01.boulder.ibm.com [9.17.195.167]) by d03relay04.boulder.ibm.com (8.12.10/NCO/VERS6.8) with ESMTP id jAAHXalu069426 for ; Thu, 10 Nov 2005 10:33:36 -0700 Received: from d03av01.boulder.ibm.com (loopback [127.0.0.1]) by d03av01.boulder.ibm.com (8.12.11/8.13.3) with ESMTP id jAAHWOHY027006 for ; Thu, 10 Nov 2005 10:32:24 -0700 To: nfsv4 , fsdevel Sender: linux-fsdevel-owner@vger.kernel.org List-Id: linux-fsdevel.vger.kernel.org The following patch allows stackable file systems, such as ClearCase's mvfs, to run atop nfs. mvfs has it's own file and inode structures, but points its inode->i_mapping to the lower file system's mapping. This causes problems when nfs's address space operations try to extract the open context from file->private_data. The patch adds a small overhead of checking the file structure to see if it contains an inode that is not the mapping's host. I am curious if there are any other stackable file systems that could benefit from this. Signed-off-by: Dave Kleikamp diff -Nurp linux-2.6.14-git/fs/nfs/direct.c linux/fs/nfs/direct.c --- linux-2.6.14-git/fs/nfs/direct.c 2005-11-07 07:53:49.000000000 -0600 +++ linux/fs/nfs/direct.c 2005-11-09 14:58:59.000000000 -0600 @@ -604,7 +604,19 @@ nfs_direct_IO(int rw, struct kiocb *iocb if (!is_sync_kiocb(iocb)) return result; - ctx = (struct nfs_open_context *)file->private_data; + if (nfs_is_valid_file(file)) + ctx = get_nfs_open_context((struct nfs_open_context *) + file->private_data); + else { + /* file belongs to a stackable file system. + * Can't trust the inode either */ + inode = inode->i_mapping->host; + + ctx = nfs_find_open_context(inode, NULL, + (rw == READ) ? FMODE_READ : FMODE_WRITE); + if (ctx == NULL) + return -EBADF; + } switch (rw) { case READ: dprintk("NFS: direct_IO(read) (%s) off/no(%Lu/%lu)\n", @@ -623,6 +635,7 @@ nfs_direct_IO(int rw, struct kiocb *iocb default: break; } + put_nfs_open_context(ctx); return result; } diff -Nurp linux-2.6.14-git/fs/nfs/read.c linux/fs/nfs/read.c --- linux-2.6.14-git/fs/nfs/read.c 2005-11-07 07:53:49.000000000 -0600 +++ linux/fs/nfs/read.c 2005-11-09 11:47:05.000000000 -0600 @@ -506,7 +506,7 @@ int nfs_readpage(struct file *file, stru if (error) goto out_error; - if (file == NULL) { + if (!nfs_is_valid_file(file)) { ctx = nfs_find_open_context(inode, NULL, FMODE_READ); if (ctx == NULL) return -EBADF; @@ -575,7 +575,7 @@ int nfs_readpages(struct file *filp, str (long long)NFS_FILEID(inode), nr_pages); - if (filp == NULL) { + if (!nfs_is_valid_file(filp)) { desc.ctx = nfs_find_open_context(inode, NULL, FMODE_READ); if (desc.ctx == NULL) return -EBADF; diff -Nurp linux-2.6.14-git/fs/nfs/write.c linux/fs/nfs/write.c --- linux-2.6.14-git/fs/nfs/write.c 2005-11-07 07:53:49.000000000 -0600 +++ linux/fs/nfs/write.c 2005-11-09 14:14:33.000000000 -0600 @@ -703,10 +703,16 @@ static struct nfs_page * nfs_update_requ int nfs_flush_incompatible(struct file *file, struct page *page) { - struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data; + struct nfs_open_context *ctx; struct inode *inode = page->mapping->host; struct nfs_page *req; int status = 0; + + if (nfs_is_valid_file(file)) + ctx = (struct nfs_open_context *)file->private_data; + else + ctx = NULL; + /* * Look for a request corresponding to this page. If there * is one, and it belongs to another file, we flush it out @@ -733,7 +739,7 @@ int nfs_flush_incompatible(struct file * int nfs_updatepage(struct file *file, struct page *page, unsigned int offset, unsigned int count) { - struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data; + struct nfs_open_context *ctx; struct inode *inode = page->mapping->host; struct nfs_page *req; int status = 0; @@ -743,14 +749,23 @@ int nfs_updatepage(struct file *file, st file->f_dentry->d_name.name, count, (long long)(page_offset(page) +offset)); + if (nfs_is_valid_file(file)) + ctx = get_nfs_open_context((struct nfs_open_context *) + file->private_data); + else { + ctx = nfs_find_open_context(inode, NULL, FMODE_WRITE); + if (!ctx) + return -EBADF; + } + if (IS_SYNC(inode)) { status = nfs_writepage_sync(ctx, inode, page, offset, count, 0); if (status > 0) { if (offset == 0 && status == PAGE_CACHE_SIZE) SetPageUptodate(page); - return 0; + status = 0; } - return status; + goto out; } /* If we're not using byte range locks, and we know the page @@ -803,6 +818,8 @@ done: status, (long long)i_size_read(inode)); if (status < 0) ClearPageUptodate(page); +out: + put_nfs_open_context(ctx); return status; } diff -Nurp linux-2.6.14-git/include/linux/nfs_fs.h linux/include/linux/nfs_fs.h --- linux-2.6.14-git/include/linux/nfs_fs.h 2005-11-07 07:53:50.000000000 -0600 +++ linux/include/linux/nfs_fs.h 2005-11-09 11:44:53.000000000 -0600 @@ -350,6 +350,20 @@ static inline struct rpc_cred *nfs_file_ } /* + * A stackable file system may have it's own file & inode structures, which + * point to the local inode's mapping. The address space operations cannot + * use the stackable file system's file structure to get to the open context + */ +static inline int nfs_is_valid_file(struct file *file) +{ + struct inode *inode; + if (!file) + return 0; + inode = file->f_dentry->d_inode; + return (inode == inode->i_mapping->host); +} + +/* * linux/fs/nfs/xattr.c */ #ifdef CONFIG_NFS_V3_ACL -- David Kleikamp IBM Linux Technology Center