| From: |
| Dave Kleikamp <shaggy@austin.ibm.com> |
| To: |
| nfsv4 <nfsv4@linux-nfs.org>,
fsdevel <linux-fsdevel@vger.kernel.org> |
| Subject: |
| [RFC] Support for stackable file systems on top of nfs |
| Date: |
| Thu, 10 Nov 2005 11:32:22 -0600 |
| Archive-link: |
| Article,
Thread
|
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 <shaggy@austin.ibm.com>
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
-
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html