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

Reply via email to