Hi,
here goes the spreader patch (formerly "balance patch" or no-name) which distributes a file at the time of creation into the branch with the lowest used disk space, making it a little "stripe" like you know from RAID. Of course, since we cannot know how big a file will eventually become in the future, this is not a true striper like it is with RAID or raiffs. As has been before, I do not know why files do net always get correctly spread. Assuming that I have a union with 3 branches (B1, B2, B3) each having the same amount of free space, and if I now copy a 3MB ogg file to the union, it gets put into the top branch (B1). Surprisingly, if I now copy a small text file to the union, it also gets put into the top branch rather than the next lower one (B2 or B3, depending on implementation). The branches move/rotate and the next 4MB ogg file correctly gets into the now-top branch B2. Yet, the next 6MB ogg file also gets into B2, which is more than just strange. So it looks like the move (branch_move()) is done too late -- i.e. after the file has already been created, but that can't be, since we just entered unionfs_create() so there is no new file yet. So by the time we reach "/* We start out in the leftmost branch. */" the leftmost branch is already the one with the most free space. (The ideal case, but it does not seem so, according to above.) Solutions welcome. Jan Engelhardt -- | Alphagate Systems, http://alphagate.hopto.org/ | jengelh's site, http://jengelh.hopto.org/ It is lacking a doc, but let's keep it short: branch_wmaxspc() returns the branch number of the branch with the most free space according to kstat(), which also `df` uses. branch_move(SB, N) puts branch N at the top (or in FS.CSL.SUNYSB.EDU parlance: left). 'Nuff said. diff -dpru unionfs-20050923-1803~/inode.c unionfs-20050923-1803/inode.c --- unionfs-20050923-1803~/inode.c 2005-09-28 23:25:09.000000000 +0200 +++ unionfs-20050923-1803/inode.c 2005-09-28 23:36:36.000000000 +0200 @@ -21,6 +21,83 @@ #include "fist.h" #include "unionfs.h" +static int branch_wmaxspc(struct super_block *); +static void branch_move(struct super_block *, int); + +static int branch_wmaxspc(struct super_block *sb) { + 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, &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) { + 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) { @@ -29,13 +106,18 @@ 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); fist_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); diff -dpru unionfs-20050923-1803~/main.c unionfs-20050923-1803/main.c --- unionfs-20050923-1803~/main.c 2005-09-24 00:03:15.000000000 +0200 +++ unionfs-20050923-1803/main.c 2005-09-28 23:37:36.000000000 +0200 @@ -402,6 +402,11 @@ struct unionfs_dentry_info *unionfs_pars *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) { @@ -513,6 +518,11 @@ struct unionfs_dentry_info *unionfs_pars err = -EINVAL; goto out_error; } + if(stopd(sb)->usi_spread && (MOUNT_FLAG(sb) & DELETE_WHITEOUT)) { + printk(KERN_WARNING "unionfs: Using \"spread\" option requires delete=all\n"); + err = -EINVAL; + goto out_error; + } if (mounter_f && !(copyupuid_f && copyupgid_f && copyupmode_f)) { printk(KERN_WARNING "unionfs: " diff -dpru unionfs-20050923-1803~/unionfs.h unionfs-20050923-1803/unionfs.h --- unionfs-20050923-1803~/unionfs.h 2005-09-24 00:03:15.000000000 +0200 +++ unionfs-20050923-1803/unionfs.h 2005-09-28 23:36:02.000000000 +0200 @@ -129,6 +129,7 @@ struct unionfs_sb_info { unsigned long usi_mount_flag; int usi_persistent; + int usi_spread; /* These are the pointers to our various objects. */ struct super_block *usi_sb_i[UNIONFS_INLINE_OBJECTS]; # eof _______________________________________________ unionfs mailing list [email protected] http://www.fsl.cs.sunysb.edu/mailman/listinfo/unionfs
