/* * Lightweight file lookup - no refcnt increment if fd table isn't shared. * You can use this only if it is guranteed that the current task already * holds a refcnt to that file. That check has to be done at fget() only * and a flag is returned to be passed to the corresponding fput_light(). * There must not be a cloning between an fget_light/fput_light pair. */ struct file *fget_light(unsigned int fd, int *fput_needed) { struct file *file; struct files_struct *files = current->files; *fput_needed = 0; if (likely((atomic_read(&files->count) == 1))) { file = fcheck_files(files, fd); if (unlikely(file && file->f_heavy)) goto slow; } else { slow: rcu_read_lock(); file = fcheck_files(files, fd); if (file) { if (atomic_long_inc_not_zero(&file->f_count)) *fput_needed = 1; else /* Didn't get the reference, someone's freed */ file = NULL; } rcu_read_unlock(); } return file; }
/* Actually fget_light is defined in fs/file.c but only 3.7 exports it. * Lets export it here. */ struct file *fget_light(unsigned int fd, int *fput_needed) { struct file *file; struct files_struct *files = current->files; *fput_needed = 0; if (atomic_read(&files->count) == 1) { file = fcheck_files(files, fd); if (file && (file->f_mode & FMODE_PATH)) file = NULL; } else { rcu_read_lock(); file = fcheck_files(files, fd); if (file) { if (!(file->f_mode & FMODE_PATH) && atomic_long_inc_not_zero(&file->f_count)) *fput_needed = 1; else /* Didn't get the reference, someone's freed */ file = NULL; } rcu_read_unlock(); } return file; }
static struct bsd_acct_struct *acct_get(struct pid_namespace *ns) { struct bsd_acct_struct *res; again: smp_rmb(); rcu_read_lock(); res = to_acct(ACCESS_ONCE(ns->bacct)); if (!res) { rcu_read_unlock(); return NULL; } if (!atomic_long_inc_not_zero(&res->count)) { rcu_read_unlock(); cpu_relax(); goto again; } rcu_read_unlock(); mutex_lock(&res->lock); if (res != to_acct(ACCESS_ONCE(ns->bacct))) { mutex_unlock(&res->lock); acct_put(res); goto again; } return res; }
/* * If the current task has no IO context then create one and initialise it. * If it does have a context, take a ref on it. * * This is always called in the context of the task which submitted the I/O. */ struct io_context *get_io_context(gfp_t gfp_flags, int node) { struct io_context *ioc = NULL; /* * Check for unlikely race with exiting task. ioc ref count is * zero when ioc is being detached. */ do { ioc = current_io_context(gfp_flags, node); if (unlikely(!ioc)) break; } while (!atomic_long_inc_not_zero(&ioc->refcount)); return ioc; }
struct file *fget_raw(unsigned int fd) { struct file *file; struct files_struct *files = current->files; rcu_read_lock(); file = fcheck_files(files, fd); if (file) { /* File object ref couldn't be taken */ if (!atomic_long_inc_not_zero(&file->f_count)) file = NULL; } rcu_read_unlock(); return file; }
struct file *begin_import_dvfs_file(unsigned long dvfs_objid, struct dvfs_file_struct **dvfs_file) { struct file *file = NULL; /* Check if the file struct is already present */ *dvfs_file = grab_dvfs_file_struct(dvfs_objid); file = (*dvfs_file)->file; /* Check for a race with last fput()->__fput() */ if (file && !atomic_long_inc_not_zero(&file->f_count)) { (*dvfs_file)->file = NULL; file = NULL; } return file; }
struct file *fget(unsigned int fd) { struct file *file; struct files_struct *files = current->files; rcu_read_lock(); file = fcheck_files(files, fd); if (file) { /* */ if (file->f_mode & FMODE_PATH || !atomic_long_inc_not_zero(&file->f_count)) file = NULL; } rcu_read_unlock(); return file; }
static struct file * fget_from_files(struct files_struct *files, unsigned fd) { struct file *file; rcu_read_lock(); file = fcheck_files(files, fd); if (file) { if (file->f_mode & FMODE_PATH || !atomic_long_inc_not_zero(&file->f_count)) { file = NULL; } } rcu_read_unlock(); return file; }
struct file *fget_raw_light(unsigned int fd, int *fput_needed) { struct file *file; struct files_struct *files = current->files; *fput_needed = 0; if (atomic_read(&files->count) == 1) { file = fcheck_files(files, fd); } else { rcu_read_lock(); file = fcheck_files(files, fd); if (file) { if (atomic_long_inc_not_zero(&file->f_count)) *fput_needed = 1; else /* */ file = NULL; } rcu_read_unlock(); } return file; }
static long fd_link_ioctl (struct file *f, unsigned int ioctl, unsigned long arg) { void __user *argp = (void __user *) arg; struct task_struct *task_target = NULL; struct file *file; struct files_struct *files; struct fdtable *fdt; struct fd_copy fd_copy; switch (ioctl) { case FD_COPY: if (copy_from_user (&fd_copy, argp, sizeof (struct fd_copy))) return -EFAULT; /* * Find the task struct for the target pid */ task_target = pid_task (find_vpid (fd_copy.target_pid), PIDTYPE_PID); if (task_target == NULL) { printk (KERN_DEBUG "Failed to get mem ctx for target pid\n"); return -EFAULT; } files = get_files_struct (current); if (files == NULL) { printk (KERN_DEBUG "Failed to get files struct\n"); return -EFAULT; } rcu_read_lock (); file = fcheck_files (files, fd_copy.source_fd); if (file) { if (file->f_mode & FMODE_PATH || !atomic_long_inc_not_zero (&file->f_count)) file = NULL; } rcu_read_unlock (); put_files_struct (files); if (file == NULL) { printk (KERN_DEBUG "Failed to get file from source pid\n"); return 0; } /* * Release the existing fd in the source process */ spin_lock (&files->file_lock); filp_close (file, files); fdt = files_fdtable (files); fdt->fd[fd_copy.source_fd] = NULL; spin_unlock (&files->file_lock); /* * Find the file struct associated with the target fd. */ files = get_files_struct (task_target); if (files == NULL) { printk (KERN_DEBUG "Failed to get files struct\n"); return -EFAULT; } rcu_read_lock (); file = fcheck_files (files, fd_copy.target_fd); if (file) { if (file->f_mode & FMODE_PATH || !atomic_long_inc_not_zero (&file->f_count)) file = NULL; } rcu_read_unlock (); put_files_struct (files); if (file == NULL) { printk (KERN_DEBUG "Failed to get file from target pid\n"); return 0; } /* * Install the file struct from the target process into the * file desciptor of the source process, */ fd_install (fd_copy.source_fd, file); return 0; default: return -ENOIOCTLCMD; } }