static long cifs_ioctl_clone(unsigned int xid, struct file *dst_file, unsigned long srcfd) { int rc; struct fd src_file; struct inode *src_inode; cifs_dbg(FYI, "ioctl clone range\n"); /* the destination must be opened for writing */ if (!(dst_file->f_mode & FMODE_WRITE)) { cifs_dbg(FYI, "file target not open for write\n"); return -EINVAL; } /* check if target volume is readonly and take reference */ rc = mnt_want_write_file(dst_file); if (rc) { cifs_dbg(FYI, "mnt_want_write failed with rc %d\n", rc); return rc; } src_file = fdget(srcfd); if (!src_file.file) { rc = -EBADF; goto out_drop_write; } if (src_file.file->f_op->unlocked_ioctl != cifs_ioctl) { rc = -EBADF; cifs_dbg(VFS, "src file seems to be from a different filesystem type\n"); goto out_fput; } src_inode = file_inode(src_file.file); rc = -EINVAL; if (S_ISDIR(src_inode->i_mode)) goto out_fput; rc = cifs_file_clone_range(xid, src_file.file, dst_file); out_fput: fdput(src_file); out_drop_write: mnt_drop_write_file(dst_file); return rc; }
SYSCALL_DEFINE3(lseek, unsigned int, fd, off_t, offset, unsigned int, whence) { off_t retval; struct fd f = fdget(fd); if (!f.file) return -EBADF; retval = -EINVAL; if (whence <= SEEK_MAX) { loff_t res = vfs_llseek(f.file, offset, whence); retval = res; if (res != (loff_t)retval) retval = -EOVERFLOW; /* LFS: should only happen on 32 bit platforms */ } fdput(f); return retval; }
static long do_sys_ftruncate(unsigned int fd, loff_t length, int small) { struct inode *inode; struct dentry *dentry; struct fd f; int error; error = -EINVAL; if (length < 0) goto out; error = -EBADF; f = fdget(fd); if (!f.file) goto out; /* explicitly opened as large or we are on 64-bit box */ if (f.file->f_flags & O_LARGEFILE) small = 0; dentry = f.file->f_path.dentry; inode = dentry->d_inode; error = -EINVAL; if (!S_ISREG(inode->i_mode) || !(f.file->f_mode & FMODE_WRITE)) goto out_putf; error = -EINVAL; /* Cannot ftruncate over 2^31 bytes without large file support */ if (small && length > MAX_NON_LFS) goto out_putf; error = -EPERM; if (IS_APPEND(inode)) goto out_putf; sb_start_write(inode->i_sb); error = locks_verify_truncate(inode, f.file, length); if (!error) error = security_path_truncate(&f.file->f_path); if (!error) error = do_truncate(dentry, length, ATTR_MTIME|ATTR_CTIME, f.file); sb_end_write(inode->i_sb); out_putf: fdput(f); out: return error; }
COMPAT_SYSCALL_DEFINE3(readv, unsigned long, fd, const struct compat_iovec __user *,vec, unsigned long, vlen) { struct fd f = fdget(fd); ssize_t ret; loff_t pos; if (!f.file) return -EBADF; pos = f.file->f_pos; ret = compat_readv(f.file, vec, vlen, &pos); if (ret >= 0) f.file->f_pos = pos; fdput(f); return ret; }
static struct vfsmount *get_vfsmount_from_fd(int fd) { struct vfsmount *mnt; if (fd == AT_FDCWD) { struct fs_struct *fs = current->fs; spin_lock(&fs->lock); mnt = mntget(fs->pwd.mnt); spin_unlock(&fs->lock); } else { struct fd f = fdget(fd); if (!f.file) return ERR_PTR(-EBADF); mnt = mntget(f.file->f_path.mnt); fdput(f); } return mnt; }
static long __compat_sys_pwritev64(unsigned long fd, const struct compat_iovec __user *vec, unsigned long vlen, loff_t pos) { struct fd f; ssize_t ret; if (pos < 0) return -EINVAL; f = fdget(fd); if (!f.file) return -EBADF; ret = -ESPIPE; if (f.file->f_mode & FMODE_PWRITE) ret = compat_writev(f.file, vec, vlen, &pos); fdput(f); return ret; }
COMPAT_SYSCALL_DEFINE4(preadv64, unsigned long, fd, const struct compat_iovec __user *,vec, unsigned long, vlen, loff_t, pos) { struct fd f; ssize_t ret; if (pos < 0) return -EINVAL; f = fdget(fd); if (!f.file) return -EBADF; ret = -ESPIPE; if (f.file->f_mode & FMODE_PREAD) ret = compat_readv(f.file, vec, vlen, &pos); fdput(f); return ret; }
SYSCALL_DEFINE3(writev, unsigned long, fd, const struct iovec __user *, vec, unsigned long, vlen) { struct fd f = fdget(fd); ssize_t ret = -EBADF; if (f.file) { loff_t pos = file_pos_read(f.file); ret = vfs_writev(f.file, vec, vlen, &pos); file_pos_write(f.file, pos); fdput(f); } if (ret > 0) add_wchar(current, ret); inc_syscw(current); return ret; }
static int ovl_fadvise(struct file *file, loff_t offset, loff_t len, int advice) { struct fd real; const struct cred *old_cred; int ret; ret = ovl_real_fdget(file, &real); if (ret) return ret; old_cred = ovl_override_creds(file_inode(file)->i_sb); ret = vfs_fadvise(real.file, offset, len, advice); revert_creds(old_cred); fdput(real); return ret; }
static long do_compat_preadv64(unsigned long fd, const struct compat_iovec __user *vec, unsigned long vlen, loff_t pos, int flags) { struct fd f; ssize_t ret; if (pos < 0) return -EINVAL; f = fdget(fd); if (!f.file) return -EBADF; ret = -ESPIPE; if (f.file->f_mode & FMODE_PREAD) ret = compat_readv(f.file, vec, vlen, &pos, flags); fdput(f); return ret; }
static loff_t ovl_llseek(struct file *file, loff_t offset, int whence) { struct inode *inode = file_inode(file); struct fd real; const struct cred *old_cred; ssize_t ret; /* * The two special cases below do not need to involve real fs, * so we can optimizing concurrent callers. */ if (offset == 0) { if (whence == SEEK_CUR) return file->f_pos; if (whence == SEEK_SET) return vfs_setpos(file, 0, 0); } ret = ovl_real_fdget(file, &real); if (ret) return ret; /* * Overlay file f_pos is the master copy that is preserved * through copy up and modified on read/write, but only real * fs knows how to SEEK_HOLE/SEEK_DATA and real fs may impose * limitations that are more strict than ->s_maxbytes for specific * files, so we use the real file to perform seeks. */ inode_lock(inode); real.file->f_pos = file->f_pos; old_cred = ovl_override_creds(inode->i_sb); ret = vfs_llseek(real.file, offset, whence); revert_creds(old_cred); file->f_pos = real.file->f_pos; inode_unlock(inode); fdput(real); return ret; }
SYSCALL_DEFINE3(fchown, unsigned int, fd, uid_t, user, gid_t, group) { struct fd f = fdget(fd); int error = -EBADF; if (!f.file) goto out; error = mnt_want_write_file(f.file); if (error) goto out_fput; audit_inode(NULL, f.file->f_path.dentry, 0); error = chown_common(&f.file->f_path, user, group); mnt_drop_write_file(f.file); out_fput: fdput(f); out: return error; }
SYSCALL_DEFINE(pwrite64)(unsigned int fd, const char __user *buf, size_t count, loff_t pos) { struct fd f; ssize_t ret = -EBADF; if (pos < 0) return -EINVAL; f = fdget(fd); if (f.file) { ret = -ESPIPE; if (f.file->f_mode & FMODE_PWRITE) ret = vfs_write(f.file, buf, count, &pos); fdput(f); } return ret; }
int ksys_fchown(unsigned int fd, uid_t user, gid_t group) { struct fd f = fdget(fd); int error = -EBADF; if (!f.file) goto out; error = mnt_want_write_file_path(f.file); if (error) goto out_fput; audit_file(f.file); error = chown_common(&f.file->f_path, user, group); mnt_drop_write_file_path(f.file); out_fput: fdput(f); out: return error; }
static long ovl_real_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct fd real; const struct cred *old_cred; long ret; ret = ovl_real_fdget(file, &real); if (ret) return ret; old_cred = ovl_override_creds(file_inode(file)->i_sb); ret = vfs_ioctl(real.file, cmd, arg); revert_creds(old_cred); fdput(real); return ret; }
/* * sync a single super */ SYSCALL_DEFINE1(syncfs, int, fd) { struct fd f = fdget(fd); struct super_block *sb; int ret; #ifdef CONFIG_FSYNC_OFF return 0; #endif if (!f.file) return -EBADF; sb = f.file->f_dentry->d_sb; down_read(&sb->s_umount); ret = sync_filesystem(sb); up_read(&sb->s_umount); fdput(f); return ret; }
SYSCALL_DEFINE4(pread64, unsigned int, fd, char __user *, buf, size_t, count, loff_t, pos) { struct fd f; ssize_t ret = -EBADF; if (pos < 0) return -EINVAL; f = fdget(fd); if (f.file) { ret = -ESPIPE; if (f.file->f_mode & FMODE_PREAD) ret = vfs_read(f.file, buf, count, &pos); fdput(f); } return ret; }
SYSCALL_DEFINE3(old_readdir, unsigned int, fd, struct old_linux_dirent __user *, dirent, unsigned int, count) { int error; struct fd f = fdget(fd); struct readdir_callback buf; if (!f.file) return -EBADF; buf.result = 0; buf.dirent = dirent; error = vfs_readdir(f.file, fillonedir, &buf); if (buf.result) error = buf.result; fdput(f); return error; }
asmlinkage long sys_spu_run(int fd, __u32 __user *unpc, __u32 __user *ustatus) { long ret; struct fd arg; struct spufs_calls *calls; calls = spufs_calls_get(); if (!calls) return -ENOSYS; ret = -EBADF; arg = fdget(fd); if (arg.file) { ret = calls->spu_run(arg.file, unpc, ustatus); fdput(arg); } spufs_calls_put(calls); return ret; }
/* * sync a single super */ SYSCALL_DEFINE1(syncfs, int, fd) { struct fd f = fdget(fd); struct super_block *sb; int ret; if (!fsync_enabled) return 0; if (!f.file) return -EBADF; sb = f.file->f_dentry->d_sb; down_read(&sb->s_umount); ret = sync_filesystem(sb); up_read(&sb->s_umount); fdput(f); return ret; }
SYSCALL_DEFINE1(fchdir, unsigned int, fd) { struct fd f = fdget_raw(fd); int error; error = -EBADF; if (!f.file) goto out; error = -ENOTDIR; if (!d_can_lookup(f.file->f_path.dentry)) goto out_putf; error = inode_permission(file_inode(f.file), MAY_EXEC | MAY_CHDIR); if (!error) set_fs_pwd(current->fs, &f.file->f_path); out_putf: fdput(f); out: return error; }
static int ovl_fsync(struct file *file, loff_t start, loff_t end, int datasync) { struct fd real; const struct cred *old_cred; int ret; ret = ovl_real_fdget_meta(file, &real, !datasync); if (ret) return ret; /* Don't sync lower file for fear of receiving EROFS error */ if (file_inode(real.file) == ovl_inode_upper(file_inode(file))) { old_cred = ovl_override_creds(file_inode(file)->i_sb); ret = vfs_fsync_range(real.file, start, end, datasync); revert_creds(old_cred); } fdput(real); return ret; }
static ssize_t do_pwritev(unsigned long fd, const struct iovec __user *vec, unsigned long vlen, loff_t pos, int flags) { struct fd f; ssize_t ret = -EBADF; if (pos < 0) return -EINVAL; f = fdget(fd); if (f.file) { ret = -ESPIPE; if (f.file->f_mode & FMODE_PWRITE) ret = vfs_writev(f.file, vec, vlen, &pos, flags); fdput(f); } if (ret > 0) add_wchar(current, ret); inc_syscw(current); return ret; }
static ssize_t ovl_write_iter(struct kiocb *iocb, struct iov_iter *iter) { struct file *file = iocb->ki_filp; struct inode *inode = file_inode(file); struct fd real; const struct cred *old_cred; ssize_t ret; if (!iov_iter_count(iter)) return 0; inode_lock(inode); /* Update mode */ ovl_copyattr(ovl_inode_real(inode), inode); ret = file_remove_privs(file); if (ret) goto out_unlock; ret = ovl_real_fdget(file, &real); if (ret) goto out_unlock; old_cred = ovl_override_creds(file_inode(file)->i_sb); file_start_write(real.file); ret = vfs_iter_write(real.file, iter, &iocb->ki_pos, ovl_iocb_to_rwf(iocb)); file_end_write(real.file); revert_creds(old_cred); /* Update size */ ovl_copyattr(ovl_inode_real(inode), inode); fdput(real); out_unlock: inode_unlock(inode); return ret; }
SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd, unsigned long, arg) { struct fd f = fdget_raw(fd); long err = -EBADF; if (!f.file) goto out; if (unlikely(f.file->f_mode & FMODE_PATH)) { if (!check_fcntl_cmd(cmd)) goto out1; } err = security_file_fcntl(f.file, cmd, arg); if (err) goto out1; switch (cmd) { case F_GETLK64: case F_OFD_GETLK: err = fcntl_getlk64(f.file, cmd, (struct flock64 __user *) arg); break; case F_SETLK64: case F_SETLKW64: case F_OFD_SETLK: case F_OFD_SETLKW: err = fcntl_setlk64(fd, f.file, cmd, (struct flock64 __user *) arg); break; default: err = do_fcntl(fd, cmd, arg, f.file); break; } out1: fdput(f); out: return err; }
SYSCALL_DEFINE3(fcntl, unsigned int, fd, unsigned int, cmd, unsigned long, arg) { struct fd f = fdget_raw(fd); long err = -EBADF; if (!f.file) goto out; if (unlikely(f.file->f_mode & FMODE_PATH)) { if (!check_fcntl_cmd(cmd)) goto out1; } err = security_file_fcntl(f.file, cmd, arg); if (!err) err = do_fcntl(fd, cmd, arg, f.file); out1: fdput(f); out: return err; }
static long ovl_fallocate(struct file *file, int mode, loff_t offset, loff_t len) { struct inode *inode = file_inode(file); struct fd real; const struct cred *old_cred; int ret; ret = ovl_real_fdget(file, &real); if (ret) return ret; old_cred = ovl_override_creds(file_inode(file)->i_sb); ret = vfs_fallocate(real.file, mode, offset, len); revert_creds(old_cred); /* Update size */ ovl_copyattr(ovl_inode_real(inode), inode); fdput(real); return ret; }
SYSCALL_DEFINE5(pwritev, unsigned long, fd, const struct iovec __user *, vec, unsigned long, vlen, unsigned long, pos_l, unsigned long, pos_h) { loff_t pos = pos_from_hilo(pos_h, pos_l); struct fd f; ssize_t ret = -EBADF; if (pos < 0) return -EINVAL; f = fdget(fd); if (f.file) { ret = -ESPIPE; if (f.file->f_mode & FMODE_PWRITE) ret = vfs_writev(f.file, vec, vlen, &pos); fdput(f); } if (ret > 0) add_wchar(current, ret); inc_syscw(current); return ret; }
SYSCALL_DEFINE4(spu_create, const char __user *, name, unsigned int, flags, umode_t, mode, int, neighbor_fd) { long ret; struct spufs_calls *calls; calls = spufs_calls_get(); if (!calls) return -ENOSYS; if (flags & SPU_CREATE_AFFINITY_SPU) { struct fd neighbor = fdget(neighbor_fd); ret = -EBADF; if (neighbor.file) { ret = calls->create_thread(name, flags, mode, neighbor.file); fdput(neighbor); } } else ret = calls->create_thread(name, flags, mode, NULL); spufs_calls_put(calls); return ret; }
SYSCALL_DEFINE1(fchdir, unsigned int, fd) { struct fd f = fdget_raw(fd); struct inode *inode; int error = -EBADF; error = -EBADF; if (!f.file) goto out; inode = file_inode(f.file); error = -ENOTDIR; if (!S_ISDIR(inode->i_mode)) goto out_putf; error = inode_permission(inode, MAY_EXEC | MAY_CHDIR); if (!error) set_fs_pwd(current->fs, &f.file->f_path); out_putf: fdput(f); out: return error; }