I made a patch for disabling whiteout-lookup in the rightmost ro-branch. This 
patch too prohibits the lookup/rename of whiteouts in unionfs_create() in the 
case of an ro-branch.

This enables us to use an ro-nfs rightmost branch, which is an common use-case 
for some users of unionfs.


Am Freitag, 16. Dezember 2005 08:50 schrieb [EMAIL PROTECTED]:
> > While I was thinking about Wilhelm's question, I've got an idea of new
> > option "dirs=<branch>=ro_wh".
> > Currently these options are 'ro' and 'rw'. A 'ro_wh' option is
> > perfectly equivalent to current 'ro'. But the meaning of 'ro' option
> > changes. In case of 'ro', unionfs does not lookup a whiteout entry, but
> > 'ro_wh' does.
>
> I have tried, here is a patch.
> This is for simple lookup and unionctl, not including unionfs inode
> operations (unionfs_create, etc.).
>
>
> Junjiro Okajima
>
>
> diff -rup ./unionfs-20051130-1554.orig/branchman.c
> ./unionfs-20051130-1554/branchman.c ---
> ./unionfs-20051130-1554.orig/branchman.c      2005-12-01 05:54:06.000000000
> +0900 +++ ./unionfs-20051130-1554/branchman.c 2005-12-16 16:29:50.000000000
> +0900 @@ -211,7 +211,7 @@ int unionfs_ioctl_addbranch(struct inode
>               goto out;
>
>       err = -EINVAL;
> -     if (addargs->ab_perms & ~(MAY_READ | MAY_WRITE))
> +     if (addargs->ab_perms & ~(MAY_READ | MAY_WRITE | MAY_WHITEOUT))
>               goto out;
>       if (!(addargs->ab_perms & MAY_READ))
>               goto out;
> @@ -514,7 +514,7 @@ int unionfs_ioctl_rdwrbranch(struct inod
>       if (rdwrargs->rwb_branch < 0
>
>           || (rdwrargs->rwb_branch > (sbend(inode->i_sb) + 1)))
>
>               goto out;
> -     if (rdwrargs->rwb_perms & ~(MAY_READ | MAY_WRITE))
> +     if (rdwrargs->rwb_perms & ~(MAY_READ | MAY_WRITE | MAY_WHITEOUT))
>               goto out;
>       if (!(rdwrargs->rwb_perms & MAY_READ))
>               goto out;
> diff -rup ./unionfs-20051130-1554.orig/lookup.c
> ./unionfs-20051130-1554/lookup.c ---
> ./unionfs-20051130-1554.orig/lookup.c 2005-12-01 05:54:06.000000000 +0900
> +++ ./unionfs-20051130-1554/lookup.c  2005-12-16 16:29:50.000000000 +0900 @@
> -41,7 +41,8 @@ struct dentry *unionfs_lookup_backend(st
>       int opaque;
>       char *whname = NULL;
>       const char *name;
> -     int namelen;
> +     int namelen, whlen;
> +     struct super_block *sb;
>
>       print_entry("mode = %d", lookupmode);
>       PASSERT(dentry);
> @@ -82,6 +83,12 @@ struct dentry *unionfs_lookup_backend(st
>               err = -EPERM;
>               goto out_free;
>       }
> +     whname = get_whname(name, namelen, &whlen);
> +     if (IS_ERR(whname)) {
> +             err = PTR_ERR(whname);
> +             whname = NULL;
> +             goto out_free;
> +     }
>
>       /* must initialize dentry operations */
>       dentry->d_op = &unionfs_dops;
> @@ -91,6 +98,7 @@ struct dentry *unionfs_lookup_backend(st
>       bend = dbend(parent_dentry);
>       bopaque = dbopaque(parent_dentry);
>       ASSERT(bstart >= 0);
> +     sb = dentry->d_sb;
>
>       /* It would be ideal if we could convert partial lookups to only have
>        * to do this work when they really need to.  It could probably improve
> @@ -119,44 +127,37 @@ struct dentry *unionfs_lookup_backend(st
>               if (!S_ISDIR(hidden_dir_dentry->d_inode->i_mode))
>                       continue;
>
> -             /* Reuse the whiteout name because its value doesn't change. */
> -             if (!whname) {
> -                     whname = KMALLOC(namelen + 5, GFP_UNIONFS);
> -                     if (!whname) {
> -                             err = -ENOMEM;
> +             if (branchperms(sb, bindex) & (MAY_WRITE | MAY_WHITEOUT)) {
> +                     /* check if whiteout exists in this branch: lookup 
> .wh.foo */
> +                     wh_hidden_dentry = LOOKUP_ONE_LEN(whname, 
> hidden_dir_dentry,
> +                                                       whlen);
> +                     if (IS_ERR(wh_hidden_dentry)) {
> +                             err = PTR_ERR(wh_hidden_dentry);
>                               goto out_free;
>                       }
> -                     strcpy(whname, WHPFX);
> -                     strncat(whname, name, namelen);
> -                     whname[WHLEN + namelen] = '\0';
> -             }
>
> -             /* check if whiteout exists in this branch: lookup .wh.foo */
> -             wh_hidden_dentry = LOOKUP_ONE_LEN(whname, hidden_dir_dentry,
> -                                               namelen + WHLEN);
> -             if (IS_ERR(wh_hidden_dentry)) {
> -                     err = PTR_ERR(wh_hidden_dentry);
> -                     goto out_free;
> -             }
> +                     if (wh_hidden_dentry->d_inode) {
> +                             DPUT(wh_hidden_dentry);
> +                             /* We found a whiteout so lets give up. */
> +                             fist_dprint(8, "whiteout found in %d\n", 
> bindex);
> +                             if (S_ISREG(wh_hidden_dentry->d_inode->i_mode)) 
> {
> +                                     set_dbend(dentry, bindex);
> +                                     set_dbopaque(dentry, bindex);
> +                                     break;
> +                             }
> +                             err = -EIO;
> +                             printk(KERN_NOTICE "EIO: Invalid whiteout entry 
> type"
> +                                    " %d.\n", 
> wh_hidden_dentry->d_inode->i_mode);
> +                             goto out_free;
> +                     }
>
> -             if (wh_hidden_dentry->d_inode) {
>                       DPUT(wh_hidden_dentry);
> -                     /* We found a whiteout so lets give up. */
> -                     fist_dprint(8, "whiteout found in %d\n", bindex);
> -                     if (S_ISREG(wh_hidden_dentry->d_inode->i_mode)) {
> -                             set_dbend(dentry, bindex);
> -                             set_dbopaque(dentry, bindex);
> -                             break;
> -                     }
> -                     err = -EIO;
> -                     printk(KERN_NOTICE "EIO: Invalid whiteout entry type"
> -                            " %d.\n", wh_hidden_dentry->d_inode->i_mode);
> -                     goto out_free;
> +                     wh_hidden_dentry = NULL;
> +             } else {
> +                     fist_dprint(8, "skipped bindex %d(0x%x)\n",
> +                                 bindex, branchperms(sb, bindex));
>               }
>
> -             DPUT(wh_hidden_dentry);
> -             wh_hidden_dentry = NULL;
> -
>               /* Now do regular lookup; lookup foo */
>               hidden_dentry = LOOKUP_ONE_LEN(name, hidden_dir_dentry,
>                                              namelen);
> @@ -307,7 +308,7 @@ struct dentry *unionfs_lookup_backend(st
>               ASSERT(dbend(dentry) <= sbmax(dentry->d_sb));
>               ASSERT(dbstart(dentry) >= 0);
>       }
> -     KFREE(whname);
> +     put_whname(whname);
>       fist_print_dentry("OUT unionfs_lookup (parent)", parent_dentry);
>       fist_print_dentry("OUT unionfs_lookup (child)", dentry);
>       if (locked_parent)
> diff -rup ./unionfs-20051130-1554.orig/main.c
> ./unionfs-20051130-1554/main.c ---
> ./unionfs-20051130-1554.orig/main.c   2005-12-01 05:54:06.000000000 +0900 +++
> ./unionfs-20051130-1554/main.c        2005-12-16 16:29:50.000000000 +0900 @@
> -323,28 +323,31 @@ static int parse_dirs_option(struct supe
>       branches = 0;
>       while ((name = strsep(&options, ":")) != NULL) {
>               int perms;
> -             int l;
> +             char *p;
>
>               if (!*name)
>                       continue;
>
>               branches++;
>
> -             /* strip off =rw or =ro if it is specified. */
> -             l = strlen(name);
> -             if (!strcmp(name + l - 3, "=ro")) {
> -                     perms = MAY_READ;
> -                     name[l - 3] = '\0';
> -             } else if (!strcmp(name + l - 3, "=rw")) {
> -                     perms = MAY_READ | MAY_WRITE;
> -                     name[l - 3] = '\0';
> -             } else {
> -                     perms = MAY_READ | MAY_WRITE;
> +             /* strip off =rw|ro|roh/ro_wh if it is specified. */
> +             perms = MAY_READ | MAY_WRITE; /* default */
> +             p = strchr(name, '=');
> +             if (p) {
> +                     *p++ = '\0';
> +                     if (!strcmp(p, "ro"))
> +                             perms = MAY_READ;
> +                     else if (!strcmp(p, "roh") || !strcmp(p, "ro_wh"))
> +                             perms = MAY_READ | MAY_WHITEOUT;
> +                     else if (strcmp(p, "rw"))
> +                             printk(KERN_WARNING
> +                                    "unionfs: unknown option '%s'\n", p);
>               }
>
> -             fist_dprint(4, "unionfs: using directory: %s (%c%c)\n",
> +             fist_dprint(4, "unionfs: using directory: %s (%c%c%c)\n",
>                           name, perms & MAY_READ ? 'r' : '-',
> -                         perms & MAY_WRITE ? 'w' : '-');
> +                         perms & MAY_WRITE ? 'w' : '-',
> +                         perms & MAY_WHITEOUT ? 'h' : '-');
>
>               err = path_lookup(name, LOOKUP_FOLLOW, &nd);
>               RECORD_PATH_LOOKUP(&nd);
> diff -rup ./unionfs-20051130-1554.orig/rename.c
> ./unionfs-20051130-1554/rename.c ---
> ./unionfs-20051130-1554.orig/rename.c 2005-12-01 05:54:06.000000000 +0900
> +++ ./unionfs-20051130-1554/rename.c  2005-12-16 16:29:50.000000000 +0900 @@
> -668,42 +668,6 @@ static int unionfs_rename_all(struct ino
>       return err;
>  }
>
> -/*
> - * generate whiteout name, which is NOT terminated by NULL.
> - * @name: original d_name.name
> - * @len: original d_name.len
> - * @whlen: length of whname
> - * return value is the whname.
> - * correctly returned value as whname must be freed later.
> - * If an error occurs, returns PTR_ERR.
> - */
> -static inline char *get_whname(const char *name, int len, int *whlen)
> -{
> -     char *ret;
> -
> -     ASSERT(name && len && whlen);
> -#if 0
> -     /* TODO: check the full path length with PATH_MAX */
> -     if (len > PAGE_SIZE - WHLEN + 1)
> -             return ERR_PTR(-ENAMETOOLONG);
> -#endif
> -     ret = __getname();
> -     if (!ret)
> -             return ERR_PTR(-ENOMEM);
> -
> -     memcpy(ret, WHPFX, WHLEN);
> -     memcpy(ret + WHLEN, name, len);
> -     *whlen = len + WHLEN;
> -     ret[*whlen] = '\0';
> -
> -     return ret;
> -}
> -
> -static inline void put_whname(char *whname)
> -{
> -     __putname(whname);
> -}
> -
>  static struct dentry *lookup_whiteout(struct dentry *dentry)
>  {
>       char *whname;
> diff -rup ./unionfs-20051130-1554.orig/super.c
> ./unionfs-20051130-1554/super.c ---
> ./unionfs-20051130-1554.orig/super.c  2005-12-01 05:54:06.000000000 +0900
> +++ ./unionfs-20051130-1554/super.c   2005-12-16 16:29:50.000000000 +0900 @@
> -452,7 +452,8 @@ static int unionfs_show_options(struct s
>                          PAGE_SIZE);
>               perms = branchperms(sb, bindex);
>               seq_printf(m, "%s=%s", hidden_path,
> -                        perms & MAY_WRITE ? "rw" : "ro");
> +                        perms & MAY_WRITE ? "rw" :
> +                        perms & MAY_WHITEOUT ? "roh" : "ro");
>               if (bindex != bend) {
>                       seq_printf(m, ":");
>               }
> diff -rup ./unionfs-20051130-1554.orig/unionctl.c
> ./unionfs-20051130-1554/unionctl.c ---
> ./unionfs-20051130-1554.orig/unionctl.c       2005-12-01 05:54:06.000000000 
> +0900
> +++ ./unionfs-20051130-1554/unionctl.c        2005-12-16 16:29:50.000000000 
> +0900
> @@ -35,6 +35,7 @@
>
>  #define MAY_READ 4
>  #define MAY_WRITE 2
> +#define MAY_WHITEOUT 32
>
>  extern int find_union(const char *path, char **options, char
> **actual_path, int uniononly);
> @@ -59,9 +60,9 @@ void __attribute__ ((__noreturn__)) __us
>       fprintf(stderr,
>               "ACTION can be --add, --remove, --mode, --list, or 
> --query.\nFurther
> arguments depend on ACTION.\n"); fprintf(stderr,
> -             "\tunionctl UNION --add [ --before BRANCH | --after BRANCH ] [ 
> --mode
> (rw|ro) ] DIRECTORY\n"); +            "\tunionctl UNION --add [ --before 
> BRANCH |
> --after BRANCH ] [ --mode (rw|ro|roh) ] DIRECTORY\n"); fprintf(stderr,
> "\tunionctl UNION --remove BRANCH\n");
> -     fprintf(stderr, "\tunionctl UNION --mode BRANCH (rw|ro)\n");
> +     fprintf(stderr, "\tunionctl UNION --mode BRANCH (rw|ro|roh)\n");
>       fprintf(stderr, "\tunionctl UNION --list\n");
>       fprintf(stderr, "\tunionctl FILENAME --query\n");
>       fprintf(stderr,
> @@ -69,6 +70,18 @@ void __attribute__ ((__noreturn__)) __us
>       exit(EXIT_FAILURE);
>  }
>
> +static inline int parse_rw(char *p)
> +{
> +     if (strcmp(p, "ro") == 0)
> +             return MAY_READ;
> +     else if (strcmp(p, "roh") == 0 || strcmp(p, "ro_wh") == 0)
> +             return MAY_READ | MAY_WHITEOUT;
> +     else if (strcmp(p, "rw") == 0)
> +             return MAY_READ | MAY_WRITE;
> +     else
> +             return 0;
> +}
> +
>  static char **parse_options(char *options)
>  {
>       char **ret = NULL;
> @@ -77,8 +90,7 @@ static char **parse_options(char *option
>       char *p;
>       char *q;
>       char *r;
> -     char *s;
> -     int l;
> +     char *s, *t, *u;
>
>       p = options;
>       do {
> @@ -107,15 +119,18 @@ static char **parse_options(char *option
>                                       exit(EXIT_FAILURE);
>                               }
>
> -                             l = strlen(r);
> -                             if (((r[l - 1] == 'o') || (r[l - 1] == 'w'))
> -                                 && (r[l - 2] == 'r') && (r[l - 3] == '=')) {
> -                                     r[l - 3] = '\0';
> -                                     branchperms[n - 1] = MAY_READ;
> -                                     if (r[l - 1] == 'w') {
> -                                             branchperms[n - 1] |= MAY_WRITE;
> -                                     }
> +                             t = strchr(r, '=');
> +                             u = t+1;
> +                             if (!t || !u || !*u)
> +                                     goto err;
> +                             *t = 0;
> +                             branchperms[n - 1] = parse_rw(u);
> +                             if (!branchperms[n - 1]) {
> +                             err:
> +                                     fprintf(stderr, "cannot parse '%s'\n", 
> r);
> +                                     exit(EXIT_FAILURE);
>                               }
> +
>                               ret[n - 1] = strdup(r);
>                               ret[n] = NULL;
>
> @@ -162,10 +177,11 @@ static void dump_branches(const char *pr
>       int n = 0;
>
>       while (branches[n]) {
> -             char r, w;
> +             char r, w, h;
>               r = (branchperms[n] & MAY_READ) ? 'r' : '-';
>               w = (branchperms[n] & MAY_WRITE) ? 'w' : '-';
> -             printf("%s%s (%c%c)\n", prefix, branches[n], r, w);
> +             h = (branchperms[n] & MAY_WHITEOUT) ? 'h' : '-';
> +             printf("%s%s (%c%c%c)\n", prefix, branches[n], r, w, h);
>               n++;
>       }
>  }
> @@ -312,14 +328,10 @@ int main(int argc, char *argv[])
>                                               usage();
>                                       }
>
> -                                     if (!strcmp(argv[i], "ro")) {
> -                                             addargs.ab_perms = MAY_READ;
> -                                     } else if (!strcmp(argv[i], "rw")) {
> -                                             addargs.ab_perms =
> -                                                 MAY_READ | MAY_WRITE;
> -                                     } else {
> +                                     addargs.ab_perms = parse_rw(argv[i]);
> +                                     if (!addargs.ab_perms) {
>                                               fprintf(stderr,
> -                                                     "Valid modes are ro and 
> rw you specified: \"%s\"\n",
> +                                                     "Valid modes are 
> ro/rw/roh you specified: \"%s\"\n",
>                                                       argv[i]);
>                                               usage();
>                                       }
> @@ -379,20 +391,15 @@ int main(int argc, char *argv[])
>                       usage();
>               }
>
> -             if (!strcmp(argv[4], "ro")) {
> -                     rdwrargs.rwb_perms = MAY_READ;
> -                     branchnum = 3;
> -             } else if (!strcmp(argv[4], "rw")) {
> -                     rdwrargs.rwb_perms = MAY_READ | MAY_WRITE;
> -                     branchnum = 3;
> -             } else if (!strcmp(argv[3], "ro")) {
> -                     rdwrargs.rwb_perms = MAY_READ;
> -                     branchnum = 4;
> -             } else if (!strcmp(argv[3], "rw")) {
> -                     rdwrargs.rwb_perms = MAY_READ | MAY_WRITE;
> +             branchnum = 3;
> +             rdwrargs.rwb_perms = parse_rw(argv[4]);
> +             if (!rdwrargs.rwb_perms) {
>                       branchnum = 4;
> -             } else {
> -                     usage();
> +                     rdwrargs.rwb_perms = parse_rw(argv[3]);
> +                     if (!rdwrargs.rwb_perms) {
> +                             usage();
> +                             exit(EXIT_FAILURE);
> +                     }
>               }
>
>               if (realpath(argv[branchnum], resolv_bp) == NULL) {
> @@ -478,13 +485,14 @@ int main(int argc, char *argv[])
>               }
>
>               for (i = 0; i <= ret; i++) {
> -                     char r, w;
> +                     char r, w, h;
>                       r = (branchperms[i] & MAY_READ) ? 'r' : '-';
>                       w = (branchperms[i] & MAY_WRITE) ? 'w' : '-';
> +                     h = (branchperms[i] & MAY_WHITEOUT) ? 'h' : '-';
>
>                       if (FD_ISSET(i, &branchlist))
> -                             printf("%s\t%s (%c%c)\n", argv[unionpos],
> -                                    branches[i], r, w);
> +                             printf("%s\t%s (%c%c%c)\n", argv[unionpos],
> +                                    branches[i], r, w, h);
>               }
>               break;
>       }
> diff -rup ./unionfs-20051130-1554.orig/unionfs.h
> ./unionfs-20051130-1554/unionfs.h ---
> ./unionfs-20051130-1554.orig/unionfs.h        2005-12-01 05:54:06.000000000 
> +0900
> +++ ./unionfs-20051130-1554/unionfs.h 2005-12-16 16:29:50.000000000 +0900
> @@ -118,6 +118,20 @@ struct putmap {
>  };
>
>  /* unionfs super-block data in memory */
> +/*
> + * flags for branchperm.
> + * MAY_EXEC, MAY_WRITE, MAY_READ, MAY_APPEND in linux/fs.h.
> + * MAY_GENERIC is for unionfs_permission() and try linux
> + * generic_permission() or something after the branch i_op->permission()
> + * returned an error.
> + * MAY_GENERIC is set when the branch is marked as "<branch>=rog".
> + * MAY_WHITEOUT is for unionfs_lookup() and try lookup whiteout on
> readonly + * branch.
> + * MAY_HITEOUT is set when the branch is marked as "<branch>=roh".
> + */
> +#define __UNIONFS_PERM_LAST  MAY_APPEND
> +//#define MAY_GENERIC                (__UNIONFS_PERM_LAST<<1)
> +#define MAY_WHITEOUT         (__UNIONFS_PERM_LAST<<2)
>  struct unionfs_sb_info {
>       int b_end;
>
> @@ -640,7 +654,42 @@ static inline int __is_robranch(struct d
>  #define UNIONFS_DIR_OPAQUE_NAME "__dir_opaque"
>  #define UNIONFS_DIR_OPAQUE WHPFX UNIONFS_DIR_OPAQUE_NAME
>
> -;
> +/*
> + * generate whiteout name, which is NOT terminated by NULL.
> + * @name: original d_name.name
> + * @len: original d_name.len
> + * @whlen: length of whname
> + * return value is the whname.
> + * correctly returned value as whname must be freed later.
> + * If an error occurs, returns PTR_ERR.
> + */
> +static inline char *get_whname(const char *name, int len, int *whlen)
> +{
> +     char *ret;
> +
> +     ASSERT(name && len && whlen);
> +#if 0
> +     /* TODO: check the full path length with PATH_MAX */
> +     if (len > PAGE_SIZE - WHLEN + 1)
> +             return ERR_PTR(-ENAMETOOLONG);
> +#endif
> +     ret = __getname();
> +     if (!ret)
> +             return ERR_PTR(-ENOMEM);
> +
> +     memcpy(ret, WHPFX, WHLEN);
> +     memcpy(ret + WHLEN, name, len);
> +     *whlen = len + WHLEN;
> +     ret[*whlen] = '\0';
> +
> +     return ret;
> +}
> +
> +static inline void put_whname(char *whname)
> +{
> +     __putname(whname);
> +}
> +
>  /*
>  * Defines,structs,and functions for persistant used by kenrel and user
>  */
> _______________________________________________
> unionfs mailing list
> [email protected]
> http://www.fsl.cs.sunysb.edu/mailman/listinfo/unionfs

-- 
--
Wilhelm Meier
email: [EMAIL PROTECTED]
Only in ./unionfs-20051130-1554-rolast: .tmp_versions
diff -rup ./unionfs-20051130-1554/inode.c ./unionfs-20051130-1554-rolast/inode.c
--- ./unionfs-20051130-1554/inode.c	2005-11-30 21:54:06.000000000 +0100
+++ ./unionfs-20051130-1554-rolast/inode.c	2005-12-21 13:48:19.000000000 +0100
@@ -61,17 +61,19 @@ static int unionfs_create(struct inode *
 	strncat(name, dentry->d_name.name, dentry->d_name.len);
 	name[WHLEN + dentry->d_name.len] = '\0';
 
-	whiteout_dentry =
-	    LOOKUP_ONE_LEN(name, hidden_dentry->d_parent,
-			   dentry->d_name.len + WHLEN);
-	if (IS_ERR(whiteout_dentry)) {
-		err = PTR_ERR(whiteout_dentry);
-		whiteout_dentry = NULL;
-		goto out;
+	if (!(is_robranch_super(dentry->d_sb, bstart))) {
+		whiteout_dentry =
+			LOOKUP_ONE_LEN(name, hidden_dentry->d_parent,
+				       dentry->d_name.len + WHLEN);
+		if (IS_ERR(whiteout_dentry)) {
+			err = PTR_ERR(whiteout_dentry);
+			whiteout_dentry = NULL;
+			goto out;
+		}
+		PASSERT(whiteout_dentry);
 	}
-	PASSERT(whiteout_dentry);
 
-	if (whiteout_dentry->d_inode) {
+	if (whiteout_dentry && whiteout_dentry->d_inode) {
 		/* .wh.foo has been found. */
 		/* First truncate it and then rename it to foo (hence having
 		 * the same overall effect as a normal create.
@@ -196,7 +198,8 @@ static int unionfs_create(struct inode *
 	}
 
       out:
-	DPUT(whiteout_dentry);
+	if (whiteout_dentry)
+		DPUT(whiteout_dentry);
 	KFREE(name);
 
 	fist_print_dentry("OUT unionfs_create :", dentry);
@@ -1043,8 +1046,6 @@ struct inode_operations unionfs_main_iop
  * Local variables:
  * c-basic-offset: 8
  * c-comment-only-line-offset: 0
- * c-offsets-alist: ((statement-block-intro . +) (knr-argdecl-intro . 0)
- *              (substatement-open . 0) (label . 0) (statement-cont . +))
  * indent-tabs-mode: t
  * tab-width: 8
  * End:
diff -rup ./unionfs-20051130-1554/lookup.c ./unionfs-20051130-1554-rolast/lookup.c
--- ./unionfs-20051130-1554/lookup.c	2005-11-30 21:54:06.000000000 +0100
+++ ./unionfs-20051130-1554-rolast/lookup.c	2005-12-21 13:48:57.000000000 +0100
@@ -118,45 +118,47 @@ struct dentry *unionfs_lookup_backend(st
 		/* also skip it if the parent isn't a directory. */
 		if (!S_ISDIR(hidden_dir_dentry->d_inode->i_mode))
 			continue;
-
-		/* Reuse the whiteout name because its value doesn't change. */
-		if (!whname) {
-			whname = KMALLOC(namelen + 5, GFP_UNIONFS);
+		
+		if (bindex < bend) {
+			/* Reuse the whiteout name because its value doesn't change. */
 			if (!whname) {
-				err = -ENOMEM;
+				whname = KMALLOC(namelen + 5, GFP_UNIONFS);
+				if (!whname) {
+					err = -ENOMEM;
+					goto out_free;
+				}
+				strcpy(whname, WHPFX);
+				strncat(whname, name, namelen);
+				whname[WHLEN + namelen] = '\0';
+			}
+
+			/* check if whiteout exists in this branch: lookup .wh.foo */
+			wh_hidden_dentry = LOOKUP_ONE_LEN(whname, hidden_dir_dentry,
+							  namelen + WHLEN);
+			if (IS_ERR(wh_hidden_dentry)) {
+				err = PTR_ERR(wh_hidden_dentry);
 				goto out_free;
 			}
-			strcpy(whname, WHPFX);
-			strncat(whname, name, namelen);
-			whname[WHLEN + namelen] = '\0';
-		}
 
-		/* check if whiteout exists in this branch: lookup .wh.foo */
-		wh_hidden_dentry = LOOKUP_ONE_LEN(whname, hidden_dir_dentry,
-						  namelen + WHLEN);
-		if (IS_ERR(wh_hidden_dentry)) {
-			err = PTR_ERR(wh_hidden_dentry);
-			goto out_free;
-		}
+			if (wh_hidden_dentry->d_inode) {
+				DPUT(wh_hidden_dentry);
+				/* We found a whiteout so lets give up. */
+				fist_dprint(8, "whiteout found in %d\n", bindex);
+				if (S_ISREG(wh_hidden_dentry->d_inode->i_mode)) {
+					set_dbend(dentry, bindex);
+					set_dbopaque(dentry, bindex);
+					break;
+				}
+				err = -EIO;
+				printk(KERN_NOTICE "EIO: Invalid whiteout entry type"
+				       " %d.\n", wh_hidden_dentry->d_inode->i_mode);
+				goto out_free;
+			}
 
-		if (wh_hidden_dentry->d_inode) {
 			DPUT(wh_hidden_dentry);
-			/* We found a whiteout so lets give up. */
-			fist_dprint(8, "whiteout found in %d\n", bindex);
-			if (S_ISREG(wh_hidden_dentry->d_inode->i_mode)) {
-				set_dbend(dentry, bindex);
-				set_dbopaque(dentry, bindex);
-				break;
-			}
-			err = -EIO;
-			printk(KERN_NOTICE "EIO: Invalid whiteout entry type"
-			       " %d.\n", wh_hidden_dentry->d_inode->i_mode);
-			goto out_free;
+			wh_hidden_dentry = NULL;
 		}
-
-		DPUT(wh_hidden_dentry);
-		wh_hidden_dentry = NULL;
-
+		
 		/* Now do regular lookup; lookup foo */
 		hidden_dentry = LOOKUP_ONE_LEN(name, hidden_dir_dentry,
 					       namelen);
@@ -204,7 +206,10 @@ struct dentry *unionfs_lookup_backend(st
 			continue;
 		}
 
-		opaque = is_opaque_dir(dentry, bindex);
+		opaque = 0;
+		if (bindex < bend) {
+			opaque = is_opaque_dir(dentry, bindex);
+		}
 		if (opaque < 0) {
 			err = opaque;
 			goto out_free;
@@ -307,7 +312,9 @@ struct dentry *unionfs_lookup_backend(st
 		ASSERT(dbend(dentry) <= sbmax(dentry->d_sb));
 		ASSERT(dbstart(dentry) >= 0);
 	}
-	KFREE(whname);
+        if (whname) 
+	        KFREE(whname);
+ 
 	fist_print_dentry("OUT unionfs_lookup (parent)", parent_dentry);
 	fist_print_dentry("OUT unionfs_lookup (child)", dentry);
 	if (locked_parent)
_______________________________________________
unionfs mailing list
[email protected]
http://www.fsl.cs.sunysb.edu/mailman/listinfo/unionfs

Reply via email to