Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 16 Jan 2011 19:31:50 +0000 (11:31 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 16 Jan 2011 19:31:50 +0000 (11:31 -0800)
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6: (23 commits)
  sanitize vfsmount refcounting changes
  fix old umount_tree() breakage
  autofs4: Merge the remaining dentry ops tables
  Unexport do_add_mount() and add in follow_automount(), not ->d_automount()
  Allow d_manage() to be used in RCU-walk mode
  Remove a further kludge from __do_follow_link()
  autofs4: Bump version
  autofs4: Add v4 pseudo direct mount support
  autofs4: Fix wait validation
  autofs4: Clean up autofs4_free_ino()
  autofs4: Clean up dentry operations
  autofs4: Clean up inode operations
  autofs4: Remove unused code
  autofs4: Add d_manage() dentry operation
  autofs4: Add d_automount() dentry operation
  Remove the automount through follow_link() kludge code from pathwalk
  CIFS: Use d_automount() rather than abusing follow_link()
  NFS: Use d_automount() rather than abusing follow_link()
  AFS: Use d_automount() rather than abusing follow_link()
  Add an AT_NO_AUTOMOUNT flag to suppress terminal automount
  ...

1  2 
Documentation/filesystems/Locking
fs/dcache.c
fs/nfsd/vfs.c
include/linux/fs.h

@@@ -19,6 -19,8 +19,8 @@@ prototypes
        void (*d_release)(struct dentry *);
        void (*d_iput)(struct dentry *, struct inode *);
        char *(*d_dname)((struct dentry *dentry, char *buffer, int buflen);
+       struct vfsmount *(*d_automount)(struct path *path);
+       int (*d_manage)(struct dentry *, bool);
  
  locking rules:
                rename_lock     ->d_lock        may block       rcu-walk
@@@ -29,6 -31,8 +31,8 @@@ d_delete:     no              yes             no              n
  d_release:    no              no              yes             no
  d_iput:               no              no              yes             no
  d_dname:      no              no              no              no
+ d_automount:  no              no              yes             no
+ d_manage:     no              no              yes (ref-walk)  maybe
  
  --------------------------- inode_operations --------------------------- 
  prototypes:
@@@ -343,6 -347,7 +347,6 @@@ prototypes
        int (*fl_grant)(struct file_lock *, struct file_lock *, int);
        void (*fl_release_private)(struct file_lock *);
        void (*fl_break)(struct file_lock *); /* break_lease callback */
 -      int (*fl_mylease)(struct file_lock *, struct file_lock *);
        int (*fl_change)(struct file_lock **, int);
  
  locking rules:
@@@ -352,6 -357,7 +356,6 @@@ fl_notify:         yes             n
  fl_grant:             no              no
  fl_release_private:   maybe           no
  fl_break:             yes             no
 -fl_mylease:           yes             no
  fl_change             yes             no
  
  --------------------------- buffer_head -----------------------------------
diff --combined fs/dcache.c
@@@ -1357,8 -1357,8 +1357,8 @@@ EXPORT_SYMBOL(d_alloc_name)
  
  void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op)
  {
 -      BUG_ON(dentry->d_op);
 -      BUG_ON(dentry->d_flags & (DCACHE_OP_HASH        |
 +      WARN_ON_ONCE(dentry->d_op);
 +      WARN_ON_ONCE(dentry->d_flags & (DCACHE_OP_HASH  |
                                DCACHE_OP_COMPARE       |
                                DCACHE_OP_REVALIDATE    |
                                DCACHE_OP_DELETE ));
@@@ -1380,8 -1380,11 +1380,11 @@@ EXPORT_SYMBOL(d_set_d_op)
  static void __d_instantiate(struct dentry *dentry, struct inode *inode)
  {
        spin_lock(&dentry->d_lock);
-       if (inode)
+       if (inode) {
+               if (unlikely(IS_AUTOMOUNT(inode)))
+                       dentry->d_flags |= DCACHE_NEED_AUTOMOUNT;
                list_add(&dentry->d_alias, &inode->i_dentry);
+       }
        dentry->d_inode = inode;
        dentry_rcuwalk_barrier(dentry);
        spin_unlock(&dentry->d_lock);
diff --combined fs/nfsd/vfs.c
@@@ -1,3 -1,4 +1,3 @@@
 -#define MSNFS /* HACK HACK */
  /*
   * File operations used by nfsd. Some of these have been ripped from
   * other parts of the kernel because they weren't exported, others
@@@ -34,8 -35,8 +34,8 @@@
  #endif /* CONFIG_NFSD_V3 */
  
  #ifdef CONFIG_NFSD_V4
 -#include <linux/nfs4_acl.h>
 -#include <linux/nfsd_idmap.h>
 +#include "acl.h"
 +#include "idmap.h"
  #endif /* CONFIG_NFSD_V4 */
  
  #include "nfsd.h"
@@@ -87,8 -88,9 +87,9 @@@ nfsd_cross_mnt(struct svc_rqst *rqstp, 
                            .dentry = dget(dentry)};
        int err = 0;
  
-       while (d_mountpoint(path.dentry) && follow_down(&path))
-               ;
+       err = follow_down(&path, false);
+       if (err < 0)
+               goto out;
  
        exp2 = rqst_exp_get_by_name(rqstp, &path);
        if (IS_ERR(exp2)) {
@@@ -272,13 -274,6 +273,13 @@@ out
        return err;
  }
  
 +static int nfsd_break_lease(struct inode *inode)
 +{
 +      if (!S_ISREG(inode->i_mode))
 +              return 0;
 +      return break_lease(inode, O_WRONLY | O_NONBLOCK);
 +}
 +
  /*
   * Commit metadata changes to stable storage.
   */
@@@ -381,6 -376,16 +382,6 @@@ nfsd_setattr(struct svc_rqst *rqstp, st
                                goto out;
                }
  
 -              /*
 -               * If we are changing the size of the file, then
 -               * we need to break all leases.
 -               */
 -              host_err = break_lease(inode, O_WRONLY | O_NONBLOCK);
 -              if (host_err == -EWOULDBLOCK)
 -                      host_err = -ETIMEDOUT;
 -              if (host_err) /* ENOMEM or EWOULDBLOCK */
 -                      goto out_nfserr;
 -
                host_err = get_write_access(inode);
                if (host_err)
                        goto out_nfserr;
  
        err = nfserr_notsync;
        if (!check_guard || guardtime == inode->i_ctime.tv_sec) {
 +              host_err = nfsd_break_lease(inode);
 +              if (host_err)
 +                      goto out_nfserr;
                fh_lock(fhp);
 +
                host_err = notify_change(dentry, iap);
                err = nfserrno(host_err);
                fh_unlock(fhp);
@@@ -752,6 -753,8 +753,6 @@@ nfsd_open(struct svc_rqst *rqstp, struc
         */
        if (!(access & NFSD_MAY_NOT_BREAK_LEASE))
                host_err = break_lease(inode, O_NONBLOCK | ((access & NFSD_MAY_WRITE) ? O_WRONLY : 0));
 -      if (host_err == -EWOULDBLOCK)
 -              host_err = -ETIMEDOUT;
        if (host_err) /* NOMEM or WOULDBLOCK */
                goto out_nfserr;
  
@@@ -872,6 -875,15 +873,6 @@@ static int nfsd_direct_splice_actor(str
        return __splice_from_pipe(pipe, sd, nfsd_splice_actor);
  }
  
 -static inline int svc_msnfs(struct svc_fh *ffhp)
 -{
 -#ifdef MSNFS
 -      return (ffhp->fh_export->ex_flags & NFSEXP_MSNFS);
 -#else
 -      return 0;
 -#endif
 -}
 -
  static __be32
  nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
                loff_t offset, struct kvec *vec, int vlen, unsigned long *count)
        err = nfserr_perm;
        inode = file->f_path.dentry->d_inode;
  
 -      if (svc_msnfs(fhp) && !lock_may_read(inode, offset, *count))
 -              goto out;
 -
        if (file->f_op->splice_read && rqstp->rq_splice_ok) {
                struct splice_desc sd = {
                        .len            = 0,
                fsnotify_access(file);
        } else 
                err = nfserrno(host_err);
 -out:
        return err;
  }
  
@@@ -972,6 -988,14 +973,6 @@@ nfsd_vfs_write(struct svc_rqst *rqstp, 
        int                     stable = *stablep;
        int                     use_wgather;
  
 -#ifdef MSNFS
 -      err = nfserr_perm;
 -
 -      if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) &&
 -              (!lock_may_write(file->f_path.dentry->d_inode, offset, *cnt)))
 -              goto out;
 -#endif
 -
        dentry = file->f_path.dentry;
        inode = dentry->d_inode;
        exp   = fhp->fh_export;
@@@ -1022,6 -1046,7 +1023,6 @@@ out_nfserr
                err = 0;
        else
                err = nfserrno(host_err);
 -out:
        return err;
  }
  
@@@ -1641,12 -1666,6 +1642,12 @@@ nfsd_link(struct svc_rqst *rqstp, struc
                err = nfserrno(host_err);
                goto out_dput;
        }
 +      err = nfserr_noent;
 +      if (!dold->d_inode)
 +              goto out_drop_write;
 +      host_err = nfsd_break_lease(dold->d_inode);
 +      if (host_err)
 +              goto out_drop_write;
        host_err = vfs_link(dold, dirp, dnew);
        if (!host_err) {
                err = nfserrno(commit_metadata(ffhp));
                else
                        err = nfserrno(host_err);
        }
 +out_drop_write:
        mnt_drop_write(tfhp->fh_export->ex_path.mnt);
  out_dput:
        dput(dnew);
@@@ -1733,6 -1751,12 +1734,6 @@@ nfsd_rename(struct svc_rqst *rqstp, str
        if (ndentry == trap)
                goto out_dput_new;
  
 -      if (svc_msnfs(ffhp) &&
 -              ((odentry->d_count > 1) || (ndentry->d_count > 1))) {
 -                      host_err = -EPERM;
 -                      goto out_dput_new;
 -      }
 -
        host_err = -EXDEV;
        if (ffhp->fh_export->ex_path.mnt != tfhp->fh_export->ex_path.mnt)
                goto out_dput_new;
        if (host_err)
                goto out_dput_new;
  
 +      host_err = nfsd_break_lease(odentry->d_inode);
 +      if (host_err)
 +              goto out_drop_write;
        host_err = vfs_rename(fdir, odentry, tdir, ndentry);
        if (!host_err) {
                host_err = commit_metadata(tfhp);
                if (!host_err)
                        host_err = commit_metadata(ffhp);
        }
 -
 +out_drop_write:
        mnt_drop_write(ffhp->fh_export->ex_path.mnt);
 -
   out_dput_new:
        dput(ndentry);
   out_dput_old:
@@@ -1813,14 -1835,18 +1814,14 @@@ nfsd_unlink(struct svc_rqst *rqstp, str
        if (host_err)
                goto out_nfserr;
  
 -      if (type != S_IFDIR) { /* It's UNLINK */
 -#ifdef MSNFS
 -              if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) &&
 -                      (rdentry->d_count > 1)) {
 -                      host_err = -EPERM;
 -              } else
 -#endif
 +      host_err = nfsd_break_lease(rdentry->d_inode);
 +      if (host_err)
 +              goto out_put;
 +      if (type != S_IFDIR)
                host_err = vfs_unlink(dirp, rdentry);
 -      } else { /* It's RMDIR */
 +      else
                host_err = vfs_rmdir(dirp, rdentry);
 -      }
 -
 +out_put:
        dput(rdentry);
  
        if (!host_err)
diff --combined include/linux/fs.h
@@@ -242,6 -242,7 +242,7 @@@ struct inodes_stat_t 
  #define S_SWAPFILE    256     /* Do not truncate: swapon got its bmaps */
  #define S_PRIVATE     512     /* Inode is fs-internal */
  #define S_IMA         1024    /* Inode has an associated IMA struct */
+ #define S_AUTOMOUNT   2048    /* Automount/referral quasi-directory */
  
  /*
   * Note that nosuid etc flags are inode-specific: setting some file-system
  #define IS_SWAPFILE(inode)    ((inode)->i_flags & S_SWAPFILE)
  #define IS_PRIVATE(inode)     ((inode)->i_flags & S_PRIVATE)
  #define IS_IMA(inode)         ((inode)->i_flags & S_IMA)
+ #define IS_AUTOMOUNT(inode)   ((inode)->i_flags & S_AUTOMOUNT)
  
  /* the read-only stuff doesn't really belong here, but any other place is
     probably as bad and I don't want to create yet another include file. */
@@@ -666,7 -668,7 +668,7 @@@ struct block_device 
        int                     bd_holders;
        bool                    bd_write_holder;
  #ifdef CONFIG_SYSFS
 -      struct gendisk *        bd_holder_disk; /* for sysfs slave linkng */
 +      struct list_head        bd_holder_disks;
  #endif
        struct block_device *   bd_contains;
        unsigned                bd_block_size;
@@@ -1066,6 -1068,7 +1068,6 @@@ struct lock_manager_operations 
        int (*fl_grant)(struct file_lock *, struct file_lock *, int);
        void (*fl_release_private)(struct file_lock *);
        void (*fl_break)(struct file_lock *);
 -      int (*fl_mylease)(struct file_lock *, struct file_lock *);
        int (*fl_change)(struct file_lock **, int);
  };
  
@@@ -2057,18 -2060,12 +2059,18 @@@ extern struct block_device *blkdev_get_
  extern int blkdev_put(struct block_device *bdev, fmode_t mode);
  #ifdef CONFIG_SYSFS
  extern int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk);
 +extern void bd_unlink_disk_holder(struct block_device *bdev,
 +                                struct gendisk *disk);
  #else
  static inline int bd_link_disk_holder(struct block_device *bdev,
                                      struct gendisk *disk)
  {
        return 0;
  }
 +static inline void bd_unlink_disk_holder(struct block_device *bdev,
 +                                       struct gendisk *disk)
 +{
 +}
  #endif
  #endif