Hello again, I've taken the code from fuse/dir.c and modified it slightly to provide a pretty minimal workaround, by creating the file with read/write permission first and then revoking that permission in a separate call to aufs_setattr if necessary. That's not perfect behavior (there is a window during which the extended preliminary permissions are visible), but it appears to work. I'm not really sure we can do better without using the underlying file system's ->atomic_open op, if it has one, so we might have to keep this code around for the other file systems. diff -ur -X linux-4.0.0-rc7/Documentation/dontdiff linux-4.0.0-rc7-aufs/fs/aufs/i_op.c linux-4.0.0-rc7-aufs-hacked/fs/aufs/i_op.c --- linux-4.0.0-rc7-aufs/fs/aufs/i_op.c   2015-04-04 05:30:05.935306135 +0000 +++ linux-4.0.0-rc7-aufs-hacked/fs/aufs/i_op.c   2015-04-07 15:24:30.521005453 +0000 @@ -1219,6 +1219,61 @@   /*---------------------------------------------------------------------- */  +int aufs_atomic_open(struct inode *dir_inode, struct dentry *dentry, +          struct file *file, unsigned open_flags, +          umode_t mode, int *opened) +{ +   struct dentry *res = NULL; +   int err; +   umode_t prel_mode = mode; +   +   BUG_ON(dentry->d_inode); + +   if (d_unhashed(dentry)) { +      res = aufs_lookup(dir_inode, dentry, 0); + +      if (IS_ERR(res)) +         return PTR_ERR(res); +   +      if (res) +         dentry = res; +   } + +   if (!(open_flags & O_CREAT) || dentry->d_inode) +      goto no_open; + +   if (open_flags & O_RDWR) +      prel_mode |= 0600; +   else if (open_flags & O_WRONLY) +      prel_mode |= 0200; +   else +      prel_mode |= 0400; +   +   *opened |= FILE_CREATED; + +   err = aufs_create(dir_inode, dentry, prel_mode, (open_flags & O_EXCL) != 0); +   if (!err) +      err = finish_open(file, dentry, NULL, opened); +   if (!err && prel_mode != mode) { +      struct iattr ia; +      ia.ia_valid = ATTR_MODE; +      ia.ia_mode = mode; +      mutex_lock_nested(&dentry->d_inode->i_mutex, AuLsc_I_PARENT); +      err = notify_change(dentry, &ia, NULL); +      mutex_unlock(&dentry->d_inode->i_mutex); + +      if (err) +         fput(file); +   } +   dput(res); +   return err; + + no_open: +   return finish_no_open(file, res); +} + +/*---------------------------------------------------------------------- */ +  struct inode_operations aufs_symlink_iop = {     .permission   = aufs_permission,  #ifdef CONFIG_FS_POSIX_ACL @@ -1271,7 +1326,7 @@  #endif      .update_time   = aufs_update_time, -   /* no support for atomic_open() */ +   .atomic_open   = aufs_atomic_open,      .tmpfile   = aufs_tmpfile  }; On Tue, Apr 7, 2015 at 2:45 AM, Pip Cet <[1]pip...@gmail.com> wrote:
Hi, thank you for your response! On Mon, Apr 6, 2015 at 6:30 AM, <[2]sf...@users.sourceforge.net> wrote: Hello Pip, Pip Cet: > I've had a look at the relevant code in fs/namei.c, and it appears to me > the problem is that lookup_open(), in the absence of an ->atomic_open > method, falls back to creating a file with vfs_create, then opening it with > vfs_open, which fails in this case. It's not clear to me what a good fix > would be, though implementing ->atomic_open should work. You analized very well. I've tried implementing aufs atomic_open several years before, but it was complicated and I decided that aufs doesn't support atomic_open. I must admit I'm still not sure to what extent this is a bug in aufs, nfs4, or the vfs layer. Â It was not a big issue until now and I have not received such mail. Something might changed recently? - nfs4 becomes popular - vfs or nfs4 internal implementation changed No, the changes in outer world should not be related to this problem. You reported other versions of aufs failed similarly. And I guess aufs have never succeeded open(O_WRONLY|O_CREAT, 0400) on nfs4 branch. Probably it is just a matter of fact that who report first. I think it's best to fix it by implementing aufs_atomic_open. Maybe the code in fs/fuse/dir.c:fuse_atomic_open can serve as a starting point. However, I also think the VFS code and the nfs4 code are, at least, less than optimal in not dealing with this case very well. The nfs4 implementation expects that all file creates go through .atomic_open rather than being split by the VFS; that's currently true, but I'm not sure it's a good design decision to rely on its being true in future versions of the VFS. The VFS layer could reasonably split an open(O_CREAT|O_WRONLY, 0400) into the sequence open("file", O_CREAT|O_WRONLY, 0600); open("file", O_WRONLY); chmod("file", 0400); which I believe should be equivalent. Â > As an experiment, I've disabled nfs4's ->atomic_open method, and the result > was that with the modified kernel, my test program fails even directly on > the nfs file system. It still succeeds both directly on a ramfs and on an > aufs using said ramfs, but that appears to be because ramfs has no ->open > at all Right. I've confirmed nfs fh_verify() rejects open(O_WRONLY) for the already created readonly file. I think aufs should try supporting atomic_open (while it is complicated) now. As a first step, would you try this patch? It is just to confirm the scenario and prints a [3]kern.info log where aufs should call ->atomic_open(). That message is printed both for tar and for the test program. For tar: openat(AT_FDCWD,"x",O_WRONLY|O_CREAT|O_EXCL|O_NOCTTY|O_NONBLOCK|O_CLOEXEC, 0400[Â 416.703027] aufs aufs_lookup:245:tar[2032]: call nfs_atomic_open for b0 sivtar/x ) = -1 EACCES (Permission denied) for test3: open("x", O_WRONLY|O_CREAT, 0400<3>[Â 497.633130] aufs aufs_lookup:245:test3[2065]: call nfs_atomic_open for b0 sivtar/x )Â Â Â Â Â Â = -1 EACCES (Permission denied) (sivtar is the name of the directory I ran the tests in, and test3 is the name of the test program whose source code I posted). Â I'd ask you to try verious patterns. By this patch aufs will prints a msg. In other words, when you see an error without the aufs log msg, it means this first step is not good. So far, that hasn't happened. Thanks again, Pip References 1. mailto:pip...@gmail.com 2. mailto:sf...@users.sourceforge.net 3. http://kern.info/
diff -ur -X linux-4.0.0-rc7/Documentation/dontdiff linux-4.0.0-rc7-aufs/fs/aufs/i_op.c linux-4.0.0-rc7-aufs-hacked/fs/aufs/i_op.c --- linux-4.0.0-rc7-aufs/fs/aufs/i_op.c 2015-04-04 05:30:05.935306135 +0000 +++ linux-4.0.0-rc7-aufs-hacked/fs/aufs/i_op.c 2015-04-07 15:24:30.521005453 +0000 @@ -1219,6 +1219,61 @@ /* ---------------------------------------------------------------------- */ +int aufs_atomic_open(struct inode *dir_inode, struct dentry *dentry, + struct file *file, unsigned open_flags, + umode_t mode, int *opened) +{ + struct dentry *res = NULL; + int err; + umode_t prel_mode = mode; + + BUG_ON(dentry->d_inode); + + if (d_unhashed(dentry)) { + res = aufs_lookup(dir_inode, dentry, 0); + + if (IS_ERR(res)) + return PTR_ERR(res); + + if (res) + dentry = res; + } + + if (!(open_flags & O_CREAT) || dentry->d_inode) + goto no_open; + + if (open_flags & O_RDWR) + prel_mode |= 0600; + else if (open_flags & O_WRONLY) + prel_mode |= 0200; + else + prel_mode |= 0400; + + *opened |= FILE_CREATED; + + err = aufs_create(dir_inode, dentry, prel_mode, (open_flags & O_EXCL) != 0); + if (!err) + err = finish_open(file, dentry, NULL, opened); + if (!err && prel_mode != mode) { + struct iattr ia; + ia.ia_valid = ATTR_MODE; + ia.ia_mode = mode; + mutex_lock_nested(&dentry->d_inode->i_mutex, AuLsc_I_PARENT); + err = notify_change(dentry, &ia, NULL); + mutex_unlock(&dentry->d_inode->i_mutex); + + if (err) + fput(file); + } + dput(res); + return err; + + no_open: + return finish_no_open(file, res); +} + +/* ---------------------------------------------------------------------- */ + struct inode_operations aufs_symlink_iop = { .permission = aufs_permission, #ifdef CONFIG_FS_POSIX_ACL @@ -1271,7 +1326,7 @@ #endif .update_time = aufs_update_time, - /* no support for atomic_open() */ + .atomic_open = aufs_atomic_open, .tmpfile = aufs_tmpfile };
------------------------------------------------------------------------------ BPM Camp - Free Virtual Workshop May 6th at 10am PDT/1PM EDT Develop your own process in accordance with the BPMN 2 standard Learn Process modeling best practices with Bonita BPM through live exercises http://www.bonitasoft.com/be-part-of-it/events/bpm-camp-virtual- event?utm_ source=Sourceforge_BPM_Camp_5_6_15&utm_medium=email&utm_campaign=VA_SF