Index: linux-2.6.18_rc4/fs/unionfs/inode.c =================================================================== --- linux-2.6.18_rc4.orig/fs/unionfs/inode.c +++ linux-2.6.18_rc4/fs/unionfs/inode.c @@ -10,6 +10,7 @@ * Copyright (c) 2003 Harikesavan Krishnan * Copyright (c) 2003-2006 Stony Brook University * Copyright (c) 2003-2006 The Research Foundation of State University of New York + * Copyright © 2005-2006 Jan Engelhardt <jengelh [at] gmx de> * * For specific licensing information, see the COPYING file distributed with * this package. @@ -30,6 +31,84 @@ extern int unionfs_readlink(struct dentr extern void unionfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie); +static int branch_wmaxspc(struct super_block *); +static void branch_move(struct super_block *, int); + +//----------------------------------------------------------------------------- +static int branch_wmaxspc(struct super_block *sb) { + // Returns the number of the read-write branch with the most free space + int bstart = sbstart(sb), bend = sbmax(sb), bindex; + struct super_block *hidden_sb; + struct kstatfs statbuf = {}; + sector_t best_free = 0; + int best_branch = 0; + + for(bindex = bstart; bindex < bend; ++bindex) { + int bindex1, sb_dup = 0; + + if(!(branchperms(sb, bindex) & MAY_WRITE)) + continue; + + hidden_sb = stohs_index(sb, bindex); + for(bindex1 = bstart; bindex1 < bindex; ++bindex1) { + if(hidden_sb == stohs_index(sb, bindex1)) { + sb_dup = 1; + break; + } + } + if(sb_dup || vfs_statfs(hidden_sb->s_root, &statbuf) != 0) + continue; + if(statbuf.f_bfree > best_free) { + best_free = statbuf.f_bfree; + best_branch = bindex; + } + } + + return best_branch; +} + +static void branch_move(struct super_block *sb, int chosen) { + // Move the CHOSEN branch into first place + struct dentry *hdentry, *sroot = sb->s_root; + struct inode *hinode, *sinode = sroot->d_inode; + struct super_block *hsb; + struct vfsmount *hmount; + int count, perms, gen, i; + + lock_super(sb); + atomic_inc(&stopd(sb)->usi_generation); + gen = atomic_read(&stopd(sb)->usi_generation); + atomic_set(&dtopd(sroot)->udi_generation, gen); + atomic_set(&itopd(sinode)->uii_generation, gen); + + count = branch_count(sb, chosen); + perms = branchperms(sb, chosen); + hmount = stohiddenmnt_index(sb, chosen); + hsb = stohs_index(sb, chosen); + hdentry = dtohd_index(sroot, chosen); + hinode = itohi_index(sinode, chosen); + + for(i = chosen; i > 0; --i) { + int prev = i - 1; + set_branch_count(sb, i, branch_count(sb, prev)); + set_branchperms(sb, i, branchperms(sb, prev)); + set_stohiddenmnt_index(sb, i, stohiddenmnt_index(sb, prev)); + set_stohs_index(sb, i, stohs_index(sb, prev)); + set_dtohd_index(sroot, i, dtohd_index(sroot, prev)); + set_itohi_index(sinode, i, itohi_index(sinode, prev)); + } + + set_branch_count(sb, 0, count); + set_branchperms(sb, 0, perms); + set_stohiddenmnt_index(sb, 0, hmount); + set_stohs_index(sb, 0, hsb); + set_dtohd_index(sroot, 0, hdentry); + set_itohi_index(sinode, 0, hinode); + + unlock_super(sb); + return; +} + static int unionfs_create(struct inode *parent, struct dentry *dentry, int mode, struct nameidata *nd) { @@ -38,13 +117,17 @@ static int unionfs_create(struct inode * struct dentry *whiteout_dentry = NULL; struct dentry *new_hidden_dentry; struct dentry *hidden_parent_dentry = NULL; - int bindex = 0, bstart; + int bindex = 0, bstart, mx; char *name = NULL; print_entry_location(); lock_dentry(dentry); print_dentry("IN unionfs_create", dentry); + if(stopd(dentry->d_sb)->usi_spread && + (mx = branch_wmaxspc(dentry->d_sb)) != 0) + branch_move(dentry->d_sb, mx); + /* We start out in the leftmost branch. */ bstart = dbstart(dentry); hidden_dentry = dtohd(dentry); Index: linux-2.6.18_rc4/fs/unionfs/main.c =================================================================== --- linux-2.6.18_rc4.orig/fs/unionfs/main.c +++ linux-2.6.18_rc4/fs/unionfs/main.c @@ -487,6 +487,11 @@ static struct unionfs_dentry_info *union *optarg++ = '\0'; } + if(strcmp(optname, "spread") == 0) { + stopd(sb)->usi_spread = 1; + continue; + } + /* All of our options take an argument now. Insert ones that * don't, above this check. */ if (!optarg) { @@ -581,6 +586,11 @@ static struct unionfs_dentry_info *union err = -EINVAL; goto out_error; } + if(stopd(sb)->usi_spread && !(MOUNT_FLAG(sb) & DELETE_ALL)) { + printk(KERN_WARNING "unionfs: Using \"spread\" option requires delete=all\n"); + err = -EINVAL; + goto out_error; + } goto out; out_error: Index: linux-2.6.18_rc4/fs/unionfs/unionfs.h =================================================================== --- linux-2.6.18_rc4.orig/fs/unionfs/unionfs.h +++ linux-2.6.18_rc4/fs/unionfs/unionfs.h @@ -160,6 +160,7 @@ struct unionfs_sb_info { int usi_firstputmap; int usi_lastputmap; struct putmap **usi_putmaps; + int usi_spread; #ifdef UNIONFS_IMAP int usi_persistent; ##<<EOF>>
-`J' --
_______________________________________________ unionfs mailing list unionfs@mail.fsl.cs.sunysb.edu http://www.fsl.cs.sunysb.edu/mailman/listinfo/unionfs