[PATCH 19/42] Unionfs: readdir helper functions
Includes whiteout handling for directories. Signed-off-by: Erez Zadok <[EMAIL PROTECTED]> --- fs/unionfs/dirhelper.c | 272 1 files changed, 272 insertions(+), 0 deletions(-) create mode 100644 fs/unionfs/dirhelper.c diff --git a/fs/unionfs/dirhelper.c b/fs/unionfs/dirhelper.c new file mode 100644 index 000..2e52fc3 --- /dev/null +++ b/fs/unionfs/dirhelper.c @@ -0,0 +1,272 @@ +/* + * 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) 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" + +/* + * Delete all of the whiteouts in a given directory for rmdir. + * + * lower directory inode should be locked + */ +int do_delete_whiteouts(struct dentry *dentry, int bindex, + struct unionfs_dir_state *namelist) +{ + int err = 0; + struct dentry *lower_dir_dentry = NULL; + struct dentry *lower_dentry; + char *name = NULL, *p; + struct inode *lower_dir; + int i; + struct list_head *pos; + struct filldir_node *cursor; + + /* Find out lower parent dentry */ + lower_dir_dentry = unionfs_lower_dentry_idx(dentry, bindex); + BUG_ON(!S_ISDIR(lower_dir_dentry->d_inode->i_mode)); + lower_dir = lower_dir_dentry->d_inode; + BUG_ON(!S_ISDIR(lower_dir->i_mode)); + + err = -ENOMEM; + name = __getname(); + if (unlikely(!name)) + goto out; + strcpy(name, UNIONFS_WHPFX); + p = name + UNIONFS_WHLEN; + + err = 0; + for (i = 0; !err && i < namelist->size; i++) { + list_for_each(pos, >list[i]) { + cursor = + list_entry(pos, struct filldir_node, + file_list); + /* Only operate on whiteouts in this branch. */ + if (cursor->bindex != bindex) + continue; + if (!cursor->whiteout) + continue; + + strcpy(p, cursor->name); + lower_dentry = + lookup_one_len(name, lower_dir_dentry, + cursor->namelen + + UNIONFS_WHLEN); + if (IS_ERR(lower_dentry)) { + err = PTR_ERR(lower_dentry); + break; + } + if (lower_dentry->d_inode) + err = vfs_unlink(lower_dir, lower_dentry); + dput(lower_dentry); + if (err) + break; + } + } + + __putname(name); + + /* After all of the removals, we should copy the attributes once. */ + fsstack_copy_attr_times(dentry->d_inode, lower_dir_dentry->d_inode); + +out: + return err; +} + +/* delete whiteouts in a dir (for rmdir operation) using sioq if necessary */ +int delete_whiteouts(struct dentry *dentry, int bindex, +struct unionfs_dir_state *namelist) +{ + int err; + struct super_block *sb; + struct dentry *lower_dir_dentry; + struct inode *lower_dir; + struct sioq_args args; + + sb = dentry->d_sb; + + BUG_ON(!S_ISDIR(dentry->d_inode->i_mode)); + BUG_ON(bindex < dbstart(dentry)); + BUG_ON(bindex > dbend(dentry)); + err = is_robranch_super(sb, bindex); + if (err) + goto out; + + lower_dir_dentry = unionfs_lower_dentry_idx(dentry, bindex); + BUG_ON(!S_ISDIR(lower_dir_dentry->d_inode->i_mode)); + lower_dir = lower_dir_dentry->d_inode; + BUG_ON(!S_ISDIR(lower_dir->i_mode)); + + mutex_lock(_dir->i_mutex); + if (!permission(lower_dir, MAY_WRITE | MAY_EXEC, NULL)) { + err = do_delete_whiteouts(dentry, bindex, namelist); + } else { + args.deletewh.namelist = namelist; + args.deletewh.dentry = dentry; + args.deletewh.bindex = bindex; + run_sioq(__delete_whiteouts, ); + err = args.err; + } + mutex_unlock(_dir->i_mutex); + +out: + return err; +} + +#define RD_NONE 0 +#define RD_CHECK_EMPTY 1 +/* The callback
[PATCH 19/42] Unionfs: readdir helper functions
Includes whiteout handling for directories. Signed-off-by: Erez Zadok [EMAIL PROTECTED] --- fs/unionfs/dirhelper.c | 272 1 files changed, 272 insertions(+), 0 deletions(-) create mode 100644 fs/unionfs/dirhelper.c diff --git a/fs/unionfs/dirhelper.c b/fs/unionfs/dirhelper.c new file mode 100644 index 000..2e52fc3 --- /dev/null +++ b/fs/unionfs/dirhelper.c @@ -0,0 +1,272 @@ +/* + * 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) 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 + +/* + * Delete all of the whiteouts in a given directory for rmdir. + * + * lower directory inode should be locked + */ +int do_delete_whiteouts(struct dentry *dentry, int bindex, + struct unionfs_dir_state *namelist) +{ + int err = 0; + struct dentry *lower_dir_dentry = NULL; + struct dentry *lower_dentry; + char *name = NULL, *p; + struct inode *lower_dir; + int i; + struct list_head *pos; + struct filldir_node *cursor; + + /* Find out lower parent dentry */ + lower_dir_dentry = unionfs_lower_dentry_idx(dentry, bindex); + BUG_ON(!S_ISDIR(lower_dir_dentry-d_inode-i_mode)); + lower_dir = lower_dir_dentry-d_inode; + BUG_ON(!S_ISDIR(lower_dir-i_mode)); + + err = -ENOMEM; + name = __getname(); + if (unlikely(!name)) + goto out; + strcpy(name, UNIONFS_WHPFX); + p = name + UNIONFS_WHLEN; + + err = 0; + for (i = 0; !err i namelist-size; i++) { + list_for_each(pos, namelist-list[i]) { + cursor = + list_entry(pos, struct filldir_node, + file_list); + /* Only operate on whiteouts in this branch. */ + if (cursor-bindex != bindex) + continue; + if (!cursor-whiteout) + continue; + + strcpy(p, cursor-name); + lower_dentry = + lookup_one_len(name, lower_dir_dentry, + cursor-namelen + + UNIONFS_WHLEN); + if (IS_ERR(lower_dentry)) { + err = PTR_ERR(lower_dentry); + break; + } + if (lower_dentry-d_inode) + err = vfs_unlink(lower_dir, lower_dentry); + dput(lower_dentry); + if (err) + break; + } + } + + __putname(name); + + /* After all of the removals, we should copy the attributes once. */ + fsstack_copy_attr_times(dentry-d_inode, lower_dir_dentry-d_inode); + +out: + return err; +} + +/* delete whiteouts in a dir (for rmdir operation) using sioq if necessary */ +int delete_whiteouts(struct dentry *dentry, int bindex, +struct unionfs_dir_state *namelist) +{ + int err; + struct super_block *sb; + struct dentry *lower_dir_dentry; + struct inode *lower_dir; + struct sioq_args args; + + sb = dentry-d_sb; + + BUG_ON(!S_ISDIR(dentry-d_inode-i_mode)); + BUG_ON(bindex dbstart(dentry)); + BUG_ON(bindex dbend(dentry)); + err = is_robranch_super(sb, bindex); + if (err) + goto out; + + lower_dir_dentry = unionfs_lower_dentry_idx(dentry, bindex); + BUG_ON(!S_ISDIR(lower_dir_dentry-d_inode-i_mode)); + lower_dir = lower_dir_dentry-d_inode; + BUG_ON(!S_ISDIR(lower_dir-i_mode)); + + mutex_lock(lower_dir-i_mutex); + if (!permission(lower_dir, MAY_WRITE | MAY_EXEC, NULL)) { + err = do_delete_whiteouts(dentry, bindex, namelist); + } else { + args.deletewh.namelist = namelist; + args.deletewh.dentry = dentry; + args.deletewh.bindex = bindex; + run_sioq(__delete_whiteouts, args); + err = args.err; + } + mutex_unlock(lower_dir-i_mutex); + +out: + return err; +} + +#define RD_NONE 0 +#define RD_CHECK_EMPTY 1 +/* The callback structure