From: Erez Zadok Date: Wed, 12 Dec 2007 17:31:26 +0000 (-0500) Subject: Unionfs: avoid using drop_pagecache_sb in remount X-Git-Url: https://git.fsl.cs.sunysb.edu/?a=commitdiff_plain;h=6e35b80b122866ee20b7edc5e43d0139467db371;p=unionfs-3.14.y.git Unionfs: avoid using drop_pagecache_sb in remount Exporting drop_pagecache_sb to modules is somewhat risky because one cannot sleep inside invalidate_mapping_pages. This could cause a lot of latency in the pre-emption code. So don't export this symbol to minimize the risk that others will use it. Instead, unionfs will try to directly invalidate as many pages it can from the unionfs_remount code. Invalidating those inode pages is not strictly required, but helpful in encouraging a revalidation of inodes sooner than waiting for individual f/s ops to access the union. Since a remount is already an expensive but rare operation, this inode pages invalidation shouldn't add too much overhead. CC: Nick Piggin Signed-off-by: Erez Zadok --- diff --git a/fs/drop_caches.c b/fs/drop_caches.c index 4abfc793d31e..9fd702f5bfb2 100644 --- a/fs/drop_caches.c +++ b/fs/drop_caches.c @@ -3,7 +3,6 @@ */ #include -#include #include #include #include diff --git a/fs/unionfs/dentry.c b/fs/unionfs/dentry.c index 7d27987e873a..c7b6a7c774b7 100644 --- a/fs/unionfs/dentry.c +++ b/fs/unionfs/dentry.c @@ -276,6 +276,17 @@ static inline void purge_inode_data(struct inode *inode) truncate_inode_pages(&inode->i_data, 0); } +void purge_sb_data(struct super_block *sb) +{ + struct inode *inode; + + list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { + if (inode->i_state & (I_FREEING|I_WILL_FREE)) + continue; + purge_inode_data(inode); + } +} + /* * Revalidate a parent chain of dentries, then the actual node. * Assumes that dentry is locked, but will lock all parents if/when needed. diff --git a/fs/unionfs/super.c b/fs/unionfs/super.c index d9cf2a74377b..0ff9a9e7eeaf 100644 --- a/fs/unionfs/super.c +++ b/fs/unionfs/super.c @@ -704,29 +704,19 @@ out_no_change: */ /* - * Now we call drop_pagecache_sb() to invalidate all pages in this - * super. This function calls invalidate_inode_pages(mapping), - * which calls invalidate_mapping_pages(): the latter, however, will - * not invalidate pages which are dirty, locked, under writeback, or - * mapped into page tables. We shouldn't have to worry about dirty - * or under-writeback pages, because do_remount_sb() called - * fsync_super() which would not have returned until all dirty pages - * were flushed. - * - * But do we have to worry about locked pages? Is there any chance - * that in here we'll get locked pages? - * - * XXX: what about pages mapped into pagetables? Are these pages - * which user processes may have mmap(2)'ed? If so, then we need to - * invalidate those too, no? Maybe we'll have to write our own - * version of invalidate_mapping_pages() which also handled mapped - * pages. - * - * XXX: Alternatively, maybe we should call truncate_inode_pages(), - * which use two passes over the pages list, and will truncate all - * pages. + * Once we finish the remounting successfully, our superblock + * generation number will have increased. This will be detected by + * our dentry-revalidation code upon subsequent f/s operations + * through unionfs. The revalidation code will rebuild the union of + * lower inodes for a given unionfs inode and invalidate any pages + * of such "stale" inodes (by calling our purge_inode_data + * function). This revalidation will happen lazily and + * incrementally, as users perform operations on cached inodes. We + * would like to encourage this revalidation to happen sooner if + * possible, so we try to invalidate as many other pages in our + * superblock as we can. */ - drop_pagecache_sb(sb); + purge_sb_data(sb); /* copy new vectors into their correct place */ tmp_data = UNIONFS_SB(sb)->data; diff --git a/fs/unionfs/union.h b/fs/unionfs/union.h index 1617482ac0e2..d8f46a2ba8c9 100644 --- a/fs/unionfs/union.h +++ b/fs/unionfs/union.h @@ -369,6 +369,7 @@ extern int unionfs_rmdir(struct inode *dir, struct dentry *dentry); extern bool __unionfs_d_revalidate_chain(struct dentry *dentry, struct nameidata *nd, bool willwrite); extern bool is_newer_lower(const struct dentry *dentry); +extern void purge_sb_data(struct super_block *sb); /* The values for unionfs_interpose's flag. */ #define INTERPOSE_DEFAULT 0