Merge git://git.infradead.org/users/eparis/audit
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 22 Nov 2013 03:18:14 +0000 (19:18 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 22 Nov 2013 03:18:14 +0000 (19:18 -0800)
Pull audit updates from Eric Paris:
 "Nothing amazing.  Formatting, small bug fixes, couple of fixes where
  we didn't get records due to some old VFS changes, and a change to how
  we collect execve info..."

Fixed conflict in fs/exec.c as per Eric and linux-next.

* git://git.infradead.org/users/eparis/audit: (28 commits)
  audit: fix type of sessionid in audit_set_loginuid()
  audit: call audit_bprm() only once to add AUDIT_EXECVE information
  audit: move audit_aux_data_execve contents into audit_context union
  audit: remove unused envc member of audit_aux_data_execve
  audit: Kill the unused struct audit_aux_data_capset
  audit: do not reject all AUDIT_INODE filter types
  audit: suppress stock memalloc failure warnings since already managed
  audit: log the audit_names record type
  audit: add child record before the create to handle case where create fails
  audit: use given values in tty_audit enable api
  audit: use nlmsg_len() to get message payload length
  audit: use memset instead of trying to initialize field by field
  audit: fix info leak in AUDIT_GET requests
  audit: update AUDIT_INODE filter rule to comparator function
  audit: audit feature to set loginuid immutable
  audit: audit feature to only allow unsetting the loginuid
  audit: allow unsetting the loginuid (with priv)
  audit: remove CONFIG_AUDIT_LOGINUID_IMMUTABLE
  audit: loginuid functions coding style
  selinux: apply selinux checks on new audit message types
  ...

1  2 
fs/exec.c
fs/namei.c
include/uapi/linux/audit.h
init/Kconfig
kernel/audit.c
security/lsm_audit.c

diff --combined fs/exec.c
index 977319fd77f39de88ef66979d1de95f7d846f9a6,c5c24f2fc44ad604b1ada2438fa1fa2158384321..7ea097f6b341f06982f3ea3b068de5755b1605e0
+++ b/fs/exec.c
@@@ -74,8 -74,6 +74,8 @@@ static DEFINE_RWLOCK(binfmt_lock)
  void __register_binfmt(struct linux_binfmt * fmt, int insert)
  {
        BUG_ON(!fmt);
 +      if (WARN_ON(!fmt->load_binary))
 +              return;
        write_lock(&binfmt_lock);
        insert ? list_add(&fmt->lh, &formats) :
                 list_add_tail(&fmt->lh, &formats);
@@@ -106,7 -104,6 +106,7 @@@ static inline void put_binfmt(struct li
   */
  SYSCALL_DEFINE1(uselib, const char __user *, library)
  {
 +      struct linux_binfmt *fmt;
        struct file *file;
        struct filename *tmp = getname(library);
        int error = PTR_ERR(tmp);
        fsnotify_open(file);
  
        error = -ENOEXEC;
 -      if(file->f_op) {
 -              struct linux_binfmt * fmt;
  
 -              read_lock(&binfmt_lock);
 -              list_for_each_entry(fmt, &formats, lh) {
 -                      if (!fmt->load_shlib)
 -                              continue;
 -                      if (!try_module_get(fmt->module))
 -                              continue;
 -                      read_unlock(&binfmt_lock);
 -                      error = fmt->load_shlib(file);
 -                      read_lock(&binfmt_lock);
 -                      put_binfmt(fmt);
 -                      if (error != -ENOEXEC)
 -                              break;
 -              }
 +      read_lock(&binfmt_lock);
 +      list_for_each_entry(fmt, &formats, lh) {
 +              if (!fmt->load_shlib)
 +                      continue;
 +              if (!try_module_get(fmt->module))
 +                      continue;
                read_unlock(&binfmt_lock);
 +              error = fmt->load_shlib(file);
 +              read_lock(&binfmt_lock);
 +              put_binfmt(fmt);
 +              if (error != -ENOEXEC)
 +                      break;
        }
 +      read_unlock(&binfmt_lock);
  exit:
        fput(file);
  out:
@@@ -266,7 -266,7 +266,7 @@@ static int __bprm_mm_init(struct linux_
        BUILD_BUG_ON(VM_STACK_FLAGS & VM_STACK_INCOMPLETE_SETUP);
        vma->vm_end = STACK_TOP_MAX;
        vma->vm_start = vma->vm_end - PAGE_SIZE;
 -      vma->vm_flags = VM_STACK_FLAGS | VM_STACK_INCOMPLETE_SETUP;
 +      vma->vm_flags = VM_SOFTDIRTY | VM_STACK_FLAGS | VM_STACK_INCOMPLETE_SETUP;
        vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
        INIT_LIST_HEAD(&vma->anon_vma_chain);
  
@@@ -1275,10 -1275,13 +1275,10 @@@ static int check_unsafe_exec(struct lin
   */
  int prepare_binprm(struct linux_binprm *bprm)
  {
 -      umode_t mode;
 -      struct inode * inode = file_inode(bprm->file);
 +      struct inode *inode = file_inode(bprm->file);
 +      umode_t mode = inode->i_mode;
        int retval;
  
 -      mode = inode->i_mode;
 -      if (bprm->file->f_op == NULL)
 -              return -EACCES;
  
        /* clear any previous set[ug]id data from a previous binary */
        bprm->cred->euid = current_euid();
  }
  EXPORT_SYMBOL(remove_arg_zero);
  
 +#define printable(c) (((c)=='\t') || ((c)=='\n') || (0x20<=(c) && (c)<=0x7e))
  /*
   * cycle the list of binary formats handler, until one recognizes the image
   */
  int search_binary_handler(struct linux_binprm *bprm)
  {
 -      unsigned int depth = bprm->recursion_depth;
 -      int try,retval;
 +      bool need_retry = IS_ENABLED(CONFIG_MODULES);
        struct linux_binfmt *fmt;
 -      pid_t old_pid, old_vpid;
 +      int retval;
  
        /* This allows 4 levels of binfmt rewrites before failing hard. */
 -      if (depth > 5)
 +      if (bprm->recursion_depth > 5)
                return -ELOOP;
  
        retval = security_bprm_check(bprm);
        if (retval)
                return retval;
  
-       retval = audit_bprm(bprm);
-       if (retval)
-               return retval;
 +      retval = -ENOENT;
 + retry:
 +      read_lock(&binfmt_lock);
 +      list_for_each_entry(fmt, &formats, lh) {
 +              if (!try_module_get(fmt->module))
 +                      continue;
 +              read_unlock(&binfmt_lock);
 +              bprm->recursion_depth++;
 +              retval = fmt->load_binary(bprm);
 +              bprm->recursion_depth--;
 +              if (retval >= 0 || retval != -ENOEXEC ||
 +                  bprm->mm == NULL || bprm->file == NULL) {
 +                      put_binfmt(fmt);
 +                      return retval;
 +              }
 +              read_lock(&binfmt_lock);
 +              put_binfmt(fmt);
 +      }
 +      read_unlock(&binfmt_lock);
 +
 +      if (need_retry && retval == -ENOEXEC) {
 +              if (printable(bprm->buf[0]) && printable(bprm->buf[1]) &&
 +                  printable(bprm->buf[2]) && printable(bprm->buf[3]))
 +                      return retval;
 +              if (request_module("binfmt-%04x", *(ushort *)(bprm->buf + 2)) < 0)
 +                      return retval;
 +              need_retry = false;
 +              goto retry;
 +      }
 +
 +      return retval;
 +}
 +EXPORT_SYMBOL(search_binary_handler);
 +
 +static int exec_binprm(struct linux_binprm *bprm)
 +{
 +      pid_t old_pid, old_vpid;
 +      int ret;
 +
        /* Need to fetch pid before load_binary changes it */
        old_pid = current->pid;
        rcu_read_lock();
        old_vpid = task_pid_nr_ns(current, task_active_pid_ns(current->parent));
        rcu_read_unlock();
  
 -      retval = -ENOENT;
 -      for (try=0; try<2; try++) {
 -              read_lock(&binfmt_lock);
 -              list_for_each_entry(fmt, &formats, lh) {
 -                      int (*fn)(struct linux_binprm *) = fmt->load_binary;
 -                      if (!fn)
 -                              continue;
 -                      if (!try_module_get(fmt->module))
 -                              continue;
 -                      read_unlock(&binfmt_lock);
 -                      bprm->recursion_depth = depth + 1;
 -                      retval = fn(bprm);
 -                      bprm->recursion_depth = depth;
 -                      if (retval >= 0) {
 -                              if (depth == 0) {
 -                                      audit_bprm(bprm);
 -                                      trace_sched_process_exec(current, old_pid, bprm);
 -                                      ptrace_event(PTRACE_EVENT_EXEC, old_vpid);
 -                              }
 -                              put_binfmt(fmt);
 -                              allow_write_access(bprm->file);
 -                              if (bprm->file)
 -                                      fput(bprm->file);
 -                              bprm->file = NULL;
 -                              current->did_exec = 1;
 -                              proc_exec_connector(current);
 -                              return retval;
 -                      }
 -                      read_lock(&binfmt_lock);
 -                      put_binfmt(fmt);
 -                      if (retval != -ENOEXEC || bprm->mm == NULL)
 -                              break;
 -                      if (!bprm->file) {
 -                              read_unlock(&binfmt_lock);
 -                              return retval;
 -                      }
 -              }
 -              read_unlock(&binfmt_lock);
 -#ifdef CONFIG_MODULES
 -              if (retval != -ENOEXEC || bprm->mm == NULL) {
 -                      break;
 -              } else {
 -#define printable(c) (((c)=='\t') || ((c)=='\n') || (0x20<=(c) && (c)<=0x7e))
 -                      if (printable(bprm->buf[0]) &&
 -                          printable(bprm->buf[1]) &&
 -                          printable(bprm->buf[2]) &&
 -                          printable(bprm->buf[3]))
 -                              break; /* -ENOEXEC */
 -                      if (try)
 -                              break; /* -ENOEXEC */
 -                      request_module("binfmt-%04x", *(unsigned short *)(&bprm->buf[2]));
 +      ret = search_binary_handler(bprm);
 +      if (ret >= 0) {
++              audit_bprm(bprm);
 +              trace_sched_process_exec(current, old_pid, bprm);
 +              ptrace_event(PTRACE_EVENT_EXEC, old_vpid);
 +              current->did_exec = 1;
 +              proc_exec_connector(current);
 +
 +              if (bprm->file) {
 +                      allow_write_access(bprm->file);
 +                      fput(bprm->file);
 +                      bprm->file = NULL; /* to catch use-after-free */
                }
 -#else
 -              break;
 -#endif
        }
 -      return retval;
 -}
  
 -EXPORT_SYMBOL(search_binary_handler);
 +      return ret;
 +}
  
  /*
   * sys_execve() executes a new program.
@@@ -1534,7 -1538,7 +1531,7 @@@ static int do_execve_common(const char 
        if (retval < 0)
                goto out;
  
 -      retval = search_binary_handler(bprm);
 +      retval = exec_binprm(bprm);
        if (retval < 0)
                goto out;
  
        current->fs->in_exec = 0;
        current->in_execve = 0;
        acct_update_integrals(current);
 +      task_numa_free(current);
        free_bprm(bprm);
        if (displaced)
                put_files_struct(displaced);
@@@ -1664,12 -1667,6 +1661,12 @@@ int __get_dumpable(unsigned long mm_fla
        return (ret > SUID_DUMP_USER) ? SUID_DUMP_ROOT : ret;
  }
  
 +/*
 + * This returns the actual value of the suid_dumpable flag. For things
 + * that are using this for checking for privilege transitions, it must
 + * test against SUID_DUMP_USER rather than treating it as a boolean
 + * value.
 + */
  int get_dumpable(struct mm_struct *mm)
  {
        return __get_dumpable(mm->flags);
diff --combined fs/namei.c
index e029a4cbff7db7b23af15628ca4d8c2cac5da491,df9946e83db44caab4126059c679d2dad8434f44..8f77a8cea289350b9d0e427b284cc01a2df4691d
@@@ -482,6 -482,18 +482,6 @@@ EXPORT_SYMBOL(path_put)
   * to restart the path walk from the beginning in ref-walk mode.
   */
  
 -static inline void lock_rcu_walk(void)
 -{
 -      br_read_lock(&vfsmount_lock);
 -      rcu_read_lock();
 -}
 -
 -static inline void unlock_rcu_walk(void)
 -{
 -      rcu_read_unlock();
 -      br_read_unlock(&vfsmount_lock);
 -}
 -
  /**
   * unlazy_walk - try to switch to ref-walk mode.
   * @nd: nameidata pathwalk data
@@@ -496,75 -508,56 +496,75 @@@ static int unlazy_walk(struct nameidat
  {
        struct fs_struct *fs = current->fs;
        struct dentry *parent = nd->path.dentry;
 -      int want_root = 0;
  
        BUG_ON(!(nd->flags & LOOKUP_RCU));
 -      if (nd->root.mnt && !(nd->flags & LOOKUP_ROOT)) {
 -              want_root = 1;
 -              spin_lock(&fs->lock);
 -              if (nd->root.mnt != fs->root.mnt ||
 -                              nd->root.dentry != fs->root.dentry)
 -                      goto err_root;
 +
 +      /*
 +       * After legitimizing the bastards, terminate_walk()
 +       * will do the right thing for non-RCU mode, and all our
 +       * subsequent exit cases should rcu_read_unlock()
 +       * before returning.  Do vfsmount first; if dentry
 +       * can't be legitimized, just set nd->path.dentry to NULL
 +       * and rely on dput(NULL) being a no-op.
 +       */
 +      if (!legitimize_mnt(nd->path.mnt, nd->m_seq))
 +              return -ECHILD;
 +      nd->flags &= ~LOOKUP_RCU;
 +
 +      if (!lockref_get_not_dead(&parent->d_lockref)) {
 +              nd->path.dentry = NULL; 
 +              rcu_read_unlock();
 +              return -ECHILD;
        }
 -      spin_lock(&parent->d_lock);
 +
 +      /*
 +       * For a negative lookup, the lookup sequence point is the parents
 +       * sequence point, and it only needs to revalidate the parent dentry.
 +       *
 +       * For a positive lookup, we need to move both the parent and the
 +       * dentry from the RCU domain to be properly refcounted. And the
 +       * sequence number in the dentry validates *both* dentry counters,
 +       * since we checked the sequence number of the parent after we got
 +       * the child sequence number. So we know the parent must still
 +       * be valid if the child sequence number is still valid.
 +       */
        if (!dentry) {
 -              if (!__d_rcu_to_refcount(parent, nd->seq))
 -                      goto err_parent;
 +              if (read_seqcount_retry(&parent->d_seq, nd->seq))
 +                      goto out;
                BUG_ON(nd->inode != parent->d_inode);
        } else {
 -              if (dentry->d_parent != parent)
 -                      goto err_parent;
 -              spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
 -              if (!__d_rcu_to_refcount(dentry, nd->seq))
 -                      goto err_child;
 -              /*
 -               * If the sequence check on the child dentry passed, then
 -               * the child has not been removed from its parent. This
 -               * means the parent dentry must be valid and able to take
 -               * a reference at this point.
 -               */
 -              BUG_ON(!IS_ROOT(dentry) && dentry->d_parent != parent);
 -              BUG_ON(!parent->d_lockref.count);
 -              parent->d_lockref.count++;
 -              spin_unlock(&dentry->d_lock);
 +              if (!lockref_get_not_dead(&dentry->d_lockref))
 +                      goto out;
 +              if (read_seqcount_retry(&dentry->d_seq, nd->seq))
 +                      goto drop_dentry;
        }
 -      spin_unlock(&parent->d_lock);
 -      if (want_root) {
 +
 +      /*
 +       * Sequence counts matched. Now make sure that the root is
 +       * still valid and get it if required.
 +       */
 +      if (nd->root.mnt && !(nd->flags & LOOKUP_ROOT)) {
 +              spin_lock(&fs->lock);
 +              if (nd->root.mnt != fs->root.mnt || nd->root.dentry != fs->root.dentry)
 +                      goto unlock_and_drop_dentry;
                path_get(&nd->root);
                spin_unlock(&fs->lock);
        }
 -      mntget(nd->path.mnt);
  
 -      unlock_rcu_walk();
 -      nd->flags &= ~LOOKUP_RCU;
 +      rcu_read_unlock();
        return 0;
  
 -err_child:
 -      spin_unlock(&dentry->d_lock);
 -err_parent:
 -      spin_unlock(&parent->d_lock);
 -err_root:
 -      if (want_root)
 -              spin_unlock(&fs->lock);
 +unlock_and_drop_dentry:
 +      spin_unlock(&fs->lock);
 +drop_dentry:
 +      rcu_read_unlock();
 +      dput(dentry);
 +      goto drop_root_mnt;
 +out:
 +      rcu_read_unlock();
 +drop_root_mnt:
 +      if (!(nd->flags & LOOKUP_ROOT))
 +              nd->root.mnt = NULL;
        return -ECHILD;
  }
  
@@@ -592,23 -585,16 +592,23 @@@ static int complete_walk(struct nameida
                nd->flags &= ~LOOKUP_RCU;
                if (!(nd->flags & LOOKUP_ROOT))
                        nd->root.mnt = NULL;
 -              spin_lock(&dentry->d_lock);
 -              if (unlikely(!__d_rcu_to_refcount(dentry, nd->seq))) {
 -                      spin_unlock(&dentry->d_lock);
 -                      unlock_rcu_walk();
 +
 +              if (!legitimize_mnt(nd->path.mnt, nd->m_seq)) {
 +                      rcu_read_unlock();
 +                      return -ECHILD;
 +              }
 +              if (unlikely(!lockref_get_not_dead(&dentry->d_lockref))) {
 +                      rcu_read_unlock();
 +                      mntput(nd->path.mnt);
 +                      return -ECHILD;
 +              }
 +              if (read_seqcount_retry(&dentry->d_seq, nd->seq)) {
 +                      rcu_read_unlock();
 +                      dput(dentry);
 +                      mntput(nd->path.mnt);
                        return -ECHILD;
                }
 -              BUG_ON(nd->inode != dentry->d_inode);
 -              spin_unlock(&dentry->d_lock);
 -              mntget(nd->path.mnt);
 -              unlock_rcu_walk();
 +              rcu_read_unlock();
        }
  
        if (likely(!(nd->flags & LOOKUP_JUMPED)))
@@@ -650,6 -636,29 +650,6 @@@ static __always_inline void set_root_rc
        }
  }
  
 -static __always_inline int __vfs_follow_link(struct nameidata *nd, const char *link)
 -{
 -      int ret;
 -
 -      if (IS_ERR(link))
 -              goto fail;
 -
 -      if (*link == '/') {
 -              set_root(nd);
 -              path_put(&nd->path);
 -              nd->path = nd->root;
 -              path_get(&nd->root);
 -              nd->flags |= LOOKUP_JUMPED;
 -      }
 -      nd->inode = nd->path.dentry->d_inode;
 -
 -      ret = link_path_walk(link, nd);
 -      return ret;
 -fail:
 -      path_put(&nd->path);
 -      return PTR_ERR(link);
 -}
 -
  static void path_put_conditional(struct path *path, struct nameidata *nd)
  {
        dput(path->dentry);
@@@ -841,20 -850,7 +841,20 @@@ follow_link(struct path *link, struct n
        error = 0;
        s = nd_get_link(nd);
        if (s) {
 -              error = __vfs_follow_link(nd, s);
 +              if (unlikely(IS_ERR(s))) {
 +                      path_put(&nd->path);
 +                      put_link(nd, link, *p);
 +                      return PTR_ERR(s);
 +              }
 +              if (*s == '/') {
 +                      set_root(nd);
 +                      path_put(&nd->path);
 +                      nd->path = nd->root;
 +                      path_get(&nd->root);
 +                      nd->flags |= LOOKUP_JUMPED;
 +              }
 +              nd->inode = nd->path.dentry->d_inode;
 +              error = link_path_walk(s, nd);
                if (unlikely(error))
                        put_link(nd, link, *p);
        }
@@@ -899,15 -895,15 +899,15 @@@ int follow_up(struct path *path
        struct mount *parent;
        struct dentry *mountpoint;
  
 -      br_read_lock(&vfsmount_lock);
 +      read_seqlock_excl(&mount_lock);
        parent = mnt->mnt_parent;
        if (parent == mnt) {
 -              br_read_unlock(&vfsmount_lock);
 +              read_sequnlock_excl(&mount_lock);
                return 0;
        }
        mntget(&parent->mnt);
        mountpoint = dget(mnt->mnt_mountpoint);
 -      br_read_unlock(&vfsmount_lock);
 +      read_sequnlock_excl(&mount_lock);
        dput(path->dentry);
        path->dentry = mountpoint;
        mntput(path->mnt);
@@@ -1038,8 -1034,8 +1038,8 @@@ static int follow_managed(struct path *
  
                        /* Something is mounted on this dentry in another
                         * namespace and/or whatever was mounted there in this
 -                       * namespace got unmounted before we managed to get the
 -                       * vfsmount_lock */
 +                       * namespace got unmounted before lookup_mnt() could
 +                       * get it */
                }
  
                /* Handle an automount point */
@@@ -1101,7 -1097,7 +1101,7 @@@ static bool __follow_mount_rcu(struct n
                if (!d_mountpoint(path->dentry))
                        break;
  
 -              mounted = __lookup_mnt(path->mnt, path->dentry, 1);
 +              mounted = __lookup_mnt(path->mnt, path->dentry);
                if (!mounted)
                        break;
                path->mnt = &mounted->mnt;
@@@ -1122,7 -1118,7 +1122,7 @@@ static void follow_mount_rcu(struct nam
  {
        while (d_mountpoint(nd->path.dentry)) {
                struct mount *mounted;
 -              mounted = __lookup_mnt(nd->path.mnt, nd->path.dentry, 1);
 +              mounted = __lookup_mnt(nd->path.mnt, nd->path.dentry);
                if (!mounted)
                        break;
                nd->path.mnt = &mounted->mnt;
@@@ -1164,7 -1160,7 +1164,7 @@@ failed
        nd->flags &= ~LOOKUP_RCU;
        if (!(nd->flags & LOOKUP_ROOT))
                nd->root.mnt = NULL;
 -      unlock_rcu_walk();
 +      rcu_read_unlock();
        return -ECHILD;
  }
  
@@@ -1298,8 -1294,8 +1298,8 @@@ static struct dentry *lookup_dcache(str
  }
  
  /*
 - * Call i_op->lookup on the dentry.  The dentry must be negative but may be
 - * hashed if it was pouplated with DCACHE_NEED_LOOKUP.
 + * Call i_op->lookup on the dentry.  The dentry must be negative and
 + * unhashed.
   *
   * dir->d_inode->i_mutex must be held
   */
@@@ -1491,7 -1487,7 +1491,7 @@@ static void terminate_walk(struct namei
                nd->flags &= ~LOOKUP_RCU;
                if (!(nd->flags & LOOKUP_ROOT))
                        nd->root.mnt = NULL;
 -              unlock_rcu_walk();
 +              rcu_read_unlock();
        }
  }
  
   * so we keep a cache of "no, this doesn't need follow_link"
   * for the common case.
   */
 -static inline int should_follow_link(struct inode *inode, int follow)
 +static inline int should_follow_link(struct dentry *dentry, int follow)
  {
 -      if (unlikely(!(inode->i_opflags & IOP_NOFOLLOW))) {
 -              if (likely(inode->i_op->follow_link))
 -                      return follow;
 -
 -              /* This gets set once for the inode lifetime */
 -              spin_lock(&inode->i_lock);
 -              inode->i_opflags |= IOP_NOFOLLOW;
 -              spin_unlock(&inode->i_lock);
 -      }
 -      return 0;
 +      return unlikely(d_is_symlink(dentry)) ? follow : 0;
  }
  
  static inline int walk_component(struct nameidata *nd, struct path *path,
        if (!inode)
                goto out_path_put;
  
 -      if (should_follow_link(inode, follow)) {
 +      if (should_follow_link(path->dentry, follow)) {
                if (nd->flags & LOOKUP_RCU) {
                        if (unlikely(unlazy_walk(nd, path->dentry))) {
                                err = -ECHILD;
@@@ -1591,6 -1596,26 +1591,6 @@@ static inline int nested_symlink(struc
        return res;
  }
  
 -/*
 - * We really don't want to look at inode->i_op->lookup
 - * when we don't have to. So we keep a cache bit in
 - * the inode ->i_opflags field that says "yes, we can
 - * do lookup on this inode".
 - */
 -static inline int can_lookup(struct inode *inode)
 -{
 -      if (likely(inode->i_opflags & IOP_LOOKUP))
 -              return 1;
 -      if (likely(!inode->i_op->lookup))
 -              return 0;
 -
 -      /* We do this once for the lifetime of the inode */
 -      spin_lock(&inode->i_lock);
 -      inode->i_opflags |= IOP_LOOKUP;
 -      spin_unlock(&inode->i_lock);
 -      return 1;
 -}
 -
  /*
   * We can do the critical dentry name comparison and hashing
   * operations one word at a time, but we are limited to:
@@@ -1794,7 -1819,7 +1794,7 @@@ static int link_path_walk(const char *n
                        if (err)
                                return err;
                }
 -              if (!can_lookup(nd->inode)) {
 +              if (!d_is_directory(nd->path.dentry)) {
                        err = -ENOTDIR; 
                        break;
                }
@@@ -1812,10 -1837,9 +1812,10 @@@ static int path_init(int dfd, const cha
        nd->flags = flags | LOOKUP_JUMPED;
        nd->depth = 0;
        if (flags & LOOKUP_ROOT) {
 -              struct inode *inode = nd->root.dentry->d_inode;
 +              struct dentry *root = nd->root.dentry;
 +              struct inode *inode = root->d_inode;
                if (*name) {
 -                      if (!can_lookup(inode))
 +                      if (!d_is_directory(root))
                                return -ENOTDIR;
                        retval = inode_permission(inode, MAY_EXEC);
                        if (retval)
                nd->path = nd->root;
                nd->inode = inode;
                if (flags & LOOKUP_RCU) {
 -                      lock_rcu_walk();
 +                      rcu_read_lock();
                        nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq);
 +                      nd->m_seq = read_seqbegin(&mount_lock);
                } else {
                        path_get(&nd->path);
                }
  
        nd->root.mnt = NULL;
  
 +      nd->m_seq = read_seqbegin(&mount_lock);
        if (*name=='/') {
                if (flags & LOOKUP_RCU) {
 -                      lock_rcu_walk();
 +                      rcu_read_lock();
                        set_root_rcu(nd);
                } else {
                        set_root(nd);
                        struct fs_struct *fs = current->fs;
                        unsigned seq;
  
 -                      lock_rcu_walk();
 +                      rcu_read_lock();
  
                        do {
                                seq = read_seqcount_begin(&fs->seq);
                dentry = f.file->f_path.dentry;
  
                if (*name) {
 -                      if (!can_lookup(dentry->d_inode)) {
 +                      if (!d_is_directory(dentry)) {
                                fdput(f);
                                return -ENOTDIR;
                        }
                        if (f.need_put)
                                *fp = f.file;
                        nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq);
 -                      lock_rcu_walk();
 +                      rcu_read_lock();
                } else {
                        path_get(&nd->path);
                        fdput(f);
@@@ -1953,7 -1975,7 +1953,7 @@@ static int path_lookupat(int dfd, cons
                err = complete_walk(nd);
  
        if (!err && nd->flags & LOOKUP_DIRECTORY) {
 -              if (!can_lookup(nd->inode)) {
 +              if (!d_is_directory(nd->path.dentry)) {
                        path_put(&nd->path);
                        err = -ENOTDIR;
                }
@@@ -2162,198 -2184,6 +2162,198 @@@ user_path_parent(int dfd, const char __
        return s;
  }
  
 +/**
 + * mountpoint_last - look up last component for umount
 + * @nd:   pathwalk nameidata - currently pointing at parent directory of "last"
 + * @path: pointer to container for result
 + *
 + * This is a special lookup_last function just for umount. In this case, we
 + * need to resolve the path without doing any revalidation.
 + *
 + * The nameidata should be the result of doing a LOOKUP_PARENT pathwalk. Since
 + * mountpoints are always pinned in the dcache, their ancestors are too. Thus,
 + * in almost all cases, this lookup will be served out of the dcache. The only
 + * cases where it won't are if nd->last refers to a symlink or the path is
 + * bogus and it doesn't exist.
 + *
 + * Returns:
 + * -error: if there was an error during lookup. This includes -ENOENT if the
 + *         lookup found a negative dentry. The nd->path reference will also be
 + *         put in this case.
 + *
 + * 0:      if we successfully resolved nd->path and found it to not to be a
 + *         symlink that needs to be followed. "path" will also be populated.
 + *         The nd->path reference will also be put.
 + *
 + * 1:      if we successfully resolved nd->last and found it to be a symlink
 + *         that needs to be followed. "path" will be populated with the path
 + *         to the link, and nd->path will *not* be put.
 + */
 +static int
 +mountpoint_last(struct nameidata *nd, struct path *path)
 +{
 +      int error = 0;
 +      struct dentry *dentry;
 +      struct dentry *dir = nd->path.dentry;
 +
 +      /* If we're in rcuwalk, drop out of it to handle last component */
 +      if (nd->flags & LOOKUP_RCU) {
 +              if (unlazy_walk(nd, NULL)) {
 +                      error = -ECHILD;
 +                      goto out;
 +              }
 +      }
 +
 +      nd->flags &= ~LOOKUP_PARENT;
 +
 +      if (unlikely(nd->last_type != LAST_NORM)) {
 +              error = handle_dots(nd, nd->last_type);
 +              if (error)
 +                      goto out;
 +              dentry = dget(nd->path.dentry);
 +              goto done;
 +      }
 +
 +      mutex_lock(&dir->d_inode->i_mutex);
 +      dentry = d_lookup(dir, &nd->last);
 +      if (!dentry) {
 +              /*
 +               * No cached dentry. Mounted dentries are pinned in the cache,
 +               * so that means that this dentry is probably a symlink or the
 +               * path doesn't actually point to a mounted dentry.
 +               */
 +              dentry = d_alloc(dir, &nd->last);
 +              if (!dentry) {
 +                      error = -ENOMEM;
 +                      mutex_unlock(&dir->d_inode->i_mutex);
 +                      goto out;
 +              }
 +              dentry = lookup_real(dir->d_inode, dentry, nd->flags);
 +              error = PTR_ERR(dentry);
 +              if (IS_ERR(dentry)) {
 +                      mutex_unlock(&dir->d_inode->i_mutex);
 +                      goto out;
 +              }
 +      }
 +      mutex_unlock(&dir->d_inode->i_mutex);
 +
 +done:
 +      if (!dentry->d_inode) {
 +              error = -ENOENT;
 +              dput(dentry);
 +              goto out;
 +      }
 +      path->dentry = dentry;
 +      path->mnt = mntget(nd->path.mnt);
 +      if (should_follow_link(dentry, nd->flags & LOOKUP_FOLLOW))
 +              return 1;
 +      follow_mount(path);
 +      error = 0;
 +out:
 +      terminate_walk(nd);
 +      return error;
 +}
 +
 +/**
 + * path_mountpoint - look up a path to be umounted
 + * @dfd:      directory file descriptor to start walk from
 + * @name:     full pathname to walk
 + * @path:     pointer to container for result
 + * @flags:    lookup flags
 + *
 + * Look up the given name, but don't attempt to revalidate the last component.
 + * Returns 0 and "path" will be valid on success; Returns error otherwise.
 + */
 +static int
 +path_mountpoint(int dfd, const char *name, struct path *path, unsigned int flags)
 +{
 +      struct file *base = NULL;
 +      struct nameidata nd;
 +      int err;
 +
 +      err = path_init(dfd, name, flags | LOOKUP_PARENT, &nd, &base);
 +      if (unlikely(err))
 +              return err;
 +
 +      current->total_link_count = 0;
 +      err = link_path_walk(name, &nd);
 +      if (err)
 +              goto out;
 +
 +      err = mountpoint_last(&nd, path);
 +      while (err > 0) {
 +              void *cookie;
 +              struct path link = *path;
 +              err = may_follow_link(&link, &nd);
 +              if (unlikely(err))
 +                      break;
 +              nd.flags |= LOOKUP_PARENT;
 +              err = follow_link(&link, &nd, &cookie);
 +              if (err)
 +                      break;
 +              err = mountpoint_last(&nd, path);
 +              put_link(&nd, &link, cookie);
 +      }
 +out:
 +      if (base)
 +              fput(base);
 +
 +      if (nd.root.mnt && !(nd.flags & LOOKUP_ROOT))
 +              path_put(&nd.root);
 +
 +      return err;
 +}
 +
 +static int
 +filename_mountpoint(int dfd, struct filename *s, struct path *path,
 +                      unsigned int flags)
 +{
 +      int error = path_mountpoint(dfd, s->name, path, flags | LOOKUP_RCU);
 +      if (unlikely(error == -ECHILD))
 +              error = path_mountpoint(dfd, s->name, path, flags);
 +      if (unlikely(error == -ESTALE))
 +              error = path_mountpoint(dfd, s->name, path, flags | LOOKUP_REVAL);
 +      if (likely(!error))
 +              audit_inode(s, path->dentry, 0);
 +      return error;
 +}
 +
 +/**
 + * user_path_mountpoint_at - lookup a path from userland in order to umount it
 + * @dfd:      directory file descriptor
 + * @name:     pathname from userland
 + * @flags:    lookup flags
 + * @path:     pointer to container to hold result
 + *
 + * A umount is a special case for path walking. We're not actually interested
 + * in the inode in this situation, and ESTALE errors can be a problem. We
 + * simply want track down the dentry and vfsmount attached at the mountpoint
 + * and avoid revalidating the last component.
 + *
 + * Returns 0 and populates "path" on success.
 + */
 +int
 +user_path_mountpoint_at(int dfd, const char __user *name, unsigned int flags,
 +                      struct path *path)
 +{
 +      struct filename *s = getname(name);
 +      int error;
 +      if (IS_ERR(s))
 +              return PTR_ERR(s);
 +      error = filename_mountpoint(dfd, s, path, flags);
 +      putname(s);
 +      return error;
 +}
 +
 +int
 +kern_path_mountpoint(int dfd, const char *name, struct path *path,
 +                      unsigned int flags)
 +{
 +      struct filename s = {.name = name};
 +      return filename_mountpoint(dfd, &s, path, flags);
 +}
 +EXPORT_SYMBOL(kern_path_mountpoint);
 +
  /*
   * It's inline, so penalty for filesystems that don't use sticky bit is
   * minimal.
@@@ -2390,14 -2220,12 +2390,14 @@@ static inline int check_sticky(struct i
   * 10. We don't allow removal of NFS sillyrenamed files; it's handled by
   *     nfs_async_unlink().
   */
 -static int may_delete(struct inode *dir,struct dentry *victim,int isdir)
 +static int may_delete(struct inode *dir, struct dentry *victim, bool isdir)
  {
 +      struct inode *inode = victim->d_inode;
        int error;
  
 -      if (!victim->d_inode)
 +      if (d_is_negative(victim))
                return -ENOENT;
 +      BUG_ON(!inode);
  
        BUG_ON(victim->d_parent->d_inode != dir);
        audit_inode_child(dir, victim, AUDIT_TYPE_CHILD_DELETE);
                return error;
        if (IS_APPEND(dir))
                return -EPERM;
 -      if (check_sticky(dir, victim->d_inode)||IS_APPEND(victim->d_inode)||
 -          IS_IMMUTABLE(victim->d_inode) || IS_SWAPFILE(victim->d_inode))
 +
 +      if (check_sticky(dir, inode) || IS_APPEND(inode) ||
 +          IS_IMMUTABLE(inode) || IS_SWAPFILE(inode))
                return -EPERM;
        if (isdir) {
 -              if (!S_ISDIR(victim->d_inode->i_mode))
 +              if (!d_is_directory(victim) && !d_is_autodir(victim))
                        return -ENOTDIR;
                if (IS_ROOT(victim))
                        return -EBUSY;
 -      } else if (S_ISDIR(victim->d_inode->i_mode))
 +      } else if (d_is_directory(victim) || d_is_autodir(victim))
                return -EISDIR;
        if (IS_DEADDIR(dir))
                return -ENOENT;
   */
  static inline int may_create(struct inode *dir, struct dentry *child)
  {
+       audit_inode_child(dir, child, AUDIT_TYPE_CHILD_CREATE);
        if (child->d_inode)
                return -EEXIST;
        if (IS_DEADDIR(dir))
@@@ -2624,7 -2452,6 +2625,7 @@@ static int atomic_open(struct nameidat
        int acc_mode;
        int create_error = 0;
        struct dentry *const DENTRY_NOT_SET = (void *) -1UL;
 +      bool excl;
  
        BUG_ON(dentry->d_inode);
  
        if ((open_flag & O_CREAT) && !IS_POSIXACL(dir))
                mode &= ~current_umask();
  
 -      if ((open_flag & (O_EXCL | O_CREAT)) == (O_EXCL | O_CREAT)) {
 +      excl = (open_flag & (O_EXCL | O_CREAT)) == (O_EXCL | O_CREAT);
 +      if (excl)
                open_flag &= ~O_TRUNC;
 -              *opened |= FILE_CREATED;
 -      }
  
        /*
         * Checking write permission is tricky, bacuse we don't know if we are
                goto out;
        }
  
 -      acc_mode = op->acc_mode;
 -      if (*opened & FILE_CREATED) {
 -              fsnotify_create(dir, dentry);
 -              acc_mode = MAY_OPEN;
 -      }
 -
        if (error) {    /* returned 1, that is */
                if (WARN_ON(file->f_path.dentry == DENTRY_NOT_SET)) {
                        error = -EIO;
                        dput(dentry);
                        dentry = file->f_path.dentry;
                }
 -              if (create_error && dentry->d_inode == NULL) {
 -                      error = create_error;
 -                      goto out;
 +              if (*opened & FILE_CREATED)
 +                      fsnotify_create(dir, dentry);
 +              if (!dentry->d_inode) {
 +                      WARN_ON(*opened & FILE_CREATED);
 +                      if (create_error) {
 +                              error = create_error;
 +                              goto out;
 +                      }
 +              } else {
 +                      if (excl && !(*opened & FILE_CREATED)) {
 +                              error = -EEXIST;
 +                              goto out;
 +                      }
                }
                goto looked_up;
        }
         * We didn't have the inode before the open, so check open permission
         * here.
         */
 +      acc_mode = op->acc_mode;
 +      if (*opened & FILE_CREATED) {
 +              WARN_ON(!(open_flag & O_CREAT));
 +              fsnotify_create(dir, dentry);
 +              acc_mode = MAY_OPEN;
 +      }
        error = may_open(&file->f_path, acc_mode, open_flag);
        if (error)
                fput(file);
@@@ -2950,7 -2768,7 +2951,7 @@@ retry_lookup
        /*
         * create/update audit record if it already exists.
         */
 -      if (path->dentry->d_inode)
 +      if (d_is_positive(path->dentry))
                audit_inode(name, path->dentry, 0);
  
        /*
  finish_lookup:
        /* we _can_ be in RCU mode here */
        error = -ENOENT;
 -      if (!inode) {
 +      if (d_is_negative(path->dentry)) {
                path_to_nameidata(path, nd);
                goto out;
        }
  
 -      if (should_follow_link(inode, !symlink_ok)) {
 +      if (should_follow_link(path->dentry, !symlink_ok)) {
                if (nd->flags & LOOKUP_RCU) {
                        if (unlikely(unlazy_walk(nd, path->dentry))) {
                                error = -ECHILD;
@@@ -3013,11 -2831,10 +3014,11 @@@ finish_open
        }
        audit_inode(name, nd->path.dentry, 0);
        error = -EISDIR;
 -      if ((open_flag & O_CREAT) && S_ISDIR(nd->inode->i_mode))
 +      if ((open_flag & O_CREAT) &&
 +          (d_is_directory(nd->path.dentry) || d_is_autodir(nd->path.dentry)))
                goto out;
        error = -ENOTDIR;
 -      if ((nd->flags & LOOKUP_DIRECTORY) && !can_lookup(nd->inode))
 +      if ((nd->flags & LOOKUP_DIRECTORY) && !d_is_directory(nd->path.dentry))
                goto out;
        if (!S_ISREG(nd->inode->i_mode))
                will_truncate = false;
@@@ -3243,7 -3060,7 +3244,7 @@@ struct file *do_file_open_root(struct d
        nd.root.mnt = mnt;
        nd.root.dentry = dentry;
  
 -      if (dentry->d_inode->i_op->follow_link && op->intent & LOOKUP_OPEN)
 +      if (d_is_symlink(dentry) && op->intent & LOOKUP_OPEN)
                return ERR_PTR(-ELOOP);
  
        file = path_openat(-1, &filename, &nd, op, flags | LOOKUP_RCU);
@@@ -3293,9 -3110,8 +3294,9 @@@ struct dentry *kern_path_create(int dfd
                goto unlock;
  
        error = -EEXIST;
 -      if (dentry->d_inode)
 +      if (d_is_positive(dentry))
                goto fail;
 +
        /*
         * Special case - lookup gave negative, but... we had foo/bar/
         * From the vfs_mknod() POV we just have a negative dentry -
@@@ -3616,27 -3432,8 +3617,27 @@@ SYSCALL_DEFINE1(rmdir, const char __use
        return do_rmdir(AT_FDCWD, pathname);
  }
  
 -int vfs_unlink(struct inode *dir, struct dentry *dentry)
 +/**
 + * vfs_unlink - unlink a filesystem object
 + * @dir:      parent directory
 + * @dentry:   victim
 + * @delegated_inode: returns victim inode, if the inode is delegated.
 + *
 + * The caller must hold dir->i_mutex.
 + *
 + * If vfs_unlink discovers a delegation, it will return -EWOULDBLOCK and
 + * return a reference to the inode in delegated_inode.  The caller
 + * should then break the delegation on that inode and retry.  Because
 + * breaking a delegation may take a long time, the caller should drop
 + * dir->i_mutex before doing so.
 + *
 + * Alternatively, a caller may pass NULL for delegated_inode.  This may
 + * be appropriate for callers that expect the underlying filesystem not
 + * to be NFS exported.
 + */
 +int vfs_unlink(struct inode *dir, struct dentry *dentry, struct inode **delegated_inode)
  {
 +      struct inode *target = dentry->d_inode;
        int error = may_delete(dir, dentry, 0);
  
        if (error)
        if (!dir->i_op->unlink)
                return -EPERM;
  
 -      mutex_lock(&dentry->d_inode->i_mutex);
 +      mutex_lock(&target->i_mutex);
        if (d_mountpoint(dentry))
                error = -EBUSY;
        else {
                error = security_inode_unlink(dir, dentry);
                if (!error) {
 +                      error = try_break_deleg(target, delegated_inode);
 +                      if (error)
 +                              goto out;
                        error = dir->i_op->unlink(dir, dentry);
                        if (!error)
                                dont_mount(dentry);
                }
        }
 -      mutex_unlock(&dentry->d_inode->i_mutex);
 +out:
 +      mutex_unlock(&target->i_mutex);
  
        /* We don't d_delete() NFS sillyrenamed files--they still exist. */
        if (!error && !(dentry->d_flags & DCACHE_NFSFS_RENAMED)) {
 -              fsnotify_link_count(dentry->d_inode);
 +              fsnotify_link_count(target);
                d_delete(dentry);
        }
  
@@@ -3684,7 -3477,6 +3685,7 @@@ static long do_unlinkat(int dfd, const 
        struct dentry *dentry;
        struct nameidata nd;
        struct inode *inode = NULL;
 +      struct inode *delegated_inode = NULL;
        unsigned int lookup_flags = 0;
  retry:
        name = user_path_parent(dfd, pathname, &nd, lookup_flags);
        error = mnt_want_write(nd.path.mnt);
        if (error)
                goto exit1;
 -
 +retry_deleg:
        mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
        dentry = lookup_hash(&nd);
        error = PTR_ERR(dentry);
                if (nd.last.name[nd.last.len])
                        goto slashes;
                inode = dentry->d_inode;
 -              if (!inode)
 +              if (d_is_negative(dentry))
                        goto slashes;
                ihold(inode);
                error = security_path_unlink(&nd.path, dentry);
                if (error)
                        goto exit2;
 -              error = vfs_unlink(nd.path.dentry->d_inode, dentry);
 +              error = vfs_unlink(nd.path.dentry->d_inode, dentry, &delegated_inode);
  exit2:
                dput(dentry);
        }
        mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
        if (inode)
                iput(inode);    /* truncate the inode here */
 +      inode = NULL;
 +      if (delegated_inode) {
 +              error = break_deleg_wait(&delegated_inode);
 +              if (!error)
 +                      goto retry_deleg;
 +      }
        mnt_drop_write(nd.path.mnt);
  exit1:
        path_put(&nd.path);
        return error;
  
  slashes:
 -      error = !dentry->d_inode ? -ENOENT :
 -              S_ISDIR(dentry->d_inode->i_mode) ? -EISDIR : -ENOTDIR;
 +      if (d_is_negative(dentry))
 +              error = -ENOENT;
 +      else if (d_is_directory(dentry) || d_is_autodir(dentry))
 +              error = -EISDIR;
 +      else
 +              error = -ENOTDIR;
        goto exit2;
  }
  
@@@ -3820,26 -3602,7 +3821,26 @@@ SYSCALL_DEFINE2(symlink, const char __u
        return sys_symlinkat(oldname, AT_FDCWD, newname);
  }
  
 -int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
 +/**
 + * vfs_link - create a new link
 + * @old_dentry:       object to be linked
 + * @dir:      new parent
 + * @new_dentry:       where to create the new link
 + * @delegated_inode: returns inode needing a delegation break
 + *
 + * The caller must hold dir->i_mutex
 + *
 + * If vfs_link discovers a delegation on the to-be-linked file in need
 + * of breaking, it will return -EWOULDBLOCK and return a reference to the
 + * inode in delegated_inode.  The caller should then break the delegation
 + * and retry.  Because breaking a delegation may take a long time, the
 + * caller should drop the i_mutex before doing so.
 + *
 + * Alternatively, a caller may pass NULL for delegated_inode.  This may
 + * be appropriate for callers that expect the underlying filesystem not
 + * to be NFS exported.
 + */
 +int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry, struct inode **delegated_inode)
  {
        struct inode *inode = old_dentry->d_inode;
        unsigned max_links = dir->i_sb->s_max_links;
                error =  -ENOENT;
        else if (max_links && inode->i_nlink >= max_links)
                error = -EMLINK;
 -      else
 -              error = dir->i_op->link(old_dentry, dir, new_dentry);
 +      else {
 +              error = try_break_deleg(inode, delegated_inode);
 +              if (!error)
 +                      error = dir->i_op->link(old_dentry, dir, new_dentry);
 +      }
  
        if (!error && (inode->i_state & I_LINKABLE)) {
                spin_lock(&inode->i_lock);
@@@ -3906,7 -3666,6 +3907,7 @@@ SYSCALL_DEFINE5(linkat, int, olddfd, co
  {
        struct dentry *new_dentry;
        struct path old_path, new_path;
 +      struct inode *delegated_inode = NULL;
        int how = 0;
        int error;
  
@@@ -3945,14 -3704,9 +3946,14 @@@ retry
        error = security_path_link(old_path.dentry, &new_path, new_dentry);
        if (error)
                goto out_dput;
 -      error = vfs_link(old_path.dentry, new_path.dentry->d_inode, new_dentry);
 +      error = vfs_link(old_path.dentry, new_path.dentry->d_inode, new_dentry, &delegated_inode);
  out_dput:
        done_path_create(&new_path, new_dentry);
 +      if (delegated_inode) {
 +              error = break_deleg_wait(&delegated_inode);
 +              if (!error)
 +                      goto retry;
 +      }
        if (retry_estale(error, how)) {
                how |= LOOKUP_REVAL;
                goto retry;
@@@ -3977,8 -3731,7 +3978,8 @@@ SYSCALL_DEFINE2(link, const char __use
   *       That's where 4.4 screws up. Current fix: serialization on
   *       sb->s_vfs_rename_mutex. We might be more accurate, but that's another
   *       story.
 - *    c) we have to lock _three_ objects - parents and victim (if it exists).
 + *    c) we have to lock _four_ objects - parents and victim (if it exists),
 + *       and source (if it is not a directory).
   *       And that - after we got ->i_mutex on parents (until then we don't know
   *       whether the target exists).  Solution: try to be smart with locking
   *       order for inodes.  We rely on the fact that tree topology may change
  }
  
  static int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry,
 -                          struct inode *new_dir, struct dentry *new_dentry)
 +                          struct inode *new_dir, struct dentry *new_dentry,
 +                          struct inode **delegated_inode)
  {
        struct inode *target = new_dentry->d_inode;
 +      struct inode *source = old_dentry->d_inode;
        int error;
  
        error = security_inode_rename(old_dir, old_dentry, new_dir, new_dentry);
                return error;
  
        dget(new_dentry);
 -      if (target)
 -              mutex_lock(&target->i_mutex);
 +      lock_two_nondirectories(source, target);
  
        error = -EBUSY;
        if (d_mountpoint(old_dentry)||d_mountpoint(new_dentry))
                goto out;
  
 +      error = try_break_deleg(source, delegated_inode);
 +      if (error)
 +              goto out;
 +      if (target) {
 +              error = try_break_deleg(target, delegated_inode);
 +              if (error)
 +                      goto out;
 +      }
        error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
        if (error)
                goto out;
        if (!(old_dir->i_sb->s_type->fs_flags & FS_RENAME_DOES_D_MOVE))
                d_move(old_dentry, new_dentry);
  out:
 -      if (target)
 -              mutex_unlock(&target->i_mutex);
 +      unlock_two_nondirectories(source, target);
        dput(new_dentry);
        return error;
  }
  
 +/**
 + * vfs_rename - rename a filesystem object
 + * @old_dir:  parent of source
 + * @old_dentry:       source
 + * @new_dir:  parent of destination
 + * @new_dentry:       destination
 + * @delegated_inode: returns an inode needing a delegation break
 + *
 + * The caller must hold multiple mutexes--see lock_rename()).
 + *
 + * If vfs_rename discovers a delegation in need of breaking at either
 + * the source or destination, it will return -EWOULDBLOCK and return a
 + * reference to the inode in delegated_inode.  The caller should then
 + * break the delegation and retry.  Because breaking a delegation may
 + * take a long time, the caller should drop all locks before doing
 + * so.
 + *
 + * Alternatively, a caller may pass NULL for delegated_inode.  This may
 + * be appropriate for callers that expect the underlying filesystem not
 + * to be NFS exported.
 + */
  int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
 -             struct inode *new_dir, struct dentry *new_dentry)
 +             struct inode *new_dir, struct dentry *new_dentry,
 +             struct inode **delegated_inode)
  {
        int error;
 -      int is_dir = S_ISDIR(old_dentry->d_inode->i_mode);
 +      int is_dir = d_is_directory(old_dentry) || d_is_autodir(old_dentry);
        const unsigned char *old_name;
  
        if (old_dentry->d_inode == new_dentry->d_inode)
        if (is_dir)
                error = vfs_rename_dir(old_dir,old_dentry,new_dir,new_dentry);
        else
 -              error = vfs_rename_other(old_dir,old_dentry,new_dir,new_dentry);
 +              error = vfs_rename_other(old_dir,old_dentry,new_dir,new_dentry,delegated_inode);
        if (!error)
                fsnotify_move(old_dir, new_dir, old_name, is_dir,
                              new_dentry->d_inode, old_dentry);
@@@ -4158,7 -3881,6 +4159,7 @@@ SYSCALL_DEFINE4(renameat, int, olddfd, 
        struct dentry *old_dentry, *new_dentry;
        struct dentry *trap;
        struct nameidata oldnd, newnd;
 +      struct inode *delegated_inode = NULL;
        struct filename *from;
        struct filename *to;
        unsigned int lookup_flags = 0;
@@@ -4198,7 -3920,6 +4199,7 @@@ retry
        newnd.flags &= ~LOOKUP_PARENT;
        newnd.flags |= LOOKUP_RENAME_TARGET;
  
 +retry_deleg:
        trap = lock_rename(new_dir, old_dir);
  
        old_dentry = lookup_hash(&oldnd);
                goto exit3;
        /* source must exist */
        error = -ENOENT;
 -      if (!old_dentry->d_inode)
 +      if (d_is_negative(old_dentry))
                goto exit4;
        /* unless the source is a directory trailing slashes give -ENOTDIR */
 -      if (!S_ISDIR(old_dentry->d_inode->i_mode)) {
 +      if (!d_is_directory(old_dentry) && !d_is_autodir(old_dentry)) {
                error = -ENOTDIR;
                if (oldnd.last.name[oldnd.last.len])
                        goto exit4;
        if (error)
                goto exit5;
        error = vfs_rename(old_dir->d_inode, old_dentry,
 -                                 new_dir->d_inode, new_dentry);
 +                                 new_dir->d_inode, new_dentry,
 +                                 &delegated_inode);
  exit5:
        dput(new_dentry);
  exit4:
        dput(old_dentry);
  exit3:
        unlock_rename(new_dir, old_dir);
 +      if (delegated_inode) {
 +              error = break_deleg_wait(&delegated_inode);
 +              if (!error)
 +                      goto retry_deleg;
 +      }
        mnt_drop_write(oldnd.path.mnt);
  exit2:
        if (retry_estale(error, lookup_flags))
@@@ -4310,6 -4025,11 +4311,6 @@@ int generic_readlink(struct dentry *den
        return res;
  }
  
 -int vfs_follow_link(struct nameidata *nd, const char *link)
 -{
 -      return __vfs_follow_link(nd, link);
 -}
 -
  /* get the link contents into pagecache */
  static char *page_getlink(struct dentry * dentry, struct page **ppage)
  {
@@@ -4421,6 -4141,7 +4422,6 @@@ EXPORT_SYMBOL(vfs_path_lookup)
  EXPORT_SYMBOL(inode_permission);
  EXPORT_SYMBOL(unlock_rename);
  EXPORT_SYMBOL(vfs_create);
 -EXPORT_SYMBOL(vfs_follow_link);
  EXPORT_SYMBOL(vfs_link);
  EXPORT_SYMBOL(vfs_mkdir);
  EXPORT_SYMBOL(vfs_mknod);
index db0b825b48109f2e8cc011f211749043757a33e5,e2f0d997713125b1c47398d0ec97602e7e709b04..44b05a09f1933a1c293a2174eb58d4db7b473b80
@@@ -68,6 -68,9 +68,9 @@@
  #define AUDIT_MAKE_EQUIV      1015    /* Append to watched tree */
  #define AUDIT_TTY_GET         1016    /* Get TTY auditing status */
  #define AUDIT_TTY_SET         1017    /* Set TTY auditing status */
+ #define AUDIT_SET_FEATURE     1018    /* Turn an audit feature on or off */
+ #define AUDIT_GET_FEATURE     1019    /* Get which features are enabled */
+ #define AUDIT_FEATURE_CHANGE  1020    /* audit log listing feature changes */
  
  #define AUDIT_FIRST_USER_MSG  1100    /* Userspace messages mostly uninteresting to kernel */
  #define AUDIT_USER_AVC                1107    /* We filter this differently */
@@@ -329,6 -332,7 +332,6 @@@ enum 
  #define AUDIT_ARCH_ARMEB      (EM_ARM)
  #define AUDIT_ARCH_CRIS               (EM_CRIS|__AUDIT_ARCH_LE)
  #define AUDIT_ARCH_FRV                (EM_FRV)
 -#define AUDIT_ARCH_H8300      (EM_H8_300)
  #define AUDIT_ARCH_I386               (EM_386|__AUDIT_ARCH_LE)
  #define AUDIT_ARCH_IA64               (EM_IA_64|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE)
  #define AUDIT_ARCH_M32R               (EM_M32R)
  #define AUDIT_PERM_READ               4
  #define AUDIT_PERM_ATTR               8
  
+ /* MAX_AUDIT_MESSAGE_LENGTH is set in audit:lib/libaudit.h as:
+  * 8970 // PATH_MAX*2+CONTEXT_SIZE*2+11+256+1
+  * max header+body+tailer: 44 + 29 + 32 + 262 + 7 + pad
+  */
+ #define AUDIT_MESSAGE_TEXT_MAX        8560
  struct audit_status {
        __u32           mask;           /* Bit mask for valid entries */
        __u32           enabled;        /* 1 = enabled, 0 = disabled */
        __u32           backlog;        /* messages waiting in queue */
  };
  
+ struct audit_features {
+ #define AUDIT_FEATURE_VERSION 1
+       __u32   vers;
+       __u32   mask;           /* which bits we are dealing with */
+       __u32   features;       /* which feature to enable/disable */
+       __u32   lock;           /* which features to lock */
+ };
+ #define AUDIT_FEATURE_ONLY_UNSET_LOGINUID     0
+ #define AUDIT_FEATURE_LOGINUID_IMMUTABLE      1
+ #define AUDIT_LAST_FEATURE                    AUDIT_FEATURE_LOGINUID_IMMUTABLE
+ #define audit_feature_valid(x)                ((x) >= 0 && (x) <= AUDIT_LAST_FEATURE)
+ #define AUDIT_FEATURE_TO_MASK(x)      (1 << ((x) & 31)) /* mask for __u32 */
  struct audit_tty_status {
        __u32           enabled;        /* 1 = enabled, 0 = disabled */
        __u32           log_passwd;     /* 1 = enabled, 0 = disabled */
  };
  
+ #define AUDIT_UID_UNSET (unsigned int)-1
  /* audit_rule_data supports filter rules with both integer and string
   * fields.  It corresponds with AUDIT_ADD_RULE, AUDIT_DEL_RULE and
   * AUDIT_LIST_RULES requests.
diff --combined init/Kconfig
index 3fc8a2f2fac4462eb7b1d1c5c1c1b7c4c3cabdf7,18a98c893d0783d59618f232356dc4be4e011058..296dfcaf613fcc5daa618f263ebd5435028f0cb4
@@@ -284,7 -284,7 +284,7 @@@ config AUDI
  
  config AUDITSYSCALL
        bool "Enable system-call auditing support"
 -      depends on AUDIT && (X86 || PPC || S390 || IA64 || UML || SPARC64 || SUPERH || (ARM && AEABI && !OABI_COMPAT))
 +      depends on AUDIT && (X86 || PARISC || PPC || S390 || IA64 || UML || SPARC64 || SUPERH || (ARM && AEABI && !OABI_COMPAT))
        default y if SECURITY_SELINUX
        help
          Enable low-overhead system-call auditing infrastructure that
@@@ -301,20 -301,6 +301,6 @@@ config AUDIT_TRE
        depends on AUDITSYSCALL
        select FSNOTIFY
  
- config AUDIT_LOGINUID_IMMUTABLE
-       bool "Make audit loginuid immutable"
-       depends on AUDIT
-       help
-         The config option toggles if a task setting its loginuid requires
-         CAP_SYS_AUDITCONTROL or if that task should require no special permissions
-         but should instead only allow setting its loginuid if it was never
-         previously set.  On systems which use systemd or a similar central
-         process to restart login services this should be set to true.  On older
-         systems in which an admin would typically have to directly stop and
-         start processes this should be set to false.  Setting this to true allows
-         one to drop potentially dangerous capabilites from the login tasks,
-         but may not be backwards compatible with older init systems.
  source "kernel/irq/Kconfig"
  source "kernel/time/Kconfig"
  
@@@ -354,8 -340,7 +340,8 @@@ config VIRT_CPU_ACCOUNTING_NATIV
  
  config VIRT_CPU_ACCOUNTING_GEN
        bool "Full dynticks CPU time accounting"
 -      depends on HAVE_CONTEXT_TRACKING && 64BIT
 +      depends on HAVE_CONTEXT_TRACKING
 +      depends on HAVE_VIRT_CPU_ACCOUNTING_GEN
        select VIRT_CPU_ACCOUNTING
        select CONTEXT_TRACKING
        help
@@@ -471,7 -456,6 +457,7 @@@ config TREE_RC
  config TREE_PREEMPT_RCU
        bool "Preemptible tree-based hierarchical RCU"
        depends on PREEMPT
 +      select IRQ_WORK
        help
          This option selects the RCU implementation that is
          designed for very large SMP systems with hundreds or
@@@ -529,29 -513,13 +515,29 @@@ config RCU_USER_Q
  config CONTEXT_TRACKING_FORCE
        bool "Force context tracking"
        depends on CONTEXT_TRACKING
 -      default CONTEXT_TRACKING
 +      default y if !NO_HZ_FULL
        help
 -        Probe on user/kernel boundaries by default in order to
 -        test the features that rely on it such as userspace RCU extended
 -        quiescent states.
 -        This test is there for debugging until we have a real user like the
 -        full dynticks mode.
 +        The major pre-requirement for full dynticks to work is to
 +        support the context tracking subsystem. But there are also
 +        other dependencies to provide in order to make the full
 +        dynticks working.
 +
 +        This option stands for testing when an arch implements the
 +        context tracking backend but doesn't yet fullfill all the
 +        requirements to make the full dynticks feature working.
 +        Without the full dynticks, there is no way to test the support
 +        for context tracking and the subsystems that rely on it: RCU
 +        userspace extended quiescent state and tickless cputime
 +        accounting. This option copes with the absence of the full
 +        dynticks subsystem by forcing the context tracking on all
 +        CPUs in the system.
 +
 +        Say Y only if you're working on the developpement of an
 +        architecture backend for the context tracking.
 +
 +        Say N otherwise, this option brings an overhead that you
 +        don't want in production.
 +
  
  config RCU_FANOUT
        int "Tree-based hierarchical RCU fanout value"
@@@ -845,7 -813,7 +831,7 @@@ config NUMA_BALANCING_DEFAULT_ENABLE
        default y
        depends on NUMA_BALANCING
        help
 -        If set, autonumic NUMA balancing will be enabled if running on a NUMA
 +        If set, automatic NUMA balancing will be enabled if running on a NUMA
          machine.
  
  config NUMA_BALANCING
        help
          This option adds support for automatic NUMA aware memory/task placement.
          The mechanism is quite primitive and is based on migrating memory when
 -        it is references to the node the task is running on.
 +        it has references to the node the task is running on.
  
          This system will be inactive on UMA systems.
  
@@@ -1124,6 -1092,7 +1110,6 @@@ config IPC_N
  
  config USER_NS
        bool "User namespace"
 -      depends on UIDGID_CONVERTED
        select UIDGID_STRICT_TYPE_CHECKS
  
        default n
@@@ -1157,8 -1126,20 +1143,8 @@@ config NET_N
  
  endif # NAMESPACES
  
 -config UIDGID_CONVERTED
 -      # True if all of the selected software conmponents are known
 -      # to have uid_t and gid_t converted to kuid_t and kgid_t
 -      # where appropriate and are otherwise safe to use with
 -      # the user namespace.
 -      bool
 -      default y
 -
 -      # Filesystems
 -      depends on XFS_FS = n
 -
  config UIDGID_STRICT_TYPE_CHECKS
        bool "Require conversions between uid/gids and their internal representation"
 -      depends on UIDGID_CONVERTED
        default n
        help
         While the nececessary conversions are being added to all subsystems this option allows
@@@ -1603,7 -1584,7 +1589,7 @@@ endchoic
  
  config SLUB_CPU_PARTIAL
        default y
 -      depends on SLUB
 +      depends on SLUB && SMP
        bool "SLUB per cpu partial cache"
        help
          Per cpu partial caches accellerate objects allocation and freeing
@@@ -1671,7 -1652,6 +1657,7 @@@ config BASE_SMAL
  
  menuconfig MODULES
        bool "Enable loadable module support"
 +      option modules
        help
          Kernel modules are small pieces of compiled code which can
          be inserted in the running kernel, rather than being
diff --combined kernel/audit.c
index 7b0e23a740ce345987c33f9e012302c24de0f4db,b8831ac25b709ec07d0cf2e893d01994d5240b4e..906ae5a0233a1011d558ff47c548808517ef9a03
@@@ -60,7 -60,6 +60,6 @@@
  #ifdef CONFIG_SECURITY
  #include <linux/security.h>
  #endif
- #include <net/netlink.h>
  #include <linux/freezer.h>
  #include <linux/tty.h>
  #include <linux/pid_namespace.h>
@@@ -140,6 -139,17 +139,17 @@@ static struct task_struct *kauditd_task
  static DECLARE_WAIT_QUEUE_HEAD(kauditd_wait);
  static DECLARE_WAIT_QUEUE_HEAD(audit_backlog_wait);
  
+ static struct audit_features af = {.vers = AUDIT_FEATURE_VERSION,
+                                  .mask = -1,
+                                  .features = 0,
+                                  .lock = 0,};
+ static char *audit_feature_names[2] = {
+       "only_unset_loginuid",
+       "loginuid_immutable",
+ };
  /* Serialize requests from userspace. */
  DEFINE_MUTEX(audit_cmd_mutex);
  
@@@ -584,6 -594,8 +594,8 @@@ static int audit_netlink_ok(struct sk_b
                return -EOPNOTSUPP;
        case AUDIT_GET:
        case AUDIT_SET:
+       case AUDIT_GET_FEATURE:
+       case AUDIT_SET_FEATURE:
        case AUDIT_LIST_RULES:
        case AUDIT_ADD_RULE:
        case AUDIT_DEL_RULE:
@@@ -613,7 -625,7 +625,7 @@@ static int audit_log_common_recv_msg(st
        int rc = 0;
        uid_t uid = from_kuid(&init_user_ns, current_uid());
  
-       if (!audit_enabled) {
+       if (!audit_enabled && msg_type != AUDIT_USER_AVC) {
                *ab = NULL;
                return rc;
        }
        return rc;
  }
  
+ int is_audit_feature_set(int i)
+ {
+       return af.features & AUDIT_FEATURE_TO_MASK(i);
+ }
+ static int audit_get_feature(struct sk_buff *skb)
+ {
+       u32 seq;
+       seq = nlmsg_hdr(skb)->nlmsg_seq;
+       audit_send_reply(NETLINK_CB(skb).portid, seq, AUDIT_GET, 0, 0,
+                        &af, sizeof(af));
+       return 0;
+ }
+ static void audit_log_feature_change(int which, u32 old_feature, u32 new_feature,
+                                    u32 old_lock, u32 new_lock, int res)
+ {
+       struct audit_buffer *ab;
+       ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_FEATURE_CHANGE);
+       audit_log_format(ab, "feature=%s new=%d old=%d old_lock=%d new_lock=%d res=%d",
+                        audit_feature_names[which], !!old_feature, !!new_feature,
+                        !!old_lock, !!new_lock, res);
+       audit_log_end(ab);
+ }
+ static int audit_set_feature(struct sk_buff *skb)
+ {
+       struct audit_features *uaf;
+       int i;
+       BUILD_BUG_ON(AUDIT_LAST_FEATURE + 1 > sizeof(audit_feature_names)/sizeof(audit_feature_names[0]));
+       uaf = nlmsg_data(nlmsg_hdr(skb));
+       /* if there is ever a version 2 we should handle that here */
+       for (i = 0; i <= AUDIT_LAST_FEATURE; i++) {
+               u32 feature = AUDIT_FEATURE_TO_MASK(i);
+               u32 old_feature, new_feature, old_lock, new_lock;
+               /* if we are not changing this feature, move along */
+               if (!(feature & uaf->mask))
+                       continue;
+               old_feature = af.features & feature;
+               new_feature = uaf->features & feature;
+               new_lock = (uaf->lock | af.lock) & feature;
+               old_lock = af.lock & feature;
+               /* are we changing a locked feature? */
+               if ((af.lock & feature) && (new_feature != old_feature)) {
+                       audit_log_feature_change(i, old_feature, new_feature,
+                                                old_lock, new_lock, 0);
+                       return -EPERM;
+               }
+       }
+       /* nothing invalid, do the changes */
+       for (i = 0; i <= AUDIT_LAST_FEATURE; i++) {
+               u32 feature = AUDIT_FEATURE_TO_MASK(i);
+               u32 old_feature, new_feature, old_lock, new_lock;
+               /* if we are not changing this feature, move along */
+               if (!(feature & uaf->mask))
+                       continue;
+               old_feature = af.features & feature;
+               new_feature = uaf->features & feature;
+               old_lock = af.lock & feature;
+               new_lock = (uaf->lock | af.lock) & feature;
+               if (new_feature != old_feature)
+                       audit_log_feature_change(i, old_feature, new_feature,
+                                                old_lock, new_lock, 1);
+               if (new_feature)
+                       af.features |= feature;
+               else
+                       af.features &= ~feature;
+               af.lock |= new_lock;
+       }
+       return 0;
+ }
  static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
  {
        u32                     seq;
  
        switch (msg_type) {
        case AUDIT_GET:
+               memset(&status_set, 0, sizeof(status_set));
                status_set.enabled       = audit_enabled;
                status_set.failure       = audit_failure;
                status_set.pid           = audit_pid;
                                 &status_set, sizeof(status_set));
                break;
        case AUDIT_SET:
-               if (nlh->nlmsg_len < sizeof(struct audit_status))
+               if (nlmsg_len(nlh) < sizeof(struct audit_status))
                        return -EINVAL;
                status_get   = (struct audit_status *)data;
                if (status_get->mask & AUDIT_STATUS_ENABLED) {
                if (status_get->mask & AUDIT_STATUS_BACKLOG_LIMIT)
                        err = audit_set_backlog_limit(status_get->backlog_limit);
                break;
+       case AUDIT_GET_FEATURE:
+               err = audit_get_feature(skb);
+               if (err)
+                       return err;
+               break;
+       case AUDIT_SET_FEATURE:
+               err = audit_set_feature(skb);
+               if (err)
+                       return err;
+               break;
        case AUDIT_USER:
        case AUDIT_FIRST_USER_MSG ... AUDIT_LAST_USER_MSG:
        case AUDIT_FIRST_USER_MSG2 ... AUDIT_LAST_USER_MSG2:
                        }
                        audit_log_common_recv_msg(&ab, msg_type);
                        if (msg_type != AUDIT_USER_TTY)
-                               audit_log_format(ab, " msg='%.1024s'",
+                               audit_log_format(ab, " msg='%.*s'",
+                                                AUDIT_MESSAGE_TEXT_MAX,
                                                 (char *)data);
                        else {
                                int size;
                struct task_struct *tsk = current;
  
                spin_lock(&tsk->sighand->siglock);
-               s.enabled = tsk->signal->audit_tty != 0;
+               s.enabled = tsk->signal->audit_tty;
                s.log_passwd = tsk->signal->audit_tty_log_passwd;
                spin_unlock(&tsk->sighand->siglock);
  
  
                memset(&s, 0, sizeof(s));
                /* guard against past and future API changes */
-               memcpy(&s, data, min(sizeof(s), (size_t)nlh->nlmsg_len));
+               memcpy(&s, data, min_t(size_t, sizeof(s), nlmsg_len(nlh)));
                if ((s.enabled != 0 && s.enabled != 1) ||
                    (s.log_passwd != 0 && s.log_passwd != 1))
                        return -EINVAL;
@@@ -1067,13 -1179,6 +1179,6 @@@ static void wait_for_auditd(unsigned lo
        remove_wait_queue(&audit_backlog_wait, &wait);
  }
  
- /* Obtain an audit buffer.  This routine does locking to obtain the
-  * audit buffer, but then no locking is required for calls to
-  * audit_log_*format.  If the tsk is a task that is currently in a
-  * syscall, then the syscall is marked as auditable and an audit record
-  * will be written at syscall exit.  If there is no associated task, tsk
-  * should be NULL. */
  /**
   * audit_log_start - obtain an audit buffer
   * @ctx: audit_context (may be NULL)
@@@ -1117,10 -1222,9 +1222,10 @@@ struct audit_buffer *audit_log_start(st
  
                        sleep_time = timeout_start + audit_backlog_wait_time -
                                        jiffies;
 -                      if ((long)sleep_time > 0)
 +                      if ((long)sleep_time > 0) {
                                wait_for_auditd(sleep_time);
 -                      continue;
 +                              continue;
 +                      }
                }
                if (audit_rate_check() && printk_ratelimit())
                        printk(KERN_WARNING
@@@ -1389,7 -1493,7 +1494,7 @@@ void audit_log_session_info(struct audi
        u32 sessionid = audit_get_sessionid(current);
        uid_t auid = from_kuid(&init_user_ns, audit_get_loginuid(current));
  
-       audit_log_format(ab, " auid=%u ses=%u\n", auid, sessionid);
+       audit_log_format(ab, " auid=%u ses=%u", auid, sessionid);
  }
  
  void audit_log_key(struct audit_buffer *ab, char *key)
@@@ -1536,6 -1640,26 +1641,26 @@@ void audit_log_name(struct audit_contex
                }
        }
  
+       /* log the audit_names record type */
+       audit_log_format(ab, " nametype=");
+       switch(n->type) {
+       case AUDIT_TYPE_NORMAL:
+               audit_log_format(ab, "NORMAL");
+               break;
+       case AUDIT_TYPE_PARENT:
+               audit_log_format(ab, "PARENT");
+               break;
+       case AUDIT_TYPE_CHILD_DELETE:
+               audit_log_format(ab, "DELETE");
+               break;
+       case AUDIT_TYPE_CHILD_CREATE:
+               audit_log_format(ab, "CREATE");
+               break;
+       default:
+               audit_log_format(ab, "UNKNOWN");
+               break;
+       }
        audit_log_fcaps(ab, n);
        audit_log_end(ab);
  }
diff --combined security/lsm_audit.c
index 234bc2ab450c61b42b1db2b53f631ab72bc48a39,b0f249d1a1ef673596829b9e3d1731f3ddec59e0..9a62045e6282467493567a52f546d1e8d269bcd6
@@@ -302,19 -302,18 +302,19 @@@ static void dump_common_audit_data(stru
                                                "faddr", "fport");
                                break;
                        }
 +#if IS_ENABLED(CONFIG_IPV6)
                        case AF_INET6: {
                                struct inet_sock *inet = inet_sk(sk);
 -                              struct ipv6_pinfo *inet6 = inet6_sk(sk);
  
 -                              print_ipv6_addr(ab, &inet6->rcv_saddr,
 +                              print_ipv6_addr(ab, &sk->sk_v6_rcv_saddr,
                                                inet->inet_sport,
                                                "laddr", "lport");
 -                              print_ipv6_addr(ab, &inet6->daddr,
 +                              print_ipv6_addr(ab, &sk->sk_v6_daddr,
                                                inet->inet_dport,
                                                "faddr", "fport");
                                break;
                        }
 +#endif
                        case AF_UNIX:
                                u = unix_sk(sk);
                                if (u->path.dentry) {
@@@ -397,7 -396,8 +397,8 @@@ void common_lsm_audit(struct common_aud
        if (a == NULL)
                return;
        /* we use GFP_ATOMIC so we won't sleep */
-       ab = audit_log_start(current->audit_context, GFP_ATOMIC, AUDIT_AVC);
+       ab = audit_log_start(current->audit_context, GFP_ATOMIC | __GFP_NOWARN,
+                            AUDIT_AVC);
  
        if (ab == NULL)
                return;