Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Linus Torvalds [Wed, 27 Feb 2013 04:16:07 +0000 (20:16 -0800)]
Pull vfs pile (part one) from Al Viro:
 "Assorted stuff - cleaning namei.c up a bit, fixing ->d_name/->d_parent
  locking violations, etc.

  The most visible changes here are death of FS_REVAL_DOT (replaced with
  "has ->d_weak_revalidate()") and a new helper getting from struct file
  to inode.  Some bits of preparation to xattr method interface changes.

  Misc patches by various people sent this cycle *and* ocfs2 fixes from
  several cycles ago that should've been upstream right then.

  PS: the next vfs pile will be xattr stuff."

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (46 commits)
  saner proc_get_inode() calling conventions
  proc: avoid extra pde_put() in proc_fill_super()
  fs: change return values from -EACCES to -EPERM
  fs/exec.c: make bprm_mm_init() static
  ocfs2/dlm: use GFP_ATOMIC inside a spin_lock
  ocfs2: fix possible use-after-free with AIO
  ocfs2: Fix oops in ocfs2_fast_symlink_readpage() code path
  get_empty_filp()/alloc_file() leave both ->f_pos and ->f_version zero
  target: writev() on single-element vector is pointless
  export kernel_write(), convert open-coded instances
  fs: encode_fh: return FILEID_INVALID if invalid fid_type
  kill f_vfsmnt
  vfs: kill FS_REVAL_DOT by adding a d_weak_revalidate dentry op
  nfsd: handle vfs_getattr errors in acl protocol
  switch vfs_getattr() to struct path
  default SET_PERSONALITY() in linux/elf.h
  ceph: prepopulate inodes only when request is aborted
  d_hash_and_lookup(): export, switch open-coded instances
  9p: switch v9fs_set_create_acl() to inode+fid, do it before d_instantiate()
  9p: split dropping the acls from v9fs_set_create_acl()
  ...

109 files changed:
1  2 
arch/mips/kernel/vpe.c
arch/s390/kernel/debug.c
drivers/base/firmware_class.c
drivers/char/mem.c
drivers/char/sonypi.c
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/omapdrm/omap_gem_helpers.c
drivers/hid/hidraw.c
drivers/infiniband/core/uverbs_cmd.c
drivers/iommu/tegra-smmu.c
drivers/isdn/i4l/isdn_common.c
drivers/media/v4l2-core/v4l2-dev.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
drivers/net/wan/cosa.c
drivers/net/wireless/ray_cs.c
drivers/platform/x86/sony-laptop.c
drivers/platform/x86/thinkpad_acpi.c
drivers/platform/x86/toshiba_acpi.c
drivers/s390/char/fs3270.c
drivers/staging/bcm/Misc.c
drivers/staging/dgrp/dgrp_specproc.c
drivers/staging/usbip/usbip_common.c
drivers/staging/vme/devices/vme_user.c
drivers/target/target_core_file.c
drivers/usb/core/devices.c
drivers/usb/core/devio.c
drivers/usb/gadget/atmel_usba_udc.c
drivers/usb/gadget/f_mass_storage.c
drivers/usb/gadget/storage_common.c
drivers/video/fbmem.c
fs/9p/vfs_file.c
fs/9p/vfs_inode_dotl.c
fs/binfmt_elf.c
fs/binfmt_elf_fdpic.c
fs/block_dev.c
fs/btrfs/file.c
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/send.c
fs/buffer.c
fs/ceph/inode.c
fs/cifs/cifsfs.c
fs/cifs/file.c
fs/cifs/inode.c
fs/coda/inode.c
fs/configfs/dir.c
fs/ext3/namei.c
fs/ext4/dir.c
fs/ext4/extents.c
fs/ext4/file.c
fs/ext4/inline.c
fs/ext4/inode.c
fs/ext4/ioctl.c
fs/ext4/move_extent.c
fs/ext4/namei.c
fs/ext4/super.c
fs/f2fs/dir.c
fs/fuse/dir.c
fs/fuse/inode.c
fs/gfs2/file.c
fs/gfs2/rgrp.c
fs/gfs2/sys.c
fs/lockd/clntproc.c
fs/ncpfs/inode.c
fs/ncpfs/ioctl.c
fs/nfs/idmap.c
fs/nfs/inode.c
fs/nfs/super.c
fs/nfsd/nfs3xdr.c
fs/nfsd/nfs4xdr.c
fs/nfsd/nfsxdr.c
fs/nfsd/vfs.c
fs/nilfs2/file.c
fs/nilfs2/ioctl.c
fs/ocfs2/aops.c
fs/ocfs2/dir.c
fs/ocfs2/file.c
fs/ocfs2/refcounttree.c
fs/proc/proc_net.c
fs/ubifs/file.c
fs/xfs/xfs_dfrag.c
include/linux/fs.h
include/linux/hugetlb.h
ipc/mqueue.c
ipc/shm.c
kernel/acct.c
kernel/cgroup.c
kernel/events/core.c
kernel/fork.c
kernel/module.c
kernel/nsproxy.c
kernel/sys.c
kernel/sysctl_binary.c
mm/fadvise.c
mm/filemap.c
mm/hugetlb.c
mm/mmap.c
mm/nommu.c
mm/shmem.c
mm/swapfile.c
net/atm/proc.c
net/netfilter/xt_recent.c
net/netlink/af_netlink.c
net/socket.c
net/sunrpc/auth_gss/auth_gss.c
security/integrity/ima/ima_api.c
security/integrity/ima/ima_crypto.c
security/integrity/ima/ima_main.c
security/selinux/hooks.c

Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index e4a66a3,0000000..f9eb679
mode 100644,000000..100644
--- /dev/null
@@@ -1,169 -1,0 +1,169 @@@
 +/*
 + * drivers/gpu/drm/omapdrm/omap_gem_helpers.c
 + *
 + * Copyright (C) 2011 Texas Instruments
 + * Author: Rob Clark <rob.clark@linaro.org>
 + *
 + * This program is free software; you can redistribute it and/or modify it
 + * under the terms of the GNU General Public License version 2 as published by
 + * the Free Software Foundation.
 + *
 + * This program is distributed in the hope that it will be useful, but WITHOUT
 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 + * more details.
 + *
 + * You should have received a copy of the GNU General Public License along with
 + * this program.  If not, see <http://www.gnu.org/licenses/>.
 + */
 +
 +/* temporary copy of drm_gem_{get,put}_pages() until the
 + * "drm/gem: add functions to get/put pages" patch is merged..
 + */
 +
 +#include <linux/module.h>
 +#include <linux/types.h>
 +#include <linux/shmem_fs.h>
 +
 +#include <drm/drmP.h>
 +
 +/**
 + * drm_gem_get_pages - helper to allocate backing pages for a GEM object
 + * @obj: obj in question
 + * @gfpmask: gfp mask of requested pages
 + */
 +struct page **_drm_gem_get_pages(struct drm_gem_object *obj, gfp_t gfpmask)
 +{
 +      struct inode *inode;
 +      struct address_space *mapping;
 +      struct page *p, **pages;
 +      int i, npages;
 +
 +      /* This is the shared memory object that backs the GEM resource */
-       inode = obj->filp->f_path.dentry->d_inode;
++      inode = file_inode(obj->filp);
 +      mapping = inode->i_mapping;
 +
 +      npages = obj->size >> PAGE_SHIFT;
 +
 +      pages = drm_malloc_ab(npages, sizeof(struct page *));
 +      if (pages == NULL)
 +              return ERR_PTR(-ENOMEM);
 +
 +      gfpmask |= mapping_gfp_mask(mapping);
 +
 +      for (i = 0; i < npages; i++) {
 +              p = shmem_read_mapping_page_gfp(mapping, i, gfpmask);
 +              if (IS_ERR(p))
 +                      goto fail;
 +              pages[i] = p;
 +
 +              /* There is a hypothetical issue w/ drivers that require
 +               * buffer memory in the low 4GB.. if the pages are un-
 +               * pinned, and swapped out, they can end up swapped back
 +               * in above 4GB.  If pages are already in memory, then
 +               * shmem_read_mapping_page_gfp will ignore the gfpmask,
 +               * even if the already in-memory page disobeys the mask.
 +               *
 +               * It is only a theoretical issue today, because none of
 +               * the devices with this limitation can be populated with
 +               * enough memory to trigger the issue.  But this BUG_ON()
 +               * is here as a reminder in case the problem with
 +               * shmem_read_mapping_page_gfp() isn't solved by the time
 +               * it does become a real issue.
 +               *
 +               * See this thread: http://lkml.org/lkml/2011/7/11/238
 +               */
 +              BUG_ON((gfpmask & __GFP_DMA32) &&
 +                              (page_to_pfn(p) >= 0x00100000UL));
 +      }
 +
 +      return pages;
 +
 +fail:
 +      while (i--)
 +              page_cache_release(pages[i]);
 +
 +      drm_free_large(pages);
 +      return ERR_CAST(p);
 +}
 +
 +/**
 + * drm_gem_put_pages - helper to free backing pages for a GEM object
 + * @obj: obj in question
 + * @pages: pages to free
 + */
 +void _drm_gem_put_pages(struct drm_gem_object *obj, struct page **pages,
 +              bool dirty, bool accessed)
 +{
 +      int i, npages;
 +
 +      npages = obj->size >> PAGE_SHIFT;
 +
 +      for (i = 0; i < npages; i++) {
 +              if (dirty)
 +                      set_page_dirty(pages[i]);
 +
 +              if (accessed)
 +                      mark_page_accessed(pages[i]);
 +
 +              /* Undo the reference we took when populating the table */
 +              page_cache_release(pages[i]);
 +      }
 +
 +      drm_free_large(pages);
 +}
 +
 +int
 +_drm_gem_create_mmap_offset_size(struct drm_gem_object *obj, size_t size)
 +{
 +      struct drm_device *dev = obj->dev;
 +      struct drm_gem_mm *mm = dev->mm_private;
 +      struct drm_map_list *list;
 +      struct drm_local_map *map;
 +      int ret = 0;
 +
 +      /* Set the object up for mmap'ing */
 +      list = &obj->map_list;
 +      list->map = kzalloc(sizeof(struct drm_map_list), GFP_KERNEL);
 +      if (!list->map)
 +              return -ENOMEM;
 +
 +      map = list->map;
 +      map->type = _DRM_GEM;
 +      map->size = size;
 +      map->handle = obj;
 +
 +      /* Get a DRM GEM mmap offset allocated... */
 +      list->file_offset_node = drm_mm_search_free(&mm->offset_manager,
 +                      size / PAGE_SIZE, 0, 0);
 +
 +      if (!list->file_offset_node) {
 +              DRM_ERROR("failed to allocate offset for bo %d\n", obj->name);
 +              ret = -ENOSPC;
 +              goto out_free_list;
 +      }
 +
 +      list->file_offset_node = drm_mm_get_block(list->file_offset_node,
 +                      size / PAGE_SIZE, 0);
 +      if (!list->file_offset_node) {
 +              ret = -ENOMEM;
 +              goto out_free_list;
 +      }
 +
 +      list->hash.key = list->file_offset_node->start;
 +      ret = drm_ht_insert_item(&mm->offset_hash, &list->hash);
 +      if (ret) {
 +              DRM_ERROR("failed to add to map hash\n");
 +              goto out_free_mm;
 +      }
 +
 +      return 0;
 +
 +out_free_mm:
 +      drm_mm_put_block(list->file_offset_node);
 +out_free_list:
 +      kfree(list->map);
 +      list->map = NULL;
 +
 +      return ret;
 +}
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
diff --cc fs/binfmt_elf.c
Simple merge
Simple merge
diff --cc fs/block_dev.c
Simple merge
diff --cc fs/btrfs/file.c
Simple merge
Simple merge
Simple merge
diff --cc fs/btrfs/send.c
Simple merge
diff --cc fs/buffer.c
Simple merge
diff --cc fs/ceph/inode.c
Simple merge
Simple merge
diff --cc fs/cifs/file.c
Simple merge
diff --cc fs/cifs/inode.c
Simple merge
diff --cc fs/coda/inode.c
Simple merge
Simple merge
diff --cc fs/ext3/namei.c
Simple merge
diff --cc fs/ext4/dir.c
Simple merge
Simple merge
diff --cc fs/ext4/file.c
Simple merge
Simple merge
diff --cc fs/ext4/inode.c
Simple merge
diff --cc fs/ext4/ioctl.c
Simple merge
Simple merge
diff --cc fs/ext4/namei.c
Simple merge
diff --cc fs/ext4/super.c
Simple merge
diff --cc fs/f2fs/dir.c
Simple merge
diff --cc fs/fuse/dir.c
@@@ -1183,152 -1155,14 +1183,152 @@@ static int parse_dirfile(char *buf, siz
        return 0;
  }
  
 -static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
 +static int fuse_direntplus_link(struct file *file,
 +                              struct fuse_direntplus *direntplus,
 +                              u64 attr_version)
  {
        int err;
 +      struct fuse_entry_out *o = &direntplus->entry_out;
 +      struct fuse_dirent *dirent = &direntplus->dirent;
 +      struct dentry *parent = file->f_path.dentry;
 +      struct qstr name = QSTR_INIT(dirent->name, dirent->namelen);
 +      struct dentry *dentry;
 +      struct dentry *alias;
 +      struct inode *dir = parent->d_inode;
 +      struct fuse_conn *fc;
 +      struct inode *inode;
 +
 +      if (!o->nodeid) {
 +              /*
 +               * Unlike in the case of fuse_lookup, zero nodeid does not mean
 +               * ENOENT. Instead, it only means the userspace filesystem did
 +               * not want to return attributes/handle for this entry.
 +               *
 +               * So do nothing.
 +               */
 +              return 0;
 +      }
 +
 +      if (name.name[0] == '.') {
 +              /*
 +               * We could potentially refresh the attributes of the directory
 +               * and its parent?
 +               */
 +              if (name.len == 1)
 +                      return 0;
 +              if (name.name[1] == '.' && name.len == 2)
 +                      return 0;
 +      }
 +      fc = get_fuse_conn(dir);
 +
 +      name.hash = full_name_hash(name.name, name.len);
 +      dentry = d_lookup(parent, &name);
 +      if (dentry && dentry->d_inode) {
 +              inode = dentry->d_inode;
 +              if (get_node_id(inode) == o->nodeid) {
 +                      struct fuse_inode *fi;
 +                      fi = get_fuse_inode(inode);
 +                      spin_lock(&fc->lock);
 +                      fi->nlookup++;
 +                      spin_unlock(&fc->lock);
 +
 +                      /*
 +                       * The other branch to 'found' comes via fuse_iget()
 +                       * which bumps nlookup inside
 +                       */
 +                      goto found;
 +              }
 +              err = d_invalidate(dentry);
 +              if (err)
 +                      goto out;
 +              dput(dentry);
 +              dentry = NULL;
 +      }
 +
 +      dentry = d_alloc(parent, &name);
 +      err = -ENOMEM;
 +      if (!dentry)
 +              goto out;
 +
 +      inode = fuse_iget(dir->i_sb, o->nodeid, o->generation,
 +                        &o->attr, entry_attr_timeout(o), attr_version);
 +      if (!inode)
 +              goto out;
 +
 +      alias = d_materialise_unique(dentry, inode);
 +      err = PTR_ERR(alias);
 +      if (IS_ERR(alias))
 +              goto out;
 +      if (alias) {
 +              dput(dentry);
 +              dentry = alias;
 +      }
 +
 +found:
 +      fuse_change_attributes(inode, &o->attr, entry_attr_timeout(o),
 +                             attr_version);
 +
 +      fuse_change_entry_timeout(dentry, o);
 +
 +      err = 0;
 +out:
 +      if (dentry)
 +              dput(dentry);
 +      return err;
 +}
 +
 +static int parse_dirplusfile(char *buf, size_t nbytes, struct file *file,
 +                           void *dstbuf, filldir_t filldir, u64 attr_version)
 +{
 +      struct fuse_direntplus *direntplus;
 +      struct fuse_dirent *dirent;
 +      size_t reclen;
 +      int over = 0;
 +      int ret;
 +
 +      while (nbytes >= FUSE_NAME_OFFSET_DIRENTPLUS) {
 +              direntplus = (struct fuse_direntplus *) buf;
 +              dirent = &direntplus->dirent;
 +              reclen = FUSE_DIRENTPLUS_SIZE(direntplus);
 +
 +              if (!dirent->namelen || dirent->namelen > FUSE_NAME_MAX)
 +                      return -EIO;
 +              if (reclen > nbytes)
 +                      break;
 +
 +              if (!over) {
 +                      /* We fill entries into dstbuf only as much as
 +                         it can hold. But we still continue iterating
 +                         over remaining entries to link them. If not,
 +                         we need to send a FORGET for each of those
 +                         which we did not link.
 +                      */
 +                      over = filldir(dstbuf, dirent->name, dirent->namelen,
 +                                     file->f_pos, dirent->ino,
 +                                     dirent->type);
 +                      file->f_pos = dirent->off;
 +              }
 +
 +              buf += reclen;
 +              nbytes -= reclen;
 +
 +              ret = fuse_direntplus_link(file, direntplus, attr_version);
 +              if (ret)
 +                      fuse_force_forget(file, direntplus->entry_out.nodeid);
 +      }
 +
 +      return 0;
 +}
 +
 +static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir)
 +{
 +      int plus, err;
        size_t nbytes;
        struct page *page;
-       struct inode *inode = file->f_path.dentry->d_inode;
+       struct inode *inode = file_inode(file);
        struct fuse_conn *fc = get_fuse_conn(inode);
        struct fuse_req *req;
 +      u64 attr_version = 0;
  
        if (is_bad_inode(inode))
                return -EIO;
diff --cc fs/fuse/inode.c
Simple merge
diff --cc fs/gfs2/file.c
Simple merge
diff --cc fs/gfs2/rgrp.c
Simple merge
diff --cc fs/gfs2/sys.c
Simple merge
Simple merge
Simple merge
@@@ -811,9 -808,9 +811,9 @@@ outrel
  
  long ncp_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
  {
-       struct inode *inode = filp->f_dentry->d_inode;
+       struct inode *inode = file_inode(filp);
        struct ncp_server *server = NCP_SERVER(inode);
 -      uid_t uid = current_uid();
 +      kuid_t uid = current_uid();
        int need_drop_write = 0;
        long ret;
  
diff --cc fs/nfs/idmap.c
Simple merge
diff --cc fs/nfs/inode.c
Simple merge
diff --cc fs/nfs/super.c
Simple merge
Simple merge
Simple merge
Simple merge
diff --cc fs/nfsd/vfs.c
Simple merge
Simple merge
Simple merge
diff --cc fs/ocfs2/aops.c
Simple merge
diff --cc fs/ocfs2/dir.c
Simple merge
diff --cc fs/ocfs2/file.c
Simple merge
Simple merge
Simple merge
diff --cc fs/ubifs/file.c
Simple merge
Simple merge
Simple merge
Simple merge
diff --cc ipc/mqueue.c
Simple merge
diff --cc ipc/shm.c
Simple merge
diff --cc kernel/acct.c
Simple merge
diff --cc kernel/cgroup.c
Simple merge
Simple merge
diff --cc kernel/fork.c
Simple merge
diff --cc kernel/module.c
Simple merge
Simple merge
diff --cc kernel/sys.c
Simple merge
Simple merge
diff --cc mm/fadvise.c
Simple merge
diff --cc mm/filemap.c
Simple merge
diff --cc mm/hugetlb.c
Simple merge
diff --cc mm/mmap.c
Simple merge
diff --cc mm/nommu.c
Simple merge
diff --cc mm/shmem.c
Simple merge
diff --cc mm/swapfile.c
Simple merge
diff --cc net/atm/proc.c
Simple merge
Simple merge
Simple merge
diff --cc net/socket.c
Simple merge
@@@ -620,10 -616,9 +620,10 @@@ gss_pipe_downcall(struct file *filp, co
        const void *p, *end;
        void *buf;
        struct gss_upcall_msg *gss_msg;
-       struct rpc_pipe *pipe = RPC_I(filp->f_dentry->d_inode)->pipe;
+       struct rpc_pipe *pipe = RPC_I(file_inode(filp))->pipe;
        struct gss_cl_ctx *ctx;
 -      uid_t uid;
 +      uid_t id;
 +      kuid_t uid;
        ssize_t err = -EFBIG;
  
        if (mlen > MSG_BUF_MAXSIZE)
@@@ -145,10 -145,10 +145,10 @@@ int ima_collect_measurement(struct inte
        int result = 0;
  
        if (!(iint->flags & IMA_COLLECTED)) {
-               u64 i_version = file->f_dentry->d_inode->i_version;
+               u64 i_version = file_inode(file)->i_version;
  
                iint->ima_xattr.type = IMA_XATTR_DIGEST;
 -              result = ima_calc_hash(file, iint->ima_xattr.digest);
 +              result = ima_calc_file_hash(file, iint->ima_xattr.digest);
                if (!result) {
                        iint->version = i_version;
                        iint->flags |= IMA_COLLECTED;
Simple merge
@@@ -139,14 -145,13 +139,14 @@@ void ima_file_free(struct file *file
        ima_check_last_writer(iint, inode, file);
  }
  
 -static int process_measurement(struct file *file, const unsigned char *filename,
 +static int process_measurement(struct file *file, const char *filename,
                               int mask, int function)
  {
-       struct inode *inode = file->f_dentry->d_inode;
+       struct inode *inode = file_inode(file);
        struct integrity_iint_cache *iint;
 -      unsigned char *pathname = NULL, *pathbuf = NULL;
 -      int rc = -ENOMEM, action, must_appraise;
 +      char *pathbuf = NULL;
 +      const char *pathname = NULL;
 +      int rc = -ENOMEM, action, must_appraise, _func;
  
        if (!ima_initialized || !S_ISREG(inode->i_mode))
                return 0;
Simple merge