/*
       *  linux/fs/proc/base.c
       *
       *  Copyright (C) 1991, 1992 Linus Torvalds
       *
       *  proc base directory handling functions
       *
       *  1999, Al Viro. Rewritten. Now it covers the whole per-process part.
       *  Instead of using magical inumbers to determine the kind of object
       *  we allocate and fill in-core inodes upon lookup. They don't even
       *  go into icache. We cache the reference to task_struct upon lookup too.
       *  Eventually it should become a filesystem in its own. We don't use the
       *  rest of procfs anymore.
       *
       *
       *  Changelog:
       *  17-Jan-2005
       *  Allan Bezerra
       *  Bruna Moreira <bruna.moreira@indt.org.br>
       *  Edjard Mota <edjard.mota@indt.org.br>
       *  Ilias Biris <ilias.biris@indt.org.br>
       *  Mauricio Lin <mauricio.lin@indt.org.br>
       *
       *  Embedded Linux Lab - 10LE Instituto Nokia de Tecnologia - INdT
       *
       *  A new process specific entry (smaps) included in /proc. It shows the
       *  size of rss for each memory area. The maps entry lacks information
       *  about physical memory size (rss) for each mapped file, i.e.,
       *  rss information for executables and library files.
       *  This additional information is useful for any tools that need to know
       *  about physical memory consumption for a process specific library.
       *
       *  Changelog:
       *  21-Feb-2005
       *  Embedded Linux Lab - 10LE Instituto Nokia de Tecnologia - INdT
       *  Pud inclusion in the page table walking.
       *
       *  ChangeLog:
       *  10-Mar-2005
       *  10LE Instituto Nokia de Tecnologia - INdT:
       *  A better way to walks through the page table as suggested by Hugh Dickins.
       *
       *  Simo Piiroinen <simo.piiroinen@nokia.com>:
       *  Smaps information related to shared, private, clean and dirty pages.
       *
       *  Paul Mundt <paul.mundt@nokia.com>:
       *  Overall revision about smaps.
       */
      
      #include <asm/uaccess.h>
      
      #include <linux/errno.h>
      #include <linux/time.h>
      #include <linux/proc_fs.h>
      #include <linux/stat.h>
      #include <linux/task_io_accounting_ops.h>
      #include <linux/init.h>
      #include <linux/capability.h>
      #include <linux/file.h>
      #include <linux/fdtable.h>
      #include <linux/string.h>
      #include <linux/seq_file.h>
      #include <linux/namei.h>
      #include <linux/mnt_namespace.h>
      #include <linux/mm.h>
      #include <linux/swap.h>
      #include <linux/rcupdate.h>
      #include <linux/kallsyms.h>
      #include <linux/stacktrace.h>
      #include <linux/resource.h>
      #include <linux/module.h>
      #include <linux/mount.h>
      #include <linux/security.h>
      #include <linux/ptrace.h>
      #include <linux/tracehook.h>
      #include <linux/printk.h>
      #include <linux/cgroup.h>
      #include <linux/cpuset.h>
      #include <linux/audit.h>
      #include <linux/poll.h>
      #include <linux/nsproxy.h>
      #include <linux/oom.h>
      #include <linux/elf.h>
      #include <linux/pid_namespace.h>
      #include <linux/user_namespace.h>
      #include <linux/fs_struct.h>
      #include <linux/slab.h>
      #include <linux/flex_array.h>
      #include <linux/posix-timers.h>
      #include <linux/cpufreq_times.h>
      #ifdef CONFIG_HARDWALL
      #include <asm/hardwall.h>
      #endif
      #include <trace/events/oom.h>
      #include "internal.h"
      #include "fd.h"
      
      #include "../../lib/kstrtox.h"
      
      /* NOTE:
       *        Implementing inode permission operations in /proc is almost
       *        certainly an error.  Permission checks need to happen during
       *        each system call not at open time.  The reason is that most of
       *        what we wish to check for permissions in /proc varies at runtime.
       *
       *        The classic example of a problem is opening file descriptors
       *        in /proc for a task before it execs a suid executable.
       */
      
      struct pid_entry {
              const char *name;
              int len;
              umode_t mode;
              const struct inode_operations *iop;
              const struct file_operations *fop;
              union proc_op op;
      };
      
      #define NOD(NAME, MODE, IOP, FOP, OP) {                        \
              .name = (NAME),                                        \
              .len  = sizeof(NAME) - 1,                        \
              .mode = MODE,                                        \
              .iop  = IOP,                                        \
              .fop  = FOP,                                        \
              .op   = OP,                                        \
      }
      
      #define DIR(NAME, MODE, iops, fops)        \
              NOD(NAME, (S_IFDIR|(MODE)), &iops, &fops, {} )
      #define LNK(NAME, get_link)                                        \
              NOD(NAME, (S_IFLNK|S_IRWXUGO),                                \
                      &proc_pid_link_inode_operations, NULL,                \
                      { .proc_get_link = get_link } )
      #define REG(NAME, MODE, fops)                                \
              NOD(NAME, (S_IFREG|(MODE)), NULL, &fops, {})
      #define ONE(NAME, MODE, show)                                \
              NOD(NAME, (S_IFREG|(MODE)),                         \
                      NULL, &proc_single_file_operations,        \
                      { .proc_show = show } )
      
      /*
       * Count the number of hardlinks for the pid_entry table, excluding the .
       * and .. links.
       */
      static unsigned int pid_entry_count_dirs(const struct pid_entry *entries,
              unsigned int n)
      {
              unsigned int i;
              unsigned int count;
      
  137         count = 0;
  137         for (i = 0; i < n; ++i) {
  137                 if (S_ISDIR(entries[i].mode))
  137                         ++count;
              }
      
              return count;
      }
      
      static int get_task_root(struct task_struct *task, struct path *root)
      {
              int result = -ENOENT;
      
    2         task_lock(task);
              if (task->fs) {
    2                 get_fs_root(task->fs, root);
                      result = 0;
              }
    2         task_unlock(task);
              return result;
      }
      
      static int proc_cwd_link(struct dentry *dentry, struct path *path)
      {
    2         struct task_struct *task = get_proc_task(d_inode(dentry));
              int result = -ENOENT;
      
              if (task) {
    2                 task_lock(task);
                      if (task->fs) {
    2                         get_fs_pwd(task->fs, path);
                              result = 0;
                      }
    2                 task_unlock(task);
    2                 put_task_struct(task);
              }
    2         return result;
      }
      
      static int proc_root_link(struct dentry *dentry, struct path *path)
      {
    2         struct task_struct *task = get_proc_task(d_inode(dentry));
              int result = -ENOENT;
      
              if (task) {
    2                 result = get_task_root(task, path);
    2                 put_task_struct(task);
              }
    2         return result;
      }
      
      static ssize_t proc_pid_cmdline_read(struct file *file, char __user *buf,
                                           size_t _count, loff_t *pos)
      {
              struct task_struct *tsk;
              struct mm_struct *mm;
              char *page;
              unsigned long count = _count;
              unsigned long arg_start, arg_end, env_start, env_end;
              unsigned long len1, len2, len;
              unsigned long p;
              char c;
              ssize_t rv;
      
    9         BUG_ON(*pos < 0);
      
    9         tsk = get_proc_task(file_inode(file));
              if (!tsk)
                      return -ESRCH;
    8         mm = get_task_mm(tsk);
    8         put_task_struct(tsk);
    8         if (!mm)
                      return 0;
              /* Check if process spawned far enough to have cmdline. */
    7         if (!mm->env_end) {
                      rv = 0;
                      goto out_mmput;
              }
      
    7         page = (char *)__get_free_page(GFP_TEMPORARY);
              if (!page) {
                      rv = -ENOMEM;
                      goto out_mmput;
              }
      
    7         down_read(&mm->mmap_sem);
              arg_start = mm->arg_start;
              arg_end = mm->arg_end;
              env_start = mm->env_start;
              env_end = mm->env_end;
              up_read(&mm->mmap_sem);
      
              BUG_ON(arg_start > arg_end);
    7         BUG_ON(env_start > env_end);
      
    7         len1 = arg_end - arg_start;
              len2 = env_end - env_start;
      
              /* Empty ARGV. */
              if (len1 == 0) {
                      rv = 0;
                      goto out_free_page;
              }
              /*
               * Inherently racy -- command line shares address space
               * with code and data.
               */
    7         rv = access_remote_vm(mm, arg_end - 1, &c, 1, FOLL_ANON);
              if (rv <= 0)
                      goto out_free_page;
      
              rv = 0;
      
              if (c == '\0') {
                      /* Command line (set of strings) occupies whole ARGV. */
    7                 if (len1 <= *pos)
                              goto out_free_page;
      
    7                 p = arg_start + *pos;
                      len = len1 - *pos;
    6                 while (count > 0 && len > 0) {
                              unsigned int _count;
                              int nr_read;
      
    6                         _count = min3(count, len, PAGE_SIZE);
                              nr_read = access_remote_vm(mm, p, page, _count, FOLL_ANON);
                              if (nr_read < 0)
                                      rv = nr_read;
    6                         if (nr_read <= 0)
                                      goto out_free_page;
      
    6                         if (copy_to_user(buf, page, nr_read)) {
                                      rv = -EFAULT;
                                      goto out_free_page;
                              }
      
    6                         p        += nr_read;
                              len        -= nr_read;
                              buf        += nr_read;
                              count        -= nr_read;
                              rv        += nr_read;
                      }
              } else {
                      /*
                       * Command line (1 string) occupies ARGV and maybe
                       * extends into ENVP.
                       */
                      if (len1 + len2 <= *pos)
                              goto skip_argv_envp;
                      if (len1 <= *pos)
                              goto skip_argv;
      
                      p = arg_start + *pos;
                      len = len1 - *pos;
                      while (count > 0 && len > 0) {
                              unsigned int _count, l;
                              int nr_read;
                              bool final;
      
                              _count = min3(count, len, PAGE_SIZE);
                              nr_read = access_remote_vm(mm, p, page, _count, FOLL_ANON);
                              if (nr_read < 0)
                                      rv = nr_read;
                              if (nr_read <= 0)
                                      goto out_free_page;
      
                              /*
                               * Command line can be shorter than whole ARGV
                               * even if last "marker" byte says it is not.
                               */
                              final = false;
                              l = strnlen(page, nr_read);
                              if (l < nr_read) {
                                      nr_read = l;
                                      final = true;
                              }
      
                              if (copy_to_user(buf, page, nr_read)) {
                                      rv = -EFAULT;
                                      goto out_free_page;
                              }
      
                              p        += nr_read;
                              len        -= nr_read;
                              buf        += nr_read;
                              count        -= nr_read;
                              rv        += nr_read;
      
                              if (final)
                                      goto out_free_page;
                      }
      skip_argv:
                      /*
                       * Command line (1 string) occupies ARGV and
                       * extends into ENVP.
                       */
                      if (len1 <= *pos) {
                              p = env_start + *pos - len1;
                              len = len1 + len2 - *pos;
                      } else {
                              p = env_start;
                              len = len2;
                      }
                      while (count > 0 && len > 0) {
                              unsigned int _count, l;
                              int nr_read;
                              bool final;
      
                              _count = min3(count, len, PAGE_SIZE);
                              nr_read = access_remote_vm(mm, p, page, _count, FOLL_ANON);
                              if (nr_read < 0)
                                      rv = nr_read;
                              if (nr_read <= 0)
                                      goto out_free_page;
      
                              /* Find EOS. */
                              final = false;
                              l = strnlen(page, nr_read);
                              if (l < nr_read) {
                                      nr_read = l;
                                      final = true;
                              }
      
                              if (copy_to_user(buf, page, nr_read)) {
                                      rv = -EFAULT;
                                      goto out_free_page;
                              }
      
                              p        += nr_read;
                              len        -= nr_read;
                              buf        += nr_read;
                              count        -= nr_read;
                              rv        += nr_read;
      
                              if (final)
                                      goto out_free_page;
                      }
      skip_argv_envp:
                      ;
              }
      
      out_free_page:
    7         free_page((unsigned long)page);
      out_mmput:
              mmput(mm);
    9         if (rv > 0)
    6                 *pos += rv;
              return rv;
      }
      
      static const struct file_operations proc_pid_cmdline_ops = {
              .read        = proc_pid_cmdline_read,
              .llseek        = generic_file_llseek,
      };
      
      static int proc_pid_auxv(struct seq_file *m, struct pid_namespace *ns,
                               struct pid *pid, struct task_struct *task)
      {
    3         struct mm_struct *mm = mm_access(task, PTRACE_MODE_READ_FSCREDS);
    2         if (mm && !IS_ERR(mm)) {
                      unsigned int nwords = 0;
                      do {
    2                         nwords += 2;
                      } while (mm->saved_auxv[nwords - 2] != 0); /* AT_NULL */
    2                 seq_write(m, mm->saved_auxv, nwords * sizeof(mm->saved_auxv[0]));
                      mmput(mm);
    3                 return 0;
              } else
    1                 return PTR_ERR(mm);
      }
      
      
      #ifdef CONFIG_KALLSYMS
      /*
       * Provides a wchan file via kallsyms in a proper one-value-per-file format.
       * Returns the resolved symbol.  If that fails, simply return the address.
       */
      static int proc_pid_wchan(struct seq_file *m, struct pid_namespace *ns,
                                struct pid *pid, struct task_struct *task)
      {
              unsigned long wchan;
              char symname[KSYM_NAME_LEN];
      
    5         wchan = get_wchan(task);
      
    5         if (wchan && ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)
    4                         && !lookup_symbol_name(wchan, symname))
    4                 seq_printf(m, "%s", symname);
              else
    2                 seq_putc(m, '0');
      
    5         return 0;
      }
      #endif /* CONFIG_KALLSYMS */
      
   10 static int lock_trace(struct task_struct *task)
      {
   10         int err = mutex_lock_killable(&task->signal->cred_guard_mutex);
   10         if (err)
                      return err;
   10         if (!ptrace_may_access(task, PTRACE_MODE_ATTACH_FSCREDS)) {
    1                 mutex_unlock(&task->signal->cred_guard_mutex);
                      return -EPERM;
              }
              return 0;
      }
      
      static void unlock_trace(struct task_struct *task)
      {
    7         mutex_unlock(&task->signal->cred_guard_mutex);
      }
      
      #ifdef CONFIG_STACKTRACE
      
      #define MAX_STACK_TRACE_DEPTH        64
      
      static int proc_pid_stack(struct seq_file *m, struct pid_namespace *ns,
                                struct pid *pid, struct task_struct *task)
      {
              struct stack_trace trace;
              unsigned long *entries;
              int err;
              int i;
      
              /*
               * The ability to racily run the kernel stack unwinder on a running task
               * and then observe the unwinder output is scary; while it is useful for
               * debugging kernel issues, it can also allow an attacker to leak kernel
               * stack contents.
               * Doing this in a manner that is at least safe from races would require
               * some work to ensure that the remote task can not be scheduled; and
               * even then, this would still expose the unwinder as local attack
               * surface.
               * Therefore, this interface is restricted to root.
               */
    3         if (!file_ns_capable(m->file, &init_user_ns, CAP_SYS_ADMIN))
                      return -EACCES;
      
              entries = kmalloc(MAX_STACK_TRACE_DEPTH * sizeof(*entries), GFP_KERNEL);
              if (!entries)
                      return -ENOMEM;
      
              trace.nr_entries        = 0;
              trace.max_entries        = MAX_STACK_TRACE_DEPTH;
              trace.entries                = entries;
              trace.skip                = 0;
      
              err = lock_trace(task);
              if (!err) {
                      save_stack_trace_tsk(task, &trace);
      
                      for (i = 0; i < trace.nr_entries; i++) {
                              seq_printf(m, "[<%pK>] %pS\n",
                                         (void *)entries[i], (void *)entries[i]);
                      }
                      unlock_trace(task);
              }
              kfree(entries);
      
    3         return err;
      }
      #endif
      
      #ifdef CONFIG_SCHED_INFO
      /*
       * Provides /proc/PID/schedstat
       */
      static int proc_pid_schedstat(struct seq_file *m, struct pid_namespace *ns,
                                    struct pid *pid, struct task_struct *task)
      {
              if (unlikely(!sched_info_on()))
                      seq_printf(m, "0 0 0\n");
              else
    2                 seq_printf(m, "%llu %llu %lu\n",
                         (unsigned long long)task->se.sum_exec_runtime,
                         (unsigned long long)task->sched_info.run_delay,
                         task->sched_info.pcount);
      
              return 0;
      }
      #endif
      
      #ifdef CONFIG_LATENCYTOP
      static int lstats_show_proc(struct seq_file *m, void *v)
      {
              int i;
              struct inode *inode = m->private;
              struct task_struct *task = get_proc_task(inode);
      
              if (!task)
                      return -ESRCH;
              seq_puts(m, "Latency Top version : v0.1\n");
              for (i = 0; i < 32; i++) {
                      struct latency_record *lr = &task->latency_record[i];
                      if (lr->backtrace[0]) {
                              int q;
                              seq_printf(m, "%i %li %li",
                                         lr->count, lr->time, lr->max);
                              for (q = 0; q < LT_BACKTRACEDEPTH; q++) {
                                      unsigned long bt = lr->backtrace[q];
                                      if (!bt)
                                              break;
                                      if (bt == ULONG_MAX)
                                              break;
                                      seq_printf(m, " %ps", (void *)bt);
                              }
                              seq_putc(m, '\n');
                      }
      
              }
              put_task_struct(task);
              return 0;
      }
      
      static int lstats_open(struct inode *inode, struct file *file)
      {
              return single_open(file, lstats_show_proc, inode);
      }
      
      static ssize_t lstats_write(struct file *file, const char __user *buf,
                                  size_t count, loff_t *offs)
      {
              struct task_struct *task = get_proc_task(file_inode(file));
      
              if (!task)
                      return -ESRCH;
              clear_all_latency_tracing(task);
              put_task_struct(task);
      
              return count;
      }
      
      static const struct file_operations proc_lstats_operations = {
              .open                = lstats_open,
              .read                = seq_read,
              .write                = lstats_write,
              .llseek                = seq_lseek,
              .release        = single_release,
      };
      
      #endif
      
      static int proc_oom_score(struct seq_file *m, struct pid_namespace *ns,
                                struct pid *pid, struct task_struct *task)
      {
    4         unsigned long totalpages = totalram_pages + total_swap_pages;
              unsigned long points = 0;
      
              read_lock(&tasklist_lock);
              if (pid_alive(task))
                      points = oom_badness(task, NULL, NULL, totalpages) *
                                                      1000 / totalpages;
    4         read_unlock(&tasklist_lock);
              seq_printf(m, "%lu\n", points);
      
              return 0;
      }
      
      struct limit_names {
              const char *name;
              const char *unit;
      };
      
      static const struct limit_names lnames[RLIM_NLIMITS] = {
              [RLIMIT_CPU] = {"Max cpu time", "seconds"},
              [RLIMIT_FSIZE] = {"Max file size", "bytes"},
              [RLIMIT_DATA] = {"Max data size", "bytes"},
              [RLIMIT_STACK] = {"Max stack size", "bytes"},
              [RLIMIT_CORE] = {"Max core file size", "bytes"},
              [RLIMIT_RSS] = {"Max resident set", "bytes"},
              [RLIMIT_NPROC] = {"Max processes", "processes"},
              [RLIMIT_NOFILE] = {"Max open files", "files"},
              [RLIMIT_MEMLOCK] = {"Max locked memory", "bytes"},
              [RLIMIT_AS] = {"Max address space", "bytes"},
              [RLIMIT_LOCKS] = {"Max file locks", "locks"},
              [RLIMIT_SIGPENDING] = {"Max pending signals", "signals"},
              [RLIMIT_MSGQUEUE] = {"Max msgqueue size", "bytes"},
              [RLIMIT_NICE] = {"Max nice priority", NULL},
              [RLIMIT_RTPRIO] = {"Max realtime priority", NULL},
              [RLIMIT_RTTIME] = {"Max realtime timeout", "us"},
      };
      
      /* Display limits for a process */
      static int proc_pid_limits(struct seq_file *m, struct pid_namespace *ns,
                                 struct pid *pid, struct task_struct *task)
      {
              unsigned int i;
              unsigned long flags;
      
              struct rlimit rlim[RLIM_NLIMITS];
      
    2         if (!lock_task_sighand(task, &flags))
                      return 0;
    2         memcpy(rlim, task->signal->rlim, sizeof(struct rlimit) * RLIM_NLIMITS);
              unlock_task_sighand(task, &flags);
      
              /*
               * print the file header
               */
             seq_printf(m, "%-25s %-20s %-20s %-10s\n",
                        "Limit", "Soft Limit", "Hard Limit", "Units");
      
    2         for (i = 0; i < RLIM_NLIMITS; i++) {
    2                 if (rlim[i].rlim_cur == RLIM_INFINITY)
    2                         seq_printf(m, "%-25s %-20s ",
                                         lnames[i].name, "unlimited");
                      else
    2                         seq_printf(m, "%-25s %-20lu ",
                                         lnames[i].name, rlim[i].rlim_cur);
      
    2                 if (rlim[i].rlim_max == RLIM_INFINITY)
    2                         seq_printf(m, "%-20s ", "unlimited");
                      else
    2                         seq_printf(m, "%-20lu ", rlim[i].rlim_max);
      
    2                 if (lnames[i].unit)
    2                         seq_printf(m, "%-10s\n", lnames[i].unit);
                      else
    2                         seq_putc(m, '\n');
              }
      
              return 0;
      }
      
      #ifdef CONFIG_HAVE_ARCH_TRACEHOOK
    7 static int proc_pid_syscall(struct seq_file *m, struct pid_namespace *ns,
                                  struct pid *pid, struct task_struct *task)
      {
              long nr;
              unsigned long args[6], sp, pc;
              int res;
      
    7         res = lock_trace(task);
    7         if (res)
                      return res;
      
    7         if (task_current_syscall(task, &nr, args, 6, &sp, &pc))
    2                 seq_puts(m, "running\n");
    7         else if (nr < 0)
                      seq_printf(m, "%ld 0x%lx 0x%lx\n", nr, sp, pc);
              else
    7                 seq_printf(m,
                             "%ld 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n",
                             nr,
                             args[0], args[1], args[2], args[3], args[4], args[5],
                             sp, pc);
    7         unlock_trace(task);
      
              return 0;
      }
      #endif /* CONFIG_HAVE_ARCH_TRACEHOOK */
      
      /************************************************************************/
      /*                       Here the fs part begins                        */
      /************************************************************************/
      
      /* permission checks */
      static int proc_fd_access_allowed(struct inode *inode)
      {
              struct task_struct *task;
              int allowed = 0;
              /* Allow access to a task's file descriptors if it is us or we
               * may use ptrace attach to the process and find out that
               * information.
               */
   60         task = get_proc_task(inode);
              if (task) {
   60                 allowed = ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS);
   60                 put_task_struct(task);
              }
   60         return allowed;
      }
      
      int proc_setattr(struct dentry *dentry, struct iattr *attr)
      {
              int error;
    5         struct inode *inode = d_inode(dentry);
      
              if (attr->ia_valid & ATTR_MODE)
                      return -EPERM;
      
    4         error = inode_change_ok(inode, attr);
              if (error)
                      return error;
      
    3         setattr_copy(inode, attr);
              mark_inode_dirty(inode);
    5         return 0;
      }
      
      /*
       * May current process learn task's sched/cmdline info (for hide_pid_min=1)
       * or euid/egid (for hide_pid_min=2)?
       */
      static bool has_pid_permissions(struct pid_namespace *pid,
                                       struct task_struct *task,
                                       int hide_pid_min)
      {
              if (pid->hide_pid < hide_pid_min)
                      return true;
              if (in_group_p(pid->pid_gid))
                      return true;
              return ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS);
      }
      
      
      static int proc_pid_permission(struct inode *inode, int mask)
      {
  616         struct pid_namespace *pid = inode->i_sb->s_fs_info;
              struct task_struct *task;
              bool has_perms;
      
              task = get_proc_task(inode);
              if (!task)
                      return -ESRCH;
  615         has_perms = has_pid_permissions(pid, task, 1);
  615         put_task_struct(task);
      
  615         if (!has_perms) {
                      if (pid->hide_pid == 2) {
                              /*
                               * Let's make getdents(), stat(), and open()
                               * consistent with each other.  If a process
                               * may not stat() a file, it shouldn't be seen
                               * in procfs at all.
                               */
                              return -ENOENT;
                      }
      
  616                 return -EPERM;
              }
  615         return generic_permission(inode, mask);
      }
      
      
      
      static const struct inode_operations proc_def_inode_operations = {
              .setattr        = proc_setattr,
      };
      
      static int proc_single_show(struct seq_file *m, void *v)
      {
   66         struct inode *inode = m->private;
              struct pid_namespace *ns;
              struct pid *pid;
              struct task_struct *task;
              int ret;
      
              ns = inode->i_sb->s_fs_info;
              pid = proc_pid(inode);
              task = get_pid_task(pid, PIDTYPE_PID);
              if (!task)
                      return -ESRCH;
      
   65         ret = PROC_I(inode)->op.proc_show(m, ns, pid, task);
      
   61         put_task_struct(task);
              return ret;
      }
      
      static int proc_single_open(struct inode *inode, struct file *filp)
      {
   13         return single_open(filp, proc_single_show, inode);
      }
      
      static const struct file_operations proc_single_file_operations = {
              .open                = proc_single_open,
              .read                = seq_read,
              .llseek                = seq_lseek,
              .release        = single_release,
      };
      
      
      struct mm_struct *proc_mem_open(struct inode *inode, unsigned int mode)
      {
   84         struct task_struct *task = get_proc_task(inode);
              struct mm_struct *mm = ERR_PTR(-ESRCH);
      
              if (task) {
   81                 mm = mm_access(task, mode | PTRACE_MODE_FSCREDS);
   82                 put_task_struct(task);
      
   82                 if (!IS_ERR_OR_NULL(mm)) {
                              /* ensure this mm_struct can't be freed */
   81                         atomic_inc(&mm->mm_count);
                              /* but do not pin its memory */
                              mmput(mm);
                      }
              }
      
   85         return mm;
      }
      
      static int __mem_open(struct inode *inode, struct file *file, unsigned int mode)
      {
   16         struct mm_struct *mm = proc_mem_open(inode, mode);
      
              if (IS_ERR(mm))
    3                 return PTR_ERR(mm);
      
   14         file->private_data = mm;
              return 0;
      }
      
      static int mem_open(struct inode *inode, struct file *file)
      {
   14         int ret = __mem_open(inode, file, PTRACE_MODE_ATTACH);
      
              /* OK to pass negative loff_t, we can catch out-of-range */
   14         file->f_mode |= FMODE_UNSIGNED_OFFSET;
      
              return ret;
      }
      
      static ssize_t mem_rw(struct file *file, char __user *buf,
                              size_t count, loff_t *ppos, int write)
      {
              struct mm_struct *mm = file->private_data;
   46         unsigned long addr = *ppos;
              ssize_t copied;
              char *page;
              unsigned int flags;
      
   47         if (!mm)
                      return 0;
      
   44         page = (char *)__get_free_page(GFP_TEMPORARY);
              if (!page)
                      return -ENOMEM;
      
              copied = 0;
   45         if (!atomic_inc_not_zero(&mm->mm_users))
                      goto free;
      
              /* Maybe we should limit FOLL_FORCE to actual ptrace users? */
              flags = FOLL_FORCE;
   45         if (write)
                      flags |= FOLL_WRITE;
      
              while (count > 0) {
   45                 int this_len = min_t(int, count, PAGE_SIZE);
      
   11                 if (write && copy_from_user(page, buf, this_len)) {
                              copied = -EFAULT;
                              break;
                      }
      
   45                 this_len = access_remote_vm(mm, addr, page, this_len, flags);
   10                 if (!this_len) {
    6                         if (!copied)
                                      copied = -EIO;
                              break;
                      }
      
   33                 if (!write && copy_to_user(buf, page, this_len)) {
                              copied = -EFAULT;
                              break;
                      }
      
   43                 buf += this_len;
                      addr += this_len;
                      copied += this_len;
                      count -= this_len;
              }
   11         *ppos = addr;
      
              mmput(mm);
      free:
   11         free_page((unsigned long) page);
   12         return copied;
    3 }
      
      static ssize_t mem_read(struct file *file, char __user *buf,
                              size_t count, loff_t *ppos)
      {
   35         return mem_rw(file, buf, count, ppos, 0);
      }
      
      static ssize_t mem_write(struct file *file, const char __user *buf,
                               size_t count, loff_t *ppos)
      {
   12         return mem_rw(file, (char __user*)buf, count, ppos, 1);
      }
      
      loff_t mem_lseek(struct file *file, loff_t offset, int orig)
      {
    3         switch (orig) {
              case 0:
    1                 file->f_pos = offset;
                      break;
              case 1:
    1                 file->f_pos += offset;
                      break;
              default:
                      return -EINVAL;
              }
              force_successful_syscall_return();
    2         return file->f_pos;
    1 }
      
      static int mem_release(struct inode *inode, struct file *file)
      {
    2         struct mm_struct *mm = file->private_data;
              if (mm)
    2                 mmdrop(mm);
    2         return 0;
      }
      
      static const struct file_operations proc_mem_operations = {
              .llseek                = mem_lseek,
              .read                = mem_read,
              .write                = mem_write,
              .open                = mem_open,
              .release        = mem_release,
      };
      
      static int environ_open(struct inode *inode, struct file *file)
      {
    3         return __mem_open(inode, file, PTRACE_MODE_READ);
      }
      
      static ssize_t environ_read(struct file *file, char __user *buf,
                              size_t count, loff_t *ppos)
      {
              char *page;
    3         unsigned long src = *ppos;
              int ret = 0;
    3         struct mm_struct *mm = file->private_data;
              unsigned long env_start, env_end;
      
              /* Ensure the process spawned far enough to have an environment. */
    3         if (!mm || !mm->env_end)
                      return 0;
      
              page = (char *)__get_free_page(GFP_TEMPORARY);
              if (!page)
                      return -ENOMEM;
      
              ret = 0;
    3         if (!atomic_inc_not_zero(&mm->mm_users))
                      goto free;
      
              down_read(&mm->mmap_sem);
              env_start = mm->env_start;
              env_end = mm->env_end;
              up_read(&mm->mmap_sem);
      
              while (count > 0) {
                      size_t this_len, max_len;
                      int retval;
      
    2                 if (src >= (env_end - env_start))
                              break;
      
                      this_len = env_end - (env_start + src);
      
                      max_len = min_t(size_t, PAGE_SIZE, count);
                      this_len = min(max_len, this_len);
      
                      retval = access_remote_vm(mm, (env_start + src), page, this_len, FOLL_ANON);
      
                      if (retval <= 0) {
                              ret = retval;
                              break;
                      }
      
                      if (copy_to_user(buf, page, retval)) {
                              ret = -EFAULT;
                              break;
                      }
      
                      ret += retval;
                      src += retval;
                      buf += retval;
                      count -= retval;
              }
    3         *ppos = src;
              mmput(mm);
      
      free:
    3         free_page((unsigned long) page);
              return ret;
      }
      
      static const struct file_operations proc_environ_operations = {
              .open                = environ_open,
              .read                = environ_read,
              .llseek                = generic_file_llseek,
              .release        = mem_release,
      };
      
      static ssize_t oom_adj_read(struct file *file, char __user *buf, size_t count,
                                  loff_t *ppos)
      {
   10         struct task_struct *task = get_proc_task(file_inode(file));
              char buffer[PROC_NUMBUF];
              int oom_adj = OOM_ADJUST_MIN;
              size_t len;
              unsigned long flags;
      
              if (!task)
                      return -ESRCH;
    9         if (lock_task_sighand(task, &flags)) {
    9                 if (task->signal->oom_score_adj == OOM_SCORE_ADJ_MAX)
                              oom_adj = OOM_ADJUST_MAX;
                      else
    4                         oom_adj = (task->signal->oom_score_adj * -OOM_DISABLE) /
                                        OOM_SCORE_ADJ_MAX;
    9                 unlock_task_sighand(task, &flags);
              }
    9         put_task_struct(task);
    9         len = snprintf(buffer, sizeof(buffer), "%d\n", oom_adj);
   10         return simple_read_from_buffer(buf, count, ppos, buffer, len);
      }
      
      /*
       * /proc/pid/oom_adj exists solely for backwards compatibility with previous
       * kernels.  The effective policy is defined by oom_score_adj, which has a
       * different scale: oom_adj grew exponentially and oom_score_adj grows linearly.
       * Values written to oom_adj are simply mapped linearly to oom_score_adj.
       * Processes that become oom disabled via oom_adj will still be oom disabled
       * with this implementation.
       *
       * oom_adj cannot be removed since existing userspace binaries use it.
       */
      static ssize_t oom_adj_write(struct file *file, const char __user *buf,
                                   size_t count, loff_t *ppos)
      {
              struct task_struct *task;
              char buffer[PROC_NUMBUF];
              int oom_adj;
              unsigned long flags;
              int err;
      
    8         memset(buffer, 0, sizeof(buffer));
              if (count > sizeof(buffer) - 1)
                      count = sizeof(buffer) - 1;
    8         if (copy_from_user(buffer, buf, count)) {
                      err = -EFAULT;
                      goto out;
              }
      
    8         err = kstrtoint(strstrip(buffer), 0, &oom_adj);
              if (err)
                      goto out;
    8         if ((oom_adj < OOM_ADJUST_MIN || oom_adj > OOM_ADJUST_MAX) &&
                   oom_adj != OOM_DISABLE) {
                      err = -EINVAL;
                      goto out;
              }
      
    7         task = get_proc_task(file_inode(file));
              if (!task) {
                      err = -ESRCH;
                      goto out;
              }
      
    7         task_lock(task);
              if (!task->mm) {
                      err = -EINVAL;
                      goto err_task_lock;
              }
      
    6         if (!lock_task_sighand(task, &flags)) {
                      err = -ESRCH;
                      goto err_task_lock;
              }
      
              /*
               * Scale /proc/pid/oom_score_adj appropriately ensuring that a maximum
               * value is always attainable.
               */
    6         if (oom_adj == OOM_ADJUST_MAX)
                      oom_adj = OOM_SCORE_ADJ_MAX;
              else
    6                 oom_adj = (oom_adj * OOM_SCORE_ADJ_MAX) / -OOM_DISABLE;
      
              if (oom_adj < task->signal->oom_score_adj &&
    1             !capable(CAP_SYS_RESOURCE)) {
                      err = -EACCES;
                      goto err_sighand;
              }
      
              /*
               * /proc/pid/oom_adj is provided for legacy purposes, ask users to use
               * /proc/pid/oom_score_adj instead.
               */
    6         pr_warn_once("%s (%d): /proc/%d/oom_adj is deprecated, please use /proc/%d/oom_score_adj instead.\n",
                        current->comm, task_pid_nr(current), task_pid_nr(task),
                        task_pid_nr(task));
      
    6         task->signal->oom_score_adj = oom_adj;
    6         trace_oom_score_adj_update(task);
      err_sighand:
    6         unlock_task_sighand(task, &flags);
      err_task_lock:
    7         task_unlock(task);
    7         put_task_struct(task);
      out:
    7         return err < 0 ? err : count;
      }
      
      static const struct file_operations proc_oom_adj_operations = {
              .read                = oom_adj_read,
              .write                = oom_adj_write,
              .llseek                = generic_file_llseek,
      };
      
      static ssize_t oom_score_adj_read(struct file *file, char __user *buf,
                                              size_t count, loff_t *ppos)
      {
   10         struct task_struct *task = get_proc_task(file_inode(file));
              char buffer[PROC_NUMBUF];
              short oom_score_adj = OOM_SCORE_ADJ_MIN;
              unsigned long flags;
              size_t len;
      
              if (!task)
                      return -ESRCH;
    9         if (lock_task_sighand(task, &flags)) {
    9                 oom_score_adj = task->signal->oom_score_adj;
                      unlock_task_sighand(task, &flags);
              }
    9         put_task_struct(task);
    9         len = snprintf(buffer, sizeof(buffer), "%hd\n", oom_score_adj);
   10         return simple_read_from_buffer(buf, count, ppos, buffer, len);
      }
      
      static ssize_t oom_score_adj_write(struct file *file, const char __user *buf,
                                              size_t count, loff_t *ppos)
      {
              struct task_struct *task;
              char buffer[PROC_NUMBUF];
              unsigned long flags;
              int oom_score_adj;
              int err;
      
   18         memset(buffer, 0, sizeof(buffer));
              if (count > sizeof(buffer) - 1)
                      count = sizeof(buffer) - 1;
   16         if (copy_from_user(buffer, buf, count)) {
                      err = -EFAULT;
                      goto out;
              }
      
   18         err = kstrtoint(strstrip(buffer), 0, &oom_score_adj);
              if (err)
                      goto out;
   16         if (oom_score_adj < OOM_SCORE_ADJ_MIN ||
                              oom_score_adj > OOM_SCORE_ADJ_MAX) {
                      err = -EINVAL;
                      goto out;
              }
      
   16         task = get_proc_task(file_inode(file));
              if (!task) {
                      err = -ESRCH;
                      goto out;
              }
      
   16         task_lock(task);
              if (!task->mm) {
                      err = -EINVAL;
                      goto err_task_lock;
              }
      
   14         if (!lock_task_sighand(task, &flags)) {
                      err = -ESRCH;
                      goto err_task_lock;
              }
      
   14         if ((short)oom_score_adj < task->signal->oom_score_adj_min &&
    1                         !capable(CAP_SYS_RESOURCE)) {
                      err = -EACCES;
                      goto err_sighand;
              }
      
   13         task->signal->oom_score_adj = (short)oom_score_adj;
              if (has_capability_noaudit(current, CAP_SYS_RESOURCE))
                      task->signal->oom_score_adj_min = (short)oom_score_adj;
   13         trace_oom_score_adj_update(task);
      
      err_sighand:
   14         unlock_task_sighand(task, &flags);
      err_task_lock:
   15         task_unlock(task);
   15         put_task_struct(task);
      out:
   16         return err < 0 ? err : count;
      }
      
      static const struct file_operations proc_oom_score_adj_operations = {
              .read                = oom_score_adj_read,
              .write                = oom_score_adj_write,
              .llseek                = default_llseek,
      };
      
      #ifdef CONFIG_AUDITSYSCALL
      #define TMPBUFLEN 21
      static ssize_t proc_loginuid_read(struct file * file, char __user * buf,
                                        size_t count, loff_t *ppos)
      {
    7         struct inode * inode = file_inode(file);
              struct task_struct *task = get_proc_task(inode);
              ssize_t length;
              char tmpbuf[TMPBUFLEN];
      
              if (!task)
                      return -ESRCH;
    6         length = scnprintf(tmpbuf, TMPBUFLEN, "%u",
                                 from_kuid(file->f_cred->user_ns,
                                           audit_get_loginuid(task)));
    6         put_task_struct(task);
    7         return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
      }
      
      static ssize_t proc_loginuid_write(struct file * file, const char __user * buf,
                                         size_t count, loff_t *ppos)
      {
    9         struct inode * inode = file_inode(file);
              uid_t loginuid;
              kuid_t kloginuid;
              int rv;
      
    9         rcu_read_lock();
    9         if (current != pid_task(proc_pid(inode), PIDTYPE_PID)) {
    2                 rcu_read_unlock();
                      return -EPERM;
              }
    7         rcu_read_unlock();
      
              if (*ppos != 0) {
                      /* No partial writes. */
                      return -EINVAL;
              }
      
    5         rv = kstrtou32_from_user(buf, count, 10, &loginuid);
              if (rv < 0)
                      return rv;
      
              /* is userspace tring to explicitly UNSET the loginuid? */
    4         if (loginuid == AUDIT_UID_UNSET) {
                      kloginuid = INVALID_UID;
              } else {
    3                 kloginuid = make_kuid(file->f_cred->user_ns, loginuid);
                      if (!uid_valid(kloginuid))
                              return -EINVAL;
              }
      
    3         rv = audit_set_loginuid(kloginuid);
              if (rv < 0)
    3                 return rv;
    8         return count;
      }
      
      static const struct file_operations proc_loginuid_operations = {
              .read                = proc_loginuid_read,
              .write                = proc_loginuid_write,
              .llseek                = generic_file_llseek,
      };
      
      static ssize_t proc_sessionid_read(struct file * file, char __user * buf,
                                        size_t count, loff_t *ppos)
      {
    5         struct inode * inode = file_inode(file);
              struct task_struct *task = get_proc_task(inode);
              ssize_t length;
              char tmpbuf[TMPBUFLEN];
      
              if (!task)
                      return -ESRCH;
    5         length = scnprintf(tmpbuf, TMPBUFLEN, "%u",
                                      audit_get_sessionid(task));
    5         put_task_struct(task);
    5         return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
      }
      
      static const struct file_operations proc_sessionid_operations = {
              .read                = proc_sessionid_read,
              .llseek                = generic_file_llseek,
      };
      #endif
      
      #ifdef CONFIG_FAULT_INJECTION
      static ssize_t proc_fault_inject_read(struct file * file, char __user * buf,
                                            size_t count, loff_t *ppos)
      {
              struct task_struct *task = get_proc_task(file_inode(file));
              char buffer[PROC_NUMBUF];
              size_t len;
              int make_it_fail;
      
              if (!task)
                      return -ESRCH;
              make_it_fail = task->make_it_fail;
              put_task_struct(task);
      
              len = snprintf(buffer, sizeof(buffer), "%i\n", make_it_fail);
      
              return simple_read_from_buffer(buf, count, ppos, buffer, len);
      }
      
      static ssize_t proc_fault_inject_write(struct file * file,
                              const char __user * buf, size_t count, loff_t *ppos)
      {
              struct task_struct *task;
              char buffer[PROC_NUMBUF];
              int make_it_fail;
              int rv;
      
              if (!capable(CAP_SYS_RESOURCE))
                      return -EPERM;
              memset(buffer, 0, sizeof(buffer));
              if (count > sizeof(buffer) - 1)
                      count = sizeof(buffer) - 1;
              if (copy_from_user(buffer, buf, count))
                      return -EFAULT;
              rv = kstrtoint(strstrip(buffer), 0, &make_it_fail);
              if (rv < 0)
                      return rv;
              if (make_it_fail < 0 || make_it_fail > 1)
                      return -EINVAL;
      
              task = get_proc_task(file_inode(file));
              if (!task)
                      return -ESRCH;
              task->make_it_fail = make_it_fail;
              put_task_struct(task);
      
              return count;
      }
      
      static const struct file_operations proc_fault_inject_operations = {
              .read                = proc_fault_inject_read,
              .write                = proc_fault_inject_write,
              .llseek                = generic_file_llseek,
      };
      #endif
      
      
      #ifdef CONFIG_SCHED_DEBUG
      /*
       * Print out various scheduling related per-task fields:
       */
      static int sched_show(struct seq_file *m, void *v)
      {
    6         struct inode *inode = m->private;
              struct task_struct *p;
      
              p = get_proc_task(inode);
              if (!p)
                      return -ESRCH;
    4         proc_sched_show_task(p, m);
      
    4         put_task_struct(p);
      
    6         return 0;
      }
      
      static ssize_t
      sched_write(struct file *file, const char __user *buf,
                  size_t count, loff_t *offset)
      {
    4         struct inode *inode = file_inode(file);
              struct task_struct *p;
      
              p = get_proc_task(inode);
              if (!p)
                      return -ESRCH;
    3         proc_sched_set_task(p);
      
    3         put_task_struct(p);
      
    4         return count;
      }
      
      static int sched_open(struct inode *inode, struct file *filp)
      {
    1         return single_open(filp, sched_show, inode);
      }
      
      static const struct file_operations proc_pid_sched_operations = {
              .open                = sched_open,
              .read                = seq_read,
              .write                = sched_write,
              .llseek                = seq_lseek,
              .release        = single_release,
      };
      
      #endif
      
      #ifdef CONFIG_SCHED_AUTOGROUP
      /*
       * Print out autogroup related information:
       */
      static int sched_autogroup_show(struct seq_file *m, void *v)
      {
              struct inode *inode = m->private;
              struct task_struct *p;
      
              p = get_proc_task(inode);
              if (!p)
                      return -ESRCH;
              proc_sched_autogroup_show_task(p, m);
      
              put_task_struct(p);
      
              return 0;
      }
      
      static ssize_t
      sched_autogroup_write(struct file *file, const char __user *buf,
                  size_t count, loff_t *offset)
      {
              struct inode *inode = file_inode(file);
              struct task_struct *p;
              char buffer[PROC_NUMBUF];
              int nice;
              int err;
      
              memset(buffer, 0, sizeof(buffer));
              if (count > sizeof(buffer) - 1)
                      count = sizeof(buffer) - 1;
              if (copy_from_user(buffer, buf, count))
                      return -EFAULT;
      
              err = kstrtoint(strstrip(buffer), 0, &nice);
              if (err < 0)
                      return err;
      
              p = get_proc_task(inode);
              if (!p)
                      return -ESRCH;
      
              err = proc_sched_autogroup_set_nice(p, nice);
              if (err)
                      count = err;
      
              put_task_struct(p);
      
              return count;
      }
      
      static int sched_autogroup_open(struct inode *inode, struct file *filp)
      {
              int ret;
      
              ret = single_open(filp, sched_autogroup_show, NULL);
              if (!ret) {
                      struct seq_file *m = filp->private_data;
      
                      m->private = inode;
              }
              return ret;
      }
      
      static const struct file_operations proc_pid_sched_autogroup_operations = {
              .open                = sched_autogroup_open,
              .read                = seq_read,
              .write                = sched_autogroup_write,
              .llseek                = seq_lseek,
              .release        = single_release,
      };
      
      #endif /* CONFIG_SCHED_AUTOGROUP */
      
      static ssize_t comm_write(struct file *file, const char __user *buf,
                                      size_t count, loff_t *offset)
      {
   11         struct inode *inode = file_inode(file);
              struct task_struct *p;
              char buffer[TASK_COMM_LEN];
              const size_t maxlen = sizeof(buffer) - 1;
      
              memset(buffer, 0, sizeof(buffer));
              if (copy_from_user(buffer, buf, count > maxlen ? maxlen : count))
                      return -EFAULT;
      
   11         p = get_proc_task(inode);
              if (!p)
                      return -ESRCH;
      
   10         if (same_thread_group(current, p))
   10                 set_task_comm(p, buffer);
              else
                      count = -EINVAL;
      
   10         put_task_struct(p);
      
   11         return count;
      }
      
      static int comm_show(struct seq_file *m, void *v)
      {
    5         struct inode *inode = m->private;
              struct task_struct *p;
      
              p = get_proc_task(inode);
              if (!p)
                      return -ESRCH;
      
    4         task_lock(p);
              seq_printf(m, "%s\n", p->comm);
              task_unlock(p);
      
    4         put_task_struct(p);
      
    5         return 0;
      }
      
      static int comm_open(struct inode *inode, struct file *filp)
      {
   14         return single_open(filp, comm_show, inode);
      }
      
      static const struct file_operations proc_pid_set_comm_operations = {
              .open                = comm_open,
              .read                = seq_read,
              .write                = comm_write,
              .llseek                = seq_lseek,
              .release        = single_release,
      };
      
      static int proc_exe_link(struct dentry *dentry, struct path *exe_path)
      {
              struct task_struct *task;
              struct file *exe_file;
      
    4         task = get_proc_task(d_inode(dentry));
              if (!task)
                      return -ENOENT;
    4         exe_file = get_task_exe_file(task);
    4         put_task_struct(task);
    4         if (exe_file) {
    4                 *exe_path = exe_file->f_path;
                      path_get(&exe_file->f_path);
                      fput(exe_file);
    4                 return 0;
              } else
                      return -ENOENT;
      }
      
      static const char *proc_pid_follow_link(struct dentry *dentry, void **cookie)
      {
   55         struct inode *inode = d_inode(dentry);
              struct path path;
              int error = -EACCES;
      
              /* Are we allowed to snoop on the tasks file descriptors? */
              if (!proc_fd_access_allowed(inode))
                      goto out;
      
   55         error = PROC_I(inode)->op.proc_get_link(dentry, &path);
   55         if (error)
                      goto out;
      
   55         nd_jump_link(&path);
              return NULL;
      out:
              return ERR_PTR(error);
      }
      
      static int do_proc_readlink(struct path *path, char __user *buffer, int buflen)
      {
    5         char *tmp = (char*)__get_free_page(GFP_TEMPORARY);
              char *pathname;
              int len;
      
              if (!tmp)
                      return -ENOMEM;
      
    5         pathname = d_path(path, tmp, PAGE_SIZE);
              len = PTR_ERR(pathname);
              if (IS_ERR(pathname))
                      goto out;
    5         len = tmp + PAGE_SIZE - 1 - pathname;
      
              if (len > buflen)
                      len = buflen;
              if (copy_to_user(buffer, pathname, len))
                      len = -EFAULT;
       out:
    5         free_page((unsigned long)tmp);
              return len;
      }
      
      static int proc_pid_readlink(struct dentry * dentry, char __user * buffer, int buflen)
      {
              int error = -EACCES;
    5         struct inode *inode = d_inode(dentry);
              struct path path;
      
              /* Are we allowed to snoop on the tasks file descriptors? */
              if (!proc_fd_access_allowed(inode))
                      goto out;
      
    5         error = PROC_I(inode)->op.proc_get_link(dentry, &path);
              if (error)
                      goto out;
      
    5         error = do_proc_readlink(&path, buffer, buflen);
    5         path_put(&path);
      out:
    5         return error;
      }
      
      const struct inode_operations proc_pid_link_inode_operations = {
              .readlink        = proc_pid_readlink,
              .follow_link        = proc_pid_follow_link,
              .setattr        = proc_setattr,
      };
      
      
      /* building an inode */
      
      struct inode *proc_pid_make_inode(struct super_block * sb, struct task_struct *task)
      {
              struct inode * inode;
              struct proc_inode *ei;
              const struct cred *cred;
      
              /* We need a new inode */
      
  542         inode = new_inode(sb);
              if (!inode)
                      goto out;
      
              /* Common stuff */
              ei = PROC_I(inode);
  541         inode->i_ino = get_next_ino();
              inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
              inode->i_op = &proc_def_inode_operations;
      
              /*
               * grab the reference to task.
               */
              ei->pid = get_task_pid(task, PIDTYPE_PID);
              if (!ei->pid)
                      goto out_unlock;
      
  541         if (task_dumpable(task)) {
  536                 rcu_read_lock();
  536                 cred = __task_cred(task);
  536                 inode->i_uid = cred->euid;
                      inode->i_gid = cred->egid;
  536                 rcu_read_unlock();
              }
  541         security_task_to_inode(task, inode);
      
      out:
              return inode;
      
      out_unlock:
              iput(inode);
              return NULL;
      }
      
      int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
      {
    7         struct inode *inode = d_inode(dentry);
              struct task_struct *task;
              const struct cred *cred;
              struct pid_namespace *pid = dentry->d_sb->s_fs_info;
      
              generic_fillattr(inode, stat);
      
    7         rcu_read_lock();
    7         stat->uid = GLOBAL_ROOT_UID;
              stat->gid = GLOBAL_ROOT_GID;
              task = pid_task(proc_pid(inode), PIDTYPE_PID);
              if (task) {
    6                 if (!has_pid_permissions(pid, task, 2)) {
                              rcu_read_unlock();
                              /*
                               * This doesn't prevent learning whether PID exists,
                               * it only makes getattr() consistent with readdir().
                               */
                              return -ENOENT;
                      }
    6                 if ((inode->i_mode == (S_IFDIR|S_IRUGO|S_IXUGO)) ||
    5                     task_dumpable(task)) {
    3                         cred = __task_cred(task);
    3                         stat->uid = cred->euid;
                              stat->gid = cred->egid;
                      }
              }
    7         rcu_read_unlock();
    7         return 0;
      }
      
      /* dentry stuff */
      
      /*
       *        Exceptional case: normally we are not allowed to unhash a busy
       * directory. In this case, however, we can do it - no aliasing problems
       * due to the way we treat inodes.
       *
       * Rewrite the inode's ownerships here because the owning task may have
       * performed a setuid(), etc.
       *
       * Before the /proc/pid/status file was created the only way to read
       * the effective uid of a /process was to stat /proc/pid.  Reading
       * /proc/pid/status is slow enough that procps and other packages
       * kept stating /proc/pid.  To keep the rules in /proc simple I have
       * made this apply to all per process world readable and executable
       * directories.
       */
      int pid_revalidate(struct dentry *dentry, unsigned int flags)
      {
              struct inode *inode;
              struct task_struct *task;
              const struct cred *cred;
      
  640         if (flags & LOOKUP_RCU)
                      return -ECHILD;
      
  640         inode = d_inode(dentry);
              task = get_proc_task(inode);
      
              if (task) {
  640                 if ((inode->i_mode == (S_IFDIR|S_IRUGO|S_IXUGO)) ||
  305                     task_dumpable(task)) {
  639                         rcu_read_lock();
  639                         cred = __task_cred(task);
  639                         inode->i_uid = cred->euid;
                              inode->i_gid = cred->egid;
  639                         rcu_read_unlock();
                      } else {
    3                         inode->i_uid = GLOBAL_ROOT_UID;
                              inode->i_gid = GLOBAL_ROOT_GID;
                      }
  640                 inode->i_mode &= ~(S_ISUID | S_ISGID);
                      security_task_to_inode(task, inode);
  640                 put_task_struct(task);
  640                 return 1;
              }
              return 0;
      }
      
      static inline bool proc_inode_is_dead(struct inode *inode)
      {
              return !proc_pid(inode)->tasks[PIDTYPE_PID].first;
      }
      
      int pid_delete_dentry(const struct dentry *dentry)
      {
              /* Is the task we represent dead?
               * If so, then don't put the dentry on the lru list,
               * kill it immediately.
               */
  235         return proc_inode_is_dead(d_inode(dentry));
      }
      
      const struct dentry_operations pid_dentry_operations =
      {
              .d_revalidate        = pid_revalidate,
              .d_delete        = pid_delete_dentry,
      };
      
      /* Lookups */
      
      /*
       * Fill a directory entry.
       *
       * If possible create the dcache entry and derive our inode number and
       * file type from dcache entry.
       *
       * Since all of the proc inode numbers are dynamically generated, the inode
       * numbers do not exist until the inode is cache.  This means creating the
       * the dcache entry in readdir is necessary to keep the inode numbers
       * reported by readdir in sync with the inode numbers reported
       * by stat.
       */
      bool proc_fill_cache(struct file *file, struct dir_context *ctx,
              const char *name, int len,
              instantiate_t instantiate, struct task_struct *task, const void *ptr)
      {
   45         struct dentry *child, *dir = file->f_path.dentry;
              struct qstr qname = QSTR_INIT(name, len);
              struct inode *inode;
              unsigned type;
              ino_t ino;
      
              child = d_hash_and_lookup(dir, &qname);
              if (!child) {
   41                 child = d_alloc(dir, &qname);
                      if (!child)
                              goto end_instantiate;
   41                 if (instantiate(d_inode(dir), child, task, ptr) < 0) {
                              dput(child);
                              goto end_instantiate;
                      }
              }
   44         inode = d_inode(child);
              ino = inode->i_ino;
              type = inode->i_mode >> 12;
              dput(child);
              return dir_emit(ctx, name, len, ino, type);
      
      end_instantiate:
              return dir_emit(ctx, name, len, 1, DT_UNKNOWN);
      }
      
      /*
       * dname_to_vma_addr - maps a dentry name into two unsigned longs
       * which represent vma start and end addresses.
       */
      static int dname_to_vma_addr(struct dentry *dentry,
                                   unsigned long *start, unsigned long *end)
      {
              const char *str = dentry->d_name.name;
              unsigned long long sval, eval;
              unsigned int len;
      
   11         len = _parse_integer(str, 16, &sval);
              if (len & KSTRTOX_OVERFLOW)
                      return -EINVAL;
              if (sval != (unsigned long)sval)
                      return -EINVAL;
   10         str += len;
      
              if (*str != '-')
                      return -EINVAL;
    8         str++;
      
              len = _parse_integer(str, 16, &eval);
              if (len & KSTRTOX_OVERFLOW)
                      return -EINVAL;
              if (eval != (unsigned long)eval)
                      return -EINVAL;
    8         str += len;
      
              if (*str != '\0')
                      return -EINVAL;
      
    7         *start = sval;
              *end = eval;
      
   11         return 0;
      }
      
      static int map_files_d_revalidate(struct dentry *dentry, unsigned int flags)
      {
              unsigned long vm_start, vm_end;
              bool exact_vma_exists = false;
              struct mm_struct *mm = NULL;
              struct task_struct *task;
              const struct cred *cred;
              struct inode *inode;
              int status = 0;
      
    2         if (flags & LOOKUP_RCU)
                      return -ECHILD;
      
    2         inode = d_inode(dentry);
              task = get_proc_task(inode);
              if (!task)
                      goto out_notask;
      
    2         mm = mm_access(task, PTRACE_MODE_READ_FSCREDS);
    2         if (IS_ERR_OR_NULL(mm))
                      goto out;
      
    2         if (!dname_to_vma_addr(dentry, &vm_start, &vm_end)) {
    2                 down_read(&mm->mmap_sem);
    2                 exact_vma_exists = !!find_exact_vma(mm, vm_start, vm_end);
    2                 up_read(&mm->mmap_sem);
              }
      
              mmput(mm);
      
              if (exact_vma_exists) {
    2                 if (task_dumpable(task)) {
    2                         rcu_read_lock();
    2                         cred = __task_cred(task);
    2                         inode->i_uid = cred->euid;
                              inode->i_gid = cred->egid;
    2                         rcu_read_unlock();
                      } else {
                              inode->i_uid = GLOBAL_ROOT_UID;
                              inode->i_gid = GLOBAL_ROOT_GID;
                      }
    2                 security_task_to_inode(task, inode);
                      status = 1;
              }
      
      out:
    2         put_task_struct(task);
      
      out_notask:
              return status;
      }
      
      static const struct dentry_operations tid_map_files_dentry_operations = {
              .d_revalidate        = map_files_d_revalidate,
              .d_delete        = pid_delete_dentry,
      };
      
      static int proc_map_files_get_link(struct dentry *dentry, struct path *path)
      {
              unsigned long vm_start, vm_end;
              struct vm_area_struct *vma;
              struct task_struct *task;
              struct mm_struct *mm;
              int rc;
      
              rc = -ENOENT;
              task = get_proc_task(d_inode(dentry));
              if (!task)
                      goto out;
      
              mm = get_task_mm(task);
              put_task_struct(task);
              if (!mm)
                      goto out;
      
              rc = dname_to_vma_addr(dentry, &vm_start, &vm_end);
              if (rc)
                      goto out_mmput;
      
              rc = -ENOENT;
              down_read(&mm->mmap_sem);
              vma = find_exact_vma(mm, vm_start, vm_end);
              if (vma && vma->vm_file) {
                      *path = vma->vm_file->f_path;
                      path_get(path);
                      rc = 0;
              }
              up_read(&mm->mmap_sem);
      
      out_mmput:
              mmput(mm);
      out:
              return rc;
      }
      
      struct map_files_info {
              fmode_t                mode;
              unsigned long        len;
              unsigned char        name[4*sizeof(long)+2]; /* max: %lx-%lx\0 */
      };
      
      /*
       * Only allow CAP_SYS_ADMIN to follow the links, due to concerns about how the
       * symlinks may be used to bypass permissions on ancestor directories in the
       * path to the file in question.
       */
      static const char *
    5 proc_map_files_follow_link(struct dentry *dentry, void **cookie)
      {
    5         if (!capable(CAP_SYS_ADMIN))
                      return ERR_PTR(-EPERM);
      
    5         return proc_pid_follow_link(dentry, NULL);
      }
      
      /*
       * Identical to proc_pid_link_inode_operations except for follow_link()
       */
      static const struct inode_operations proc_map_files_link_inode_operations = {
              .readlink        = proc_pid_readlink,
              .follow_link        = proc_map_files_follow_link,
              .setattr        = proc_setattr,
      };
      
      static int
      proc_map_files_instantiate(struct inode *dir, struct dentry *dentry,
                                 struct task_struct *task, const void *ptr)
      {
    9         fmode_t mode = (fmode_t)(unsigned long)ptr;
              struct proc_inode *ei;
              struct inode *inode;
      
              inode = proc_pid_make_inode(dir->i_sb, task);
              if (!inode)
                      return -ENOENT;
      
              ei = PROC_I(inode);
    9         ei->op.proc_get_link = proc_map_files_get_link;
      
              inode->i_op = &proc_map_files_link_inode_operations;
              inode->i_size = 64;
              inode->i_mode = S_IFLNK;
      
              if (mode & FMODE_READ)
    9                 inode->i_mode |= S_IRUSR;
    9         if (mode & FMODE_WRITE)
    6                 inode->i_mode |= S_IWUSR;
      
    9         d_set_d_op(dentry, &tid_map_files_dentry_operations);
              d_add(dentry, inode);
      
    9         return 0;
      }
      
      static struct dentry *proc_map_files_lookup(struct inode *dir,
                      struct dentry *dentry, unsigned int flags)
      {
              unsigned long vm_start, vm_end;
              struct vm_area_struct *vma;
              struct task_struct *task;
              int result;
              struct mm_struct *mm;
      
              result = -ENOENT;
   11         task = get_proc_task(dir);
              if (!task)
                      goto out;
      
              result = -EACCES;
   10         if (!ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS))
                      goto out_put_task;
      
              result = -ENOENT;
   10         if (dname_to_vma_addr(dentry, &vm_start, &vm_end))
                      goto out_put_task;
      
    5         mm = get_task_mm(task);
              if (!mm)
                      goto out_put_task;
      
    5         down_read(&mm->mmap_sem);
    5         vma = find_exact_vma(mm, vm_start, vm_end);
              if (!vma)
                      goto out_no_vma;
      
    3         if (vma->vm_file)
                      result = proc_map_files_instantiate(dir, dentry, task,
    3                                 (void *)(unsigned long)vma->vm_file->f_mode);
      
      out_no_vma:
    5         up_read(&mm->mmap_sem);
              mmput(mm);
      out_put_task:
   10         put_task_struct(task);
      out:
              return ERR_PTR(result);
      }
      
      static const struct inode_operations proc_map_files_inode_operations = {
              .lookup                = proc_map_files_lookup,
              .permission        = proc_fd_permission,
              .setattr        = proc_setattr,
      };
      
      static int
      proc_map_files_readdir(struct file *file, struct dir_context *ctx)
      {
              struct vm_area_struct *vma;
              struct task_struct *task;
              struct mm_struct *mm;
              unsigned long nr_files, pos, i;
              struct flex_array *fa = NULL;
              struct map_files_info info;
              struct map_files_info *p;
              int ret;
      
              ret = -ENOENT;
    9         task = get_proc_task(file_inode(file));
              if (!task)
                      goto out;
      
              ret = -EACCES;
    8         if (!ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS))
                      goto out_put_task;
      
              ret = 0;
    7         if (!dir_emit_dots(file, ctx))
                      goto out_put_task;
      
    6         mm = get_task_mm(task);
              if (!mm)
                      goto out_put_task;
    6         down_read(&mm->mmap_sem);
      
              nr_files = 0;
      
              /*
               * We need two passes here:
               *
               *  1) Collect vmas of mapped files with mmap_sem taken
               *  2) Release mmap_sem and instantiate entries
               *
               * otherwise we get lockdep complained, since filldir()
               * routine might require mmap_sem taken in might_fault().
               */
      
    6         for (vma = mm->mmap, pos = 2; vma; vma = vma->vm_next) {
    6                 if (vma->vm_file && ++pos > ctx->pos)
    6                         nr_files++;
              }
      
    6         if (nr_files) {
    6                 fa = flex_array_alloc(sizeof(info), nr_files,
                                              GFP_KERNEL);
    6                 if (!fa || flex_array_prealloc(fa, 0, nr_files,
                                                      GFP_KERNEL)) {
                              ret = -ENOMEM;
                              if (fa)
                                      flex_array_free(fa);
                              up_read(&mm->mmap_sem);
                              mmput(mm);
                              goto out_put_task;
                      }
    6                 for (i = 0, vma = mm->mmap, pos = 2; vma;
    6                                 vma = vma->vm_next) {
    6                         if (!vma->vm_file)
                                      continue;
    6                         if (++pos <= ctx->pos)
                                      continue;
      
    6                         info.mode = vma->vm_file->f_mode;
                              info.len = snprintf(info.name,
                                              sizeof(info.name), "%lx-%lx",
                                              vma->vm_start, vma->vm_end);
                              if (flex_array_put(fa, i++, &info, GFP_KERNEL))
                                      BUG();
                      }
              }
    6         up_read(&mm->mmap_sem);
      
              for (i = 0; i < nr_files; i++) {
    6                 p = flex_array_get(fa, i);
                      if (!proc_fill_cache(file, ctx,
                                            p->name, p->len,
                                            proc_map_files_instantiate,
                                            task,
                                            (void *)(unsigned long)p->mode))
                              break;
    6                 ctx->pos++;
              }
    5         if (fa)
    5                 flex_array_free(fa);
    6         mmput(mm);
      
      out_put_task:
    7         put_task_struct(task);
      out:
    8         return ret;
      }
      
      static const struct file_operations proc_map_files_operations = {
              .read                = generic_read_dir,
              .iterate        = proc_map_files_readdir,
              .llseek                = default_llseek,
      };
      
      struct timers_private {
              struct pid *pid;
              struct task_struct *task;
              struct sighand_struct *sighand;
              struct pid_namespace *ns;
              unsigned long flags;
      };
      
      static void *timers_start(struct seq_file *m, loff_t *pos)
      {
              struct timers_private *tp = m->private;
      
              tp->task = get_pid_task(tp->pid, PIDTYPE_PID);
              if (!tp->task)
                      return ERR_PTR(-ESRCH);
      
              tp->sighand = lock_task_sighand(tp->task, &tp->flags);
              if (!tp->sighand)
                      return ERR_PTR(-ESRCH);
      
              return seq_list_start(&tp->task->signal->posix_timers, *pos);
      }
      
      static void *timers_next(struct seq_file *m, void *v, loff_t *pos)
      {
              struct timers_private *tp = m->private;
              return seq_list_next(v, &tp->task->signal->posix_timers, pos);
      }
      
      static void timers_stop(struct seq_file *m, void *v)
      {
              struct timers_private *tp = m->private;
      
              if (tp->sighand) {
                      unlock_task_sighand(tp->task, &tp->flags);
                      tp->sighand = NULL;
              }
      
              if (tp->task) {
                      put_task_struct(tp->task);
                      tp->task = NULL;
              }
      }
      
      static int show_timer(struct seq_file *m, void *v)
      {
              struct k_itimer *timer;
              struct timers_private *tp = m->private;
              int notify;
              static const char * const nstr[] = {
                      [SIGEV_SIGNAL] = "signal",
                      [SIGEV_NONE] = "none",
                      [SIGEV_THREAD] = "thread",
              };
      
              timer = list_entry((struct list_head *)v, struct k_itimer, list);
              notify = timer->it_sigev_notify;
      
              seq_printf(m, "ID: %d\n", timer->it_id);
              seq_printf(m, "signal: %d/%p\n",
                         timer->sigq->info.si_signo,
                         timer->sigq->info.si_value.sival_ptr);
              seq_printf(m, "notify: %s/%s.%d\n",
                         nstr[notify & ~SIGEV_THREAD_ID],
                         (notify & SIGEV_THREAD_ID) ? "tid" : "pid",
                         pid_nr_ns(timer->it_pid, tp->ns));
              seq_printf(m, "ClockID: %d\n", timer->it_clock);
      
              return 0;
      }
      
      static const struct seq_operations proc_timers_seq_ops = {
              .start        = timers_start,
              .next        = timers_next,
              .stop        = timers_stop,
              .show        = show_timer,
      };
      
      static int proc_timers_open(struct inode *inode, struct file *file)
      {
              struct timers_private *tp;
      
              tp = __seq_open_private(file, &proc_timers_seq_ops,
                              sizeof(struct timers_private));
              if (!tp)
                      return -ENOMEM;
      
              tp->pid = proc_pid(inode);
              tp->ns = inode->i_sb->s_fs_info;
              return 0;
      }
      
      static const struct file_operations proc_timers_operations = {
              .open                = proc_timers_open,
              .read                = seq_read,
              .llseek                = seq_lseek,
              .release        = seq_release_private,
      };
      
      static ssize_t timerslack_ns_write(struct file *file, const char __user *buf,
                                              size_t count, loff_t *offset)
      {
              struct inode *inode = file_inode(file);
              struct task_struct *p;
              u64 slack_ns;
              int err;
      
              err = kstrtoull_from_user(buf, count, 10, &slack_ns);
              if (err < 0)
                      return err;
      
              p = get_proc_task(inode);
              if (!p)
                      return -ESRCH;
      
              if (p != current) {
                      if (!capable(CAP_SYS_NICE)) {
                              count = -EPERM;
                              goto out;
                      }
      
                      err = security_task_setscheduler(p);
                      if (err) {
                              count = err;
                              goto out;
                      }
              }
      
              task_lock(p);
              if (slack_ns == 0)
                      p->timer_slack_ns = p->default_timer_slack_ns;
              else
                      p->timer_slack_ns = slack_ns;
              task_unlock(p);
      
      out:
              put_task_struct(p);
      
              return count;
      }
      
      static int timerslack_ns_show(struct seq_file *m, void *v)
      {
              struct inode *inode = m->private;
              struct task_struct *p;
              int err = 0;
      
              p = get_proc_task(inode);
              if (!p)
                      return -ESRCH;
      
              if (p != current) {
      
                      if (!capable(CAP_SYS_NICE)) {
                              err = -EPERM;
                              goto out;
                      }
                      err = security_task_getscheduler(p);
                      if (err)
                              goto out;
              }
      
              task_lock(p);
              seq_printf(m, "%llu\n", p->timer_slack_ns);
              task_unlock(p);
      
      out:
              put_task_struct(p);
      
              return err;
      }
      
      static int timerslack_ns_open(struct inode *inode, struct file *filp)
      {
              return single_open(filp, timerslack_ns_show, inode);
      }
      
      static const struct file_operations proc_pid_set_timerslack_ns_operations = {
              .open                = timerslack_ns_open,
              .read                = seq_read,
              .write                = timerslack_ns_write,
              .llseek                = seq_lseek,
              .release        = single_release,
      };
      
      static int proc_pident_instantiate(struct inode *dir,
              struct dentry *dentry, struct task_struct *task, const void *ptr)
      {
              const struct pid_entry *p = ptr;
              struct inode *inode;
              struct proc_inode *ei;
      
  502         inode = proc_pid_make_inode(dir->i_sb, task);
              if (!inode)
                      goto out;
      
              ei = PROC_I(inode);
  502         inode->i_mode = p->mode;
              if (S_ISDIR(inode->i_mode))
  403                 set_nlink(inode, 2);        /* Use getattr to fix if necessary */
  502         if (p->iop)
  408                 inode->i_op = p->iop;
  502         if (p->fop)
  497                 inode->i_fop = p->fop;
  502         ei->op = p->op;
              d_set_d_op(dentry, &pid_dentry_operations);
              d_add(dentry, inode);
              /* Close the race of the process dying before we return the dentry */
              if (pid_revalidate(dentry, 0))
  501                 return 0;
      out:
              return -ENOENT;
      }
      
      static struct dentry *proc_pident_lookup(struct inode *dir, 
                                               struct dentry *dentry,
                                               const struct pid_entry *ents,
                                               unsigned int nents)
      {
              int error;
  542         struct task_struct *task = get_proc_task(dir);
              const struct pid_entry *p, *last;
      
              error = -ENOENT;
      
              if (!task)
                      goto out_no_task;
      
              /*
               * Yes, it does not scale. And it should not. Don't add
               * new entries into /proc/<tgid>/ without very good reasons.
               */
  541         last = &ents[nents - 1];
  502         for (p = ents; p <= last; p++) {
  541                 if (p->len != dentry->d_name.len)
                              continue;
  539                 if (!memcmp(dentry->d_name.name, p->name, p->len))
                              break;
              }
              if (p > last)
                      goto out;
      
  492         error = proc_pident_instantiate(dir, dentry, task, p);
      out:
  540         put_task_struct(task);
      out_no_task:
  541         return ERR_PTR(error);
      }
      
      static int proc_pident_readdir(struct file *file, struct dir_context *ctx,
                      const struct pid_entry *ents, unsigned int nents)
      {
   13         struct task_struct *task = get_proc_task(file_inode(file));
              const struct pid_entry *p;
      
              if (!task)
                      return -ENOENT;
      
   12         if (!dir_emit_dots(file, ctx))
                      goto out;
      
    4         if (ctx->pos >= nents + 2)
                      goto out;
      
   10         for (p = ents + (ctx->pos - 2); p <= ents + nents - 1; p++) {
   10                 if (!proc_fill_cache(file, ctx, p->name, p->len,
                                      proc_pident_instantiate, task, p))
                              break;
   10                 ctx->pos++;
              }
      out:
    9         put_task_struct(task);
   10         return 0;
      }
      
      #ifdef CONFIG_SECURITY
      static ssize_t proc_pid_attr_read(struct file * file, char __user * buf,
                                        size_t count, loff_t *ppos)
      {
   17         struct inode * inode = file_inode(file);
              char *p = NULL;
              ssize_t length;
              struct task_struct *task = get_proc_task(inode);
      
              if (!task)
                      return -ESRCH;
      
              length = security_getprocattr(task,
   16                                       (char*)file->f_path.dentry->d_name.name,
                                            &p);
   15         put_task_struct(task);
   15         if (length > 0)
    7                 length = simple_read_from_buffer(buf, count, ppos, p, length);
   15         kfree(p);
   16         return length;
      }
      
      static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf,
                                         size_t count, loff_t *ppos)
      {
   32         struct inode * inode = file_inode(file);
              char *page;
              ssize_t length;
              struct task_struct *task = get_proc_task(inode);
      
              length = -ESRCH;
              if (!task)
                      goto out_no_task;
              if (count > PAGE_SIZE)
                      count = PAGE_SIZE;
      
              /* No partial writes. */
              length = -EINVAL;
   31         if (*ppos != 0)
                      goto out;
      
              length = -ENOMEM;
   31         page = (char*)__get_free_page(GFP_TEMPORARY);
   30         if (!page)
                      goto out;
      
              length = -EFAULT;
              if (copy_from_user(page, buf, count))
                      goto out_free;
      
              /* Guard against adverse ptrace interaction */
   30         length = mutex_lock_interruptible(&task->signal->cred_guard_mutex);
              if (length < 0)
                      goto out_free;
      
              length = security_setprocattr(task,
   31                                       (char*)file->f_path.dentry->d_name.name,
                                            (void*)page, count);
              mutex_unlock(&task->signal->cred_guard_mutex);
      out_free:
   24         free_page((unsigned long) page);
      out:
   24         put_task_struct(task);
      out_no_task:
   25         return length;
      }
      
      static const struct file_operations proc_pid_attr_operations = {
              .read                = proc_pid_attr_read,
              .write                = proc_pid_attr_write,
              .llseek                = generic_file_llseek,
      };
      
      static const struct pid_entry attr_dir_stuff[] = {
              REG("current",    S_IRUGO|S_IWUGO, proc_pid_attr_operations),
              REG("prev",       S_IRUGO,           proc_pid_attr_operations),
              REG("exec",       S_IRUGO|S_IWUGO, proc_pid_attr_operations),
              REG("fscreate",   S_IRUGO|S_IWUGO, proc_pid_attr_operations),
              REG("keycreate",  S_IRUGO|S_IWUGO, proc_pid_attr_operations),
              REG("sockcreate", S_IRUGO|S_IWUGO, proc_pid_attr_operations),
      };
      
      static int proc_attr_dir_readdir(struct file *file, struct dir_context *ctx)
      {
    2         return proc_pident_readdir(file, ctx, 
                                         attr_dir_stuff, ARRAY_SIZE(attr_dir_stuff));
      }
      
      static const struct file_operations proc_attr_dir_operations = {
              .read                = generic_read_dir,
              .iterate        = proc_attr_dir_readdir,
              .llseek                = default_llseek,
      };
      
      static struct dentry *proc_attr_dir_lookup(struct inode *dir,
                                      struct dentry *dentry, unsigned int flags)
      {
   43         return proc_pident_lookup(dir, dentry,
                                        attr_dir_stuff, ARRAY_SIZE(attr_dir_stuff));
      }
      
      static const struct inode_operations proc_attr_dir_inode_operations = {
              .lookup                = proc_attr_dir_lookup,
              .getattr        = pid_getattr,
              .setattr        = proc_setattr,
      };
      
      #endif
      
      #ifdef CONFIG_ELF_CORE
      static ssize_t proc_coredump_filter_read(struct file *file, char __user *buf,
                                               size_t count, loff_t *ppos)
      {
    5         struct task_struct *task = get_proc_task(file_inode(file));
              struct mm_struct *mm;
              char buffer[PROC_NUMBUF];
              size_t len;
              int ret;
      
              if (!task)
                      return -ESRCH;
      
              ret = 0;
    5         mm = get_task_mm(task);
              if (mm) {
                      len = snprintf(buffer, sizeof(buffer), "%08lx\n",
    4                                ((mm->flags & MMF_DUMP_FILTER_MASK) >>
                                      MMF_DUMP_FILTER_SHIFT));
                      mmput(mm);
                      ret = simple_read_from_buffer(buf, count, ppos, buffer, len);
              }
      
    5         put_task_struct(task);
      
    5         return ret;
      }
      
      static ssize_t proc_coredump_filter_write(struct file *file,
                                                const char __user *buf,
                                                size_t count,
                                                loff_t *ppos)
      {
              struct task_struct *task;
              struct mm_struct *mm;
              unsigned int val;
              int ret;
              int i;
              unsigned long mask;
      
   12         ret = kstrtouint_from_user(buf, count, 0, &val);
              if (ret < 0)
                      return ret;
      
              ret = -ESRCH;
    8         task = get_proc_task(file_inode(file));
              if (!task)
                      goto out_no_task;
      
    7         mm = get_task_mm(task);
    6         if (!mm)
                      goto out_no_mm;
              ret = 0;
      
    6         for (i = 0, mask = 1; i < MMF_DUMP_FILTER_BITS; i++, mask <<= 1) {
    6                 if (val & mask)
    3                         set_bit(i + MMF_DUMP_FILTER_SHIFT, &mm->flags);
                      else
   10                         clear_bit(i + MMF_DUMP_FILTER_SHIFT, &mm->flags);
              }
      
    6         mmput(mm);
       out_no_mm:
    7         put_task_struct(task);
       out_no_task:
    7         if (ret < 0)
                      return ret;
    6         return count;
      }
      
      static const struct file_operations proc_coredump_filter_operations = {
              .read                = proc_coredump_filter_read,
              .write                = proc_coredump_filter_write,
              .llseek                = generic_file_llseek,
      };
      #endif
      
      #ifdef CONFIG_TASK_IO_ACCOUNTING
      static int do_io_accounting(struct task_struct *task, struct seq_file *m, int whole)
      {
    7         struct task_io_accounting acct = task->ioac;
              unsigned long flags;
              int result;
      
              result = mutex_lock_killable(&task->signal->cred_guard_mutex);
    6         if (result)
                      return result;
      
    7         if (!ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)) {
                      result = -EACCES;
                      goto out_unlock;
              }
      
    6         if (whole && lock_task_sighand(task, &flags)) {
                      struct task_struct *t = task;
      
    4                 task_io_accounting_add(&acct, &task->signal->ioac);
                      while_each_thread(task, t)
    3                         task_io_accounting_add(&acct, &t->ioac);
      
    4                 unlock_task_sighand(task, &flags);
              }
    6         seq_printf(m,
                         "rchar: %llu\n"
                         "wchar: %llu\n"
                         "syscr: %llu\n"
                         "syscw: %llu\n"
                         "read_bytes: %llu\n"
                         "write_bytes: %llu\n"
                         "cancelled_write_bytes: %llu\n",
                         (unsigned long long)acct.rchar,
                         (unsigned long long)acct.wchar,
                         (unsigned long long)acct.syscr,
                         (unsigned long long)acct.syscw,
                         (unsigned long long)acct.read_bytes,
                         (unsigned long long)acct.write_bytes,
                         (unsigned long long)acct.cancelled_write_bytes);
              result = 0;
      
      out_unlock:
    6         mutex_unlock(&task->signal->cred_guard_mutex);
              return result;
      }
      
      static int proc_tid_io_accounting(struct seq_file *m, struct pid_namespace *ns,
                                        struct pid *pid, struct task_struct *task)
      {
    2         return do_io_accounting(task, m, 0);
      }
      
      static int proc_tgid_io_accounting(struct seq_file *m, struct pid_namespace *ns,
                                         struct pid *pid, struct task_struct *task)
      {
    5         return do_io_accounting(task, m, 1);
      }
      #endif /* CONFIG_TASK_IO_ACCOUNTING */
      
      #ifdef CONFIG_USER_NS
      static int proc_id_map_open(struct inode *inode, struct file *file,
              const struct seq_operations *seq_ops)
      {
              struct user_namespace *ns = NULL;
              struct task_struct *task;
              struct seq_file *seq;
              int ret = -EINVAL;
      
    9         task = get_proc_task(inode);
              if (task) {
    8                 rcu_read_lock();
    8                 ns = get_user_ns(task_cred_xxx(task, user_ns));
    8                 rcu_read_unlock();
    8                 put_task_struct(task);
              }
    8         if (!ns)
                      goto err;
      
    8         ret = seq_open(file, seq_ops);
              if (ret)
                      goto err_put_ns;
      
    8         seq = file->private_data;
              seq->private = ns;
      
    9         return 0;
      err_put_ns:
              put_user_ns(ns);
      err:
              return ret;
      }
      
      static int proc_id_map_release(struct inode *inode, struct file *file)
      {
    2         struct seq_file *seq = file->private_data;
              struct user_namespace *ns = seq->private;
    2         put_user_ns(ns);
    2         return seq_release(inode, file);
      }
      
      static int proc_uid_map_open(struct inode *inode, struct file *file)
      {
    2         return proc_id_map_open(inode, file, &proc_uid_seq_operations);
      }
      
      static int proc_gid_map_open(struct inode *inode, struct file *file)
      {
    3         return proc_id_map_open(inode, file, &proc_gid_seq_operations);
      }
      
      static int proc_projid_map_open(struct inode *inode, struct file *file)
      {
    4         return proc_id_map_open(inode, file, &proc_projid_seq_operations);
      }
      
      static const struct file_operations proc_uid_map_operations = {
              .open                = proc_uid_map_open,
              .write                = proc_uid_map_write,
              .read                = seq_read,
              .llseek                = seq_lseek,
              .release        = proc_id_map_release,
      };
      
      static const struct file_operations proc_gid_map_operations = {
              .open                = proc_gid_map_open,
              .write                = proc_gid_map_write,
              .read                = seq_read,
              .llseek                = seq_lseek,
              .release        = proc_id_map_release,
      };
      
      static const struct file_operations proc_projid_map_operations = {
              .open                = proc_projid_map_open,
              .write                = proc_projid_map_write,
              .read                = seq_read,
              .llseek                = seq_lseek,
              .release        = proc_id_map_release,
      };
      
      static int proc_setgroups_open(struct inode *inode, struct file *file)
      {
              struct user_namespace *ns = NULL;
              struct task_struct *task;
              int ret;
      
              ret = -ESRCH;
    4         task = get_proc_task(inode);
              if (task) {
    4                 rcu_read_lock();
    4                 ns = get_user_ns(task_cred_xxx(task, user_ns));
    4                 rcu_read_unlock();
    4                 put_task_struct(task);
              }
    4         if (!ns)
                      goto err;
      
    4         if (file->f_mode & FMODE_WRITE) {
                      ret = -EACCES;
    4                 if (!ns_capable(ns, CAP_SYS_ADMIN))
                              goto err_put_ns;
              }
      
    4         ret = single_open(file, &proc_setgroups_show, ns);
    4         if (ret)
                      goto err_put_ns;
      
              return 0;
      err_put_ns:
    1         put_user_ns(ns);
      err:
              return ret;
      }
      
      static int proc_setgroups_release(struct inode *inode, struct file *file)
      {
    2         struct seq_file *seq = file->private_data;
              struct user_namespace *ns = seq->private;
              int ret = single_release(inode, file);
    1         put_user_ns(ns);
    1         return ret;
      }
      
      static const struct file_operations proc_setgroups_operations = {
              .open                = proc_setgroups_open,
              .write                = proc_setgroups_write,
              .read                = seq_read,
              .llseek                = seq_lseek,
              .release        = proc_setgroups_release,
      };
      #endif /* CONFIG_USER_NS */
      
    2 static int proc_pid_personality(struct seq_file *m, struct pid_namespace *ns,
                                      struct pid *pid, struct task_struct *task)
      {
    3         int err = lock_trace(task);
              if (!err) {
    2                 seq_printf(m, "%08x\n", task->personality);
                      unlock_trace(task);
              }
    3         return err;
      }
      
      /*
       * Thread groups
       */
      static const struct file_operations proc_task_operations;
      static const struct inode_operations proc_task_inode_operations;
      
      static const struct pid_entry tgid_base_stuff[] = {
              DIR("task",       S_IRUGO|S_IXUGO, proc_task_inode_operations, proc_task_operations),
              DIR("fd",         S_IRUSR|S_IXUSR, proc_fd_inode_operations, proc_fd_operations),
              DIR("map_files",  S_IRUSR|S_IXUSR, proc_map_files_inode_operations, proc_map_files_operations),
              DIR("fdinfo",     S_IRUSR|S_IXUSR, proc_fdinfo_inode_operations, proc_fdinfo_operations),
              DIR("ns",          S_IRUSR|S_IXUGO, proc_ns_dir_inode_operations, proc_ns_dir_operations),
      #ifdef CONFIG_NET
              DIR("net",        S_IRUGO|S_IXUGO, proc_net_inode_operations, proc_net_operations),
      #endif
              REG("environ",    S_IRUSR, proc_environ_operations),
              ONE("auxv",       S_IRUSR, proc_pid_auxv),
              ONE("status",     S_IRUGO, proc_pid_status),
              ONE("personality", S_IRUSR, proc_pid_personality),
              ONE("limits",          S_IRUGO, proc_pid_limits),
      #ifdef CONFIG_SCHED_DEBUG
              REG("sched",      S_IRUGO|S_IWUSR, proc_pid_sched_operations),
      #endif
      #ifdef CONFIG_SCHED_AUTOGROUP
              REG("autogroup",  S_IRUGO|S_IWUSR, proc_pid_sched_autogroup_operations),
      #endif
              REG("comm",      S_IRUGO|S_IWUSR, proc_pid_set_comm_operations),
      #ifdef CONFIG_HAVE_ARCH_TRACEHOOK
              ONE("syscall",    S_IRUSR, proc_pid_syscall),
      #endif
              REG("cmdline",    S_IRUGO, proc_pid_cmdline_ops),
              ONE("stat",       S_IRUGO, proc_tgid_stat),
              ONE("statm",      S_IRUGO, proc_pid_statm),
              REG("maps",       S_IRUGO, proc_pid_maps_operations),
      #ifdef CONFIG_NUMA
              REG("numa_maps",  S_IRUGO, proc_pid_numa_maps_operations),
      #endif
              REG("mem",        S_IRUSR|S_IWUSR, proc_mem_operations),
              LNK("cwd",        proc_cwd_link),
              LNK("root",       proc_root_link),
              LNK("exe",        proc_exe_link),
              REG("mounts",     S_IRUGO, proc_mounts_operations),
              REG("mountinfo",  S_IRUGO, proc_mountinfo_operations),
              REG("mountstats", S_IRUSR, proc_mountstats_operations),
      #ifdef CONFIG_PROC_PAGE_MONITOR
              REG("clear_refs", S_IWUSR, proc_clear_refs_operations),
              REG("smaps",      S_IRUGO, proc_pid_smaps_operations),
              REG("pagemap",    S_IRUSR, proc_pagemap_operations),
      #endif
      #ifdef CONFIG_SECURITY
              DIR("attr",       S_IRUGO|S_IXUGO, proc_attr_dir_inode_operations, proc_attr_dir_operations),
      #endif
      #ifdef CONFIG_KALLSYMS
              ONE("wchan",      S_IRUGO, proc_pid_wchan),
      #endif
      #ifdef CONFIG_STACKTRACE
              ONE("stack",      S_IRUSR, proc_pid_stack),
      #endif
      #ifdef CONFIG_SCHED_INFO
              ONE("schedstat",  S_IRUGO, proc_pid_schedstat),
      #endif
      #ifdef CONFIG_LATENCYTOP
              REG("latency",  S_IRUGO, proc_lstats_operations),
      #endif
      #ifdef CONFIG_PROC_PID_CPUSET
              ONE("cpuset",     S_IRUGO, proc_cpuset_show),
      #endif
      #ifdef CONFIG_CGROUPS
              ONE("cgroup",  S_IRUGO, proc_cgroup_show),
      #endif
              ONE("oom_score",  S_IRUGO, proc_oom_score),
              REG("oom_adj",    S_IRUGO|S_IWUSR, proc_oom_adj_operations),
              REG("oom_score_adj", S_IRUGO|S_IWUSR, proc_oom_score_adj_operations),
      #ifdef CONFIG_AUDITSYSCALL
              REG("loginuid",   S_IWUSR|S_IRUGO, proc_loginuid_operations),
              REG("sessionid",  S_IRUGO, proc_sessionid_operations),
      #endif
      #ifdef CONFIG_FAULT_INJECTION
              REG("make-it-fail", S_IRUGO|S_IWUSR, proc_fault_inject_operations),
      #endif
      #ifdef CONFIG_ELF_CORE
              REG("coredump_filter", S_IRUGO|S_IWUSR, proc_coredump_filter_operations),
      #endif
      #ifdef CONFIG_TASK_IO_ACCOUNTING
              ONE("io",        S_IRUSR, proc_tgid_io_accounting),
      #endif
      #ifdef CONFIG_HARDWALL
              ONE("hardwall",   S_IRUGO, proc_pid_hardwall),
      #endif
      #ifdef CONFIG_USER_NS
              REG("uid_map",    S_IRUGO|S_IWUSR, proc_uid_map_operations),
              REG("gid_map",    S_IRUGO|S_IWUSR, proc_gid_map_operations),
              REG("projid_map", S_IRUGO|S_IWUSR, proc_projid_map_operations),
              REG("setgroups",  S_IRUGO|S_IWUSR, proc_setgroups_operations),
      #endif
      #ifdef CONFIG_CHECKPOINT_RESTORE
              REG("timers",          S_IRUGO, proc_timers_operations),
      #endif
              REG("timerslack_ns", S_IRUGO|S_IWUGO, proc_pid_set_timerslack_ns_operations),
      #ifdef CONFIG_CPU_FREQ_TIMES
              ONE("time_in_state", 0444, proc_time_in_state_show),
      #endif
      };
      
      static int proc_tgid_base_readdir(struct file *file, struct dir_context *ctx)
      {
    9         return proc_pident_readdir(file, ctx,
                                         tgid_base_stuff, ARRAY_SIZE(tgid_base_stuff));
      }
      
      static const struct file_operations proc_tgid_base_operations = {
              .read                = generic_read_dir,
              .iterate        = proc_tgid_base_readdir,
              .llseek                = default_llseek,
      };
      
      static struct dentry *proc_tgid_base_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
      {
  539         return proc_pident_lookup(dir, dentry,
                                        tgid_base_stuff, ARRAY_SIZE(tgid_base_stuff));
      }
      
      static const struct inode_operations proc_tgid_base_inode_operations = {
              .lookup                = proc_tgid_base_lookup,
              .getattr        = pid_getattr,
              .setattr        = proc_setattr,
              .permission        = proc_pid_permission,
      };
      
      static void proc_flush_task_mnt(struct vfsmount *mnt, pid_t pid, pid_t tgid)
      {
              struct dentry *dentry, *leader, *dir;
              char buf[PROC_NUMBUF];
              struct qstr name;
      
              name.name = buf;
              name.len = snprintf(buf, sizeof(buf), "%d", pid);
              /* no ->d_hash() rejects on procfs */
              dentry = d_hash_and_lookup(mnt->mnt_root, &name);
              if (dentry) {
    9                 d_invalidate(dentry);
                      dput(dentry);
              }
      
   41         if (pid == tgid)
                      return;
      
    5         name.name = buf;
              name.len = snprintf(buf, sizeof(buf), "%d", tgid);
              leader = d_hash_and_lookup(mnt->mnt_root, &name);
              if (!leader)
                      goto out;
      
    3         name.name = "task";
              name.len = strlen(name.name);
              dir = d_hash_and_lookup(leader, &name);
              if (!dir)
                      goto out_put_leader;
      
    1         name.name = buf;
              name.len = snprintf(buf, sizeof(buf), "%d", pid);
              dentry = d_hash_and_lookup(dir, &name);
              if (dentry) {
    1                 d_invalidate(dentry);
                      dput(dentry);
              }
      
    1         dput(dir);
      out_put_leader:
   41         dput(leader);
      out:
              return;
      }
      
      /**
       * proc_flush_task -  Remove dcache entries for @task from the /proc dcache.
       * @task: task that should be flushed.
       *
       * When flushing dentries from proc, one needs to flush them from global
       * proc (proc_mnt) and from all the namespaces' procs this task was seen
       * in. This call is supposed to do all of this job.
       *
       * Looks in the dcache for
       * /proc/@pid
       * /proc/@tgid/task/@pid
       * if either directory is present flushes it and all of it'ts children
       * from the dcache.
       *
       * It is safe and reasonable to cache /proc entries for a task until
       * that task exits.  After that they just clog up the dcache with
       * useless entries, possibly causing useful dcache entries to be
       * flushed instead.  This routine is proved to flush those useless
       * dcache entries at process exit time.
       *
       * NOTE: This routine is just an optimization so it does not guarantee
       *       that no dcache entries will exist at process exit time it
       *       just makes it very unlikely that any will persist.
       */
      
      void proc_flush_task(struct task_struct *task)
      {
              int i;
              struct pid *pid, *tgid;
              struct upid *upid;
      
   42         pid = task_pid(task);
              tgid = task_tgid(task);
      
              for (i = 0; i <= pid->level; i++) {
                      upid = &pid->numbers[i];
   42                 proc_flush_task_mnt(upid->ns->proc_mnt, upid->nr,
                                              tgid->numbers[i].nr);
              }
   36 }
      
      static int proc_pid_instantiate(struct inode *dir,
                                         struct dentry * dentry,
                                         struct task_struct *task, const void *ptr)
      {
              struct inode *inode;
      
    2         inode = proc_pid_make_inode(dir->i_sb, task);
              if (!inode)
                      goto out;
      
    2         inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO;
              inode->i_op = &proc_tgid_base_inode_operations;
              inode->i_fop = &proc_tgid_base_operations;
              inode->i_flags|=S_IMMUTABLE;
      
    2         set_nlink(inode, 2 + pid_entry_count_dirs(tgid_base_stuff,
                                                        ARRAY_SIZE(tgid_base_stuff)));
      
              d_set_d_op(dentry, &pid_dentry_operations);
      
              d_add(dentry, inode);
              /* Close the race of the process dying before we return the dentry */
    2         if (pid_revalidate(dentry, 0))
                      return 0;
      out:
              return -ENOENT;
      }
      
      struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, unsigned int flags)
      {
              int result = -ENOENT;
              struct task_struct *task;
              unsigned tgid;
              struct pid_namespace *ns;
      
   20         tgid = name_to_int(&dentry->d_name);
              if (tgid == ~0U)
                      goto out;
      
    2         ns = dentry->d_sb->s_fs_info;
    2         rcu_read_lock();
    2         task = find_task_by_pid_ns(tgid, ns);
              if (task)
                      get_task_struct(task);
    2         rcu_read_unlock();
              if (!task)
                      goto out;
      
              result = proc_pid_instantiate(dir, dentry, task, NULL);
              put_task_struct(task);
      out:
   20         return ERR_PTR(result);
      }
      
      /*
       * Find the first task with tgid >= tgid
       *
       */
      struct tgid_iter {
              unsigned int tgid;
              struct task_struct *task;
      };
    6 static struct tgid_iter next_tgid(struct pid_namespace *ns, struct tgid_iter iter)
      {
              struct pid *pid;
      
              if (iter.task)
    5                 put_task_struct(iter.task);
    6         rcu_read_lock();
      retry:
              iter.task = NULL;
    6         pid = find_ge_pid(iter.tgid, ns);
              if (pid) {
    6                 iter.tgid = pid_nr_ns(pid, ns);
                      iter.task = pid_task(pid, PIDTYPE_PID);
                      /* What we to know is if the pid we have find is the
                       * pid of a thread_group_leader.  Testing for task
                       * being a thread_group_leader is the obvious thing
                       * todo but there is a window when it fails, due to
                       * the pid transfer logic in de_thread.
                       *
                       * So we perform the straight forward test of seeing
                       * if the pid we have found is the pid of a thread
                       * group leader, and don't worry if the task we have
                       * found doesn't happen to be a thread group leader.
                       * As we don't care in the case of readdir.
                       */
    6                 if (!iter.task || !has_group_leader_pid(iter.task)) {
    5                         iter.tgid += 1;
                              goto retry;
                      }
    6                 get_task_struct(iter.task);
              }
    6         rcu_read_unlock();
              return iter;
      }
      
      #define TGID_OFFSET (FIRST_PROCESS_ENTRY + 2)
      
      /* for the /proc/ directory itself, after non-process stuff has been done */
      int proc_pid_readdir(struct file *file, struct dir_context *ctx)
      {
              struct tgid_iter iter;
    9         struct pid_namespace *ns = file_inode(file)->i_sb->s_fs_info;
    9         loff_t pos = ctx->pos;
      
              if (pos >= PID_MAX_LIMIT + TGID_OFFSET)
                      return 0;
      
              if (pos == TGID_OFFSET - 2) {
    7                 struct inode *inode = d_inode(ns->proc_self);
                      if (!dir_emit(ctx, "self", 4, inode->i_ino, DT_LNK))
                              return 0;
    7                 ctx->pos = pos = pos + 1;
              }
    4         if (pos == TGID_OFFSET - 1) {
    8                 struct inode *inode = d_inode(ns->proc_thread_self);
                      if (!dir_emit(ctx, "thread-self", 11, inode->i_ino, DT_LNK))
                              return 0;
    5                 ctx->pos = pos = pos + 1;
              }
              iter.tgid = pos - TGID_OFFSET;
              iter.task = NULL;
    6         for (iter = next_tgid(ns, iter);
                   iter.task;
                   iter.tgid += 1, iter = next_tgid(ns, iter)) {
                      char name[PROC_NUMBUF];
                      int len;
      
    6                 cond_resched();
    6                 if (!has_pid_permissions(ns, iter.task, 2))
    5                         continue;
      
    6                 len = snprintf(name, sizeof(name), "%d", iter.tgid);
                      ctx->pos = iter.tgid + TGID_OFFSET;
                      if (!proc_fill_cache(file, ctx, name, len,
                                           proc_pid_instantiate, iter.task, NULL)) {
    2                         put_task_struct(iter.task);
    7                         return 0;
                      }
              }
    3         ctx->pos = PID_MAX_LIMIT + TGID_OFFSET;
              return 0;
      }
      
      /*
       * proc_tid_comm_permission is a special permission function exclusively
       * used for the node /proc/<pid>/task/<tid>/comm.
       * It bypasses generic permission checks in the case where a task of the same
       * task group attempts to access the node.
       * The rationale behind this is that glibc and bionic access this node for
       * cross thread naming (pthread_set/getname_np(!self)). However, if
       * PR_SET_DUMPABLE gets set to 0 this node among others becomes uid=0 gid=0,
       * which locks out the cross thread naming implementation.
       * This function makes sure that the node is always accessible for members of
       * same thread group.
       */
      static int proc_tid_comm_permission(struct inode *inode, int mask)
      {
              bool is_same_tgroup;
              struct task_struct *task;
      
   15         task = get_proc_task(inode);
              if (!task)
                      return -ESRCH;
   14         is_same_tgroup = same_thread_group(current, task);
   14         put_task_struct(task);
      
   14         if (likely(is_same_tgroup && !(mask & MAY_EXEC))) {
                      /* This file (/proc/<pid>/task/<tid>/comm) can always be
                       * read or written by the members of the corresponding
                       * thread group.
                       */
   15                 return 0;
              }
      
    1         return generic_permission(inode, mask);
      }
      
      static const struct inode_operations proc_tid_comm_inode_operations = {
                      .permission = proc_tid_comm_permission,
      };
      
      /*
       * Tasks
       */
      static const struct pid_entry tid_base_stuff[] = {
              DIR("fd",        S_IRUSR|S_IXUSR, proc_fd_inode_operations, proc_fd_operations),
              DIR("fdinfo",    S_IRUSR|S_IXUSR, proc_fdinfo_inode_operations, proc_fdinfo_operations),
              DIR("ns",         S_IRUSR|S_IXUGO, proc_ns_dir_inode_operations, proc_ns_dir_operations),
      #ifdef CONFIG_NET
              DIR("net",        S_IRUGO|S_IXUGO, proc_net_inode_operations, proc_net_operations),
      #endif
              REG("environ",   S_IRUSR, proc_environ_operations),
              ONE("auxv",      S_IRUSR, proc_pid_auxv),
              ONE("status",    S_IRUGO, proc_pid_status),
              ONE("personality", S_IRUSR, proc_pid_personality),
              ONE("limits",         S_IRUGO, proc_pid_limits),
      #ifdef CONFIG_SCHED_DEBUG
              REG("sched",     S_IRUGO|S_IWUSR, proc_pid_sched_operations),
      #endif
              NOD("comm",      S_IFREG|S_IRUGO|S_IWUSR,
                               &proc_tid_comm_inode_operations,
                               &proc_pid_set_comm_operations, {}),
      #ifdef CONFIG_HAVE_ARCH_TRACEHOOK
              ONE("syscall",   S_IRUSR, proc_pid_syscall),
      #endif
              REG("cmdline",   S_IRUGO, proc_pid_cmdline_ops),
              ONE("stat",      S_IRUGO, proc_tid_stat),
              ONE("statm",     S_IRUGO, proc_pid_statm),
              REG("maps",      S_IRUGO, proc_tid_maps_operations),
      #ifdef CONFIG_PROC_CHILDREN
              REG("children",  S_IRUGO, proc_tid_children_operations),
      #endif
      #ifdef CONFIG_NUMA
              REG("numa_maps", S_IRUGO, proc_tid_numa_maps_operations),
      #endif
              REG("mem",       S_IRUSR|S_IWUSR, proc_mem_operations),
              LNK("cwd",       proc_cwd_link),
              LNK("root",      proc_root_link),
              LNK("exe",       proc_exe_link),
              REG("mounts",    S_IRUGO, proc_mounts_operations),
              REG("mountinfo",  S_IRUGO, proc_mountinfo_operations),
      #ifdef CONFIG_PROC_PAGE_MONITOR
              REG("clear_refs", S_IWUSR, proc_clear_refs_operations),
              REG("smaps",     S_IRUGO, proc_tid_smaps_operations),
              REG("pagemap",    S_IRUSR, proc_pagemap_operations),
      #endif
      #ifdef CONFIG_SECURITY
              DIR("attr",      S_IRUGO|S_IXUGO, proc_attr_dir_inode_operations, proc_attr_dir_operations),
      #endif
      #ifdef CONFIG_KALLSYMS
              ONE("wchan",     S_IRUGO, proc_pid_wchan),
      #endif
      #ifdef CONFIG_STACKTRACE
              ONE("stack",      S_IRUSR, proc_pid_stack),
      #endif
      #ifdef CONFIG_SCHED_INFO
              ONE("schedstat", S_IRUGO, proc_pid_schedstat),
      #endif
      #ifdef CONFIG_LATENCYTOP
              REG("latency",  S_IRUGO, proc_lstats_operations),
      #endif
      #ifdef CONFIG_PROC_PID_CPUSET
              ONE("cpuset",    S_IRUGO, proc_cpuset_show),
      #endif
      #ifdef CONFIG_CGROUPS
              ONE("cgroup",  S_IRUGO, proc_cgroup_show),
      #endif
              ONE("oom_score", S_IRUGO, proc_oom_score),
              REG("oom_adj",   S_IRUGO|S_IWUSR, proc_oom_adj_operations),
              REG("oom_score_adj", S_IRUGO|S_IWUSR, proc_oom_score_adj_operations),
      #ifdef CONFIG_AUDITSYSCALL
              REG("loginuid",  S_IWUSR|S_IRUGO, proc_loginuid_operations),
              REG("sessionid",  S_IRUGO, proc_sessionid_operations),
      #endif
      #ifdef CONFIG_FAULT_INJECTION
              REG("make-it-fail", S_IRUGO|S_IWUSR, proc_fault_inject_operations),
      #endif
      #ifdef CONFIG_TASK_IO_ACCOUNTING
              ONE("io",        S_IRUSR, proc_tid_io_accounting),
      #endif
      #ifdef CONFIG_HARDWALL
              ONE("hardwall",   S_IRUGO, proc_pid_hardwall),
      #endif
      #ifdef CONFIG_USER_NS
              REG("uid_map",    S_IRUGO|S_IWUSR, proc_uid_map_operations),
              REG("gid_map",    S_IRUGO|S_IWUSR, proc_gid_map_operations),
              REG("projid_map", S_IRUGO|S_IWUSR, proc_projid_map_operations),
              REG("setgroups",  S_IRUGO|S_IWUSR, proc_setgroups_operations),
      #endif
      #ifdef CONFIG_CPU_FREQ_TIMES
              ONE("time_in_state", 0444, proc_time_in_state_show),
      #endif
      };
      
      static int proc_tid_base_readdir(struct file *file, struct dir_context *ctx)
      {
    2         return proc_pident_readdir(file, ctx,
                                         tid_base_stuff, ARRAY_SIZE(tid_base_stuff));
      }
      
      static struct dentry *proc_tid_base_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
      {
   96         return proc_pident_lookup(dir, dentry,
                                        tid_base_stuff, ARRAY_SIZE(tid_base_stuff));
      }
      
      static const struct file_operations proc_tid_base_operations = {
              .read                = generic_read_dir,
              .iterate        = proc_tid_base_readdir,
              .llseek                = default_llseek,
      };
      
      static const struct inode_operations proc_tid_base_inode_operations = {
              .lookup                = proc_tid_base_lookup,
              .getattr        = pid_getattr,
              .setattr        = proc_setattr,
      };
      
      static int proc_task_instantiate(struct inode *dir,
              struct dentry *dentry, struct task_struct *task, const void *ptr)
      {
              struct inode *inode;
  137         inode = proc_pid_make_inode(dir->i_sb, task);
      
              if (!inode)
                      goto out;
  135         inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO;
              inode->i_op = &proc_tid_base_inode_operations;
              inode->i_fop = &proc_tid_base_operations;
              inode->i_flags|=S_IMMUTABLE;
      
  135         set_nlink(inode, 2 + pid_entry_count_dirs(tid_base_stuff,
                                                        ARRAY_SIZE(tid_base_stuff)));
      
              d_set_d_op(dentry, &pid_dentry_operations);
      
              d_add(dentry, inode);
              /* Close the race of the process dying before we return the dentry */
  133         if (pid_revalidate(dentry, 0))
                      return 0;
      out:
              return -ENOENT;
      }
      
      static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry, unsigned int flags)
      {
              int result = -ENOENT;
              struct task_struct *task;
  136         struct task_struct *leader = get_proc_task(dir);
              unsigned tid;
              struct pid_namespace *ns;
      
              if (!leader)
                      goto out_no_task;
      
  135         tid = name_to_int(&dentry->d_name);
              if (tid == ~0U)
                      goto out;
      
  133         ns = dentry->d_sb->s_fs_info;
  133         rcu_read_lock();
  133         task = find_task_by_pid_ns(tid, ns);
              if (task)
  132                 get_task_struct(task);
  133         rcu_read_unlock();
              if (!task)
                      goto out;
  131         if (!same_thread_group(leader, task))
                      goto out_drop_task;
      
  129         result = proc_task_instantiate(dir, dentry, task, NULL);
      out_drop_task:
  128         put_task_struct(task);
      out:
  135         put_task_struct(leader);
      out_no_task:
  131         return ERR_PTR(result);
      }
      
      /*
       * Find the first tid of a thread group to return to user space.
       *
       * Usually this is just the thread group leader, but if the users
       * buffer was too small or there was a seek into the middle of the
       * directory we have more work todo.
       *
       * In the case of a short read we start with find_task_by_pid.
       *
       * In the case of a seek we start with the leader and walk nr
       * threads past it.
       */
      static struct task_struct *first_tid(struct pid *pid, int tid, loff_t f_pos,
                                              struct pid_namespace *ns)
      {
              struct task_struct *pos, *task;
              unsigned long nr = f_pos;
      
              if (nr != f_pos)        /* 32bit overflow? */
                      return NULL;
      
   10         rcu_read_lock();
   10         task = pid_task(pid, PIDTYPE_PID);
              if (!task)
                      goto fail;
      
              /* Attempt to start with the tid of a thread */
   10         if (tid && nr) {
    4                 pos = find_task_by_pid_ns(tid, ns);
    4                 if (pos && same_thread_group(pos, task))
                              goto found;
              }
      
              /* If nr exceeds the number of threads there is nothing todo */
    9         if (nr >= get_nr_threads(task))
                      goto fail;
      
              /* If we haven't found our starting place yet start
               * with the leader and walk nr threads forward.
               */
    8         pos = task = task->group_leader;
              do {
    8                 if (!nr--)
                              goto found;
    1         } while_each_thread(task, pos);
      fail:
              pos = NULL;
              goto out;
      found:
    9         get_task_struct(pos);
      out:
   10         rcu_read_unlock();
              return pos;
      }
      
      /*
       * Find the next thread in the thread list.
       * Return NULL if there is an error or no next thread.
       *
       * The reference to the input task_struct is released.
       */
      static struct task_struct *next_tid(struct task_struct *start)
      {
              struct task_struct *pos = NULL;
    6         rcu_read_lock();
    6         if (pid_alive(start)) {
    6                 pos = next_thread(start);
                      if (thread_group_leader(pos))
                              pos = NULL;
                      else
                              get_task_struct(pos);
              }
    6         rcu_read_unlock();
    6         put_task_struct(start);
              return pos;
      }
      
      /* for the /proc/TGID/task/ directories */
      static int proc_task_readdir(struct file *file, struct dir_context *ctx)
      {
   11         struct inode *inode = file_inode(file);
              struct task_struct *task;
              struct pid_namespace *ns;
              int tid;
      
              if (proc_inode_is_dead(inode))
                      return -ENOENT;
      
   11         if (!dir_emit_dots(file, ctx))
                      return 0;
      
              /* f_version caches the tgid value that the last readdir call couldn't
               * return. lseek aka telldir automagically resets f_version to 0.
               */
   10         ns = inode->i_sb->s_fs_info;
              tid = (int)file->f_version;
              file->f_version = 0;
   10         for (task = first_tid(proc_pid(inode), tid, ctx->pos - 2, ns);
                   task;
    6              task = next_tid(task), ctx->pos++) {
                      char name[PROC_NUMBUF];
                      int len;
    9                 tid = task_pid_nr_ns(task, ns);
                      len = snprintf(name, sizeof(name), "%d", tid);
    6                 if (!proc_fill_cache(file, ctx, name, len,
                                      proc_task_instantiate, task, NULL)) {
                              /* returning this tgid failed, save it as the first
                               * pid for the next readir call */
    5                         file->f_version = (u64)tid;
    5                         put_task_struct(task);
    5                         break;
                      }
              }
      
   10         return 0;
      }
      
      static int proc_task_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
      {
    3         struct inode *inode = d_inode(dentry);
              struct task_struct *p = get_proc_task(inode);
              generic_fillattr(inode, stat);
      
              if (p) {
    2                 stat->nlink += get_nr_threads(p);
    2                 put_task_struct(p);
              }
      
    3         return 0;
      }
      
      static const struct inode_operations proc_task_inode_operations = {
              .lookup                = proc_task_lookup,
              .getattr        = proc_task_getattr,
              .setattr        = proc_setattr,
              .permission        = proc_pid_permission,
      };
      
      static const struct file_operations proc_task_operations = {
              .read                = generic_read_dir,
              .iterate        = proc_task_readdir,
              .llseek                = default_llseek,
      };
      #ifndef _ASM_GENERIC_BITOPS_LE_H_
      #define _ASM_GENERIC_BITOPS_LE_H_
      
      #include <asm/types.h>
      #include <asm/byteorder.h>
      
      #if defined(__LITTLE_ENDIAN)
      
      #define BITOP_LE_SWIZZLE        0
      
      static inline unsigned long find_next_zero_bit_le(const void *addr,
                      unsigned long size, unsigned long offset)
      {
              return find_next_zero_bit(addr, size, offset);
      }
      
      static inline unsigned long find_next_bit_le(const void *addr,
                      unsigned long size, unsigned long offset)
      {
              return find_next_bit(addr, size, offset);
      }
      
      static inline unsigned long find_first_zero_bit_le(const void *addr,
                      unsigned long size)
      {
              return find_first_zero_bit(addr, size);
      }
      
      #elif defined(__BIG_ENDIAN)
      
      #define BITOP_LE_SWIZZLE        ((BITS_PER_LONG-1) & ~0x7)
      
      #ifndef find_next_zero_bit_le
      extern unsigned long find_next_zero_bit_le(const void *addr,
                      unsigned long size, unsigned long offset);
      #endif
      
      #ifndef find_next_bit_le
      extern unsigned long find_next_bit_le(const void *addr,
                      unsigned long size, unsigned long offset);
      #endif
      
      #ifndef find_first_zero_bit_le
      #define find_first_zero_bit_le(addr, size) \
              find_next_zero_bit_le((addr), (size), 0)
      #endif
      
      #else
      #error "Please fix <asm/byteorder.h>"
      #endif
      
      static inline int test_bit_le(int nr, const void *addr)
      {
              return test_bit(nr ^ BITOP_LE_SWIZZLE, addr);
      }
      
      static inline void set_bit_le(int nr, void *addr)
      {
              set_bit(nr ^ BITOP_LE_SWIZZLE, addr);
      }
      
      static inline void clear_bit_le(int nr, void *addr)
      {
              clear_bit(nr ^ BITOP_LE_SWIZZLE, addr);
      }
      
      static inline void __set_bit_le(int nr, void *addr)
      {
  249         __set_bit(nr ^ BITOP_LE_SWIZZLE, addr);
      }
      
      static inline void __clear_bit_le(int nr, void *addr)
      {
              __clear_bit(nr ^ BITOP_LE_SWIZZLE, addr);
      }
      
      static inline int test_and_set_bit_le(int nr, void *addr)
      {
              return test_and_set_bit(nr ^ BITOP_LE_SWIZZLE, addr);
      }
      
      static inline int test_and_clear_bit_le(int nr, void *addr)
      {
              return test_and_clear_bit(nr ^ BITOP_LE_SWIZZLE, addr);
      }
      
      static inline int __test_and_set_bit_le(int nr, void *addr)
      {
              return __test_and_set_bit(nr ^ BITOP_LE_SWIZZLE, addr);
      }
      
      static inline int __test_and_clear_bit_le(int nr, void *addr)
      {
              return __test_and_clear_bit(nr ^ BITOP_LE_SWIZZLE, addr);
      }
      
      #endif /* _ASM_GENERIC_BITOPS_LE_H_ */
      /*
       * rtc and date/time utility functions
       *
       * Copyright (C) 2005-06 Tower Technologies
       * Author: Alessandro Zummo <a.zummo@towertech.it>
       *
       * based on arch/arm/common/rtctime.c and other bits
       *
       * 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.
      */
      
      #include <linux/module.h>
      #include <linux/rtc.h>
      
      static const unsigned char rtc_days_in_month[] = {
              31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
      };
      
      static const unsigned short rtc_ydays[2][13] = {
              /* Normal years */
              { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
              /* Leap years */
              { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
      };
      
      #define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400)
      
      /*
       * The number of days in the month.
       */
      int rtc_month_days(unsigned int month, unsigned int year)
      {
   26         return rtc_days_in_month[month] + (is_leap_year(year) && month == 1);
      }
      EXPORT_SYMBOL(rtc_month_days);
      
      /*
       * The number of days since January 1. (0 to 365)
       */
      int rtc_year_days(unsigned int day, unsigned int month, unsigned int year)
      {
              return rtc_ydays[is_leap_year(year)][month] + day-1;
      }
      EXPORT_SYMBOL(rtc_year_days);
      
      
      /*
       * rtc_time_to_tm64 - Converts time64_t to rtc_time.
       * Convert seconds since 01-01-1970 00:00:00 to Gregorian date.
       */
      void rtc_time64_to_tm(time64_t time, struct rtc_time *tm)
      {
              unsigned int month, year, secs;
              int days;
      
              /* time must be positive */
              days = div_s64_rem(time, 86400, &secs);
   21 
              /* day of the week, 1970-01-01 was a Thursday */
              tm->tm_wday = (days + 4) % 7;
      
              year = 1970 + days / 365;
              days -= (year - 1970) * 365
                      + LEAPS_THRU_END_OF(year - 1)
                      - LEAPS_THRU_END_OF(1970 - 1);
              if (days < 0) {
                      year -= 1;
   16                 days += 365 + is_leap_year(year);
              }
    5         tm->tm_year = year - 1900;
              tm->tm_yday = days + 1;
   21 
              for (month = 0; month < 11; month++) {
                      int newdays;
   17 
                      newdays = days - rtc_month_days(month, year);
                      if (newdays < 0)
   21                         break;
   16                 days = newdays;
              }
              tm->tm_mon = month;
              tm->tm_mday = days + 1;
   21 
              tm->tm_hour = secs / 3600;
              secs -= tm->tm_hour * 3600;
              tm->tm_min = secs / 60;
              tm->tm_sec = secs - tm->tm_min * 60;
      
              tm->tm_isdst = 0;
      }
      EXPORT_SYMBOL(rtc_time64_to_tm);
      
      /*
       * Does the rtc_time represent a valid date/time?
       */
      int rtc_valid_tm(struct rtc_time *tm)
      {
              if (tm->tm_year < 70
                      || ((unsigned)tm->tm_mon) >= 12
   26                 || tm->tm_mday < 1
   25                 || tm->tm_mday > rtc_month_days(tm->tm_mon, tm->tm_year + 1900)
   23                 || ((unsigned)tm->tm_hour) >= 24
   22                 || ((unsigned)tm->tm_min) >= 60
   21                 || ((unsigned)tm->tm_sec) >= 60)
   21                 return -EINVAL;
   21 
              return 0;
      }
   25 EXPORT_SYMBOL(rtc_valid_tm);
      
      /*
       * rtc_tm_to_time64 - Converts rtc_time to time64_t.
       * Convert Gregorian date to seconds since 01-01-1970 00:00:00.
       */
      time64_t rtc_tm_to_time64(struct rtc_time *tm)
      {
              return mktime64(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
                              tm->tm_hour, tm->tm_min, tm->tm_sec);
      }
   19 EXPORT_SYMBOL(rtc_tm_to_time64);
      
      /*
       * Convert rtc_time to ktime
       */
      ktime_t rtc_tm_to_ktime(struct rtc_time tm)
      {
              return ktime_set(rtc_tm_to_time64(&tm), 0);
      }
   18 EXPORT_SYMBOL_GPL(rtc_tm_to_ktime);
      
      /*
       * Convert ktime to rtc_time
       */
      struct rtc_time rtc_ktime_to_tm(ktime_t kt)
      {
              struct timespec64 ts;
              struct rtc_time ret;
      
              ts = ktime_to_timespec64(kt);
              /* Round up any ns */
   20         if (ts.tv_nsec)
                      ts.tv_sec++;
              rtc_time64_to_tm(ts.tv_sec, &ret);
    4         return ret;
   20 }
      EXPORT_SYMBOL_GPL(rtc_ktime_to_tm);
      
      MODULE_LICENSE("GPL");
      /*
       * LED Core
       *
       * Copyright 2005 Openedhand Ltd.
       *
       * Author: Richard Purdie <rpurdie@openedhand.com>
       *
       * 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.
       *
       */
      #ifndef __LEDS_H_INCLUDED
      #define __LEDS_H_INCLUDED
      
      #include <linux/rwsem.h>
      #include <linux/leds.h>
      
      static inline void led_set_brightness_async(struct led_classdev *led_cdev,
                                              enum led_brightness value)
      {
    2         value = min(value, led_cdev->max_brightness);
              led_cdev->brightness = value;
      
              if (!(led_cdev->flags & LED_SUSPENDED))
    2                 led_cdev->brightness_set(led_cdev, value);
      }
      
      static inline int led_set_brightness_sync(struct led_classdev *led_cdev,
                                              enum led_brightness value)
      {
              int ret = 0;
      
              led_cdev->brightness = min(value, led_cdev->max_brightness);
      
              if (!(led_cdev->flags & LED_SUSPENDED))
    2                 ret = led_cdev->brightness_set_sync(led_cdev,
                                                      led_cdev->brightness);
              return ret;
      }
      
      static inline int led_get_brightness(struct led_classdev *led_cdev)
      {
              return led_cdev->brightness;
      }
      
      void led_init_core(struct led_classdev *led_cdev);
      void led_stop_software_blink(struct led_classdev *led_cdev);
      
      extern struct rw_semaphore leds_list_lock;
      extern struct list_head leds_list;
      
      #endif        /* __LEDS_H_INCLUDED */
      #include <linux/stat.h>
      #include <linux/sysctl.h>
      #include "../fs/xfs/xfs_sysctl.h"
      #include <linux/sunrpc/debug.h>
      #include <linux/string.h>
      #include <linux/syscalls.h>
      #include <linux/namei.h>
      #include <linux/mount.h>
      #include <linux/fs.h>
      #include <linux/nsproxy.h>
      #include <linux/pid_namespace.h>
      #include <linux/file.h>
      #include <linux/ctype.h>
      #include <linux/netdevice.h>
      #include <linux/kernel.h>
      #include <linux/slab.h>
      #include <linux/compat.h>
      
      #ifdef CONFIG_SYSCTL_SYSCALL
      
      struct bin_table;
      typedef ssize_t bin_convert_t(struct file *file,
              void __user *oldval, size_t oldlen, void __user *newval, size_t newlen);
      
      static bin_convert_t bin_dir;
      static bin_convert_t bin_string;
      static bin_convert_t bin_intvec;
      static bin_convert_t bin_ulongvec;
      static bin_convert_t bin_uuid;
      static bin_convert_t bin_dn_node_address;
      
      #define CTL_DIR   bin_dir
      #define CTL_STR   bin_string
      #define CTL_INT   bin_intvec
      #define CTL_ULONG bin_ulongvec
      #define CTL_UUID  bin_uuid
      #define CTL_DNADR bin_dn_node_address
      
      #define BUFSZ 256
      
      struct bin_table {
              bin_convert_t                *convert;
              int                        ctl_name;
              const char                *procname;
              const struct bin_table        *child;
      };
      
      static const struct bin_table bin_random_table[] = {
              { CTL_INT,        RANDOM_POOLSIZE,        "poolsize" },
              { CTL_INT,        RANDOM_ENTROPY_COUNT,        "entropy_avail" },
              { CTL_INT,        RANDOM_READ_THRESH,        "read_wakeup_threshold" },
              { CTL_INT,        RANDOM_WRITE_THRESH,        "write_wakeup_threshold" },
              { CTL_UUID,        RANDOM_BOOT_ID,                "boot_id" },
              { CTL_UUID,        RANDOM_UUID,                "uuid" },
              {}
      };
      
      static const struct bin_table bin_pty_table[] = {
              { CTL_INT,        PTY_MAX,        "max" },
              { CTL_INT,        PTY_NR,                "nr" },
              {}
      };
      
      static const struct bin_table bin_kern_table[] = {
              { CTL_STR,        KERN_OSTYPE,                        "ostype" },
              { CTL_STR,        KERN_OSRELEASE,                        "osrelease" },
              /* KERN_OSREV not used */
              { CTL_STR,        KERN_VERSION,                        "version" },
              /* KERN_SECUREMASK not used */
              /* KERN_PROF not used */
              { CTL_STR,        KERN_NODENAME,                        "hostname" },
              { CTL_STR,        KERN_DOMAINNAME,                "domainname" },
      
              { CTL_INT,        KERN_PANIC,                        "panic" },
              { CTL_INT,        KERN_REALROOTDEV,                "real-root-dev" },
      
              { CTL_STR,        KERN_SPARC_REBOOT,                "reboot-cmd" },
              { CTL_INT,        KERN_CTLALTDEL,                        "ctrl-alt-del" },
              { CTL_INT,        KERN_PRINTK,                        "printk" },
      
              /* KERN_NAMETRANS not used */
              /* KERN_PPC_HTABRECLAIM not used */
              /* KERN_PPC_ZEROPAGED not used */
              { CTL_INT,        KERN_PPC_POWERSAVE_NAP,                "powersave-nap" },
      
              { CTL_STR,        KERN_MODPROBE,                        "modprobe" },
              { CTL_INT,        KERN_SG_BIG_BUFF,                "sg-big-buff" },
              { CTL_INT,        KERN_ACCT,                        "acct" },
              /* KERN_PPC_L2CR "l2cr" no longer used */
      
              /* KERN_RTSIGNR not used */
              /* KERN_RTSIGMAX not used */
      
              { CTL_ULONG,        KERN_SHMMAX,                        "shmmax" },
              { CTL_INT,        KERN_MSGMAX,                        "msgmax" },
              { CTL_INT,        KERN_MSGMNB,                        "msgmnb" },
              /* KERN_MSGPOOL not used*/
              { CTL_INT,        KERN_SYSRQ,                        "sysrq" },
              { CTL_INT,        KERN_MAX_THREADS,                "threads-max" },
              { CTL_DIR,        KERN_RANDOM,                        "random",        bin_random_table },
              { CTL_ULONG,        KERN_SHMALL,                        "shmall" },
              { CTL_INT,        KERN_MSGMNI,                        "msgmni" },
              { CTL_INT,        KERN_SEM,                        "sem" },
              { CTL_INT,        KERN_SPARC_STOP_A,                "stop-a" },
              { CTL_INT,        KERN_SHMMNI,                        "shmmni" },
      
              { CTL_INT,        KERN_OVERFLOWUID,                "overflowuid" },
              { CTL_INT,        KERN_OVERFLOWGID,                "overflowgid" },
      
              { CTL_STR,        KERN_HOTPLUG,                        "hotplug", },
              { CTL_INT,        KERN_IEEE_EMULATION_WARNINGS,        "ieee_emulation_warnings" },
      
              { CTL_INT,        KERN_S390_USER_DEBUG_LOGGING,        "userprocess_debug" },
              { CTL_INT,        KERN_CORE_USES_PID,                "core_uses_pid" },
              /* KERN_TAINTED "tainted" no longer used */
              { CTL_INT,        KERN_CADPID,                        "cad_pid" },
              { CTL_INT,        KERN_PIDMAX,                        "pid_max" },
              { CTL_STR,        KERN_CORE_PATTERN,                "core_pattern" },
              { CTL_INT,        KERN_PANIC_ON_OOPS,                "panic_on_oops" },
              { CTL_INT,        KERN_HPPA_PWRSW,                "soft-power" },
              { CTL_INT,        KERN_HPPA_UNALIGNED,                "unaligned-trap" },
      
              { CTL_INT,        KERN_PRINTK_RATELIMIT,                "printk_ratelimit" },
              { CTL_INT,        KERN_PRINTK_RATELIMIT_BURST,        "printk_ratelimit_burst" },
      
              { CTL_DIR,        KERN_PTY,                        "pty",                bin_pty_table },
              { CTL_INT,        KERN_NGROUPS_MAX,                "ngroups_max" },
              { CTL_INT,        KERN_SPARC_SCONS_PWROFF,        "scons-poweroff" },
              /* KERN_HZ_TIMER "hz_timer" no longer used */
              { CTL_INT,        KERN_UNKNOWN_NMI_PANIC,                "unknown_nmi_panic" },
              { CTL_INT,        KERN_BOOTLOADER_TYPE,                "bootloader_type" },
              { CTL_INT,        KERN_RANDOMIZE,                        "randomize_va_space" },
      
              { CTL_INT,        KERN_SPIN_RETRY,                "spin_retry" },
              /* KERN_ACPI_VIDEO_FLAGS "acpi_video_flags" no longer used */
              { CTL_INT,        KERN_IA64_UNALIGNED,                "ignore-unaligned-usertrap" },
              { CTL_INT,        KERN_COMPAT_LOG,                "compat-log" },
              { CTL_INT,        KERN_MAX_LOCK_DEPTH,                "max_lock_depth" },
              { CTL_INT,        KERN_PANIC_ON_NMI,                "panic_on_unrecovered_nmi" },
              { CTL_INT,        KERN_PANIC_ON_WARN,                "panic_on_warn" },
              {}
      };
      
      static const struct bin_table bin_vm_table[] = {
              { CTL_INT,        VM_OVERCOMMIT_MEMORY,                "overcommit_memory" },
              { CTL_INT,        VM_PAGE_CLUSTER,                "page-cluster" },
              { CTL_INT,        VM_DIRTY_BACKGROUND,                "dirty_background_ratio" },
              { CTL_INT,        VM_DIRTY_RATIO,                        "dirty_ratio" },
              /* VM_DIRTY_WB_CS "dirty_writeback_centisecs" no longer used */
              /* VM_DIRTY_EXPIRE_CS "dirty_expire_centisecs" no longer used */
              /* VM_NR_PDFLUSH_THREADS "nr_pdflush_threads" no longer used */
              { CTL_INT,        VM_OVERCOMMIT_RATIO,                "overcommit_ratio" },
              /* VM_PAGEBUF unused */
              /* VM_HUGETLB_PAGES "nr_hugepages" no longer used */
              { CTL_INT,        VM_SWAPPINESS,                        "swappiness" },
              { CTL_INT,        VM_LOWMEM_RESERVE_RATIO,        "lowmem_reserve_ratio" },
              { CTL_INT,        VM_MIN_FREE_KBYTES,                "min_free_kbytes" },
              { CTL_INT,        VM_MAX_MAP_COUNT,                "max_map_count" },
              { CTL_INT,        VM_LAPTOP_MODE,                        "laptop_mode" },
              { CTL_INT,        VM_BLOCK_DUMP,                        "block_dump" },
              { CTL_INT,        VM_HUGETLB_GROUP,                "hugetlb_shm_group" },
              { CTL_INT,        VM_VFS_CACHE_PRESSURE,        "vfs_cache_pressure" },
              { CTL_INT,        VM_LEGACY_VA_LAYOUT,                "legacy_va_layout" },
              /* VM_SWAP_TOKEN_TIMEOUT unused */
              { CTL_INT,        VM_DROP_PAGECACHE,                "drop_caches" },
              { CTL_INT,        VM_PERCPU_PAGELIST_FRACTION,        "percpu_pagelist_fraction" },
              { CTL_INT,        VM_ZONE_RECLAIM_MODE,                "zone_reclaim_mode" },
              { CTL_INT,        VM_MIN_UNMAPPED,                "min_unmapped_ratio" },
              { CTL_INT,        VM_PANIC_ON_OOM,                "panic_on_oom" },
              { CTL_INT,        VM_VDSO_ENABLED,                "vdso_enabled" },
              { CTL_INT,        VM_MIN_SLAB,                        "min_slab_ratio" },
      
              {}
      };
      
      static const struct bin_table bin_net_core_table[] = {
              { CTL_INT,        NET_CORE_WMEM_MAX,        "wmem_max" },
              { CTL_INT,        NET_CORE_RMEM_MAX,        "rmem_max" },
              { CTL_INT,        NET_CORE_WMEM_DEFAULT,        "wmem_default" },
              { CTL_INT,        NET_CORE_RMEM_DEFAULT,        "rmem_default" },
              /* NET_CORE_DESTROY_DELAY unused */
              { CTL_INT,        NET_CORE_MAX_BACKLOG,        "netdev_max_backlog" },
              /* NET_CORE_FASTROUTE unused */
              { CTL_INT,        NET_CORE_MSG_COST,        "message_cost" },
              { CTL_INT,        NET_CORE_MSG_BURST,        "message_burst" },
              { CTL_INT,        NET_CORE_OPTMEM_MAX,        "optmem_max" },
              /* NET_CORE_HOT_LIST_LENGTH unused */
              /* NET_CORE_DIVERT_VERSION unused */
              /* NET_CORE_NO_CONG_THRESH unused */
              /* NET_CORE_NO_CONG unused */
              /* NET_CORE_LO_CONG unused */
              /* NET_CORE_MOD_CONG unused */
              { CTL_INT,        NET_CORE_DEV_WEIGHT,        "dev_weight" },
              { CTL_INT,        NET_CORE_SOMAXCONN,        "somaxconn" },
              { CTL_INT,        NET_CORE_BUDGET,        "netdev_budget" },
              { CTL_INT,        NET_CORE_AEVENT_ETIME,        "xfrm_aevent_etime" },
              { CTL_INT,        NET_CORE_AEVENT_RSEQTH,        "xfrm_aevent_rseqth" },
              { CTL_INT,        NET_CORE_WARNINGS,        "warnings" },
              {},
      };
      
      static const struct bin_table bin_net_unix_table[] = {
              /* NET_UNIX_DESTROY_DELAY unused */
              /* NET_UNIX_DELETE_DELAY unused */
              { CTL_INT,        NET_UNIX_MAX_DGRAM_QLEN,        "max_dgram_qlen" },
              {}
      };
      
      static const struct bin_table bin_net_ipv4_route_table[] = {
              { CTL_INT,        NET_IPV4_ROUTE_FLUSH,                        "flush" },
              /* NET_IPV4_ROUTE_MIN_DELAY "min_delay" no longer used */
              /* NET_IPV4_ROUTE_MAX_DELAY "max_delay" no longer used */
              { CTL_INT,        NET_IPV4_ROUTE_GC_THRESH,                "gc_thresh" },
              { CTL_INT,        NET_IPV4_ROUTE_MAX_SIZE,                "max_size" },
              { CTL_INT,        NET_IPV4_ROUTE_GC_MIN_INTERVAL,                "gc_min_interval" },
              { CTL_INT,        NET_IPV4_ROUTE_GC_MIN_INTERVAL_MS,        "gc_min_interval_ms" },
              { CTL_INT,        NET_IPV4_ROUTE_GC_TIMEOUT,                "gc_timeout" },
              /* NET_IPV4_ROUTE_GC_INTERVAL "gc_interval" no longer used */
              { CTL_INT,        NET_IPV4_ROUTE_REDIRECT_LOAD,                "redirect_load" },
              { CTL_INT,        NET_IPV4_ROUTE_REDIRECT_NUMBER,                "redirect_number" },
              { CTL_INT,        NET_IPV4_ROUTE_REDIRECT_SILENCE,        "redirect_silence" },
              { CTL_INT,        NET_IPV4_ROUTE_ERROR_COST,                "error_cost" },
              { CTL_INT,        NET_IPV4_ROUTE_ERROR_BURST,                "error_burst" },
              { CTL_INT,        NET_IPV4_ROUTE_GC_ELASTICITY,                "gc_elasticity" },
              { CTL_INT,        NET_IPV4_ROUTE_MTU_EXPIRES,                "mtu_expires" },
              { CTL_INT,        NET_IPV4_ROUTE_MIN_PMTU,                "min_pmtu" },
              { CTL_INT,        NET_IPV4_ROUTE_MIN_ADVMSS,                "min_adv_mss" },
              {}
      };
      
      static const struct bin_table bin_net_ipv4_conf_vars_table[] = {
              { CTL_INT,        NET_IPV4_CONF_FORWARDING,                "forwarding" },
              { CTL_INT,        NET_IPV4_CONF_MC_FORWARDING,                "mc_forwarding" },
      
              { CTL_INT,        NET_IPV4_CONF_ACCEPT_REDIRECTS,                "accept_redirects" },
              { CTL_INT,        NET_IPV4_CONF_SECURE_REDIRECTS,                "secure_redirects" },
              { CTL_INT,        NET_IPV4_CONF_SEND_REDIRECTS,                "send_redirects" },
              { CTL_INT,        NET_IPV4_CONF_SHARED_MEDIA,                "shared_media" },
              { CTL_INT,        NET_IPV4_CONF_RP_FILTER,                "rp_filter" },
              { CTL_INT,        NET_IPV4_CONF_ACCEPT_SOURCE_ROUTE,        "accept_source_route" },
              { CTL_INT,        NET_IPV4_CONF_PROXY_ARP,                "proxy_arp" },
              { CTL_INT,        NET_IPV4_CONF_MEDIUM_ID,                "medium_id" },
              { CTL_INT,        NET_IPV4_CONF_BOOTP_RELAY,                "bootp_relay" },
              { CTL_INT,        NET_IPV4_CONF_LOG_MARTIANS,                "log_martians" },
              { CTL_INT,        NET_IPV4_CONF_TAG,                        "tag" },
              { CTL_INT,        NET_IPV4_CONF_ARPFILTER,                "arp_filter" },
              { CTL_INT,        NET_IPV4_CONF_ARP_ANNOUNCE,                "arp_announce" },
              { CTL_INT,        NET_IPV4_CONF_ARP_IGNORE,                "arp_ignore" },
              { CTL_INT,        NET_IPV4_CONF_ARP_ACCEPT,                "arp_accept" },
              { CTL_INT,        NET_IPV4_CONF_ARP_NOTIFY,                "arp_notify" },
      
              { CTL_INT,        NET_IPV4_CONF_NOXFRM,                        "disable_xfrm" },
              { CTL_INT,        NET_IPV4_CONF_NOPOLICY,                        "disable_policy" },
              { CTL_INT,        NET_IPV4_CONF_FORCE_IGMP_VERSION,        "force_igmp_version" },
              { CTL_INT,        NET_IPV4_CONF_PROMOTE_SECONDARIES,        "promote_secondaries" },
              {}
      };
      
      static const struct bin_table bin_net_ipv4_conf_table[] = {
              { CTL_DIR,        NET_PROTO_CONF_ALL,        "all",                bin_net_ipv4_conf_vars_table },
              { CTL_DIR,        NET_PROTO_CONF_DEFAULT,        "default",        bin_net_ipv4_conf_vars_table },
              { CTL_DIR,        0, NULL, bin_net_ipv4_conf_vars_table },
              {}
      };
      
      static const struct bin_table bin_net_neigh_vars_table[] = {
              { CTL_INT,        NET_NEIGH_MCAST_SOLICIT,        "mcast_solicit" },
              { CTL_INT,        NET_NEIGH_UCAST_SOLICIT,        "ucast_solicit" },
              { CTL_INT,        NET_NEIGH_APP_SOLICIT,                "app_solicit" },
              /* NET_NEIGH_RETRANS_TIME "retrans_time" no longer used */
              { CTL_INT,        NET_NEIGH_REACHABLE_TIME,        "base_reachable_time" },
              { CTL_INT,        NET_NEIGH_DELAY_PROBE_TIME,        "delay_first_probe_time" },
              { CTL_INT,        NET_NEIGH_GC_STALE_TIME,        "gc_stale_time" },
              { CTL_INT,        NET_NEIGH_UNRES_QLEN,                "unres_qlen" },
              { CTL_INT,        NET_NEIGH_PROXY_QLEN,                "proxy_qlen" },
              /* NET_NEIGH_ANYCAST_DELAY "anycast_delay" no longer used */
              /* NET_NEIGH_PROXY_DELAY "proxy_delay" no longer used */
              /* NET_NEIGH_LOCKTIME "locktime" no longer used */
              { CTL_INT,        NET_NEIGH_GC_INTERVAL,                "gc_interval" },
              { CTL_INT,        NET_NEIGH_GC_THRESH1,                "gc_thresh1" },
              { CTL_INT,        NET_NEIGH_GC_THRESH2,                "gc_thresh2" },
              { CTL_INT,        NET_NEIGH_GC_THRESH3,                "gc_thresh3" },
              { CTL_INT,        NET_NEIGH_RETRANS_TIME_MS,        "retrans_time_ms" },
              { CTL_INT,        NET_NEIGH_REACHABLE_TIME_MS,        "base_reachable_time_ms" },
              {}
      };
      
      static const struct bin_table bin_net_neigh_table[] = {
              { CTL_DIR,        NET_PROTO_CONF_DEFAULT, "default", bin_net_neigh_vars_table },
              { CTL_DIR,        0, NULL, bin_net_neigh_vars_table },
              {}
      };
      
      static const struct bin_table bin_net_ipv4_netfilter_table[] = {
              { CTL_INT,        NET_IPV4_NF_CONNTRACK_MAX,                "ip_conntrack_max" },
      
              /* NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_SENT "ip_conntrack_tcp_timeout_syn_sent" no longer used */
              /* NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_RECV "ip_conntrack_tcp_timeout_syn_recv" no longer used */
              /* NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED "ip_conntrack_tcp_timeout_established" no longer used */
              /* NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_FIN_WAIT "ip_conntrack_tcp_timeout_fin_wait" no longer used */
              /* NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE_WAIT        "ip_conntrack_tcp_timeout_close_wait" no longer used */
              /* NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_LAST_ACK "ip_conntrack_tcp_timeout_last_ack" no longer used */
              /* NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_TIME_WAIT "ip_conntrack_tcp_timeout_time_wait" no longer used */
              /* NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE "ip_conntrack_tcp_timeout_close" no longer used */
      
              /* NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT "ip_conntrack_udp_timeout" no longer used */
              /* NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT_STREAM "ip_conntrack_udp_timeout_stream" no longer used */
              /* NET_IPV4_NF_CONNTRACK_ICMP_TIMEOUT "ip_conntrack_icmp_timeout" no longer used */
              /* NET_IPV4_NF_CONNTRACK_GENERIC_TIMEOUT "ip_conntrack_generic_timeout" no longer used */
      
              { CTL_INT,        NET_IPV4_NF_CONNTRACK_BUCKETS,                "ip_conntrack_buckets" },
              { CTL_INT,        NET_IPV4_NF_CONNTRACK_LOG_INVALID,        "ip_conntrack_log_invalid" },
              /* NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_MAX_RETRANS "ip_conntrack_tcp_timeout_max_retrans" no longer used */
              { CTL_INT,        NET_IPV4_NF_CONNTRACK_TCP_LOOSE,        "ip_conntrack_tcp_loose" },
              { CTL_INT,        NET_IPV4_NF_CONNTRACK_TCP_BE_LIBERAL,        "ip_conntrack_tcp_be_liberal" },
              { CTL_INT,        NET_IPV4_NF_CONNTRACK_TCP_MAX_RETRANS,        "ip_conntrack_tcp_max_retrans" },
      
              /* NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_CLOSED "ip_conntrack_sctp_timeout_closed" no longer used */
              /* NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_COOKIE_WAIT "ip_conntrack_sctp_timeout_cookie_wait" no longer used */
              /* NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_COOKIE_ECHOED "ip_conntrack_sctp_timeout_cookie_echoed" no longer used */
              /* NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_ESTABLISHED "ip_conntrack_sctp_timeout_established" no longer used */
              /* NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_SENT "ip_conntrack_sctp_timeout_shutdown_sent" no longer used */
              /* NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_RECD "ip_conntrack_sctp_timeout_shutdown_recd" no longer used */
              /* NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_ACK_SENT "ip_conntrack_sctp_timeout_shutdown_ack_sent" no longer used */
      
              { CTL_INT,        NET_IPV4_NF_CONNTRACK_COUNT,                "ip_conntrack_count" },
              { CTL_INT,        NET_IPV4_NF_CONNTRACK_CHECKSUM,                "ip_conntrack_checksum" },
              {}
      };
      
      static const struct bin_table bin_net_ipv4_table[] = {
              {CTL_INT,        NET_IPV4_FORWARD,                        "ip_forward" },
      
              { CTL_DIR,        NET_IPV4_CONF,                "conf",                bin_net_ipv4_conf_table },
              { CTL_DIR,        NET_IPV4_NEIGH,                "neigh",        bin_net_neigh_table },
              { CTL_DIR,        NET_IPV4_ROUTE,                "route",        bin_net_ipv4_route_table },
              /* NET_IPV4_FIB_HASH unused */
              { CTL_DIR,        NET_IPV4_NETFILTER,        "netfilter",        bin_net_ipv4_netfilter_table },
      
              { CTL_INT,        NET_IPV4_TCP_TIMESTAMPS,                "tcp_timestamps" },
              { CTL_INT,        NET_IPV4_TCP_WINDOW_SCALING,                "tcp_window_scaling" },
              { CTL_INT,        NET_IPV4_TCP_SACK,                        "tcp_sack" },
              { CTL_INT,        NET_IPV4_TCP_RETRANS_COLLAPSE,                "tcp_retrans_collapse" },
              { CTL_INT,        NET_IPV4_DEFAULT_TTL,                        "ip_default_ttl" },
              /* NET_IPV4_AUTOCONFIG unused */
              { CTL_INT,        NET_IPV4_NO_PMTU_DISC,                        "ip_no_pmtu_disc" },
              { CTL_INT,        NET_IPV4_NONLOCAL_BIND,                        "ip_nonlocal_bind" },
              { CTL_INT,        NET_IPV4_TCP_SYN_RETRIES,                "tcp_syn_retries" },
              { CTL_INT,        NET_TCP_SYNACK_RETRIES,                        "tcp_synack_retries" },
              { CTL_INT,        NET_TCP_MAX_ORPHANS,                        "tcp_max_orphans" },
              { CTL_INT,        NET_TCP_MAX_TW_BUCKETS,                        "tcp_max_tw_buckets" },
              { CTL_INT,        NET_IPV4_DYNADDR,                        "ip_dynaddr" },
              { CTL_INT,        NET_IPV4_TCP_KEEPALIVE_TIME,                "tcp_keepalive_time" },
              { CTL_INT,        NET_IPV4_TCP_KEEPALIVE_PROBES,                "tcp_keepalive_probes" },
              { CTL_INT,        NET_IPV4_TCP_KEEPALIVE_INTVL,                "tcp_keepalive_intvl" },
              { CTL_INT,        NET_IPV4_TCP_RETRIES1,                        "tcp_retries1" },
              { CTL_INT,        NET_IPV4_TCP_RETRIES2,                        "tcp_retries2" },
              { CTL_INT,        NET_IPV4_TCP_FIN_TIMEOUT,                "tcp_fin_timeout" },
              { CTL_INT,        NET_TCP_SYNCOOKIES,                        "tcp_syncookies" },
              { CTL_INT,        NET_TCP_TW_RECYCLE,                        "tcp_tw_recycle" },
              { CTL_INT,        NET_TCP_ABORT_ON_OVERFLOW,                "tcp_abort_on_overflow" },
              { CTL_INT,        NET_TCP_STDURG,                                "tcp_stdurg" },
              { CTL_INT,        NET_TCP_RFC1337,                        "tcp_rfc1337" },
              { CTL_INT,        NET_TCP_MAX_SYN_BACKLOG,                "tcp_max_syn_backlog" },
              { CTL_INT,        NET_IPV4_LOCAL_PORT_RANGE,                "ip_local_port_range" },
              { CTL_INT,        NET_IPV4_IGMP_MAX_MEMBERSHIPS,                "igmp_max_memberships" },
              { CTL_INT,        NET_IPV4_IGMP_MAX_MSF,                        "igmp_max_msf" },
              { CTL_INT,        NET_IPV4_INET_PEER_THRESHOLD,                "inet_peer_threshold" },
              { CTL_INT,        NET_IPV4_INET_PEER_MINTTL,                "inet_peer_minttl" },
              { CTL_INT,        NET_IPV4_INET_PEER_MAXTTL,                "inet_peer_maxttl" },
              { CTL_INT,        NET_IPV4_INET_PEER_GC_MINTIME,                "inet_peer_gc_mintime" },
              { CTL_INT,        NET_IPV4_INET_PEER_GC_MAXTIME,                "inet_peer_gc_maxtime" },
              { CTL_INT,        NET_TCP_ORPHAN_RETRIES,                        "tcp_orphan_retries" },
              { CTL_INT,        NET_TCP_FACK,                                "tcp_fack" },
              { CTL_INT,        NET_TCP_REORDERING,                        "tcp_reordering" },
              { CTL_INT,        NET_TCP_ECN,                                "tcp_ecn" },
              { CTL_INT,        NET_TCP_DSACK,                                "tcp_dsack" },
              { CTL_INT,        NET_TCP_MEM,                                "tcp_mem" },
              { CTL_INT,        NET_TCP_WMEM,                                "tcp_wmem" },
              { CTL_INT,        NET_TCP_RMEM,                                "tcp_rmem" },
              { CTL_INT,        NET_TCP_APP_WIN,                        "tcp_app_win" },
              { CTL_INT,        NET_TCP_ADV_WIN_SCALE,                        "tcp_adv_win_scale" },
              { CTL_INT,        NET_TCP_TW_REUSE,                        "tcp_tw_reuse" },
              { CTL_INT,        NET_TCP_FRTO,                                "tcp_frto" },
              { CTL_INT,        NET_TCP_FRTO_RESPONSE,                        "tcp_frto_response" },
              { CTL_INT,        NET_TCP_LOW_LATENCY,                        "tcp_low_latency" },
              { CTL_INT,        NET_TCP_NO_METRICS_SAVE,                "tcp_no_metrics_save" },
              { CTL_INT,        NET_TCP_MODERATE_RCVBUF,                "tcp_moderate_rcvbuf" },
              { CTL_INT,        NET_TCP_TSO_WIN_DIVISOR,                "tcp_tso_win_divisor" },
              { CTL_STR,        NET_TCP_CONG_CONTROL,                        "tcp_congestion_control" },
              { CTL_INT,        NET_TCP_MTU_PROBING,                        "tcp_mtu_probing" },
              { CTL_INT,        NET_TCP_BASE_MSS,                        "tcp_base_mss" },
              { CTL_INT,        NET_IPV4_TCP_WORKAROUND_SIGNED_WINDOWS,        "tcp_workaround_signed_windows" },
              { CTL_INT,        NET_TCP_SLOW_START_AFTER_IDLE,                "tcp_slow_start_after_idle" },
              { CTL_INT,        NET_CIPSOV4_CACHE_ENABLE,                "cipso_cache_enable" },
              { CTL_INT,        NET_CIPSOV4_CACHE_BUCKET_SIZE,                "cipso_cache_bucket_size" },
              { CTL_INT,        NET_CIPSOV4_RBM_OPTFMT,                        "cipso_rbm_optfmt" },
              { CTL_INT,        NET_CIPSOV4_RBM_STRICTVALID,                "cipso_rbm_strictvalid" },
              /* NET_TCP_AVAIL_CONG_CONTROL "tcp_available_congestion_control" no longer used */
              { CTL_STR,        NET_TCP_ALLOWED_CONG_CONTROL,                "tcp_allowed_congestion_control" },
              { CTL_INT,        NET_TCP_MAX_SSTHRESH,                        "tcp_max_ssthresh" },
      
              { CTL_INT,        NET_IPV4_ICMP_ECHO_IGNORE_ALL,                "icmp_echo_ignore_all" },
              { CTL_INT,        NET_IPV4_ICMP_ECHO_IGNORE_BROADCASTS,        "icmp_echo_ignore_broadcasts" },
              { CTL_INT,        NET_IPV4_ICMP_IGNORE_BOGUS_ERROR_RESPONSES,        "icmp_ignore_bogus_error_responses" },
              { CTL_INT,        NET_IPV4_ICMP_ERRORS_USE_INBOUND_IFADDR,        "icmp_errors_use_inbound_ifaddr" },
              { CTL_INT,        NET_IPV4_ICMP_RATELIMIT,                "icmp_ratelimit" },
              { CTL_INT,        NET_IPV4_ICMP_RATEMASK,                        "icmp_ratemask" },
      
              { CTL_INT,        NET_IPV4_IPFRAG_HIGH_THRESH,                "ipfrag_high_thresh" },
              { CTL_INT,        NET_IPV4_IPFRAG_LOW_THRESH,                "ipfrag_low_thresh" },
              { CTL_INT,        NET_IPV4_IPFRAG_TIME,                        "ipfrag_time" },
      
              { CTL_INT,        NET_IPV4_IPFRAG_SECRET_INTERVAL,        "ipfrag_secret_interval" },
              /* NET_IPV4_IPFRAG_MAX_DIST "ipfrag_max_dist" no longer used */
      
              { CTL_INT,        2088 /* NET_IPQ_QMAX */,                "ip_queue_maxlen" },
      
              /* NET_TCP_DEFAULT_WIN_SCALE unused */
              /* NET_TCP_BIC_BETA unused */
              /* NET_IPV4_TCP_MAX_KA_PROBES unused */
              /* NET_IPV4_IP_MASQ_DEBUG unused */
              /* NET_TCP_SYN_TAILDROP unused */
              /* NET_IPV4_ICMP_SOURCEQUENCH_RATE unused */
              /* NET_IPV4_ICMP_DESTUNREACH_RATE unused */
              /* NET_IPV4_ICMP_TIMEEXCEED_RATE unused */
              /* NET_IPV4_ICMP_PARAMPROB_RATE unused */
              /* NET_IPV4_ICMP_ECHOREPLY_RATE unused */
              /* NET_IPV4_ALWAYS_DEFRAG unused */
              {}
      };
      
      static const struct bin_table bin_net_ipx_table[] = {
              { CTL_INT,        NET_IPX_PPROP_BROADCASTING,        "ipx_pprop_broadcasting" },
              /* NET_IPX_FORWARDING unused */
              {}
      };
      
      static const struct bin_table bin_net_atalk_table[] = {
              { CTL_INT,        NET_ATALK_AARP_EXPIRY_TIME,                "aarp-expiry-time" },
              { CTL_INT,        NET_ATALK_AARP_TICK_TIME,                "aarp-tick-time" },
              { CTL_INT,        NET_ATALK_AARP_RETRANSMIT_LIMIT,        "aarp-retransmit-limit" },
              { CTL_INT,        NET_ATALK_AARP_RESOLVE_TIME,                "aarp-resolve-time" },
              {},
      };
      
      static const struct bin_table bin_net_netrom_table[] = {
              { CTL_INT,        NET_NETROM_DEFAULT_PATH_QUALITY,                "default_path_quality" },
              { CTL_INT,        NET_NETROM_OBSOLESCENCE_COUNT_INITIALISER,        "obsolescence_count_initialiser" },
              { CTL_INT,        NET_NETROM_NETWORK_TTL_INITIALISER,                "network_ttl_initialiser" },
              { CTL_INT,        NET_NETROM_TRANSPORT_TIMEOUT,                        "transport_timeout" },
              { CTL_INT,        NET_NETROM_TRANSPORT_MAXIMUM_TRIES,                "transport_maximum_tries" },
              { CTL_INT,        NET_NETROM_TRANSPORT_ACKNOWLEDGE_DELAY,                "transport_acknowledge_delay" },
              { CTL_INT,        NET_NETROM_TRANSPORT_BUSY_DELAY,                "transport_busy_delay" },
              { CTL_INT,        NET_NETROM_TRANSPORT_REQUESTED_WINDOW_SIZE,        "transport_requested_window_size" },
              { CTL_INT,        NET_NETROM_TRANSPORT_NO_ACTIVITY_TIMEOUT,        "transport_no_activity_timeout" },
              { CTL_INT,        NET_NETROM_ROUTING_CONTROL,                        "routing_control" },
              { CTL_INT,        NET_NETROM_LINK_FAILS_COUNT,                        "link_fails_count" },
              { CTL_INT,        NET_NETROM_RESET,                                "reset" },
              {}
      };
      
      static const struct bin_table bin_net_ax25_param_table[] = {
              { CTL_INT,        NET_AX25_IP_DEFAULT_MODE,        "ip_default_mode" },
              { CTL_INT,        NET_AX25_DEFAULT_MODE,                "ax25_default_mode" },
              { CTL_INT,        NET_AX25_BACKOFF_TYPE,                "backoff_type" },
              { CTL_INT,        NET_AX25_CONNECT_MODE,                "connect_mode" },
              { CTL_INT,        NET_AX25_STANDARD_WINDOW,        "standard_window_size" },
              { CTL_INT,        NET_AX25_EXTENDED_WINDOW,        "extended_window_size" },
              { CTL_INT,        NET_AX25_T1_TIMEOUT,                "t1_timeout" },
              { CTL_INT,        NET_AX25_T2_TIMEOUT,                "t2_timeout" },
              { CTL_INT,        NET_AX25_T3_TIMEOUT,                "t3_timeout" },
              { CTL_INT,        NET_AX25_IDLE_TIMEOUT,                "idle_timeout" },
              { CTL_INT,        NET_AX25_N2,                        "maximum_retry_count" },
              { CTL_INT,        NET_AX25_PACLEN,                "maximum_packet_length" },
              { CTL_INT,        NET_AX25_PROTOCOL,                "protocol" },
              { CTL_INT,        NET_AX25_DAMA_SLAVE_TIMEOUT,        "dama_slave_timeout" },
              {}
      };
      
      static const struct bin_table bin_net_ax25_table[] = {
              { CTL_DIR,        0, NULL, bin_net_ax25_param_table },
              {}
      };
      
      static const struct bin_table bin_net_rose_table[] = {
              { CTL_INT,        NET_ROSE_RESTART_REQUEST_TIMEOUT,        "restart_request_timeout" },
              { CTL_INT,        NET_ROSE_CALL_REQUEST_TIMEOUT,                "call_request_timeout" },
              { CTL_INT,        NET_ROSE_RESET_REQUEST_TIMEOUT,                "reset_request_timeout" },
              { CTL_INT,        NET_ROSE_CLEAR_REQUEST_TIMEOUT,                "clear_request_timeout" },
              { CTL_INT,        NET_ROSE_ACK_HOLD_BACK_TIMEOUT,                "acknowledge_hold_back_timeout" },
              { CTL_INT,        NET_ROSE_ROUTING_CONTROL,                "routing_control" },
              { CTL_INT,        NET_ROSE_LINK_FAIL_TIMEOUT,                "link_fail_timeout" },
              { CTL_INT,        NET_ROSE_MAX_VCS,                        "maximum_virtual_circuits" },
              { CTL_INT,        NET_ROSE_WINDOW_SIZE,                        "window_size" },
              { CTL_INT,        NET_ROSE_NO_ACTIVITY_TIMEOUT,                "no_activity_timeout" },
              {}
      };
      
      static const struct bin_table bin_net_ipv6_conf_var_table[] = {
              { CTL_INT,        NET_IPV6_FORWARDING,                        "forwarding" },
              { CTL_INT,        NET_IPV6_HOP_LIMIT,                        "hop_limit" },
              { CTL_INT,        NET_IPV6_MTU,                                "mtu" },
              { CTL_INT,        NET_IPV6_ACCEPT_RA,                        "accept_ra" },
              { CTL_INT,        NET_IPV6_ACCEPT_REDIRECTS,                "accept_redirects" },
              { CTL_INT,        NET_IPV6_AUTOCONF,                        "autoconf" },
              { CTL_INT,        NET_IPV6_DAD_TRANSMITS,                        "dad_transmits" },
              { CTL_INT,        NET_IPV6_RTR_SOLICITS,                        "router_solicitations" },
              { CTL_INT,        NET_IPV6_RTR_SOLICIT_INTERVAL,                "router_solicitation_interval" },
              { CTL_INT,        NET_IPV6_RTR_SOLICIT_DELAY,                "router_solicitation_delay" },
              { CTL_INT,        NET_IPV6_USE_TEMPADDR,                        "use_tempaddr" },
              { CTL_INT,        NET_IPV6_TEMP_VALID_LFT,                "temp_valid_lft" },
              { CTL_INT,        NET_IPV6_TEMP_PREFERED_LFT,                "temp_prefered_lft" },
              { CTL_INT,        NET_IPV6_REGEN_MAX_RETRY,                "regen_max_retry" },
              { CTL_INT,        NET_IPV6_MAX_DESYNC_FACTOR,                "max_desync_factor" },
              { CTL_INT,        NET_IPV6_MAX_ADDRESSES,                        "max_addresses" },
              { CTL_INT,        NET_IPV6_FORCE_MLD_VERSION,                "force_mld_version" },
              { CTL_INT,        NET_IPV6_ACCEPT_RA_DEFRTR,                "accept_ra_defrtr" },
              { CTL_INT,        NET_IPV6_ACCEPT_RA_PINFO,                "accept_ra_pinfo" },
              { CTL_INT,        NET_IPV6_ACCEPT_RA_RTR_PREF,                "accept_ra_rtr_pref" },
              { CTL_INT,        NET_IPV6_RTR_PROBE_INTERVAL,                "router_probe_interval" },
              { CTL_INT,        NET_IPV6_ACCEPT_RA_RT_INFO_MAX_PLEN,        "accept_ra_rt_info_max_plen" },
              { CTL_INT,        NET_IPV6_PROXY_NDP,                        "proxy_ndp" },
              { CTL_INT,        NET_IPV6_ACCEPT_SOURCE_ROUTE,                "accept_source_route" },
              { CTL_INT,        NET_IPV6_ACCEPT_RA_FROM_LOCAL,                "accept_ra_from_local" },
              {}
      };
      
      static const struct bin_table bin_net_ipv6_conf_table[] = {
              { CTL_DIR,        NET_PROTO_CONF_ALL,                "all",        bin_net_ipv6_conf_var_table },
              { CTL_DIR,        NET_PROTO_CONF_DEFAULT,         "default", bin_net_ipv6_conf_var_table },
              { CTL_DIR,        0, NULL, bin_net_ipv6_conf_var_table },
              {}
      };
      
      static const struct bin_table bin_net_ipv6_route_table[] = {
              /* NET_IPV6_ROUTE_FLUSH        "flush"  no longer used */
              { CTL_INT,        NET_IPV6_ROUTE_GC_THRESH,                "gc_thresh" },
              { CTL_INT,        NET_IPV6_ROUTE_MAX_SIZE,                "max_size" },
              { CTL_INT,        NET_IPV6_ROUTE_GC_MIN_INTERVAL,                "gc_min_interval" },
              { CTL_INT,        NET_IPV6_ROUTE_GC_TIMEOUT,                "gc_timeout" },
              { CTL_INT,        NET_IPV6_ROUTE_GC_INTERVAL,                "gc_interval" },
              { CTL_INT,        NET_IPV6_ROUTE_GC_ELASTICITY,                "gc_elasticity" },
              { CTL_INT,        NET_IPV6_ROUTE_MTU_EXPIRES,                "mtu_expires" },
              { CTL_INT,        NET_IPV6_ROUTE_MIN_ADVMSS,                "min_adv_mss" },
              { CTL_INT,        NET_IPV6_ROUTE_GC_MIN_INTERVAL_MS,        "gc_min_interval_ms" },
              {}
      };
      
      static const struct bin_table bin_net_ipv6_icmp_table[] = {
              { CTL_INT,        NET_IPV6_ICMP_RATELIMIT,        "ratelimit" },
              {}
      };
      
      static const struct bin_table bin_net_ipv6_table[] = {
              { CTL_DIR,        NET_IPV6_CONF,                "conf",                bin_net_ipv6_conf_table },
              { CTL_DIR,        NET_IPV6_NEIGH,                "neigh",        bin_net_neigh_table },
              { CTL_DIR,        NET_IPV6_ROUTE,                "route",        bin_net_ipv6_route_table },
              { CTL_DIR,        NET_IPV6_ICMP,                "icmp",                bin_net_ipv6_icmp_table },
              { CTL_INT,        NET_IPV6_BINDV6ONLY,                "bindv6only" },
              { CTL_INT,        NET_IPV6_IP6FRAG_HIGH_THRESH,        "ip6frag_high_thresh" },
              { CTL_INT,        NET_IPV6_IP6FRAG_LOW_THRESH,        "ip6frag_low_thresh" },
              { CTL_INT,        NET_IPV6_IP6FRAG_TIME,                "ip6frag_time" },
              { CTL_INT,        NET_IPV6_IP6FRAG_SECRET_INTERVAL,        "ip6frag_secret_interval" },
              { CTL_INT,        NET_IPV6_MLD_MAX_MSF,                "mld_max_msf" },
              { CTL_INT,        2088 /* IPQ_QMAX */,                "ip6_queue_maxlen" },
              {}
      };
      
      static const struct bin_table bin_net_x25_table[] = {
              { CTL_INT,        NET_X25_RESTART_REQUEST_TIMEOUT,        "restart_request_timeout" },
              { CTL_INT,        NET_X25_CALL_REQUEST_TIMEOUT,                "call_request_timeout" },
              { CTL_INT,        NET_X25_RESET_REQUEST_TIMEOUT,        "reset_request_timeout" },
              { CTL_INT,        NET_X25_CLEAR_REQUEST_TIMEOUT,        "clear_request_timeout" },
              { CTL_INT,        NET_X25_ACK_HOLD_BACK_TIMEOUT,        "acknowledgement_hold_back_timeout" },
              { CTL_INT,        NET_X25_FORWARD,                        "x25_forward" },
              {}
      };
      
      static const struct bin_table bin_net_tr_table[] = {
              { CTL_INT,        NET_TR_RIF_TIMEOUT,        "rif_timeout" },
              {}
      };
      
      
      static const struct bin_table bin_net_decnet_conf_vars[] = {
              { CTL_INT,        NET_DECNET_CONF_DEV_FORWARDING,        "forwarding" },
              { CTL_INT,        NET_DECNET_CONF_DEV_PRIORITY,        "priority" },
              { CTL_INT,        NET_DECNET_CONF_DEV_T2,                "t2" },
              { CTL_INT,        NET_DECNET_CONF_DEV_T3,                "t3" },
              {}
      };
      
      static const struct bin_table bin_net_decnet_conf[] = {
              { CTL_DIR, NET_DECNET_CONF_ETHER,    "ethernet", bin_net_decnet_conf_vars },
              { CTL_DIR, NET_DECNET_CONF_GRE,             "ipgre",    bin_net_decnet_conf_vars },
              { CTL_DIR, NET_DECNET_CONF_X25,             "x25",      bin_net_decnet_conf_vars },
              { CTL_DIR, NET_DECNET_CONF_PPP,             "ppp",      bin_net_decnet_conf_vars },
              { CTL_DIR, NET_DECNET_CONF_DDCMP,    "ddcmp",    bin_net_decnet_conf_vars },
              { CTL_DIR, NET_DECNET_CONF_LOOPBACK, "loopback", bin_net_decnet_conf_vars },
              { CTL_DIR, 0,                             NULL,         bin_net_decnet_conf_vars },
              {}
      };
      
      static const struct bin_table bin_net_decnet_table[] = {
              { CTL_DIR,        NET_DECNET_CONF,                "conf",        bin_net_decnet_conf },
              { CTL_DNADR,        NET_DECNET_NODE_ADDRESS,        "node_address" },
              { CTL_STR,        NET_DECNET_NODE_NAME,                "node_name" },
              { CTL_STR,        NET_DECNET_DEFAULT_DEVICE,        "default_device" },
              { CTL_INT,        NET_DECNET_TIME_WAIT,                "time_wait" },
              { CTL_INT,        NET_DECNET_DN_COUNT,                "dn_count" },
              { CTL_INT,        NET_DECNET_DI_COUNT,                "di_count" },
              { CTL_INT,        NET_DECNET_DR_COUNT,                "dr_count" },
              { CTL_INT,        NET_DECNET_DST_GC_INTERVAL,        "dst_gc_interval" },
              { CTL_INT,        NET_DECNET_NO_FC_MAX_CWND,        "no_fc_max_cwnd" },
              { CTL_INT,        NET_DECNET_MEM,                "decnet_mem" },
              { CTL_INT,        NET_DECNET_RMEM,                "decnet_rmem" },
              { CTL_INT,        NET_DECNET_WMEM,                "decnet_wmem" },
              { CTL_INT,        NET_DECNET_DEBUG_LEVEL,        "debug" },
              {}
      };
      
      static const struct bin_table bin_net_sctp_table[] = {
              { CTL_INT,        NET_SCTP_RTO_INITIAL,                "rto_initial" },
              { CTL_INT,        NET_SCTP_RTO_MIN,                "rto_min" },
              { CTL_INT,        NET_SCTP_RTO_MAX,                "rto_max" },
              { CTL_INT,        NET_SCTP_RTO_ALPHA,                "rto_alpha_exp_divisor" },
              { CTL_INT,        NET_SCTP_RTO_BETA,                "rto_beta_exp_divisor" },
              { CTL_INT,        NET_SCTP_VALID_COOKIE_LIFE,        "valid_cookie_life" },
              { CTL_INT,        NET_SCTP_ASSOCIATION_MAX_RETRANS,        "association_max_retrans" },
              { CTL_INT,        NET_SCTP_PATH_MAX_RETRANS,        "path_max_retrans" },
              { CTL_INT,        NET_SCTP_MAX_INIT_RETRANSMITS,        "max_init_retransmits" },
              { CTL_INT,        NET_SCTP_HB_INTERVAL,                "hb_interval" },
              { CTL_INT,        NET_SCTP_PRESERVE_ENABLE,        "cookie_preserve_enable" },
              { CTL_INT,        NET_SCTP_MAX_BURST,                "max_burst" },
              { CTL_INT,        NET_SCTP_ADDIP_ENABLE,                "addip_enable" },
              { CTL_INT,        NET_SCTP_PRSCTP_ENABLE,                "prsctp_enable" },
              { CTL_INT,        NET_SCTP_SNDBUF_POLICY,                "sndbuf_policy" },
              { CTL_INT,        NET_SCTP_SACK_TIMEOUT,                "sack_timeout" },
              { CTL_INT,        NET_SCTP_RCVBUF_POLICY,                "rcvbuf_policy" },
              {}
      };
      
      static const struct bin_table bin_net_llc_llc2_timeout_table[] = {
              { CTL_INT,        NET_LLC2_ACK_TIMEOUT,        "ack" },
              { CTL_INT,        NET_LLC2_P_TIMEOUT,        "p" },
              { CTL_INT,        NET_LLC2_REJ_TIMEOUT,        "rej" },
              { CTL_INT,        NET_LLC2_BUSY_TIMEOUT,        "busy" },
              {}
      };
      
      static const struct bin_table bin_net_llc_station_table[] = {
              { CTL_INT,        NET_LLC_STATION_ACK_TIMEOUT,        "ack_timeout" },
              {}
      };
      
      static const struct bin_table bin_net_llc_llc2_table[] = {
              { CTL_DIR,        NET_LLC2,                "timeout",        bin_net_llc_llc2_timeout_table },
              {}
      };
      
      static const struct bin_table bin_net_llc_table[] = {
              { CTL_DIR,        NET_LLC2,                "llc2",                bin_net_llc_llc2_table },
              { CTL_DIR,        NET_LLC_STATION,        "station",        bin_net_llc_station_table },
              {}
      };
      
      static const struct bin_table bin_net_netfilter_table[] = {
              { CTL_INT,        NET_NF_CONNTRACK_MAX,                        "nf_conntrack_max" },
              /* NET_NF_CONNTRACK_TCP_TIMEOUT_SYN_SENT "nf_conntrack_tcp_timeout_syn_sent" no longer used */
              /* NET_NF_CONNTRACK_TCP_TIMEOUT_SYN_RECV "nf_conntrack_tcp_timeout_syn_recv" no longer used */
              /* NET_NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED "nf_conntrack_tcp_timeout_established" no longer used */
              /* NET_NF_CONNTRACK_TCP_TIMEOUT_FIN_WAIT "nf_conntrack_tcp_timeout_fin_wait" no longer used */
              /* NET_NF_CONNTRACK_TCP_TIMEOUT_CLOSE_WAIT "nf_conntrack_tcp_timeout_close_wait" no longer used */
              /* NET_NF_CONNTRACK_TCP_TIMEOUT_LAST_ACK "nf_conntrack_tcp_timeout_last_ack" no longer used */
              /* NET_NF_CONNTRACK_TCP_TIMEOUT_TIME_WAIT "nf_conntrack_tcp_timeout_time_wait" no longer used */
              /* NET_NF_CONNTRACK_TCP_TIMEOUT_CLOSE "nf_conntrack_tcp_timeout_close" no longer used */
              /* NET_NF_CONNTRACK_UDP_TIMEOUT        "nf_conntrack_udp_timeout" no longer used */
              /* NET_NF_CONNTRACK_UDP_TIMEOUT_STREAM "nf_conntrack_udp_timeout_stream" no longer used */
              /* NET_NF_CONNTRACK_ICMP_TIMEOUT "nf_conntrack_icmp_timeout" no longer used */
              /* NET_NF_CONNTRACK_GENERIC_TIMEOUT "nf_conntrack_generic_timeout" no longer used */
              { CTL_INT,        NET_NF_CONNTRACK_BUCKETS,                "nf_conntrack_buckets" },
              { CTL_INT,        NET_NF_CONNTRACK_LOG_INVALID,                "nf_conntrack_log_invalid" },
              /* NET_NF_CONNTRACK_TCP_TIMEOUT_MAX_RETRANS "nf_conntrack_tcp_timeout_max_retrans" no longer used */
              { CTL_INT,        NET_NF_CONNTRACK_TCP_LOOSE,                "nf_conntrack_tcp_loose" },
              { CTL_INT,        NET_NF_CONNTRACK_TCP_BE_LIBERAL,        "nf_conntrack_tcp_be_liberal" },
              { CTL_INT,        NET_NF_CONNTRACK_TCP_MAX_RETRANS,        "nf_conntrack_tcp_max_retrans" },
              /* NET_NF_CONNTRACK_SCTP_TIMEOUT_CLOSED "nf_conntrack_sctp_timeout_closed" no longer used */
              /* NET_NF_CONNTRACK_SCTP_TIMEOUT_COOKIE_WAIT "nf_conntrack_sctp_timeout_cookie_wait" no longer used */
              /* NET_NF_CONNTRACK_SCTP_TIMEOUT_COOKIE_ECHOED "nf_conntrack_sctp_timeout_cookie_echoed" no longer used */
              /* NET_NF_CONNTRACK_SCTP_TIMEOUT_ESTABLISHED "nf_conntrack_sctp_timeout_established" no longer used */
              /* NET_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_SENT "nf_conntrack_sctp_timeout_shutdown_sent" no longer used */
              /* NET_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_RECD "nf_conntrack_sctp_timeout_shutdown_recd" no longer used */
              /* NET_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_ACK_SENT "nf_conntrack_sctp_timeout_shutdown_ack_sent" no longer used */
              { CTL_INT,        NET_NF_CONNTRACK_COUNT,                        "nf_conntrack_count" },
              /* NET_NF_CONNTRACK_ICMPV6_TIMEOUT "nf_conntrack_icmpv6_timeout" no longer used */
              /* NET_NF_CONNTRACK_FRAG6_TIMEOUT "nf_conntrack_frag6_timeout" no longer used */
              { CTL_INT,        NET_NF_CONNTRACK_FRAG6_LOW_THRESH,        "nf_conntrack_frag6_low_thresh" },
              { CTL_INT,        NET_NF_CONNTRACK_FRAG6_HIGH_THRESH,        "nf_conntrack_frag6_high_thresh" },
              { CTL_INT,        NET_NF_CONNTRACK_CHECKSUM,                "nf_conntrack_checksum" },
      
              {}
      };
      
      static const struct bin_table bin_net_irda_table[] = {
              { CTL_INT,        NET_IRDA_DISCOVERY,                "discovery" },
              { CTL_STR,        NET_IRDA_DEVNAME,                "devname" },
              { CTL_INT,        NET_IRDA_DEBUG,                        "debug" },
              { CTL_INT,        NET_IRDA_FAST_POLL,                "fast_poll_increase" },
              { CTL_INT,        NET_IRDA_DISCOVERY_SLOTS,        "discovery_slots" },
              { CTL_INT,        NET_IRDA_DISCOVERY_TIMEOUT,        "discovery_timeout" },
              { CTL_INT,        NET_IRDA_SLOT_TIMEOUT,                "slot_timeout" },
              { CTL_INT,        NET_IRDA_MAX_BAUD_RATE,                "max_baud_rate" },
              { CTL_INT,        NET_IRDA_MIN_TX_TURN_TIME,        "min_tx_turn_time" },
              { CTL_INT,        NET_IRDA_MAX_TX_DATA_SIZE,        "max_tx_data_size" },
              { CTL_INT,        NET_IRDA_MAX_TX_WINDOW,                "max_tx_window" },
              { CTL_INT,        NET_IRDA_MAX_NOREPLY_TIME,        "max_noreply_time" },
              { CTL_INT,        NET_IRDA_WARN_NOREPLY_TIME,        "warn_noreply_time" },
              { CTL_INT,        NET_IRDA_LAP_KEEPALIVE_TIME,        "lap_keepalive_time" },
              {}
      };
      
      static const struct bin_table bin_net_table[] = {
              { CTL_DIR,        NET_CORE,                "core",                bin_net_core_table },
              /* NET_ETHER not used */
              /* NET_802 not used */
              { CTL_DIR,        NET_UNIX,                "unix",                bin_net_unix_table },
              { CTL_DIR,        NET_IPV4,                "ipv4",                bin_net_ipv4_table },
              { CTL_DIR,        NET_IPX,                "ipx",                bin_net_ipx_table },
              { CTL_DIR,        NET_ATALK,                "appletalk",        bin_net_atalk_table },
              { CTL_DIR,        NET_NETROM,                "netrom",        bin_net_netrom_table },
              { CTL_DIR,        NET_AX25,                "ax25",                bin_net_ax25_table },
              /*  NET_BRIDGE "bridge" no longer used */
              { CTL_DIR,        NET_ROSE,                "rose",                bin_net_rose_table },
              { CTL_DIR,        NET_IPV6,                "ipv6",                bin_net_ipv6_table },
              { CTL_DIR,        NET_X25,                "x25",                bin_net_x25_table },
              { CTL_DIR,        NET_TR,                        "token-ring",        bin_net_tr_table },
              { CTL_DIR,        NET_DECNET,                "decnet",        bin_net_decnet_table },
              /*  NET_ECONET not used */
              { CTL_DIR,        NET_SCTP,                "sctp",                bin_net_sctp_table },
              { CTL_DIR,        NET_LLC,                "llc",                bin_net_llc_table },
              { CTL_DIR,        NET_NETFILTER,                "netfilter",        bin_net_netfilter_table },
              /* NET_DCCP "dccp" no longer used */
              { CTL_DIR,        NET_IRDA,                "irda",                bin_net_irda_table },
              { CTL_INT,        2089,                        "nf_conntrack_max" },
              {}
      };
      
      static const struct bin_table bin_fs_quota_table[] = {
              { CTL_INT,        FS_DQ_LOOKUPS,                "lookups" },
              { CTL_INT,        FS_DQ_DROPS,                "drops" },
              { CTL_INT,        FS_DQ_READS,                "reads" },
              { CTL_INT,        FS_DQ_WRITES,                "writes" },
              { CTL_INT,        FS_DQ_CACHE_HITS,        "cache_hits" },
              { CTL_INT,        FS_DQ_ALLOCATED,        "allocated_dquots" },
              { CTL_INT,        FS_DQ_FREE,                "free_dquots" },
              { CTL_INT,        FS_DQ_SYNCS,                "syncs" },
              { CTL_INT,        FS_DQ_WARNINGS,                "warnings" },
              {}
      };
      
      static const struct bin_table bin_fs_xfs_table[] = {
              { CTL_INT,        XFS_SGID_INHERIT,        "irix_sgid_inherit" },
              { CTL_INT,        XFS_SYMLINK_MODE,        "irix_symlink_mode" },
              { CTL_INT,        XFS_PANIC_MASK,                "panic_mask" },
      
              { CTL_INT,        XFS_ERRLEVEL,                "error_level" },
              { CTL_INT,        XFS_SYNCD_TIMER,        "xfssyncd_centisecs" },
              { CTL_INT,        XFS_INHERIT_SYNC,        "inherit_sync" },
              { CTL_INT,        XFS_INHERIT_NODUMP,        "inherit_nodump" },
              { CTL_INT,        XFS_INHERIT_NOATIME,        "inherit_noatime" },
              { CTL_INT,        XFS_BUF_TIMER,                "xfsbufd_centisecs" },
              { CTL_INT,        XFS_BUF_AGE,                "age_buffer_centisecs" },
              { CTL_INT,        XFS_INHERIT_NOSYM,        "inherit_nosymlinks" },
              { CTL_INT,        XFS_ROTORSTEP,        "rotorstep" },
              { CTL_INT,        XFS_INHERIT_NODFRG,        "inherit_nodefrag" },
              { CTL_INT,        XFS_FILESTREAM_TIMER,        "filestream_centisecs" },
              { CTL_INT,        XFS_STATS_CLEAR,        "stats_clear" },
              {}
      };
      
      static const struct bin_table bin_fs_ocfs2_nm_table[] = {
              { CTL_STR,        1, "hb_ctl_path" },
              {}
      };
      
      static const struct bin_table bin_fs_ocfs2_table[] = {
              { CTL_DIR,        1,        "nm",        bin_fs_ocfs2_nm_table },
              {}
      };
      
      static const struct bin_table bin_inotify_table[] = {
              { CTL_INT,        INOTIFY_MAX_USER_INSTANCES,        "max_user_instances" },
              { CTL_INT,        INOTIFY_MAX_USER_WATCHES,        "max_user_watches" },
              { CTL_INT,        INOTIFY_MAX_QUEUED_EVENTS,        "max_queued_events" },
              {}
      };
      
      static const struct bin_table bin_fs_table[] = {
              { CTL_INT,        FS_NRINODE,                "inode-nr" },
              { CTL_INT,        FS_STATINODE,                "inode-state" },
              /* FS_MAXINODE unused */
              /* FS_NRDQUOT unused */
              /* FS_MAXDQUOT unused */
              /* FS_NRFILE "file-nr" no longer used */
              { CTL_INT,        FS_MAXFILE,                "file-max" },
              { CTL_INT,        FS_DENTRY,                "dentry-state" },
              /* FS_NRSUPER unused */
              /* FS_MAXUPSER unused */
              { CTL_INT,        FS_OVERFLOWUID,                "overflowuid" },
              { CTL_INT,        FS_OVERFLOWGID,                "overflowgid" },
              { CTL_INT,        FS_LEASES,                "leases-enable" },
              { CTL_INT,        FS_DIR_NOTIFY,                "dir-notify-enable" },
              { CTL_INT,        FS_LEASE_TIME,                "lease-break-time" },
              { CTL_DIR,        FS_DQSTATS,                "quota",        bin_fs_quota_table },
              { CTL_DIR,        FS_XFS,                        "xfs",                bin_fs_xfs_table },
              { CTL_ULONG,        FS_AIO_NR,                "aio-nr" },
              { CTL_ULONG,        FS_AIO_MAX_NR,                "aio-max-nr" },
              { CTL_DIR,        FS_INOTIFY,                "inotify",        bin_inotify_table },
              { CTL_DIR,        FS_OCFS2,                "ocfs2",        bin_fs_ocfs2_table },
              { CTL_INT,        KERN_SETUID_DUMPABLE,        "suid_dumpable" },
              {}
      };
      
      static const struct bin_table bin_ipmi_table[] = {
              { CTL_INT,        DEV_IPMI_POWEROFF_POWERCYCLE,        "poweroff_powercycle" },
              {}
      };
      
      static const struct bin_table bin_mac_hid_files[] = {
              /* DEV_MAC_HID_KEYBOARD_SENDS_LINUX_KEYCODES unused */
              /* DEV_MAC_HID_KEYBOARD_LOCK_KEYCODES unused */
              { CTL_INT,        DEV_MAC_HID_MOUSE_BUTTON_EMULATION,        "mouse_button_emulation" },
              { CTL_INT,        DEV_MAC_HID_MOUSE_BUTTON2_KEYCODE,        "mouse_button2_keycode" },
              { CTL_INT,        DEV_MAC_HID_MOUSE_BUTTON3_KEYCODE,        "mouse_button3_keycode" },
              /* DEV_MAC_HID_ADB_MOUSE_SENDS_KEYCODES unused */
              {}
      };
      
      static const struct bin_table bin_raid_table[] = {
              { CTL_INT,        DEV_RAID_SPEED_LIMIT_MIN,        "speed_limit_min" },
              { CTL_INT,        DEV_RAID_SPEED_LIMIT_MAX,        "speed_limit_max" },
              {}
      };
      
      static const struct bin_table bin_scsi_table[] = {
              { CTL_INT, DEV_SCSI_LOGGING_LEVEL, "logging_level" },
              {}
      };
      
      static const struct bin_table bin_dev_table[] = {
              /* DEV_CDROM        "cdrom" no longer used */
              /* DEV_HWMON unused */
              /* DEV_PARPORT        "parport" no longer used */
              { CTL_DIR,        DEV_RAID,        "raid",                bin_raid_table },
              { CTL_DIR,        DEV_MAC_HID,        "mac_hid",        bin_mac_hid_files },
              { CTL_DIR,        DEV_SCSI,        "scsi",                bin_scsi_table },
              { CTL_DIR,        DEV_IPMI,        "ipmi",                bin_ipmi_table },
              {}
      };
      
      static const struct bin_table bin_bus_isa_table[] = {
              { CTL_INT,        BUS_ISA_MEM_BASE,        "membase" },
              { CTL_INT,        BUS_ISA_PORT_BASE,        "portbase" },
              { CTL_INT,        BUS_ISA_PORT_SHIFT,        "portshift" },
              {}
      };
      
      static const struct bin_table bin_bus_table[] = {
              { CTL_DIR,        CTL_BUS_ISA,        "isa",        bin_bus_isa_table },
              {}
      };
      
      
      static const struct bin_table bin_s390dbf_table[] = {
              { CTL_INT,        5678 /* CTL_S390DBF_STOPPABLE */, "debug_stoppable" },
              { CTL_INT,        5679 /* CTL_S390DBF_ACTIVE */,          "debug_active" },
              {}
      };
      
      static const struct bin_table bin_sunrpc_table[] = {
              /* CTL_RPCDEBUG        "rpc_debug"  no longer used */
              /* CTL_NFSDEBUG "nfs_debug"  no longer used */
              /* CTL_NFSDDEBUG "nfsd_debug" no longer used  */
              /* CTL_NLMDEBUG "nlm_debug" no longer used */
      
              { CTL_INT,        CTL_SLOTTABLE_UDP,        "udp_slot_table_entries" },
              { CTL_INT,        CTL_SLOTTABLE_TCP,        "tcp_slot_table_entries" },
              { CTL_INT,        CTL_MIN_RESVPORT,        "min_resvport" },
              { CTL_INT,        CTL_MAX_RESVPORT,        "max_resvport" },
              {}
      };
      
      static const struct bin_table bin_pm_table[] = {
              /* frv specific */
              /* 1 == CTL_PM_SUSPEND        "suspend"  no longer used" */
              { CTL_INT,        2 /* CTL_PM_CMODE */,                "cmode" },
              { CTL_INT,        3 /* CTL_PM_P0 */,                "p0" },
              { CTL_INT,        4 /* CTL_PM_CM */,                "cm" },
              {}
      };
      
      static const struct bin_table bin_root_table[] = {
              { CTL_DIR,        CTL_KERN,        "kernel",        bin_kern_table },
              { CTL_DIR,        CTL_VM,                "vm",                bin_vm_table },
              { CTL_DIR,        CTL_NET,        "net",                bin_net_table },
              /* CTL_PROC not used */
              { CTL_DIR,        CTL_FS,                "fs",                bin_fs_table },
              /* CTL_DEBUG "debug" no longer used */
              { CTL_DIR,        CTL_DEV,        "dev",                bin_dev_table },
              { CTL_DIR,        CTL_BUS,        "bus",                bin_bus_table },
              { CTL_DIR,        CTL_ABI,        "abi" },
              /* CTL_CPU not used */
              /* CTL_ARLAN "arlan" no longer used */
              { CTL_DIR,        CTL_S390DBF,        "s390dbf",        bin_s390dbf_table },
              { CTL_DIR,        CTL_SUNRPC,        "sunrpc",        bin_sunrpc_table },
              { CTL_DIR,        CTL_PM,                "pm",                bin_pm_table },
              {}
      };
      
      static ssize_t bin_dir(struct file *file,
              void __user *oldval, size_t oldlen, void __user *newval, size_t newlen)
      {
              return -ENOTDIR;
      }
      
      
      static ssize_t bin_string(struct file *file,
              void __user *oldval, size_t oldlen, void __user *newval, size_t newlen)
      {
              ssize_t result, copied = 0;
      
              if (oldval && oldlen) {
                      char __user *lastp;
                      loff_t pos = 0;
                      int ch;
      
                      result = vfs_read(file, oldval, oldlen, &pos);
                      if (result < 0)
                              goto out;
      
                      copied = result;
                      lastp = oldval + copied - 1;
      
                      result = -EFAULT;
                      if (get_user(ch, lastp))
                              goto out;
      
                      /* Trim off the trailing newline */
                      if (ch == '\n') {
                              result = -EFAULT;
                              if (put_user('\0', lastp))
                                      goto out;
                              copied -= 1;
                      }
              }
      
              if (newval && newlen) {
                      loff_t pos = 0;
      
                      result = vfs_write(file, newval, newlen, &pos);
                      if (result < 0)
                              goto out;
              }
      
              result = copied;
      out:
              return result;
      }
      
      static ssize_t bin_intvec(struct file *file,
              void __user *oldval, size_t oldlen, void __user *newval, size_t newlen)
      {
              ssize_t copied = 0;
              char *buffer;
              ssize_t result;
      
              result = -ENOMEM;
              buffer = kmalloc(BUFSZ, GFP_KERNEL);
              if (!buffer)
                      goto out;
      
              if (oldval && oldlen) {
                      unsigned __user *vec = oldval;
                      size_t length = oldlen / sizeof(*vec);
                      char *str, *end;
                      int i;
      
                      result = kernel_read(file, 0, buffer, BUFSZ - 1);
                      if (result < 0)
                              goto out_kfree;
      
                      str = buffer;
                      end = str + result;
                      *end++ = '\0';
                      for (i = 0; i < length; i++) {
                              unsigned long value;
      
                              value = simple_strtoul(str, &str, 10);
                              while (isspace(*str))
                                      str++;
                              
                              result = -EFAULT;
                              if (put_user(value, vec + i))
                                      goto out_kfree;
      
                              copied += sizeof(*vec);
                              if (!isdigit(*str))
                                      break;
                      }
              }
      
              if (newval && newlen) {
                      unsigned __user *vec = newval;
                      size_t length = newlen / sizeof(*vec);
                      char *str, *end;
                      int i;
      
                      str = buffer;
                      end = str + BUFSZ;
                      for (i = 0; i < length; i++) {
                              unsigned long value;
      
                              result = -EFAULT;
                              if (get_user(value, vec + i))
                                      goto out_kfree;
      
                              str += scnprintf(str, end - str, "%lu\t", value);
                      }
      
                      result = kernel_write(file, buffer, str - buffer, 0);
                      if (result < 0)
                              goto out_kfree;
              }
              result = copied;
      out_kfree:
              kfree(buffer);
      out:
              return result;
      }
      
      static ssize_t bin_ulongvec(struct file *file,
              void __user *oldval, size_t oldlen, void __user *newval, size_t newlen)
      {
              ssize_t copied = 0;
              char *buffer;
              ssize_t result;
      
              result = -ENOMEM;
              buffer = kmalloc(BUFSZ, GFP_KERNEL);
              if (!buffer)
                      goto out;
      
              if (oldval && oldlen) {
                      unsigned long __user *vec = oldval;
                      size_t length = oldlen / sizeof(*vec);
                      char *str, *end;
                      int i;
      
                      result = kernel_read(file, 0, buffer, BUFSZ - 1);
                      if (result < 0)
                              goto out_kfree;
      
                      str = buffer;
                      end = str + result;
                      *end++ = '\0';
                      for (i = 0; i < length; i++) {
                              unsigned long value;
      
                              value = simple_strtoul(str, &str, 10);
                              while (isspace(*str))
                                      str++;
                              
                              result = -EFAULT;
                              if (put_user(value, vec + i))
                                      goto out_kfree;
      
                              copied += sizeof(*vec);
                              if (!isdigit(*str))
                                      break;
                      }
              }
      
              if (newval && newlen) {
                      unsigned long __user *vec = newval;
                      size_t length = newlen / sizeof(*vec);
                      char *str, *end;
                      int i;
      
                      str = buffer;
                      end = str + BUFSZ;
                      for (i = 0; i < length; i++) {
                              unsigned long value;
      
                              result = -EFAULT;
                              if (get_user(value, vec + i))
                                      goto out_kfree;
      
                              str += scnprintf(str, end - str, "%lu\t", value);
                      }
      
                      result = kernel_write(file, buffer, str - buffer, 0);
                      if (result < 0)
                              goto out_kfree;
              }
              result = copied;
      out_kfree:
              kfree(buffer);
      out:
              return result;
      }
      
      static ssize_t bin_uuid(struct file *file,
              void __user *oldval, size_t oldlen, void __user *newval, size_t newlen)
      {
              ssize_t result, copied = 0;
      
              /* Only supports reads */
              if (oldval && oldlen) {
                      char buf[40], *str = buf;
                      unsigned char uuid[16];
                      int i;
      
                      result = kernel_read(file, 0, buf, sizeof(buf) - 1);
                      if (result < 0)
                              goto out;
      
                      buf[result] = '\0';
      
                      /* Convert the uuid to from a string to binary */
                      for (i = 0; i < 16; i++) {
                              result = -EIO;
                              if (!isxdigit(str[0]) || !isxdigit(str[1]))
                                      goto out;
      
                              uuid[i] = (hex_to_bin(str[0]) << 4) |
                                              hex_to_bin(str[1]);
                              str += 2;
                              if (*str == '-')
                                      str++;
                      }
      
                      if (oldlen > 16)
                              oldlen = 16;
      
                      result = -EFAULT;
                      if (copy_to_user(oldval, uuid, oldlen))
                              goto out;
      
                      copied = oldlen;
              }
              result = copied;
      out:
              return result;
      }
      
      static ssize_t bin_dn_node_address(struct file *file,
              void __user *oldval, size_t oldlen, void __user *newval, size_t newlen)
      {
              ssize_t result, copied = 0;
      
              if (oldval && oldlen) {
                      char buf[15], *nodep;
                      unsigned long area, node;
                      __le16 dnaddr;
      
                      result = kernel_read(file, 0, buf, sizeof(buf) - 1);
                      if (result < 0)
                              goto out;
      
                      buf[result] = '\0';
      
                      /* Convert the decnet address to binary */
                      result = -EIO;
                      nodep = strchr(buf, '.');
                      if (!nodep)
                              goto out;
                      ++nodep;
      
                      area = simple_strtoul(buf, NULL, 10);
                      node = simple_strtoul(nodep, NULL, 10);
      
                      result = -EIO;
                      if ((area > 63)||(node > 1023))
                              goto out;
      
                      dnaddr = cpu_to_le16((area << 10) | node);
      
                      result = -EFAULT;
                      if (put_user(dnaddr, (__le16 __user *)oldval))
                              goto out;
      
                      copied = sizeof(dnaddr);
              }
      
              if (newval && newlen) {
                      __le16 dnaddr;
                      char buf[15];
                      int len;
      
                      result = -EINVAL;
                      if (newlen != sizeof(dnaddr))
                              goto out;
      
                      result = -EFAULT;
                      if (get_user(dnaddr, (__le16 __user *)newval))
                              goto out;
      
                      len = scnprintf(buf, sizeof(buf), "%hu.%hu",
                                      le16_to_cpu(dnaddr) >> 10,
                                      le16_to_cpu(dnaddr) & 0x3ff);
      
                      result = kernel_write(file, buf, len, 0);
                      if (result < 0)
                              goto out;
              }
      
              result = copied;
      out:
              return result;
      }
      
      static const struct bin_table *get_sysctl(const int *name, int nlen, char *path)
      {
              const struct bin_table *table = &bin_root_table[0];
              int ctl_name;
      
              /* The binary sysctl tables have a small maximum depth so
               * there is no danger of overflowing our path as it PATH_MAX
               * bytes long.
               */
              memcpy(path, "sys/", 4);
              path += 4;
      
      repeat:
              if (!nlen)
                      return ERR_PTR(-ENOTDIR);
              ctl_name = *name;
              name++;
              nlen--;
              for ( ; table->convert; table++) {
                      int len = 0;
      
                      /*
                       * For a wild card entry map from ifindex to network
                       * device name.
                       */
                      if (!table->ctl_name) {
      #ifdef CONFIG_NET
                              struct net *net = current->nsproxy->net_ns;
                              struct net_device *dev;
                              dev = dev_get_by_index(net, ctl_name);
                              if (dev) {
                                      len = strlen(dev->name);
                                      memcpy(path, dev->name, len);
                                      dev_put(dev);
                              }
      #endif
                      /* Use the well known sysctl number to proc name mapping */
                      } else if (ctl_name == table->ctl_name) {
                              len = strlen(table->procname);
                              memcpy(path, table->procname, len);
                      }
                      if (len) {
                              path += len;
                              if (table->child) {
                                      *path++ = '/';
                                      table = table->child;
                                      goto repeat;
                              }
                              *path = '\0';
                              return table;
                      }
              }
              return ERR_PTR(-ENOTDIR);
      }
      
      static char *sysctl_getname(const int *name, int nlen, const struct bin_table **tablep)
      {
              char *tmp, *result;
      
              result = ERR_PTR(-ENOMEM);
              tmp = __getname();
              if (tmp) {
                      const struct bin_table *table = get_sysctl(name, nlen, tmp);
                      result = tmp;
                      *tablep = table;
                      if (IS_ERR(table)) {
                              __putname(tmp);
                              result = ERR_CAST(table);
                      }
              }
              return result;
      }
      
      static ssize_t binary_sysctl(const int *name, int nlen,
              void __user *oldval, size_t oldlen, void __user *newval, size_t newlen)
      {
              const struct bin_table *table = NULL;
              struct vfsmount *mnt;
              struct file *file;
              ssize_t result;
              char *pathname;
              int flags;
      
              pathname = sysctl_getname(name, nlen, &table);
              result = PTR_ERR(pathname);
              if (IS_ERR(pathname))
                      goto out;
      
              /* How should the sysctl be accessed? */
              if (oldval && oldlen && newval && newlen) {
                      flags = O_RDWR;
              } else if (newval && newlen) {
                      flags = O_WRONLY;
              } else if (oldval && oldlen) {
                      flags = O_RDONLY;
              } else {
                      result = 0;
                      goto out_putname;
              }
      
              mnt = task_active_pid_ns(current)->proc_mnt;
              file = file_open_root(mnt->mnt_root, mnt, pathname, flags, 0);
              result = PTR_ERR(file);
              if (IS_ERR(file))
                      goto out_putname;
      
              result = table->convert(file, oldval, oldlen, newval, newlen);
      
              fput(file);
      out_putname:
              __putname(pathname);
      out:
              return result;
      }
      
      
      #else /* CONFIG_SYSCTL_SYSCALL */
      
      static ssize_t binary_sysctl(const int *name, int nlen,
              void __user *oldval, size_t oldlen, void __user *newval, size_t newlen)
      {
              return -ENOSYS;
      }
      
      #endif /* CONFIG_SYSCTL_SYSCALL */
      
      
      static void deprecated_sysctl_warning(const int *name, int nlen)
      {
              int i;
      
              /*
               * CTL_KERN/KERN_VERSION is used by older glibc and cannot
               * ever go away.
               */
              if (name[0] == CTL_KERN && name[1] == KERN_VERSION)
                      return;
      
              if (printk_ratelimit()) {
                      printk(KERN_INFO
                              "warning: process `%s' used the deprecated sysctl "
                              "system call with ", current->comm);
                      for (i = 0; i < nlen; i++)
                              printk("%d.", name[i]);
                      printk("\n");
              }
              return;
      }
      
      #define WARN_ONCE_HASH_BITS 8
      #define WARN_ONCE_HASH_SIZE (1<<WARN_ONCE_HASH_BITS)
      
      static DECLARE_BITMAP(warn_once_bitmap, WARN_ONCE_HASH_SIZE);
      
      #define FNV32_OFFSET 2166136261U
      #define FNV32_PRIME 0x01000193
      
      /*
       * Print each legacy sysctl (approximately) only once.
       * To avoid making the tables non-const use a external
       * hash-table instead.
       * Worst case hash collision: 6, but very rarely.
       * NOTE! We don't use the SMP-safe bit tests. We simply
       * don't care enough.
       */
      static void warn_on_bintable(const int *name, int nlen)
      {
              int i;
              u32 hash = FNV32_OFFSET;
      
    1         for (i = 0; i < nlen; i++)
    1                 hash = (hash ^ name[i]) * FNV32_PRIME;
              hash %= WARN_ONCE_HASH_SIZE;
    5         if (__test_and_set_bit(hash, warn_once_bitmap))
                      return;
              deprecated_sysctl_warning(name, nlen);
      }
      
      static ssize_t do_sysctl(int __user *args_name, int nlen,
              void __user *oldval, size_t oldlen, void __user *newval, size_t newlen)
      {
              int name[CTL_MAXNAME];
              int i;
      
              /* Check args->nlen. */
              if (nlen < 0 || nlen > CTL_MAXNAME)
                      return -ENOTDIR;
              /* Read in the sysctl name for simplicity */
    5         for (i = 0; i < nlen; i++)
    1                 if (get_user(name[i], args_name + i))
    5                         return -EFAULT;
      
    5         warn_on_bintable(name, nlen);
      
              return binary_sysctl(name, nlen, oldval, oldlen, newval, newlen);
      }
      
    9 SYSCALL_DEFINE1(sysctl, struct __sysctl_args __user *, args)
      {
              struct __sysctl_args tmp;
              size_t oldlen = 0;
              ssize_t result;
      
              if (copy_from_user(&tmp, args, sizeof(tmp)))
                      return -EFAULT;
      
    8         if (tmp.oldval && !tmp.oldlenp)
                      return -EFAULT;
      
    7         if (tmp.oldlenp && get_user(oldlen, tmp.oldlenp))
                      return -EFAULT;
      
    5         result = do_sysctl(tmp.name, tmp.nlen, tmp.oldval, oldlen,
                                 tmp.newval, tmp.newlen);
      
              if (result >= 0) {
                      oldlen = result;
                      result = 0;
              }
      
    9         if (tmp.oldlenp && put_user(oldlen, tmp.oldlenp))
                      return -EFAULT;
      
              return result;
      }
      
      
      #ifdef CONFIG_COMPAT
      
      struct compat_sysctl_args {
              compat_uptr_t        name;
              int                nlen;
              compat_uptr_t        oldval;
              compat_uptr_t        oldlenp;
              compat_uptr_t        newval;
              compat_size_t        newlen;
              compat_ulong_t        __unused[4];
      };
      
    3 COMPAT_SYSCALL_DEFINE1(sysctl, struct compat_sysctl_args __user *, args)
      {
              struct compat_sysctl_args tmp;
              compat_size_t __user *compat_oldlenp;
              size_t oldlen = 0;
              ssize_t result;
      
              if (copy_from_user(&tmp, args, sizeof(tmp)))
                      return -EFAULT;
      
    1         if (tmp.oldval && !tmp.oldlenp)
                      return -EFAULT;
      
    1         compat_oldlenp = compat_ptr(tmp.oldlenp);
              if (compat_oldlenp && get_user(oldlen, compat_oldlenp))
                      return -EFAULT;
      
    1         result = do_sysctl(compat_ptr(tmp.name), tmp.nlen,
                                 compat_ptr(tmp.oldval), oldlen,
                                 compat_ptr(tmp.newval), tmp.newlen);
      
              if (result >= 0) {
                      oldlen = result;
    3                 result = 0;
              }
      
              if (compat_oldlenp && put_user(oldlen, compat_oldlenp))
                      return -EFAULT;
      
              return result;
      }
      
      #endif /* CONFIG_COMPAT */
      /*
        File: fs/xattr.c
      
        Extended attribute handling.
      
        Copyright (C) 2001 by Andreas Gruenbacher <a.gruenbacher@computer.org>
        Copyright (C) 2001 SGI - Silicon Graphics, Inc <linux-xfs@oss.sgi.com>
        Copyright (c) 2004 Red Hat, Inc., James Morris <jmorris@redhat.com>
       */
      #include <linux/fs.h>
      #include <linux/slab.h>
      #include <linux/file.h>
      #include <linux/xattr.h>
      #include <linux/mount.h>
      #include <linux/namei.h>
      #include <linux/security.h>
      #include <linux/evm.h>
      #include <linux/syscalls.h>
      #include <linux/export.h>
      #include <linux/fsnotify.h>
      #include <linux/audit.h>
      #include <linux/vmalloc.h>
      #include <linux/posix_acl_xattr.h>
      
      #include <asm/uaccess.h>
      
      /*
       * Check permissions for extended attribute access.  This is a bit complicated
       * because different namespaces have very different rules.
       */
      static int
      xattr_permission(struct inode *inode, const char *name, int mask)
      {
              /*
               * We can never set or remove an extended attribute on a read-only
               * filesystem  or on an immutable / append-only inode.
               */
  138         if (mask & MAY_WRITE) {
  113                 if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
                              return -EPERM;
              }
      
              /*
               * No restriction for security.* and system.* from the VFS.  Decision
               * on these is left to the underlying filesystem / security module.
               */
  137         if (!strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) ||
   84             !strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
  137                 return 0;
      
              /*
               * The trusted.* namespace can only be accessed by privileged users.
               */
   37         if (!strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN)) {
    1                 if (!capable(CAP_SYS_ADMIN))
                              return (mask & MAY_WRITE) ? -EPERM : -ENODATA;
                      return 0;
              }
      
              /*
               * In the user.* namespace, only regular files and directories can have
               * extended attributes. For sticky directories, only the owner and
               * privileged users can write attributes.
               */
   36         if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) {
   25                 if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode))
    2                         return (mask & MAY_WRITE) ? -EPERM : -ENODATA;
   24                 if (S_ISDIR(inode->i_mode) && (inode->i_mode & S_ISVTX) &&
    1                     (mask & MAY_WRITE) && !inode_owner_or_capable(inode))
                              return -EPERM;
              }
      
   35         return inode_permission2(ERR_PTR(-EOPNOTSUPP), inode, mask);
      }
      
      /**
       *  __vfs_setxattr_noperm - perform setxattr operation without performing
       *  permission checks.
       *
       *  @dentry - object to perform setxattr on
       *  @name - xattr name to set
       *  @value - value to set @name to
       *  @size - size of @value
       *  @flags - flags to pass into filesystem operations
       *
       *  returns the result of the internal setxattr or setsecurity operations.
       *
       *  This function requires the caller to lock the inode's i_mutex before it
       *  is executed. It also assumes that the caller will make the appropriate
       *  permission checks.
       */
      int __vfs_setxattr_noperm(struct dentry *dentry, const char *name,
                      const void *value, size_t size, int flags)
      {
   70         struct inode *inode = dentry->d_inode;
              int error = -EOPNOTSUPP;
              int issec = !strncmp(name, XATTR_SECURITY_PREFIX,
                                         XATTR_SECURITY_PREFIX_LEN);
      
              if (issec)
   15                 inode->i_flags &= ~S_NOSEC;
   55         if (inode->i_op->setxattr) {
   65                 error = inode->i_op->setxattr(dentry, name, value, size, flags);
                      if (!error) {
   30                         fsnotify_xattr(dentry);
                              security_inode_post_setxattr(dentry, name, value,
                                                           size, flags);
                      }
              } else if (issec) {
    3                 const char *suffix = name + XATTR_SECURITY_PREFIX_LEN;
                      error = security_inode_setsecurity(inode, suffix, value,
                                                         size, flags);
                      if (!error)
    2                         fsnotify_xattr(dentry);
              }
      
   63         return error;
      }
      
      
      int
      vfs_setxattr(struct dentry *dentry, const char *name, const void *value,
                      size_t size, int flags)
      {
   97         struct inode *inode = dentry->d_inode;
              int error;
      
              error = xattr_permission(inode, name, MAY_WRITE);
   73         if (error)
                      return error;
      
   95         mutex_lock(&inode->i_mutex);
              error = security_inode_setxattr(dentry, name, value, size, flags);
              if (error)
                      goto out;
      
   70         error = __vfs_setxattr_noperm(dentry, name, value, size, flags);
      
      out:
   72         mutex_unlock(&inode->i_mutex);
              return error;
      }
      EXPORT_SYMBOL_GPL(vfs_setxattr);
      
      ssize_t
      xattr_getsecurity(struct inode *inode, const char *name, void *value,
                              size_t size)
      {
    8         void *buffer = NULL;
              ssize_t len;
      
    4         if (!value || !size) {
    4                 len = security_inode_getsecurity(inode, name, &buffer, false);
    6                 goto out_noalloc;
              }
      
    4         len = security_inode_getsecurity(inode, name, &buffer, true);
              if (len < 0)
                      return len;
    3         if (size < len) {
                      len = -ERANGE;
                      goto out;
              }
    2         memcpy(value, buffer, len);
      out:
    3         kfree(buffer);
      out_noalloc:
              return len;
      }
      EXPORT_SYMBOL_GPL(xattr_getsecurity);
      
      /*
       * vfs_getxattr_alloc - allocate memory, if necessary, before calling getxattr
       *
       * Allocate memory, if not already allocated, or re-allocate correct size,
       * before retrieving the extended attribute.
       *
       * Returns the result of alloc, if failed, or the getxattr operation.
       */
      ssize_t
      vfs_getxattr_alloc(struct dentry *dentry, const char *name, char **xattr_value,
                         size_t xattr_size, gfp_t flags)
      {
              struct inode *inode = dentry->d_inode;
              char *value = *xattr_value;
              int error;
      
              error = xattr_permission(inode, name, MAY_READ);
              if (error)
                      return error;
      
              if (!inode->i_op->getxattr)
                      return -EOPNOTSUPP;
      
              error = inode->i_op->getxattr(dentry, name, NULL, 0);
              if (error < 0)
                      return error;
      
              if (!value || (error > xattr_size)) {
                      value = krealloc(*xattr_value, error + 1, flags);
                      if (!value)
                              return -ENOMEM;
                      memset(value, 0, error + 1);
              }
      
              error = inode->i_op->getxattr(dentry, name, value, error);
              *xattr_value = value;
              return error;
      }
      
      /* Compare an extended attribute value with the given value */
      int vfs_xattr_cmp(struct dentry *dentry, const char *xattr_name,
                        const char *value, size_t size, gfp_t flags)
      {
              char *xattr_value = NULL;
              int rc;
      
              rc = vfs_getxattr_alloc(dentry, xattr_name, &xattr_value, 0, flags);
              if (rc < 0)
                      return rc;
      
              if ((rc != size) || (memcmp(xattr_value, value, rc) != 0))
                      rc = -EINVAL;
              else
                      rc = 0;
              kfree(xattr_value);
              return rc;
      }
      
      ssize_t
      vfs_getxattr(struct dentry *dentry, const char *name, void *value, size_t size)
      {
   28         struct inode *inode = dentry->d_inode;
              int error;
      
              error = xattr_permission(inode, name, MAY_READ);
              if (error)
                      return error;
      
   27         error = security_inode_getxattr(dentry, name);
              if (error)
   24                 return error;
      
   26         if (!strncmp(name, XATTR_SECURITY_PREFIX,
                                      XATTR_SECURITY_PREFIX_LEN)) {
    8                 const char *suffix = name + XATTR_SECURITY_PREFIX_LEN;
                      int ret = xattr_getsecurity(inode, suffix, value, size);
                      /*
                       * Only overwrite the return value if a security module
                       * is actually active.
                       */
                      if (ret == -EOPNOTSUPP)
                              goto nolsm;
    4                 return ret;
              }
      nolsm:
   20         if (inode->i_op->getxattr)
   19                 error = inode->i_op->getxattr(dentry, name, value, size);
              else
                      error = -EOPNOTSUPP;
      
              return error;
      }
      EXPORT_SYMBOL_GPL(vfs_getxattr);
      
      ssize_t
   25 vfs_listxattr(struct dentry *d, char *list, size_t size)
      {
              ssize_t error;
      
   25         error = security_inode_listxattr(d);
              if (error)
                      return error;
              error = -EOPNOTSUPP;
   25         if (d->d_inode->i_op->listxattr) {
   25                 error = d->d_inode->i_op->listxattr(d, list, size);
              } else {
    6                 error = security_inode_listsecurity(d->d_inode, list, size);
    3                 if (size && error > size)
                              error = -ERANGE;
              }
              return error;
      }
      EXPORT_SYMBOL_GPL(vfs_listxattr);
      
      int
      vfs_removexattr(struct dentry *dentry, const char *name)
      {
   19         struct inode *inode = dentry->d_inode;
              int error;
      
              if (!inode->i_op->removexattr)
                      return -EOPNOTSUPP;
      
   18         error = xattr_permission(inode, name, MAY_WRITE);
   20         if (error)
                      return error;
      
   16         mutex_lock(&inode->i_mutex);
              error = security_inode_removexattr(dentry, name);
              if (error)
                      goto out;
      
   17         error = inode->i_op->removexattr(dentry, name);
      
              if (!error) {
    6                 fsnotify_xattr(dentry);
                      evm_inode_post_removexattr(dentry, name);
              }
      
      out:
   18         mutex_unlock(&inode->i_mutex);
              return error;
      }
      EXPORT_SYMBOL_GPL(vfs_removexattr);
      
      
      /*
       * Extended attribute SET operations
       */
      static long
      setxattr(struct dentry *d, const char __user *name, const void __user *value,
               size_t size, int flags)
      {
              int error;
              void *kvalue = NULL;
              void *vvalue = NULL;        /* If non-NULL, we used vmalloc() */
              char kname[XATTR_NAME_MAX + 1];
      
  111         if (flags & ~(XATTR_CREATE|XATTR_REPLACE))
                      return -EINVAL;
      
  109         error = strncpy_from_user(kname, name, sizeof(kname));
              if (error == 0 || error == sizeof(kname))
                      error = -ERANGE;
  108         if (error < 0)
                      return error;
      
  100         if (size) {
   87                 if (size > XATTR_SIZE_MAX)
                              return -E2BIG;
   86                 kvalue = kmalloc(size, GFP_KERNEL | __GFP_NOWARN);
                      if (!kvalue) {
                              vvalue = vmalloc(size);
                              if (!vvalue)
                                      return -ENOMEM;
                              kvalue = vvalue;
                      }
   86                 if (copy_from_user(kvalue, value, size)) {
                              error = -EFAULT;
                              goto out;
                      }
   84                 if ((strcmp(kname, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
   62                     (strcmp(kname, XATTR_NAME_POSIX_ACL_DEFAULT) == 0))
   29                         posix_acl_fix_xattr_from_user(kvalue, size);
              }
      
   97         error = vfs_setxattr(d, kname, kvalue, size, flags);
      out:
   75         if (vvalue)
   85                 vfree(vvalue);
              else
   75                 kfree(kvalue);
              return error;
    8 }
      
      static int path_setxattr(const char __user *pathname,
                               const char __user *name, const void __user *value,
                               size_t size, int flags, unsigned int lookup_flags)
      {
              struct path path;
              int error;
      retry:
   50         error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
              if (error)
                      return error;
   39         error = mnt_want_write(path.mnt);
              if (!error) {
   38                 error = setxattr(path.dentry, name, value, size, flags);
                      mnt_drop_write(path.mnt);
              }
   26         path_put(&path);
              if (retry_estale(error, lookup_flags)) {
                      lookup_flags |= LOOKUP_REVAL;
                      goto retry;
              }
              return error;
      }
      
   23 SYSCALL_DEFINE5(setxattr, const char __user *, pathname,
                      const char __user *, name, const void __user *, value,
                      size_t, size, int, flags)
      {
              return path_setxattr(pathname, name, value, size, flags, LOOKUP_FOLLOW);
      }
      
   28 SYSCALL_DEFINE5(lsetxattr, const char __user *, pathname,
                      const char __user *, name, const void __user *, value,
                      size_t, size, int, flags)
      {
              return path_setxattr(pathname, name, value, size, flags, 0);
      }
      
   83 SYSCALL_DEFINE5(fsetxattr, int, fd, const char __user *, name,
                      const void __user *,value, size_t, size, int, flags)
      {
   79         struct fd f = fdget(fd);
              int error = -EBADF;
      
              if (!f.file)
                      return error;
   76         audit_file(f.file);
   76         error = mnt_want_write_file(f.file);
              if (!error) {
   73                 error = setxattr(f.file->f_path.dentry, name, value, size, flags);
                      mnt_drop_write_file(f.file);
              }
   62         fdput(f);
   62         return error;
      }
      
      /*
       * Extended attribute GET operations
       */
      static ssize_t
      getxattr(struct dentry *d, const char __user *name, void __user *value,
               size_t size)
      {
              ssize_t error;
              void *kvalue = NULL;
              void *vvalue = NULL;
              char kname[XATTR_NAME_MAX + 1];
      
   35         error = strncpy_from_user(kname, name, sizeof(kname));
              if (error == 0 || error == sizeof(kname))
                      error = -ERANGE;
   34         if (error < 0)
                      return error;
      
   28         if (size) {
   12                 if (size > XATTR_SIZE_MAX)
                              size = XATTR_SIZE_MAX;
                      kvalue = kzalloc(size, GFP_KERNEL | __GFP_NOWARN);
                      if (!kvalue) {
                              vvalue = vzalloc(size);
                              if (!vvalue)
                                      return -ENOMEM;
                              kvalue = vvalue;
                      }
              }
      
   28         error = vfs_getxattr(d, kname, kvalue, size);
              if (error > 0) {
   10                 if ((strcmp(kname, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
    5                     (strcmp(kname, XATTR_NAME_POSIX_ACL_DEFAULT) == 0))
    5                         posix_acl_fix_xattr_to_user(kvalue, error);
   10                 if (size && copy_to_user(value, kvalue, error))
                              error = -EFAULT;
   14         } else if (error == -ERANGE && size >= XATTR_SIZE_MAX) {
                      /* The file system tried to returned a value bigger
                         than XATTR_SIZE_MAX bytes. Not possible. */
                      error = -E2BIG;
              }
   23         if (vvalue)
   30                 vfree(vvalue);
              else
   23                 kfree(kvalue);
              return error;
      }
      
      static ssize_t path_getxattr(const char __user *pathname,
                                   const char __user *name, void __user *value,
                                   size_t size, unsigned int lookup_flags)
      {
              struct path path;
              ssize_t error;
      retry:
   25         error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
              if (error)
                      return error;
   16         error = getxattr(path.dentry, name, value, size);
              path_put(&path);
              if (retry_estale(error, lookup_flags)) {
                      lookup_flags |= LOOKUP_REVAL;
                      goto retry;
              }
              return error;
      }
      
   14 SYSCALL_DEFINE4(getxattr, const char __user *, pathname,
                      const char __user *, name, void __user *, value, size_t, size)
      {
              return path_getxattr(pathname, name, value, size, LOOKUP_FOLLOW);
      }
      
   11 SYSCALL_DEFINE4(lgetxattr, const char __user *, pathname,
                      const char __user *, name, void __user *, value, size_t, size)
      {
              return path_getxattr(pathname, name, value, size, 0);
      }
      
   21 SYSCALL_DEFINE4(fgetxattr, int, fd, const char __user *, name,
                      void __user *, value, size_t, size)
      {
              struct fd f = fdget(fd);
              ssize_t error = -EBADF;
      
              if (!f.file)
                      return error;
   19         audit_file(f.file);
   19         error = getxattr(f.file->f_path.dentry, name, value, size);
   14         fdput(f);
              return error;
      }
      
      /*
       * Extended attribute LIST operations
       */
      static ssize_t
      listxattr(struct dentry *d, char __user *list, size_t size)
      {
              ssize_t error;
              char *klist = NULL;
              char *vlist = NULL;        /* If non-NULL, we used vmalloc() */
      
   25         if (size) {
   13                 if (size > XATTR_LIST_MAX)
                              size = XATTR_LIST_MAX;
                      klist = kmalloc(size, __GFP_NOWARN | GFP_KERNEL);
                      if (!klist) {
                              vlist = vmalloc(size);
                              if (!vlist)
                                      return -ENOMEM;
                              klist = vlist;
                      }
              }
      
   25         error = vfs_listxattr(d, klist, size);
              if (error > 0) {
    7                 if (size && copy_to_user(list, klist, error))
                              error = -EFAULT;
    5         } else if (error == -ERANGE && size >= XATTR_LIST_MAX) {
                      /* The file system tried to returned a list bigger
                         than XATTR_LIST_MAX bytes. Not possible. */
                      error = -E2BIG;
              }
   11         if (vlist)
   22                 vfree(vlist);
              else
   22                 kfree(klist);
              return error;
      }
      
      static ssize_t path_listxattr(const char __user *pathname, char __user *list,
                                    size_t size, unsigned int lookup_flags)
      {
              struct path path;
              ssize_t error;
      retry:
   20         error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
              if (error)
                      return error;
   11         error = listxattr(path.dentry, list, size);
              path_put(&path);
              if (retry_estale(error, lookup_flags)) {
                      lookup_flags |= LOOKUP_REVAL;
                      goto retry;
              }
              return error;
      }
      
    8 SYSCALL_DEFINE3(listxattr, const char __user *, pathname, char __user *, list,
                      size_t, size)
      {
              return path_listxattr(pathname, list, size, LOOKUP_FOLLOW);
      }
      
   12 SYSCALL_DEFINE3(llistxattr, const char __user *, pathname, char __user *, list,
                      size_t, size)
      {
              return path_listxattr(pathname, list, size, 0);
      }
      
   18 SYSCALL_DEFINE3(flistxattr, int, fd, char __user *, list, size_t, size)
      {
              struct fd f = fdget(fd);
              ssize_t error = -EBADF;
      
              if (!f.file)
                      return error;
   14         audit_file(f.file);
   14         error = listxattr(f.file->f_path.dentry, list, size);
   11         fdput(f);
              return error;
      }
      
      /*
       * Extended attribute REMOVE operations
       */
      static long
      removexattr(struct dentry *d, const char __user *name)
      {
              int error;
              char kname[XATTR_NAME_MAX + 1];
      
   23         error = strncpy_from_user(kname, name, sizeof(kname));
              if (error == 0 || error == sizeof(kname))
                      error = -ERANGE;
   22         if (error < 0)
                      return error;
      
   27         return vfs_removexattr(d, kname);
    3 }
      
      static int path_removexattr(const char __user *pathname,
                                  const char __user *name, unsigned int lookup_flags)
      {
              struct path path;
              int error;
      retry:
   25         error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path);
              if (error)
                      return error;
   14         error = mnt_want_write(path.mnt);
              if (!error) {
   13                 error = removexattr(path.dentry, name);
                      mnt_drop_write(path.mnt);
              }
   15         path_put(&path);
              if (retry_estale(error, lookup_flags)) {
                      lookup_flags |= LOOKUP_REVAL;
                      goto retry;
              }
              return error;
      }
      
   15 SYSCALL_DEFINE2(removexattr, const char __user *, pathname,
                      const char __user *, name)
      {
              return path_removexattr(pathname, name, LOOKUP_FOLLOW);
      }
      
   10 SYSCALL_DEFINE2(lremovexattr, const char __user *, pathname,
                      const char __user *, name)
      {
              return path_removexattr(pathname, name, 0);
      }
      
   16 SYSCALL_DEFINE2(fremovexattr, int, fd, const char __user *, name)
      {
   16         struct fd f = fdget(fd);
              int error = -EBADF;
      
              if (!f.file)
                      return error;
   11         audit_file(f.file);
   11         error = mnt_want_write_file(f.file);
              if (!error) {
   10                 error = removexattr(f.file->f_path.dentry, name);
                      mnt_drop_write_file(f.file);
              }
   10         fdput(f);
   10         return error;
      }
      
      
      static const char *
      strcmp_prefix(const char *a, const char *a_prefix)
      {
  150         while (*a_prefix && *a == *a_prefix) {
  149                 a++;
                      a_prefix++;
              }
              return *a_prefix ? NULL : a;
      }
      
      /*
       * In order to implement different sets of xattr operations for each xattr
       * prefix with the generic xattr API, a filesystem should create a
       * null-terminated array of struct xattr_handler (one for each prefix) and
       * hang a pointer to it off of the s_xattr field of the superblock.
       *
       * The generic_fooxattr() functions will use this list to dispatch xattr
       * operations to the correct xattr_handler.
       */
      #define for_each_xattr_handler(handlers, handler)                \
                      for ((handler) = *(handlers)++;                        \
                              (handler) != NULL;                        \
                              (handler) = *(handlers)++)
      
      /*
       * Find the xattr_handler with the matching prefix.
       */
      static const struct xattr_handler *
      xattr_resolve_name(const struct xattr_handler **handlers, const char **name)
      {
              const struct xattr_handler *handler;
      
  150         if (!*name)
  149                 return NULL;
      
  150         for_each_xattr_handler(handlers, handler) {
  150                 const char *n = strcmp_prefix(*name, handler->prefix);
  145                 if (n) {
  145                         *name = n;
                              break;
                      }
              }
              return handler;
      }
      
      /*
       * Find the handler for the prefix and dispatch its get() operation.
       */
      ssize_t
      generic_getxattr(struct dentry *dentry, const char *name, void *buffer, size_t size)
      {
              const struct xattr_handler *handler;
      
   93         handler = xattr_resolve_name(dentry->d_sb->s_xattr, &name);
              if (!handler)
                      return -EOPNOTSUPP;
   93         return handler->get(handler, dentry, name, buffer, size);
      }
      
      /*
       * Combine the results of the list() operation from every xattr_handler in the
       * list.
       */
      ssize_t
      generic_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
      {
              const struct xattr_handler *handler, **handlers = dentry->d_sb->s_xattr;
              unsigned int size = 0;
      
              if (!buffer) {
                      for_each_xattr_handler(handlers, handler) {
                              size += handler->list(handler, dentry, NULL, 0,
                                                    NULL, 0);
                      }
              } else {
                      char *buf = buffer;
      
                      for_each_xattr_handler(handlers, handler) {
                              size = handler->list(handler, dentry, buf, buffer_size,
                                                   NULL, 0);
                              if (size > buffer_size)
                                      return -ERANGE;
                              buf += size;
                              buffer_size -= size;
                      }
                      size = buf - buffer;
              }
              return size;
      }
      
      /*
       * Find the handler for the prefix and dispatch its set() operation.
       */
      int
      generic_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags)
      {
              const struct xattr_handler *handler;
      
   51         if (size == 0)
                      value = "";  /* empty EA, do not remove */
   51         handler = xattr_resolve_name(dentry->d_sb->s_xattr, &name);
              if (!handler)
                      return -EOPNOTSUPP;
   50         return handler->set(handler, dentry, name, value, size, flags);
      }
      
      /*
       * Find the handler for the prefix and dispatch its set() operation to remove
       * any associated extended attribute.
       */
      int
      generic_removexattr(struct dentry *dentry, const char *name)
      {
              const struct xattr_handler *handler;
      
   12         handler = xattr_resolve_name(dentry->d_sb->s_xattr, &name);
              if (!handler)
                      return -EOPNOTSUPP;
   11         return handler->set(handler, dentry, name, NULL, 0, XATTR_REPLACE);
      }
      
      EXPORT_SYMBOL(generic_getxattr);
      EXPORT_SYMBOL(generic_listxattr);
      EXPORT_SYMBOL(generic_setxattr);
      EXPORT_SYMBOL(generic_removexattr);
      
      /**
       * xattr_full_name  -  Compute full attribute name from suffix
       *
       * @handler:        handler of the xattr_handler operation
       * @name:        name passed to the xattr_handler operation
       *
       * The get and set xattr handler operations are called with the remainder of
       * the attribute name after skipping the handler's prefix: for example, "foo"
       * is passed to the get operation of a handler with prefix "user." to get
       * attribute "user.foo".  The full name is still "there" in the name though.
       *
       * Note: the list xattr handler operation when called from the vfs is passed a
       * NULL name; some file systems use this operation internally, with varying
       * semantics.
       */
      const char *xattr_full_name(const struct xattr_handler *handler,
                                  const char *name)
      {
              size_t prefix_len = strlen(handler->prefix);
      
              return name - prefix_len;
      }
      EXPORT_SYMBOL(xattr_full_name);
      
      /*
       * Allocate new xattr and copy in the value; but leave the name to callers.
       */
      struct simple_xattr *simple_xattr_alloc(const void *value, size_t size)
      {
              struct simple_xattr *new_xattr;
              size_t len;
      
              /* wrap around? */
  262         len = sizeof(*new_xattr) + size;
              if (len < sizeof(*new_xattr))
                      return NULL;
      
  262         new_xattr = kmalloc(len, GFP_KERNEL);
              if (!new_xattr)
                      return NULL;
      
  262         new_xattr->size = size;
              memcpy(new_xattr->value, value, size);
  262         return new_xattr;
      }
      
      /*
       * xattr GET operation for in-memory/pseudo filesystems
       */
      int simple_xattr_get(struct simple_xattrs *xattrs, const char *name,
                           void *buffer, size_t size)
      {
              struct simple_xattr *xattr;
              int ret = -ENODATA;
      
  304         spin_lock(&xattrs->lock);
  222         list_for_each_entry(xattr, &xattrs->head, list) {
  222                 if (strcmp(name, xattr->name))
                              continue;
      
                      ret = xattr->size;
                      if (buffer) {
                              if (size < xattr->size)
                                      ret = -ERANGE;
                              else
                                      memcpy(buffer, xattr->value, xattr->size);
                      }
                      break;
              }
  304         spin_unlock(&xattrs->lock);
              return ret;
      }
      
      static int __simple_xattr_set(struct simple_xattrs *xattrs, const char *name,
                                    const void *value, size_t size, int flags)
      {
              struct simple_xattr *xattr;
              struct simple_xattr *new_xattr = NULL;
              int err = 0;
      
              /* value == NULL means remove */
    7         if (value) {
    6                 new_xattr = simple_xattr_alloc(value, size);
                      if (!new_xattr)
                              return -ENOMEM;
      
    6                 new_xattr->name = kstrdup(name, GFP_KERNEL);
                      if (!new_xattr->name) {
                              kfree(new_xattr);
                              return -ENOMEM;
                      }
              }
      
    7         spin_lock(&xattrs->lock);
              list_for_each_entry(xattr, &xattrs->head, list) {
    5                 if (!strcmp(name, xattr->name)) {
    5                         if (flags & XATTR_CREATE) {
                                      xattr = new_xattr;
                                      err = -EEXIST;
    4                         } else if (new_xattr) {
    4                                 list_replace(&xattr->list, &new_xattr->list);
                              } else {
                                      list_del(&xattr->list);
                              }
                              goto out;
                      }
              }
    2         if (flags & XATTR_REPLACE) {
                      xattr = new_xattr;
                      err = -ENODATA;
              } else {
    1                 list_add(&new_xattr->list, &xattrs->head);
                      xattr = NULL;
              }
      out:
    6         spin_unlock(&xattrs->lock);
              if (xattr) {
    5                 kfree(xattr->name);
    7                 kfree(xattr);
              }
              return err;
      
      }
      
      /**
       * simple_xattr_set - xattr SET operation for in-memory/pseudo filesystems
       * @xattrs: target simple_xattr list
       * @name: name of the new extended attribute
       * @value: value of the new xattr. If %NULL, will remove the attribute
       * @size: size of the new xattr
       * @flags: %XATTR_{CREATE|REPLACE}
       *
       * %XATTR_CREATE is set, the xattr shouldn't exist already; otherwise fails
       * with -EEXIST.  If %XATTR_REPLACE is set, the xattr should exist;
       * otherwise, fails with -ENODATA.
       *
       * Returns 0 on success, -errno on failure.
       */
      int simple_xattr_set(struct simple_xattrs *xattrs, const char *name,
                           const void *value, size_t size, int flags)
      {
    6         if (size == 0)
                      value = ""; /* empty EA, do not remove */
    6         return __simple_xattr_set(xattrs, name, value, size, flags);
      }
      
      /*
       * xattr REMOVE operation for in-memory/pseudo filesystems
       */
      int simple_xattr_remove(struct simple_xattrs *xattrs, const char *name)
      {
    1         return __simple_xattr_set(xattrs, name, NULL, 0, XATTR_REPLACE);
      }
      
      static bool xattr_is_trusted(const char *name)
      {
    7         return !strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN);
      }
      
      /*
       * xattr LIST operation for in-memory/pseudo filesystems
       */
      ssize_t simple_xattr_list(struct simple_xattrs *xattrs, char *buffer,
                                size_t size)
      {
    8         bool trusted = capable(CAP_SYS_ADMIN);
              struct simple_xattr *xattr;
              size_t used = 0;
      
              spin_lock(&xattrs->lock);
    6         list_for_each_entry(xattr, &xattrs->head, list) {
                      size_t len;
      
                      /* skip "trusted." attributes for unprivileged callers */
    7                 if (!trusted && xattr_is_trusted(xattr->name))
                              continue;
      
    7                 len = strlen(xattr->name) + 1;
                      used += len;
                      if (buffer) {
    2                         if (size < used) {
                                      used = -ERANGE;
                                      break;
                              }
    1                         memcpy(buffer, xattr->name, len);
                              buffer += len;
                      }
              }
    8         spin_unlock(&xattrs->lock);
      
              return used;
      }
      
      /*
       * Adds an extended attribute to the list
       */
      void simple_xattr_list_add(struct simple_xattrs *xattrs,
                                 struct simple_xattr *new_xattr)
      {
  256         spin_lock(&xattrs->lock);
  256         list_add(&new_xattr->list, &xattrs->head);
  256         spin_unlock(&xattrs->lock);
      }
      /*
       * linux/kernel/capability.c
       *
       * Copyright (C) 1997  Andrew Main <zefram@fysh.org>
       *
       * Integrated into 2.1.97+,  Andrew G. Morgan <morgan@kernel.org>
       * 30 May 2002:        Cleanup, Robert M. Love <rml@tech9.net>
       */
      
      #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
      
      #include <linux/audit.h>
      #include <linux/capability.h>
      #include <linux/mm.h>
      #include <linux/export.h>
      #include <linux/security.h>
      #include <linux/syscalls.h>
      #include <linux/pid_namespace.h>
      #include <linux/user_namespace.h>
      #include <asm/uaccess.h>
      
      /*
       * Leveraged for setting/resetting capabilities
       */
      
      const kernel_cap_t __cap_empty_set = CAP_EMPTY_SET;
      EXPORT_SYMBOL(__cap_empty_set);
      
      int file_caps_enabled = 1;
      
      static int __init file_caps_disable(char *str)
      {
              file_caps_enabled = 0;
              return 1;
      }
      __setup("no_file_caps", file_caps_disable);
      
      #ifdef CONFIG_MULTIUSER
      /*
       * More recent versions of libcap are available from:
       *
       *   http://www.kernel.org/pub/linux/libs/security/linux-privs/
       */
      
      static void warn_legacy_capability_use(void)
      {
              char name[sizeof(current->comm)];
      
   11         pr_info_once("warning: `%s' uses 32-bit capabilities (legacy support in use)\n",
                           get_task_comm(name, current));
      }
      
      /*
       * Version 2 capabilities worked fine, but the linux/capability.h file
       * that accompanied their introduction encouraged their use without
       * the necessary user-space source code changes. As such, we have
       * created a version 3 with equivalent functionality to version 2, but
       * with a header change to protect legacy source code from using
       * version 2 when it wanted to use version 1. If your system has code
       * that trips the following warning, it is using version 2 specific
       * capabilities and may be doing so insecurely.
       *
       * The remedy is to either upgrade your version of libcap (to 2.10+,
       * if the application is linked against it), or recompile your
       * application with modern kernel headers and this warning will go
       * away.
       */
      
      static void warn_deprecated_v2(void)
      {
              char name[sizeof(current->comm)];
      
    9         pr_info_once("warning: `%s' uses deprecated v2 capabilities in a way that may be insecure\n",
                           get_task_comm(name, current));
      }
      
      /*
       * Version check. Return the number of u32s in each capability flag
       * array, or a negative value on error.
       */
      static int cap_validate_magic(cap_user_header_t header, unsigned *tocopy)
      {
              __u32 version;
      
   52         if (get_user(version, &header->version))
                      return -EFAULT;
      
   42         switch (version) {
              case _LINUX_CAPABILITY_VERSION_1:
   11                 warn_legacy_capability_use();
                      *tocopy = _LINUX_CAPABILITY_U32S_1;
                      break;
              case _LINUX_CAPABILITY_VERSION_2:
    9                 warn_deprecated_v2();
                      /*
                       * fall through - v3 is otherwise equivalent to v2.
                       */
              case _LINUX_CAPABILITY_VERSION_3:
   24                 *tocopy = _LINUX_CAPABILITY_U32S_3;
                      break;
              default:
   52                 if (put_user((u32)_KERNEL_CAPABILITY_VERSION, &header->version))
                              return -EFAULT;
                      return -EINVAL;
              }
      
              return 0;
      }
      
      /*
       * The only thing that can change the capabilities of the current
       * process is the current process. As such, we can't be in this code
       * at the same time as we are in the process of setting capabilities
       * in this process. The net result is that we can limit our use of
       * locks to when we are reading the caps of another process.
       */
      static inline int cap_get_target_pid(pid_t pid, kernel_cap_t *pEp,
                                           kernel_cap_t *pIp, kernel_cap_t *pPp)
      {
              int ret;
      
   10         if (pid && (pid != task_pid_vnr(current))) {
                      struct task_struct *target;
      
    3                 rcu_read_lock();
      
    3                 target = find_task_by_vpid(pid);
                      if (!target)
                              ret = -ESRCH;
                      else
    3                         ret = security_capget(target, pEp, pIp, pPp);
      
    2                 rcu_read_unlock();
              } else
    7                 ret = security_capget(current, pEp, pIp, pPp);
      
              return ret;
      }
      
      /**
       * sys_capget - get the capabilities of a given process.
       * @header: pointer to struct that contains capability version and
       *        target pid data
       * @dataptr: pointer to struct that contains the effective, permitted,
       *        and inheritable capabilities that are returned
       *
       * Returns 0 on success and < 0 on error.
       */
   19 SYSCALL_DEFINE2(capget, cap_user_header_t, header, cap_user_data_t, dataptr)
      {
              int ret = 0;
              pid_t pid;
              unsigned tocopy;
              kernel_cap_t pE, pI, pP;
      
              ret = cap_validate_magic(header, &tocopy);
   14         if ((dataptr == NULL) || (ret != 0))
   15                 return ((dataptr == NULL) && (ret == -EINVAL)) ? 0 : ret;
      
   12         if (get_user(pid, &header->pid))
                      return -EFAULT;
      
   11         if (pid < 0)
                      return -EINVAL;
      
   10         ret = cap_get_target_pid(pid, &pE, &pI, &pP);
    8         if (!ret) {
                      struct __user_cap_data_struct kdata[_KERNEL_CAPABILITY_U32S];
                      unsigned i;
      
    8                 for (i = 0; i < tocopy; i++) {
    8                         kdata[i].effective = pE.cap[i];
                              kdata[i].permitted = pP.cap[i];
                              kdata[i].inheritable = pI.cap[i];
                      }
      
                      /*
                       * Note, in the case, tocopy < _KERNEL_CAPABILITY_U32S,
                       * we silently drop the upper capabilities here. This
                       * has the effect of making older libcap
                       * implementations implicitly drop upper capability
                       * bits when they perform a: capget/modify/capset
                       * sequence.
                       *
                       * This behavior is considered fail-safe
                       * behavior. Upgrading the application to a newer
                       * version of libcap will enable access to the newer
                       * capabilities.
                       *
                       * An alternative would be to return an error here
                       * (-ERANGE), but that causes legacy applications to
                       * unexpectedly fail; the capget/modify/capset aborts
                       * before modification is attempted and the application
                       * fails.
                       */
    7                 if (copy_to_user(dataptr, kdata, tocopy
                                       * sizeof(struct __user_cap_data_struct))) {
    2                         return -EFAULT;
                      }
              }
      
    4         return ret;
      }
      
      /**
       * sys_capset - set capabilities for a process or (*) a group of processes
       * @header: pointer to struct that contains capability version and
       *        target pid data
       * @data: pointer to struct that contains the effective, permitted,
       *        and inheritable capabilities
       *
       * Set capabilities for the current process only.  The ability to any other
       * process(es) has been deprecated and removed.
       *
       * The restrictions on setting capabilities are specified as:
       *
       * I: any raised capabilities must be a subset of the old permitted
       * P: any raised capabilities must be a subset of the old permitted
       * E: must be set to a subset of new permitted
       *
       * Returns 0 on success and < 0 on error.
       */
   33 SYSCALL_DEFINE2(capset, cap_user_header_t, header, const cap_user_data_t, data)
      {
              struct __user_cap_data_struct kdata[_KERNEL_CAPABILITY_U32S];
              unsigned i, tocopy, copybytes;
              kernel_cap_t inheritable, permitted, effective;
              struct cred *new;
              int ret;
              pid_t pid;
      
              ret = cap_validate_magic(header, &tocopy);
              if (ret != 0)
   31                 return ret;
      
   22         if (get_user(pid, &header->pid))
                      return -EFAULT;
      
              /* may only affect current now */
   22         if (pid != 0 && pid != task_pid_vnr(current))
                      return -EPERM;
      
   21         copybytes = tocopy * sizeof(struct __user_cap_data_struct);
              if (copybytes > sizeof(kdata))
                      return -EFAULT;
      
   21         if (copy_from_user(&kdata, data, copybytes))
                      return -EFAULT;
      
   19         for (i = 0; i < tocopy; i++) {
   19                 effective.cap[i] = kdata[i].effective;
                      permitted.cap[i] = kdata[i].permitted;
                      inheritable.cap[i] = kdata[i].inheritable;
              }
   19         while (i < _KERNEL_CAPABILITY_U32S) {
    7                 effective.cap[i] = 0;
                      permitted.cap[i] = 0;
                      inheritable.cap[i] = 0;
                      i++;
              }
      
   19         effective.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK;
              permitted.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK;
              inheritable.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK;
      
              new = prepare_creds();
              if (!new)
                      return -ENOMEM;
      
   17         ret = security_capset(new, current_cred(),
                                    &effective, &inheritable, &permitted);
              if (ret < 0)
                      goto error;
      
    9         audit_log_capset(new, current_cred());
      
    9         return commit_creds(new);
      
      error:
    8         abort_creds(new);
              return ret;
      }
      
      /**
       * has_ns_capability - Does a task have a capability in a specific user ns
       * @t: The task in question
       * @ns: target user namespace
       * @cap: The capability to be tested for
       *
       * Return true if the specified task has the given superior capability
       * currently in effect to the specified user namespace, false if not.
       *
       * Note that this does not set PF_SUPERPRIV on the task.
       */
      bool has_ns_capability(struct task_struct *t,
                             struct user_namespace *ns, int cap)
      {
              int ret;
      
    2         rcu_read_lock();
    2         ret = security_capable(__task_cred(t), ns, cap);
    2         rcu_read_unlock();
      
              return (ret == 0);
      }
      
      /**
       * has_capability - Does a task have a capability in init_user_ns
       * @t: The task in question
       * @cap: The capability to be tested for
       *
       * Return true if the specified task has the given superior capability
       * currently in effect to the initial user namespace, false if not.
       *
       * Note that this does not set PF_SUPERPRIV on the task.
       */
      bool has_capability(struct task_struct *t, int cap)
      {
              return has_ns_capability(t, &init_user_ns, cap);
      }
      
      /**
       * has_ns_capability_noaudit - Does a task have a capability (unaudited)
       * in a specific user ns.
       * @t: The task in question
       * @ns: target user namespace
       * @cap: The capability to be tested for
       *
       * Return true if the specified task has the given superior capability
       * currently in effect to the specified user namespace, false if not.
       * Do not write an audit message for the check.
       *
       * Note that this does not set PF_SUPERPRIV on the task.
       */
      bool has_ns_capability_noaudit(struct task_struct *t,
                                     struct user_namespace *ns, int cap)
      {
              int ret;
      
   20         rcu_read_lock();
   20         ret = security_capable_noaudit(__task_cred(t), ns, cap);
   20         rcu_read_unlock();
      
              return (ret == 0);
      }
      
      /**
       * has_capability_noaudit - Does a task have a capability (unaudited) in the
       * initial user ns
       * @t: The task in question
       * @cap: The capability to be tested for
       *
       * Return true if the specified task has the given superior capability
       * currently in effect to init_user_ns, false if not.  Don't write an
       * audit message for the check.
       *
       * Note that this does not set PF_SUPERPRIV on the task.
       */
      bool has_capability_noaudit(struct task_struct *t, int cap)
      {
   18         return has_ns_capability_noaudit(t, &init_user_ns, cap);
      }
      
      static bool ns_capable_common(struct user_namespace *ns, int cap, bool audit)
      {
              int capable;
      
 3445         if (unlikely(!cap_valid(cap))) {
                      pr_crit("capable() called with invalid cap=%u\n", cap);
                      BUG();
              }
      
 3444         capable = audit ? security_capable(current_cred(), ns, cap) :
                                security_capable_noaudit(current_cred(), ns, cap);
 3419         if (capable == 0) {
 3086                 current->flags |= PF_SUPERPRIV;
 3086                 return true;
              }
              return false;
      }
      
      /**
       * ns_capable - Determine if the current task has a superior capability in effect
       * @ns:  The usernamespace we want the capability in
       * @cap: The capability to be tested for
       *
       * Return true if the current task has the given superior capability currently
       * available for use, false if not.
       *
       * This sets PF_SUPERPRIV on the task if the capability is available on the
       * assumption that it's about to be used.
       */
      bool ns_capable(struct user_namespace *ns, int cap)
      {
 2745         return ns_capable_common(ns, cap, true);
      }
      EXPORT_SYMBOL(ns_capable);
      
      /**
       * ns_capable_noaudit - Determine if the current task has a superior capability
       * (unaudited) in effect
       * @ns:  The usernamespace we want the capability in
       * @cap: The capability to be tested for
       *
       * Return true if the current task has the given superior capability currently
       * available for use, false if not.
       *
       * This sets PF_SUPERPRIV on the task if the capability is available on the
       * assumption that it's about to be used.
       */
      bool ns_capable_noaudit(struct user_namespace *ns, int cap)
      {
              return ns_capable_common(ns, cap, false);
      }
      EXPORT_SYMBOL(ns_capable_noaudit);
      
      /**
       * capable - Determine if the current task has a superior capability in effect
       * @cap: The capability to be tested for
       *
       * Return true if the current task has the given superior capability currently
       * available for use, false if not.
       *
       * This sets PF_SUPERPRIV on the task if the capability is available on the
       * assumption that it's about to be used.
       */
      bool capable(int cap)
      {
  340         return ns_capable(&init_user_ns, cap);
      }
      EXPORT_SYMBOL(capable);
      #endif /* CONFIG_MULTIUSER */
      
      /**
       * file_ns_capable - Determine if the file's opener had a capability in effect
       * @file:  The file we want to check
       * @ns:  The usernamespace we want the capability in
       * @cap: The capability to be tested for
       *
       * Return true if task that opened the file had a capability in effect
       * when the file was opened.
       *
       * This does not set PF_SUPERPRIV because the caller may not
       * actually be privileged.
       */
      bool file_ns_capable(const struct file *file, struct user_namespace *ns,
                           int cap)
      {
  931         if (WARN_ON_ONCE(!cap_valid(cap)))
                      return false;
      
  931         if (security_capable(file->f_cred, ns, cap) == 0)
                      return true;
      
              return false;
      }
      EXPORT_SYMBOL(file_ns_capable);
      
      /**
       * privileged_wrt_inode_uidgid - Do capabilities in the namespace work over the inode?
       * @ns: The user namespace in question
       * @inode: The inode in question
       *
       * Return true if the inode uid and gid are within the namespace.
       */
      bool privileged_wrt_inode_uidgid(struct user_namespace *ns, const struct inode *inode)
  787 {
  787         return kuid_has_mapping(ns, inode->i_uid) &&
                      kgid_has_mapping(ns, inode->i_gid);
  787 }
      
      /**
       * capable_wrt_inode_uidgid - Check nsown_capable and uid and gid mapped
       * @inode: The inode in question
       * @cap: The capability in question
       *
       * Return true if the current task has the given capability targeted at
       * its own user namespace and that the given inode's uid and gid are
       * mapped into the current user namespace.
       */
      bool capable_wrt_inode_uidgid(const struct inode *inode, int cap)
      {
  800         struct user_namespace *ns = current_user_ns();
      
  795         return ns_capable(ns, cap) && privileged_wrt_inode_uidgid(ns, inode);
      }
      EXPORT_SYMBOL(capable_wrt_inode_uidgid);
      
      /**
       * ptracer_capable - Determine if the ptracer holds CAP_SYS_PTRACE in the namespace
       * @tsk: The task that may be ptraced
       * @ns: The user namespace to search for CAP_SYS_PTRACE in
       *
       * Return true if the task that is ptracing the current task had CAP_SYS_PTRACE
       * in the specified user namespace.
       */
      bool ptracer_capable(struct task_struct *tsk, struct user_namespace *ns)
      {
              int ret = 0;  /* An absent tracer adds no restrictions */
              const struct cred *cred;
    2         rcu_read_lock();
    2         cred = rcu_dereference(tsk->ptracer_cred);
    2         if (cred)
                      ret = security_capable_noaudit(cred, ns, CAP_SYS_PTRACE);
    2         rcu_read_unlock();
              return (ret == 0);
      }
      /*
       *  include/linux/eventpoll.h ( Efficient event polling implementation )
       *  Copyright (C) 2001,...,2006         Davide Libenzi
       *
       *  This program is free software; you can redistribute it and/or modify
       *  it under the terms of the GNU General Public License as published by
       *  the Free Software Foundation; either version 2 of the License, or
       *  (at your option) any later version.
       *
       *  Davide Libenzi <davidel@xmailserver.org>
       *
       */
      #ifndef _LINUX_EVENTPOLL_H
      #define _LINUX_EVENTPOLL_H
      
      #include <uapi/linux/eventpoll.h>
      
      
      /* Forward declarations to avoid compiler errors */
      struct file;
      
      
      #ifdef CONFIG_EPOLL
      
      /* Used to initialize the epoll bits inside the "struct file" */
      static inline void eventpoll_init_file(struct file *file)
      {
              INIT_LIST_HEAD(&file->f_ep_links);
              INIT_LIST_HEAD(&file->f_tfile_llink);
      }
      
      
      /* Used to release the epoll bits inside the "struct file" */
      void eventpoll_release_file(struct file *file);
      
      /*
       * This is called from inside fs/file_table.c:__fput() to unlink files
       * from the eventpoll interface. We need to have this facility to cleanup
       * correctly files that are closed without being removed from the eventpoll
       * interface.
       */
      static inline void eventpoll_release(struct file *file)
      {
      
              /*
               * Fast check to avoid the get/release of the semaphore. Since
               * we're doing this outside the semaphore lock, it might return
               * false negatives, but we don't care. It'll help in 99.99% of cases
               * to avoid the semaphore lock. False positives simply cannot happen
               * because the file in on the way to be removed and nobody ( but
               * eventpoll ) has still a reference to this file.
               */
  873         if (likely(list_empty(&file->f_ep_links)))
                      return;
      
              /*
               * The file is being closed while it is still linked to an epoll
               * descriptor. We need to handle this by correctly unlinking it
               * from its containers.
               */
    5         eventpoll_release_file(file);
      }
      
      #else
      
      static inline void eventpoll_init_file(struct file *file) {}
      static inline void eventpoll_release(struct file *file) {}
      
      #endif
      
      #endif /* #ifndef _LINUX_EVENTPOLL_H */
      /*
              kmod, the new module loader (replaces kerneld)
              Kirk Petersen
      
              Reorganized not to be a daemon by Adam Richter, with guidance
              from Greg Zornetzer.
      
              Modified to avoid chroot and file sharing problems.
              Mikael Pettersson
      
              Limit the concurrent number of kmod modprobes to catch loops from
              "modprobe needs a service that is in a module".
              Keith Owens <kaos@ocs.com.au> December 1999
      
              Unblock all signals when we exec a usermode process.
              Shuu Yamaguchi <shuu@wondernetworkresources.com> December 2000
      
              call_usermodehelper wait flag, and remove exec_usermodehelper.
              Rusty Russell <rusty@rustcorp.com.au>  Jan 2003
      */
      #include <linux/module.h>
      #include <linux/sched.h>
      #include <linux/syscalls.h>
      #include <linux/unistd.h>
      #include <linux/kmod.h>
      #include <linux/slab.h>
      #include <linux/completion.h>
      #include <linux/cred.h>
      #include <linux/file.h>
      #include <linux/fdtable.h>
      #include <linux/workqueue.h>
      #include <linux/security.h>
      #include <linux/mount.h>
      #include <linux/kernel.h>
      #include <linux/init.h>
      #include <linux/resource.h>
      #include <linux/notifier.h>
      #include <linux/suspend.h>
      #include <linux/rwsem.h>
      #include <linux/ptrace.h>
      #include <linux/async.h>
      #include <asm/uaccess.h>
      
      #include <trace/events/module.h>
      
      extern int max_threads;
      
      #define CAP_BSET        (void *)1
      #define CAP_PI                (void *)2
      
      static kernel_cap_t usermodehelper_bset = CAP_FULL_SET;
      static kernel_cap_t usermodehelper_inheritable = CAP_FULL_SET;
      static DEFINE_SPINLOCK(umh_sysctl_lock);
      static DECLARE_RWSEM(umhelper_sem);
      
      #ifdef CONFIG_MODULES
      
      /*
              modprobe_path is set via /proc/sys.
      */
      char modprobe_path[KMOD_PATH_LEN] = "/sbin/modprobe";
      
      static void free_modprobe_argv(struct subprocess_info *info)
      {
  235         kfree(info->argv[3]); /* check call_modprobe() */
              kfree(info->argv);
      }
      
      static int call_modprobe(char *module_name, int wait)
      {
              struct subprocess_info *info;
              static char *envp[] = {
                      "HOME=/",
                      "TERM=linux",
                      "PATH=/sbin:/usr/sbin:/bin:/usr/bin",
                      NULL
              };
      
  286         char **argv = kmalloc(sizeof(char *[5]), GFP_KERNEL);
              if (!argv)
                      goto out;
      
  283         module_name = kstrdup(module_name, GFP_KERNEL);
              if (!module_name)
                      goto free_argv;
      
  277         argv[0] = modprobe_path;
              argv[1] = "-q";
              argv[2] = "--";
              argv[3] = module_name;        /* check free_modprobe_argv() */
              argv[4] = NULL;
      
              info = call_usermodehelper_setup(modprobe_path, argv, envp, GFP_KERNEL,
                                               NULL, free_modprobe_argv, NULL);
              if (!info)
                      goto free_module_name;
      
  270         return call_usermodehelper_exec(info, wait | UMH_KILLABLE);
      
      free_module_name:
              kfree(module_name);
      free_argv:
              kfree(argv);
      out:
              return -ENOMEM;
      }
      
      /**
       * __request_module - try to load a kernel module
       * @wait: wait (or not) for the operation to complete
       * @fmt: printf style format string for the name of the module
       * @...: arguments as specified in the format string
       *
       * Load a module using the user mode module loader. The function returns
       * zero on success or a negative errno code or positive exit code from
       * "modprobe" on failure. Note that a successful module load does not mean
       * the module did not then unload and exit on an error of its own. Callers
       * must check that the service they requested is now available not blindly
       * invoke it.
       *
       * If module auto-loading support is disabled then this function
       * becomes a no-operation.
       */
      int __request_module(bool wait, const char *fmt, ...)
      {
              va_list args;
              char module_name[MODULE_NAME_LEN];
              unsigned int max_modprobes;
              int ret;
              static atomic_t kmod_concurrent = ATOMIC_INIT(0);
      #define MAX_KMOD_CONCURRENT 50        /* Completely arbitrary value - KAO */
              static int kmod_loop_msg;
      
              /*
               * We don't allow synchronous module loading from async.  Module
               * init may invoke async_synchronize_full() which will end up
               * waiting for this task which already is waiting for the module
               * loading to complete, leading to a deadlock.
               */
  303         WARN_ON_ONCE(wait && current_is_async());
      
  316         if (!modprobe_path[0])
                      return 0;
      
  303         va_start(args, fmt);
              ret = vsnprintf(module_name, MODULE_NAME_LEN, fmt, args);
              va_end(args);
              if (ret >= MODULE_NAME_LEN)
                      return -ENAMETOOLONG;
      
  301         ret = security_kernel_module_request(module_name);
              if (ret)
                      return ret;
      
              /* If modprobe needs a service that is in a module, we get a recursive
               * loop.  Limit the number of running kmod threads to max_threads/2 or
               * MAX_KMOD_CONCURRENT, whichever is the smaller.  A cleaner method
               * would be to run the parents of this process, counting how many times
               * kmod was invoked.  That would mean accessing the internals of the
               * process tables to get the command line, proc_pid_cmdline is static
               * and it is not worth changing the proc code just to handle this case. 
               * KAO.
               *
               * "trace the ppid" is simple, but will fail if someone's
               * parent exits.  I think this is as good as it gets. --RR
               */
  287         max_modprobes = min(max_threads/2, MAX_KMOD_CONCURRENT);
              atomic_inc(&kmod_concurrent);
              if (atomic_read(&kmod_concurrent) > max_modprobes) {
                      /* We may be blaming an innocent here, but unlikely */
                      if (kmod_loop_msg < 5) {
                              printk(KERN_ERR
                                     "request_module: runaway loop modprobe %s\n",
                                     module_name);
                              kmod_loop_msg++;
                      }
                      atomic_dec(&kmod_concurrent);
                      return -ENOMEM;
              }
      
  287         trace_module_request(module_name, wait, _RET_IP_);
      
  286         ret = call_modprobe(module_name, wait ? UMH_WAIT_PROC : UMH_WAIT_EXEC);
      
  235         atomic_dec(&kmod_concurrent);
              return ret;
      }
      EXPORT_SYMBOL(__request_module);
      #endif /* CONFIG_MODULES */
      
      static void call_usermodehelper_freeinfo(struct subprocess_info *info)
      {
  241         if (info->cleanup)
  241                 (*info->cleanup)(info);
  241         kfree(info);
      }
      
      static void umh_complete(struct subprocess_info *sub_info)
      {
              struct completion *comp = xchg(&sub_info->complete, NULL);
              /*
               * See call_usermodehelper_exec(). If xchg() returns NULL
               * we own sub_info, the UMH_KILLABLE caller has gone away
               * or the caller used UMH_NO_WAIT.
               */
              if (comp)
                      complete(comp);
              else
                      call_usermodehelper_freeinfo(sub_info);
      }
      
      /*
       * This is the task which runs the usermode application
       */
      static int call_usermodehelper_exec_async(void *data)
      {
              struct subprocess_info *sub_info = data;
              struct cred *new;
              int retval;
      
              spin_lock_irq(&current->sighand->siglock);
              flush_signal_handlers(current, 1);
              spin_unlock_irq(&current->sighand->siglock);
      
              /*
               * Our parent (unbound workqueue) runs with elevated scheduling
               * priority. Avoid propagating that into the userspace child.
               */
              set_user_nice(current, 0);
      
              retval = -ENOMEM;
              new = prepare_kernel_cred(current);
              if (!new)
                      goto out;
      
              spin_lock(&umh_sysctl_lock);
              new->cap_bset = cap_intersect(usermodehelper_bset, new->cap_bset);
              new->cap_inheritable = cap_intersect(usermodehelper_inheritable,
                                                   new->cap_inheritable);
              spin_unlock(&umh_sysctl_lock);
      
              if (sub_info->init) {
                      retval = sub_info->init(sub_info, new);
                      if (retval) {
                              abort_creds(new);
                              goto out;
                      }
              }
      
              commit_creds(new);
      
              retval = do_execve(getname_kernel(sub_info->path),
                                 (const char __user *const __user *)sub_info->argv,
                                 (const char __user *const __user *)sub_info->envp);
      out:
              sub_info->retval = retval;
              /*
               * call_usermodehelper_exec_sync() will call umh_complete
               * if UHM_WAIT_PROC.
               */
              if (!(sub_info->wait & UMH_WAIT_PROC))
                      umh_complete(sub_info);
              if (!retval)
                      return 0;
              do_exit(0);
      }
      
      /* Handles UMH_WAIT_PROC.  */
      static void call_usermodehelper_exec_sync(struct subprocess_info *sub_info)
      {
              pid_t pid;
      
              /* If SIGCLD is ignored sys_wait4 won't populate the status. */
              kernel_sigaction(SIGCHLD, SIG_DFL);
              pid = kernel_thread(call_usermodehelper_exec_async, sub_info, SIGCHLD);
              if (pid < 0) {
                      sub_info->retval = pid;
              } else {
                      int ret = -ECHILD;
                      /*
                       * Normally it is bogus to call wait4() from in-kernel because
                       * wait4() wants to write the exit code to a userspace address.
                       * But call_usermodehelper_exec_sync() always runs as kernel
                       * thread (workqueue) and put_user() to a kernel address works
                       * OK for kernel threads, due to their having an mm_segment_t
                       * which spans the entire address space.
                       *
                       * Thus the __user pointer cast is valid here.
                       */
                      sys_wait4(pid, (int __user *)&ret, 0, NULL);
      
                      /*
                       * If ret is 0, either call_usermodehelper_exec_async failed and
                       * the real error code is already in sub_info->retval or
                       * sub_info->retval is 0 anyway, so don't mess with it then.
                       */
                      if (ret)
                              sub_info->retval = ret;
              }
      
              /* Restore default kernel sig handler */
              kernel_sigaction(SIGCHLD, SIG_IGN);
      
              umh_complete(sub_info);
      }
      
      /*
       * We need to create the usermodehelper kernel thread from a task that is affine
       * to an optimized set of CPUs (or nohz housekeeping ones) such that they
       * inherit a widest affinity irrespective of call_usermodehelper() callers with
       * possibly reduced affinity (eg: per-cpu workqueues). We don't want
       * usermodehelper targets to contend a busy CPU.
       *
       * Unbound workqueues provide such wide affinity and allow to block on
       * UMH_WAIT_PROC requests without blocking pending request (up to some limit).
       *
       * Besides, workqueues provide the privilege level that caller might not have
       * to perform the usermodehelper request.
       *
       */
      static void call_usermodehelper_exec_work(struct work_struct *work)
      {
              struct subprocess_info *sub_info =
                      container_of(work, struct subprocess_info, work);
      
              if (sub_info->wait & UMH_WAIT_PROC) {
                      call_usermodehelper_exec_sync(sub_info);
              } else {
                      pid_t pid;
                      /*
                       * Use CLONE_PARENT to reparent it to kthreadd; we do not
                       * want to pollute current->children, and we need a parent
                       * that always ignores SIGCHLD to ensure auto-reaping.
                       */
                      pid = kernel_thread(call_usermodehelper_exec_async, sub_info,
                                          CLONE_PARENT | SIGCHLD);
                      if (pid < 0) {
                              sub_info->retval = pid;
                              umh_complete(sub_info);
                      }
              }
      }
      
      /*
       * If set, call_usermodehelper_exec() will exit immediately returning -EBUSY
       * (used for preventing user land processes from being created after the user
       * land has been frozen during a system-wide hibernation or suspend operation).
       * Should always be manipulated under umhelper_sem acquired for write.
       */
      static enum umh_disable_depth usermodehelper_disabled = UMH_DISABLED;
      
      /* Number of helpers running */
      static atomic_t running_helpers = ATOMIC_INIT(0);
      
      /*
       * Wait queue head used by usermodehelper_disable() to wait for all running
       * helpers to finish.
       */
      static DECLARE_WAIT_QUEUE_HEAD(running_helpers_waitq);
      
      /*
       * Used by usermodehelper_read_lock_wait() to wait for usermodehelper_disabled
       * to become 'false'.
       */
      static DECLARE_WAIT_QUEUE_HEAD(usermodehelper_disabled_waitq);
      
      /*
       * Time to wait for running_helpers to become zero before the setting of
       * usermodehelper_disabled in usermodehelper_disable() fails
       */
      #define RUNNING_HELPERS_TIMEOUT        (5 * HZ)
      
      int usermodehelper_read_trylock(void)
      {
              DEFINE_WAIT(wait);
              int ret = 0;
      
              down_read(&umhelper_sem);
              for (;;) {
                      prepare_to_wait(&usermodehelper_disabled_waitq, &wait,
                                      TASK_INTERRUPTIBLE);
                      if (!usermodehelper_disabled)
                              break;
      
                      if (usermodehelper_disabled == UMH_DISABLED)
                              ret = -EAGAIN;
      
                      up_read(&umhelper_sem);
      
                      if (ret)
                              break;
      
                      schedule();
                      try_to_freeze();
      
                      down_read(&umhelper_sem);
              }
              finish_wait(&usermodehelper_disabled_waitq, &wait);
              return ret;
      }
      EXPORT_SYMBOL_GPL(usermodehelper_read_trylock);
      
      long usermodehelper_read_lock_wait(long timeout)
      {
              DEFINE_WAIT(wait);
      
              if (timeout < 0)
                      return -EINVAL;
      
              down_read(&umhelper_sem);
              for (;;) {
                      prepare_to_wait(&usermodehelper_disabled_waitq, &wait,
                                      TASK_UNINTERRUPTIBLE);
                      if (!usermodehelper_disabled)
                              break;
      
                      up_read(&umhelper_sem);
      
                      timeout = schedule_timeout(timeout);
                      if (!timeout)
                              break;
      
                      down_read(&umhelper_sem);
              }
              finish_wait(&usermodehelper_disabled_waitq, &wait);
              return timeout;
      }
      EXPORT_SYMBOL_GPL(usermodehelper_read_lock_wait);
      
      void usermodehelper_read_unlock(void)
      {
              up_read(&umhelper_sem);
      }
      EXPORT_SYMBOL_GPL(usermodehelper_read_unlock);
      
      /**
       * __usermodehelper_set_disable_depth - Modify usermodehelper_disabled.
       * @depth: New value to assign to usermodehelper_disabled.
       *
       * Change the value of usermodehelper_disabled (under umhelper_sem locked for
       * writing) and wakeup tasks waiting for it to change.
       */
      void __usermodehelper_set_disable_depth(enum umh_disable_depth depth)
      {
              down_write(&umhelper_sem);
              usermodehelper_disabled = depth;
              wake_up(&usermodehelper_disabled_waitq);
              up_write(&umhelper_sem);
      }
      
      /**
       * __usermodehelper_disable - Prevent new helpers from being started.
       * @depth: New value to assign to usermodehelper_disabled.
       *
       * Set usermodehelper_disabled to @depth and wait for running helpers to exit.
       */
      int __usermodehelper_disable(enum umh_disable_depth depth)
      {
              long retval;
      
              if (!depth)
                      return -EINVAL;
      
              down_write(&umhelper_sem);
              usermodehelper_disabled = depth;
              up_write(&umhelper_sem);
      
              /*
               * From now on call_usermodehelper_exec() won't start any new
               * helpers, so it is sufficient if running_helpers turns out to
               * be zero at one point (it may be increased later, but that
               * doesn't matter).
               */
              retval = wait_event_timeout(running_helpers_waitq,
                                              atomic_read(&running_helpers) == 0,
                                              RUNNING_HELPERS_TIMEOUT);
              if (retval)
                      return 0;
      
              __usermodehelper_set_disable_depth(UMH_ENABLED);
              return -EAGAIN;
      }
      
      static void helper_lock(void)
      {
  279         atomic_inc(&running_helpers);
              smp_mb__after_atomic();
      }
      
      static void helper_unlock(void)
      {
  241         if (atomic_dec_and_test(&running_helpers))
  221                 wake_up(&running_helpers_waitq);
      }
      
      /**
       * call_usermodehelper_setup - prepare to call a usermode helper
       * @path: path to usermode executable
       * @argv: arg vector for process
       * @envp: environment for process
       * @gfp_mask: gfp mask for memory allocation
       * @cleanup: a cleanup function
       * @init: an init function
       * @data: arbitrary context sensitive data
       *
       * Returns either %NULL on allocation failure, or a subprocess_info
       * structure.  This should be passed to call_usermodehelper_exec to
       * exec the process and free the structure.
       *
       * The init function is used to customize the helper process prior to
       * exec.  A non-zero return code causes the process to error out, exit,
       * and return the failure to the calling process
       *
       * The cleanup function is just before ethe subprocess_info is about to
       * be freed.  This can be used for freeing the argv and envp.  The
       * Function must be runnable in either a process context or the
       * context in which call_usermodehelper_exec is called.
       */
      struct subprocess_info *call_usermodehelper_setup(char *path, char **argv,
                      char **envp, gfp_t gfp_mask,
                      int (*init)(struct subprocess_info *info, struct cred *new),
                      void (*cleanup)(struct subprocess_info *info),
                      void *data)
      {
              struct subprocess_info *sub_info;
  286         sub_info = kzalloc(sizeof(struct subprocess_info), gfp_mask);
  280         if (!sub_info)
                      goto out;
      
  279         INIT_WORK(&sub_info->work, call_usermodehelper_exec_work);
              sub_info->path = path;
              sub_info->argv = argv;
              sub_info->envp = envp;
      
              sub_info->cleanup = cleanup;
              sub_info->init = init;
              sub_info->data = data;
        out:
  279         return sub_info;
      }
      EXPORT_SYMBOL(call_usermodehelper_setup);
      
      /**
       * call_usermodehelper_exec - start a usermode application
       * @sub_info: information about the subprocessa
       * @wait: wait for the application to finish and return status.
       *        when UMH_NO_WAIT don't wait at all, but you get no useful error back
       *        when the program couldn't be exec'ed. This makes it safe to call
       *        from interrupt context.
       *
       * Runs a user-space application.  The application is started
       * asynchronously if wait is not set, and runs as a child of system workqueues.
       * (ie. it runs with full root capabilities and optimized affinity).
       */
      int call_usermodehelper_exec(struct subprocess_info *sub_info, int wait)
      {
  279         DECLARE_COMPLETION_ONSTACK(done);
              int retval = 0;
      
              if (!sub_info->path) {
                      call_usermodehelper_freeinfo(sub_info);
                      return -EINVAL;
              }
  279         helper_lock();
              if (usermodehelper_disabled) {
                      retval = -EBUSY;
                      goto out;
              }
              /*
               * Set the completion pointer only if there is a waiter.
               * This makes it possible to use umh_complete to free
               * the data structure in case of UMH_NO_WAIT.
               */
  279         sub_info->complete = (wait == UMH_NO_WAIT) ? NULL : &done;
              sub_info->wait = wait;
      
              queue_work(system_unbound_wq, &sub_info->work);
              if (wait == UMH_NO_WAIT)        /* task has freed sub_info */
                      goto unlock;
      
              if (wait & UMH_KILLABLE) {
  260                 retval = wait_for_completion_killable(&done);
                      if (!retval)
                              goto wait_done;
      
                      /* umh_complete() will see NULL and free sub_info */
                      if (xchg(&sub_info->complete, NULL))
                              goto unlock;
                      /* fallthrough, umh_complete() was already called */
              }
      
    9         wait_for_completion(&done);
      wait_done:
  241         retval = sub_info->retval;
      out:
  241         call_usermodehelper_freeinfo(sub_info);
      unlock:
  241         helper_unlock();
              return retval;
      }
      EXPORT_SYMBOL(call_usermodehelper_exec);
      
      /**
       * call_usermodehelper() - prepare and start a usermode application
       * @path: path to usermode executable
       * @argv: arg vector for process
       * @envp: environment for process
       * @wait: wait for the application to finish and return status.
       *        when UMH_NO_WAIT don't wait at all, but you get no useful error back
       *        when the program couldn't be exec'ed. This makes it safe to call
       *        from interrupt context.
       *
       * This function is the equivalent to use call_usermodehelper_setup() and
       * call_usermodehelper_exec().
       */
      int call_usermodehelper(char *path, char **argv, char **envp, int wait)
      {
              struct subprocess_info *info;
              gfp_t gfp_mask = (wait == UMH_NO_WAIT) ? GFP_ATOMIC : GFP_KERNEL;
      
              info = call_usermodehelper_setup(path, argv, envp, gfp_mask,
                                               NULL, NULL, NULL);
              if (info == NULL)
                      return -ENOMEM;
      
              return call_usermodehelper_exec(info, wait);
      }
      EXPORT_SYMBOL(call_usermodehelper);
      
      static int proc_cap_handler(struct ctl_table *table, int write,
                               void __user *buffer, size_t *lenp, loff_t *ppos)
      {
              struct ctl_table t;
              unsigned long cap_array[_KERNEL_CAPABILITY_U32S];
              kernel_cap_t new_cap;
              int err, i;
      
              if (write && (!capable(CAP_SETPCAP) ||
                            !capable(CAP_SYS_MODULE)))
                      return -EPERM;
      
              /*
               * convert from the global kernel_cap_t to the ulong array to print to
               * userspace if this is a read.
               */
              spin_lock(&umh_sysctl_lock);
              for (i = 0; i < _KERNEL_CAPABILITY_U32S; i++)  {
                      if (table->data == CAP_BSET)
                              cap_array[i] = usermodehelper_bset.cap[i];
                      else if (table->data == CAP_PI)
                              cap_array[i] = usermodehelper_inheritable.cap[i];
                      else
                              BUG();
              }
              spin_unlock(&umh_sysctl_lock);
      
              t = *table;
              t.data = &cap_array;
      
              /*
               * actually read or write and array of ulongs from userspace.  Remember
               * these are least significant 32 bits first
               */
              err = proc_doulongvec_minmax(&t, write, buffer, lenp, ppos);
              if (err < 0)
                      return err;
      
              /*
               * convert from the sysctl array of ulongs to the kernel_cap_t
               * internal representation
               */
              for (i = 0; i < _KERNEL_CAPABILITY_U32S; i++)
                      new_cap.cap[i] = cap_array[i];
      
              /*
               * Drop everything not in the new_cap (but don't add things)
               */
              spin_lock(&umh_sysctl_lock);
              if (write) {
                      if (table->data == CAP_BSET)
                              usermodehelper_bset = cap_intersect(usermodehelper_bset, new_cap);
                      if (table->data == CAP_PI)
                              usermodehelper_inheritable = cap_intersect(usermodehelper_inheritable, new_cap);
              }
              spin_unlock(&umh_sysctl_lock);
      
              return 0;
      }
      
      struct ctl_table usermodehelper_table[] = {
              {
                      .procname        = "bset",
                      .data                = CAP_BSET,
                      .maxlen                = _KERNEL_CAPABILITY_U32S * sizeof(unsigned long),
                      .mode                = 0600,
                      .proc_handler        = proc_cap_handler,
              },
              {
                      .procname        = "inheritable",
                      .data                = CAP_PI,
                      .maxlen                = _KERNEL_CAPABILITY_U32S * sizeof(unsigned long),
                      .mode                = 0600,
                      .proc_handler        = proc_cap_handler,
              },
              { }
      };
      /*
       * Devices PM QoS constraints management
       *
       * Copyright (C) 2011 Texas Instruments, Inc.
       *
       * 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 module exposes the interface to kernel space for specifying
       * per-device PM QoS dependencies. It provides infrastructure for registration
       * of:
       *
       * Dependents on a QoS value : register requests
       * Watchers of QoS value : get notified when target QoS value changes
       *
       * This QoS design is best effort based. Dependents register their QoS needs.
       * Watchers register to keep track of the current QoS needs of the system.
       * Watchers can register different types of notification callbacks:
       *  . a per-device notification callback using the dev_pm_qos_*_notifier API.
       *    The notification chain data is stored in the per-device constraint
       *    data struct.
       *  . a system-wide notification callback using the dev_pm_qos_*_global_notifier
       *    API. The notification chain data is stored in a static variable.
       *
       * Note about the per-device constraint data struct allocation:
       * . The per-device constraints data struct ptr is tored into the device
       *    dev_pm_info.
       * . To minimize the data usage by the per-device constraints, the data struct
       *   is only allocated at the first call to dev_pm_qos_add_request.
       * . The data is later free'd when the device is removed from the system.
       *  . A global mutex protects the constraints users from the data being
       *     allocated and free'd.
       */
      
      #include <linux/pm_qos.h>
      #include <linux/spinlock.h>
      #include <linux/slab.h>
      #include <linux/device.h>
      #include <linux/mutex.h>
      #include <linux/export.h>
      #include <linux/pm_runtime.h>
      #include <linux/err.h>
      #include <trace/events/power.h>
      
      #include "power.h"
      
      static DEFINE_MUTEX(dev_pm_qos_mtx);
      static DEFINE_MUTEX(dev_pm_qos_sysfs_mtx);
      
      static BLOCKING_NOTIFIER_HEAD(dev_pm_notifiers);
      
      /**
       * __dev_pm_qos_flags - Check PM QoS flags for a given device.
       * @dev: Device to check the PM QoS flags for.
       * @mask: Flags to check against.
       *
       * This routine must be called with dev->power.lock held.
       */
      enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev, s32 mask)
      {
              struct dev_pm_qos *qos = dev->power.qos;
              struct pm_qos_flags *pqf;
              s32 val;
      
              lockdep_assert_held(&dev->power.lock);
      
              if (IS_ERR_OR_NULL(qos))
                      return PM_QOS_FLAGS_UNDEFINED;
      
              pqf = &qos->flags;
              if (list_empty(&pqf->list))
                      return PM_QOS_FLAGS_UNDEFINED;
      
              val = pqf->effective_flags & mask;
              if (val)
                      return (val == mask) ? PM_QOS_FLAGS_ALL : PM_QOS_FLAGS_SOME;
      
              return PM_QOS_FLAGS_NONE;
      }
      
      /**
       * dev_pm_qos_flags - Check PM QoS flags for a given device (locked).
       * @dev: Device to check the PM QoS flags for.
       * @mask: Flags to check against.
       */
      enum pm_qos_flags_status dev_pm_qos_flags(struct device *dev, s32 mask)
      {
              unsigned long irqflags;
              enum pm_qos_flags_status ret;
      
              spin_lock_irqsave(&dev->power.lock, irqflags);
              ret = __dev_pm_qos_flags(dev, mask);
              spin_unlock_irqrestore(&dev->power.lock, irqflags);
      
              return ret;
      }
      EXPORT_SYMBOL_GPL(dev_pm_qos_flags);
      
      /**
       * __dev_pm_qos_read_value - Get PM QoS constraint for a given device.
       * @dev: Device to get the PM QoS constraint value for.
       *
       * This routine must be called with dev->power.lock held.
       */
      s32 __dev_pm_qos_read_value(struct device *dev)
      {
              lockdep_assert_held(&dev->power.lock);
      
              return IS_ERR_OR_NULL(dev->power.qos) ?
                      0 : pm_qos_read_value(&dev->power.qos->resume_latency);
      }
      
      /**
       * dev_pm_qos_read_value - Get PM QoS constraint for a given device (locked).
       * @dev: Device to get the PM QoS constraint value for.
       */
      s32 dev_pm_qos_read_value(struct device *dev)
      {
              unsigned long flags;
              s32 ret;
      
              spin_lock_irqsave(&dev->power.lock, flags);
              ret = __dev_pm_qos_read_value(dev);
              spin_unlock_irqrestore(&dev->power.lock, flags);
      
              return ret;
      }
      
      /**
       * apply_constraint - Add/modify/remove device PM QoS request.
       * @req: Constraint request to apply
       * @action: Action to perform (add/update/remove).
       * @value: Value to assign to the QoS request.
       *
       * Internal function to update the constraints list using the PM QoS core
       * code and if needed call the per-device and the global notification
       * callbacks
       */
      static int apply_constraint(struct dev_pm_qos_request *req,
                                  enum pm_qos_req_action action, s32 value)
      {
              struct dev_pm_qos *qos = req->dev->power.qos;
              int ret;
      
              switch(req->type) {
              case DEV_PM_QOS_RESUME_LATENCY:
                      ret = pm_qos_update_target(&qos->resume_latency,
                                                 &req->data.pnode, action, value);
                      if (ret) {
                              value = pm_qos_read_value(&qos->resume_latency);
                              blocking_notifier_call_chain(&dev_pm_notifiers,
                                                           (unsigned long)value,
                                                           req);
                      }
                      break;
              case DEV_PM_QOS_LATENCY_TOLERANCE:
                      ret = pm_qos_update_target(&qos->latency_tolerance,
                                                 &req->data.pnode, action, value);
                      if (ret) {
                              value = pm_qos_read_value(&qos->latency_tolerance);
                              req->dev->power.set_latency_tolerance(req->dev, value);
                      }
                      break;
              case DEV_PM_QOS_FLAGS:
                      ret = pm_qos_update_flags(&qos->flags, &req->data.flr,
                                                action, value);
                      break;
              default:
                      ret = -EINVAL;
              }
      
              return ret;
      }
      
      /*
       * dev_pm_qos_constraints_allocate
       * @dev: device to allocate data for
       *
       * Called at the first call to add_request, for constraint data allocation
       * Must be called with the dev_pm_qos_mtx mutex held
       */
      static int dev_pm_qos_constraints_allocate(struct device *dev)
      {
              struct dev_pm_qos *qos;
              struct pm_qos_constraints *c;
              struct blocking_notifier_head *n;
      
              qos = kzalloc(sizeof(*qos), GFP_KERNEL);
              if (!qos)
                      return -ENOMEM;
      
              n = kzalloc(sizeof(*n), GFP_KERNEL);
              if (!n) {
                      kfree(qos);
                      return -ENOMEM;
              }
              BLOCKING_INIT_NOTIFIER_HEAD(n);
      
              c = &qos->resume_latency;
              plist_head_init(&c->list);
              c->target_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
              c->default_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
              c->no_constraint_value = PM_QOS_RESUME_LATENCY_DEFAULT_VALUE;
              c->type = PM_QOS_MIN;
              c->notifiers = n;
      
              c = &qos->latency_tolerance;
              plist_head_init(&c->list);
              c->target_value = PM_QOS_LATENCY_TOLERANCE_DEFAULT_VALUE;
              c->default_value = PM_QOS_LATENCY_TOLERANCE_DEFAULT_VALUE;
              c->no_constraint_value = PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT;
              c->type = PM_QOS_MIN;
      
              INIT_LIST_HEAD(&qos->flags.list);
      
              spin_lock_irq(&dev->power.lock);
              dev->power.qos = qos;
              spin_unlock_irq(&dev->power.lock);
      
              return 0;
      }
      
      static void __dev_pm_qos_hide_latency_limit(struct device *dev);
      static void __dev_pm_qos_hide_flags(struct device *dev);
      
      /**
       * dev_pm_qos_constraints_destroy
       * @dev: target device
       *
       * Called from the device PM subsystem on device removal under device_pm_lock().
       */
      void dev_pm_qos_constraints_destroy(struct device *dev)
      {
              struct dev_pm_qos *qos;
              struct dev_pm_qos_request *req, *tmp;
              struct pm_qos_constraints *c;
              struct pm_qos_flags *f;
      
  154         mutex_lock(&dev_pm_qos_sysfs_mtx);
      
              /*
               * If the device's PM QoS resume latency limit or PM QoS flags have been
               * exposed to user space, they have to be hidden at this point.
               */
              pm_qos_sysfs_remove_resume_latency(dev);
              pm_qos_sysfs_remove_flags(dev);
      
              mutex_lock(&dev_pm_qos_mtx);
      
              __dev_pm_qos_hide_latency_limit(dev);
              __dev_pm_qos_hide_flags(dev);
      
              qos = dev->power.qos;
              if (!qos)
                      goto out;
      
              /* Flush the constraints lists for the device. */
              c = &qos->resume_