[PATCH 18/29] Unionfs: address-space operations
Includes writepage, writepages, readpage, prepare_write, and commit_write. Signed-off-by: Erez Zadok <[EMAIL PROTECTED]> --- fs/unionfs/mmap.c | 343 + 1 files changed, 343 insertions(+), 0 deletions(-) create mode 100644 fs/unionfs/mmap.c diff --git a/fs/unionfs/mmap.c b/fs/unionfs/mmap.c new file mode 100644 index 000..ad770ac --- /dev/null +++ b/fs/unionfs/mmap.c @@ -0,0 +1,343 @@ +/* + * Copyright (c) 2003-2007 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2007 Josef 'Jeff' Sipek + * Copyright (c) 2005-2006 Junjiro Okajima + * Copyright (c) 2006 Shaya Potter + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2004-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2007 Stony Brook University + * Copyright (c) 2003-2007 The Research Foundation of SUNY + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "union.h" + +static int unionfs_writepage(struct page *page, struct writeback_control *wbc) +{ + int err = -EIO; + struct inode *inode; + struct inode *lower_inode; + struct page *lower_page; + struct address_space *lower_mapping; /* lower inode mapping */ + gfp_t mask; + + BUG_ON(!PageUptodate(page)); + inode = page->mapping->host; + /* if no lower inode, nothing to do */ + if (!inode || !UNIONFS_I(inode) || UNIONFS_I(inode)->lower_inodes) { + err = 0; + goto out; + } + lower_inode = unionfs_lower_inode(inode); + lower_mapping = lower_inode->i_mapping; + + /* +* find lower page (returns a locked page) +* +* We turn off __GFP_FS while we look for or create a new lower +* page. This prevents a recursion into the file system code, which +* under memory pressure conditions could lead to a deadlock. This +* is similar to how the loop driver behaves (see loop_set_fd in +* drivers/block/loop.c). If we can't find the lower page, we +* redirty our page and return "success" so that the VM will call us +* again in the (hopefully near) future. +*/ + mask = mapping_gfp_mask(lower_mapping) & ~(__GFP_FS); + lower_page = find_or_create_page(lower_mapping, page->index, mask); + if (!lower_page) { + err = 0; + set_page_dirty(page); + goto out; + } + + /* copy page data from our upper page to the lower page */ + copy_highpage(lower_page, page); + flush_dcache_page(lower_page); + SetPageUptodate(lower_page); + set_page_dirty(lower_page); + + /* +* Call lower writepage (expects locked page). However, if we are +* called with wbc->for_reclaim, then the VFS/VM just wants to +* reclaim our page. Therefore, we don't need to call the lower +* ->writepage: just copy our data to the lower page (already done +* above), then mark the lower page dirty and unlock it, and return +* success. +*/ + if (wbc->for_reclaim) { + unlock_page(lower_page); + goto out_release; + } + + BUG_ON(!lower_mapping->a_ops->writepage); + wait_on_page_writeback(lower_page); /* prevent multiple writers */ + clear_page_dirty_for_io(lower_page); /* emulate VFS behavior */ + err = lower_mapping->a_ops->writepage(lower_page, wbc); + if (err < 0) + goto out_release; + + /* +* Lower file systems such as ramfs and tmpfs, may return +* AOP_WRITEPAGE_ACTIVATE so that the VM won't try to (pointlessly) +* write the page again for a while. But those lower file systems +* also set the page dirty bit back again. Since we successfully +* copied our page data to the lower page, then the VM will come +* back to the lower page (directly) and try to flush it. So we can +* save the VM the hassle of coming back to our page and trying to +* flush too. Therefore, we don't re-dirty our own page, and we +* never return AOP_WRITEPAGE_ACTIVATE back to the VM (we consider +* this a success). +* +* We also unlock the lower page if the lower ->writepage returned +* AOP_WRITEPAGE_ACTIVATE. (This "anomalous" behaviour may be +* addressed in future shmem/VM code.) +*/ + if (err == AOP_WRITEPAGE_ACTIVATE) { + err = 0; + unlock_page(lower_page); + } + + /* all is well */ + + /* lower mtimes have changed: update ours */ + unionfs_copy_attr_times(inode); + +out_release: +
[PATCH 18/29] Unionfs: address-space operations
Includes writepage, writepages, readpage, prepare_write, and commit_write. Signed-off-by: Erez Zadok [EMAIL PROTECTED] --- fs/unionfs/mmap.c | 343 + 1 files changed, 343 insertions(+), 0 deletions(-) create mode 100644 fs/unionfs/mmap.c diff --git a/fs/unionfs/mmap.c b/fs/unionfs/mmap.c new file mode 100644 index 000..ad770ac --- /dev/null +++ b/fs/unionfs/mmap.c @@ -0,0 +1,343 @@ +/* + * Copyright (c) 2003-2007 Erez Zadok + * Copyright (c) 2003-2006 Charles P. Wright + * Copyright (c) 2005-2007 Josef 'Jeff' Sipek + * Copyright (c) 2005-2006 Junjiro Okajima + * Copyright (c) 2006 Shaya Potter + * Copyright (c) 2005 Arun M. Krishnakumar + * Copyright (c) 2004-2006 David P. Quigley + * Copyright (c) 2003-2004 Mohammad Nayyer Zubair + * Copyright (c) 2003 Puja Gupta + * Copyright (c) 2003 Harikesavan Krishnan + * Copyright (c) 2003-2007 Stony Brook University + * Copyright (c) 2003-2007 The Research Foundation of SUNY + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include union.h + +static int unionfs_writepage(struct page *page, struct writeback_control *wbc) +{ + int err = -EIO; + struct inode *inode; + struct inode *lower_inode; + struct page *lower_page; + struct address_space *lower_mapping; /* lower inode mapping */ + gfp_t mask; + + BUG_ON(!PageUptodate(page)); + inode = page-mapping-host; + /* if no lower inode, nothing to do */ + if (!inode || !UNIONFS_I(inode) || UNIONFS_I(inode)-lower_inodes) { + err = 0; + goto out; + } + lower_inode = unionfs_lower_inode(inode); + lower_mapping = lower_inode-i_mapping; + + /* +* find lower page (returns a locked page) +* +* We turn off __GFP_FS while we look for or create a new lower +* page. This prevents a recursion into the file system code, which +* under memory pressure conditions could lead to a deadlock. This +* is similar to how the loop driver behaves (see loop_set_fd in +* drivers/block/loop.c). If we can't find the lower page, we +* redirty our page and return success so that the VM will call us +* again in the (hopefully near) future. +*/ + mask = mapping_gfp_mask(lower_mapping) ~(__GFP_FS); + lower_page = find_or_create_page(lower_mapping, page-index, mask); + if (!lower_page) { + err = 0; + set_page_dirty(page); + goto out; + } + + /* copy page data from our upper page to the lower page */ + copy_highpage(lower_page, page); + flush_dcache_page(lower_page); + SetPageUptodate(lower_page); + set_page_dirty(lower_page); + + /* +* Call lower writepage (expects locked page). However, if we are +* called with wbc-for_reclaim, then the VFS/VM just wants to +* reclaim our page. Therefore, we don't need to call the lower +* -writepage: just copy our data to the lower page (already done +* above), then mark the lower page dirty and unlock it, and return +* success. +*/ + if (wbc-for_reclaim) { + unlock_page(lower_page); + goto out_release; + } + + BUG_ON(!lower_mapping-a_ops-writepage); + wait_on_page_writeback(lower_page); /* prevent multiple writers */ + clear_page_dirty_for_io(lower_page); /* emulate VFS behavior */ + err = lower_mapping-a_ops-writepage(lower_page, wbc); + if (err 0) + goto out_release; + + /* +* Lower file systems such as ramfs and tmpfs, may return +* AOP_WRITEPAGE_ACTIVATE so that the VM won't try to (pointlessly) +* write the page again for a while. But those lower file systems +* also set the page dirty bit back again. Since we successfully +* copied our page data to the lower page, then the VM will come +* back to the lower page (directly) and try to flush it. So we can +* save the VM the hassle of coming back to our page and trying to +* flush too. Therefore, we don't re-dirty our own page, and we +* never return AOP_WRITEPAGE_ACTIVATE back to the VM (we consider +* this a success). +* +* We also unlock the lower page if the lower -writepage returned +* AOP_WRITEPAGE_ACTIVATE. (This anomalous behaviour may be +* addressed in future shmem/VM code.) +*/ + if (err == AOP_WRITEPAGE_ACTIVATE) { + err = 0; + unlock_page(lower_page); + } + + /* all is well */ + + /* lower mtimes have changed: update ours */ + unionfs_copy_attr_times(inode); + +out_release: + /* b/c