Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6: (57 commits)
  tidy the trailing symlinks traversal up
  Turn resolution of trailing symlinks iterative everywhere
  simplify link_path_walk() tail
  Make trailing symlink resolution in path_lookupat() iterative
  update nd->inode in __do_follow_link() instead of after do_follow_link()
  pull handling of one pathname component into a helper
  fs: allow AT_EMPTY_PATH in linkat(), limit that to CAP_DAC_READ_SEARCH
  Allow passing O_PATH descriptors via SCM_RIGHTS datagrams
  readlinkat(), fchownat() and fstatat() with empty relative pathnames
  Allow O_PATH for symlinks
  New kind of open files - "location only".
  ext4: Copy fs UUID to superblock
  ext3: Copy fs UUID to superblock.
  vfs: Export file system uuid via /proc/<pid>/mountinfo
  unistd.h: Add new syscalls numbers to asm-generic
  x86: Add new syscalls for x86_64
  x86: Add new syscalls for x86_32
  fs: Remove i_nlink check from file system link callback
  fs: Don't allow to create hardlink for deleted file
  vfs: Add open by file handle support
  ...
This commit is contained in:
Linus Torvalds 2011-03-15 15:48:13 -07:00
commit 422e6c4bc4
57 changed files with 1508 additions and 1278 deletions

View File

@ -230,44 +230,24 @@ linux_to_osf_statfs(struct kstatfs *linux_stat, struct osf_statfs __user *osf_st
return copy_to_user(osf_stat, &tmp_stat, bufsiz) ? -EFAULT : 0;
}
static int
do_osf_statfs(struct path *path, struct osf_statfs __user *buffer,
unsigned long bufsiz)
SYSCALL_DEFINE3(osf_statfs, const char __user *, pathname,
struct osf_statfs __user *, buffer, unsigned long, bufsiz)
{
struct kstatfs linux_stat;
int error = vfs_statfs(path, &linux_stat);
int error = user_statfs(pathname, &linux_stat);
if (!error)
error = linux_to_osf_statfs(&linux_stat, buffer, bufsiz);
return error;
}
SYSCALL_DEFINE3(osf_statfs, const char __user *, pathname,
struct osf_statfs __user *, buffer, unsigned long, bufsiz)
{
struct path path;
int retval;
retval = user_path(pathname, &path);
if (!retval) {
retval = do_osf_statfs(&path, buffer, bufsiz);
path_put(&path);
}
return retval;
}
SYSCALL_DEFINE3(osf_fstatfs, unsigned long, fd,
struct osf_statfs __user *, buffer, unsigned long, bufsiz)
{
struct file *file;
int retval;
retval = -EBADF;
file = fget(fd);
if (file) {
retval = do_osf_statfs(&file->f_path, buffer, bufsiz);
fput(file);
}
return retval;
struct kstatfs linux_stat;
int error = fd_statfs(fd, &linux_stat);
if (!error)
error = linux_to_osf_statfs(&linux_stat, buffer, bufsiz);
return error;
}
/*

View File

@ -185,26 +185,21 @@ struct hpux_statfs {
int16_t f_pad;
};
static int do_statfs_hpux(struct path *path, struct hpux_statfs *buf)
static int do_statfs_hpux(struct kstatfs *st, struct hpux_statfs __user *p)
{
struct kstatfs st;
int retval;
retval = vfs_statfs(path, &st);
if (retval)
return retval;
memset(buf, 0, sizeof(*buf));
buf->f_type = st.f_type;
buf->f_bsize = st.f_bsize;
buf->f_blocks = st.f_blocks;
buf->f_bfree = st.f_bfree;
buf->f_bavail = st.f_bavail;
buf->f_files = st.f_files;
buf->f_ffree = st.f_ffree;
buf->f_fsid[0] = st.f_fsid.val[0];
buf->f_fsid[1] = st.f_fsid.val[1];
struct hpux_statfs buf;
memset(&buf, 0, sizeof(buf));
buf.f_type = st->f_type;
buf.f_bsize = st->f_bsize;
buf.f_blocks = st->f_blocks;
buf.f_bfree = st->f_bfree;
buf.f_bavail = st->f_bavail;
buf.f_files = st->f_files;
buf.f_ffree = st->f_ffree;
buf.f_fsid[0] = st->f_fsid.val[0];
buf.f_fsid[1] = st->f_fsid.val[1];
if (copy_to_user(p, &buf, sizeof(buf)))
return -EFAULT;
return 0;
}
@ -212,35 +207,19 @@ static int do_statfs_hpux(struct path *path, struct hpux_statfs *buf)
asmlinkage long hpux_statfs(const char __user *pathname,
struct hpux_statfs __user *buf)
{
struct path path;
int error;
error = user_path(pathname, &path);
if (!error) {
struct hpux_statfs tmp;
error = do_statfs_hpux(&path, &tmp);
if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
error = -EFAULT;
path_put(&path);
}
struct kstatfs st;
int error = user_statfs(pathname, &st);
if (!error)
error = do_statfs_hpux(&st, buf);
return error;
}
asmlinkage long hpux_fstatfs(unsigned int fd, struct hpux_statfs __user * buf)
{
struct file *file;
struct hpux_statfs tmp;
int error;
error = -EBADF;
file = fget(fd);
if (!file)
goto out;
error = do_statfs_hpux(&file->f_path, &tmp);
if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
error = -EFAULT;
fput(file);
out:
struct kstatfs st;
int error = fd_statfs(fd, &st);
if (!error)
error = do_statfs_hpux(&st, buf);
return error;
}

View File

@ -70,7 +70,7 @@ static long do_spu_create(const char __user *pathname, unsigned int flags,
if (!IS_ERR(tmp)) {
struct nameidata nd;
ret = path_lookup(tmp, LOOKUP_PARENT, &nd);
ret = kern_path_parent(tmp, &nd);
if (!ret) {
nd.flags |= LOOKUP_OPEN | LOOKUP_CREATE;
ret = spufs_create(&nd, flags, mode, neighbor);

View File

@ -124,35 +124,18 @@ void mconsole_log(struct mc_request *req)
#if 0
void mconsole_proc(struct mc_request *req)
{
struct nameidata nd;
struct vfsmount *mnt = current->nsproxy->pid_ns->proc_mnt;
struct file *file;
int n, err;
int n;
char *ptr = req->request.data, *buf;
mm_segment_t old_fs = get_fs();
ptr += strlen("proc");
ptr = skip_spaces(ptr);
err = vfs_path_lookup(mnt->mnt_root, mnt, ptr, LOOKUP_FOLLOW, &nd);
if (err) {
mconsole_reply(req, "Failed to look up file", 1, 0);
goto out;
}
err = may_open(&nd.path, MAY_READ, O_RDONLY);
if (result) {
mconsole_reply(req, "Failed to open file", 1, 0);
path_put(&nd.path);
goto out;
}
file = dentry_open(nd.path.dentry, nd.path.mnt, O_RDONLY,
current_cred());
err = PTR_ERR(file);
file = file_open_root(mnt->mnt_root, mnt, ptr, O_RDONLY);
if (IS_ERR(file)) {
mconsole_reply(req, "Failed to open file", 1, 0);
path_put(&nd.path);
goto out;
}

View File

@ -851,4 +851,6 @@ ia32_sys_call_table:
.quad sys_fanotify_init
.quad sys32_fanotify_mark
.quad sys_prlimit64 /* 340 */
.quad sys_name_to_handle_at
.quad compat_sys_open_by_handle_at
ia32_syscall_end:

View File

@ -346,10 +346,12 @@
#define __NR_fanotify_init 338
#define __NR_fanotify_mark 339
#define __NR_prlimit64 340
#define __NR_name_to_handle_at 341
#define __NR_open_by_handle_at 342
#ifdef __KERNEL__
#define NR_syscalls 341
#define NR_syscalls 343
#define __ARCH_WANT_IPC_PARSE_VERSION
#define __ARCH_WANT_OLD_READDIR

View File

@ -669,6 +669,10 @@ __SYSCALL(__NR_fanotify_init, sys_fanotify_init)
__SYSCALL(__NR_fanotify_mark, sys_fanotify_mark)
#define __NR_prlimit64 302
__SYSCALL(__NR_prlimit64, sys_prlimit64)
#define __NR_name_to_handle_at 303
__SYSCALL(__NR_name_to_handle_at, sys_name_to_handle_at)
#define __NR_open_by_handle_at 304
__SYSCALL(__NR_open_by_handle_at, sys_open_by_handle_at)
#ifndef __NO_STUBS
#define __ARCH_WANT_OLD_READDIR

View File

@ -340,3 +340,5 @@ ENTRY(sys_call_table)
.long sys_fanotify_init
.long sys_fanotify_mark
.long sys_prlimit64 /* 340 */
.long sys_name_to_handle_at
.long sys_open_by_handle_at

View File

@ -47,7 +47,7 @@ config FS_POSIX_ACL
def_bool n
config EXPORTFS
tristate
bool
config FILE_LOCKING
bool "Enable POSIX file locking API" if EXPERT

View File

@ -48,6 +48,8 @@ obj-$(CONFIG_FS_POSIX_ACL) += posix_acl.o xattr_acl.o
obj-$(CONFIG_NFS_COMMON) += nfs_common/
obj-$(CONFIG_GENERIC_ACL) += generic_acl.o
obj-$(CONFIG_FHANDLE) += fhandle.o
obj-y += quota/
obj-$(CONFIG_PROC_FS) += proc/

View File

@ -21,9 +21,13 @@ static int btrfs_encode_fh(struct dentry *dentry, u32 *fh, int *max_len,
int len = *max_len;
int type;
if ((len < BTRFS_FID_SIZE_NON_CONNECTABLE) ||
(connectable && len < BTRFS_FID_SIZE_CONNECTABLE))
if (connectable && (len < BTRFS_FID_SIZE_CONNECTABLE)) {
*max_len = BTRFS_FID_SIZE_CONNECTABLE;
return 255;
} else if (len < BTRFS_FID_SIZE_NON_CONNECTABLE) {
*max_len = BTRFS_FID_SIZE_NON_CONNECTABLE;
return 255;
}
len = BTRFS_FID_SIZE_NON_CONNECTABLE;
type = FILEID_BTRFS_WITHOUT_PARENT;

View File

@ -4806,9 +4806,6 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
int err;
int drop_inode = 0;
if (inode->i_nlink == 0)
return -ENOENT;
/* do not allow sys_link's with other subvols of the same device */
if (root->objectid != BTRFS_I(inode)->root->objectid)
return -EPERM;

View File

@ -262,35 +262,19 @@ static int put_compat_statfs(struct compat_statfs __user *ubuf, struct kstatfs *
*/
asmlinkage long compat_sys_statfs(const char __user *pathname, struct compat_statfs __user *buf)
{
struct path path;
int error;
error = user_path(pathname, &path);
if (!error) {
struct kstatfs tmp;
error = vfs_statfs(&path, &tmp);
if (!error)
error = put_compat_statfs(buf, &tmp);
path_put(&path);
}
struct kstatfs tmp;
int error = user_statfs(pathname, &tmp);
if (!error)
error = put_compat_statfs(buf, &tmp);
return error;
}
asmlinkage long compat_sys_fstatfs(unsigned int fd, struct compat_statfs __user *buf)
{
struct file * file;
struct kstatfs tmp;
int error;
error = -EBADF;
file = fget(fd);
if (!file)
goto out;
error = vfs_statfs(&file->f_path, &tmp);
int error = fd_statfs(fd, &tmp);
if (!error)
error = put_compat_statfs(buf, &tmp);
fput(file);
out:
return error;
}
@ -329,41 +313,29 @@ static int put_compat_statfs64(struct compat_statfs64 __user *ubuf, struct kstat
asmlinkage long compat_sys_statfs64(const char __user *pathname, compat_size_t sz, struct compat_statfs64 __user *buf)
{
struct path path;
int error;
if (sz != sizeof(*buf))
return -EINVAL;
error = user_path(pathname, &path);
if (!error) {
struct kstatfs tmp;
error = vfs_statfs(&path, &tmp);
if (!error)
error = put_compat_statfs64(buf, &tmp);
path_put(&path);
}
return error;
}
asmlinkage long compat_sys_fstatfs64(unsigned int fd, compat_size_t sz, struct compat_statfs64 __user *buf)
{
struct file * file;
struct kstatfs tmp;
int error;
if (sz != sizeof(*buf))
return -EINVAL;
error = -EBADF;
file = fget(fd);
if (!file)
goto out;
error = vfs_statfs(&file->f_path, &tmp);
error = user_statfs(pathname, &tmp);
if (!error)
error = put_compat_statfs64(buf, &tmp);
return error;
}
asmlinkage long compat_sys_fstatfs64(unsigned int fd, compat_size_t sz, struct compat_statfs64 __user *buf)
{
struct kstatfs tmp;
int error;
if (sz != sizeof(*buf))
return -EINVAL;
error = fd_statfs(fd, &tmp);
if (!error)
error = put_compat_statfs64(buf, &tmp);
fput(file);
out:
return error;
}
@ -2312,3 +2284,16 @@ asmlinkage long compat_sys_timerfd_gettime(int ufd,
}
#endif /* CONFIG_TIMERFD */
#ifdef CONFIG_FHANDLE
/*
* Exactly like fs/open.c:sys_open_by_handle_at(), except that it
* doesn't set the O_LARGEFILE flag.
*/
asmlinkage long
compat_sys_open_by_handle_at(int mountdirfd,
struct file_handle __user *handle, int flags)
{
return do_handle_open(mountdirfd, handle, flags);
}
#endif

View File

@ -115,13 +115,16 @@ SYSCALL_DEFINE1(uselib, const char __user *, library)
struct file *file;
char *tmp = getname(library);
int error = PTR_ERR(tmp);
static const struct open_flags uselib_flags = {
.open_flag = O_LARGEFILE | O_RDONLY | __FMODE_EXEC,
.acc_mode = MAY_READ | MAY_EXEC | MAY_OPEN,
.intent = LOOKUP_OPEN
};
if (IS_ERR(tmp))
goto out;
file = do_filp_open(AT_FDCWD, tmp,
O_LARGEFILE | O_RDONLY | __FMODE_EXEC, 0,
MAY_READ | MAY_EXEC | MAY_OPEN);
file = do_filp_open(AT_FDCWD, tmp, &uselib_flags, LOOKUP_FOLLOW);
putname(tmp);
error = PTR_ERR(file);
if (IS_ERR(file))
@ -721,10 +724,13 @@ struct file *open_exec(const char *name)
{
struct file *file;
int err;
static const struct open_flags open_exec_flags = {
.open_flag = O_LARGEFILE | O_RDONLY | __FMODE_EXEC,
.acc_mode = MAY_EXEC | MAY_OPEN,
.intent = LOOKUP_OPEN
};
file = do_filp_open(AT_FDCWD, name,
O_LARGEFILE | O_RDONLY | __FMODE_EXEC, 0,
MAY_EXEC | MAY_OPEN);
file = do_filp_open(AT_FDCWD, name, &open_exec_flags, LOOKUP_FOLLOW);
if (IS_ERR(file))
goto out;

View File

@ -320,9 +320,14 @@ static int export_encode_fh(struct dentry *dentry, struct fid *fid,
struct inode * inode = dentry->d_inode;
int len = *max_len;
int type = FILEID_INO32_GEN;
if (len < 2 || (connectable && len < 4))
if (connectable && (len < 4)) {
*max_len = 4;
return 255;
} else if (len < 2) {
*max_len = 2;
return 255;
}
len = 2;
fid->i32.ino = inode->i_ino;
@ -369,6 +374,8 @@ struct dentry *exportfs_decode_fh(struct vfsmount *mnt, struct fid *fid,
/*
* Try to get any dentry for the given file handle from the filesystem.
*/
if (!nop || !nop->fh_to_dentry)
return ERR_PTR(-ESTALE);
result = nop->fh_to_dentry(mnt->mnt_sb, fid, fh_len, fileid_type);
if (!result)
result = ERR_PTR(-ESTALE);

View File

@ -2253,13 +2253,6 @@ static int ext3_link (struct dentry * old_dentry,
dquot_initialize(dir);
/*
* Return -ENOENT if we've raced with unlink and i_nlink is 0. Doing
* otherwise has the potential to corrupt the orphan inode list.
*/
if (inode->i_nlink == 0)
return -ENOENT;
retry:
handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) +
EXT3_INDEX_EXTRA_TRANS_BLOCKS);

View File

@ -1936,6 +1936,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
sb->s_qcop = &ext3_qctl_operations;
sb->dq_op = &ext3_quota_operations;
#endif
memcpy(sb->s_uuid, es->s_uuid, sizeof(es->s_uuid));
INIT_LIST_HEAD(&sbi->s_orphan); /* unlinked but open files */
mutex_init(&sbi->s_orphan_lock);
mutex_init(&sbi->s_resize_lock);

View File

@ -2304,13 +2304,6 @@ static int ext4_link(struct dentry *old_dentry,
dquot_initialize(dir);
/*
* Return -ENOENT if we've raced with unlink and i_nlink is 0. Doing
* otherwise has the potential to corrupt the orphan inode list.
*/
if (inode->i_nlink == 0)
return -ENOENT;
retry:
handle = ext4_journal_start(dir, EXT4_DATA_TRANS_BLOCKS(dir->i_sb) +
EXT4_INDEX_EXTRA_TRANS_BLOCKS);

View File

@ -3415,6 +3415,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
sb->s_qcop = &ext4_qctl_operations;
sb->dq_op = &ext4_quota_operations;
#endif
memcpy(sb->s_uuid, es->s_uuid, sizeof(es->s_uuid));
INIT_LIST_HEAD(&sbi->s_orphan); /* unlinked but open files */
mutex_init(&sbi->s_orphan_lock);
mutex_init(&sbi->s_resize_lock);

View File

@ -757,8 +757,10 @@ fat_encode_fh(struct dentry *de, __u32 *fh, int *lenp, int connectable)
struct inode *inode = de->d_inode;
u32 ipos_h, ipos_m, ipos_l;
if (len < 5)
if (len < 5) {
*lenp = 5;
return 255; /* no room */
}
ipos_h = MSDOS_I(inode)->i_pos >> 8;
ipos_m = (MSDOS_I(inode)->i_pos & 0xf0) << 24;

View File

@ -131,7 +131,7 @@ SYSCALL_DEFINE2(dup2, unsigned int, oldfd, unsigned int, newfd)
SYSCALL_DEFINE1(dup, unsigned int, fildes)
{
int ret = -EBADF;
struct file *file = fget(fildes);
struct file *file = fget_raw(fildes);
if (file) {
ret = get_unused_fd();
@ -426,15 +426,35 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
return err;
}
static int check_fcntl_cmd(unsigned cmd)
{
switch (cmd) {
case F_DUPFD:
case F_DUPFD_CLOEXEC:
case F_GETFD:
case F_SETFD:
case F_GETFL:
return 1;
}
return 0;
}
SYSCALL_DEFINE3(fcntl, unsigned int, fd, unsigned int, cmd, unsigned long, arg)
{
struct file *filp;
long err = -EBADF;
filp = fget(fd);
filp = fget_raw(fd);
if (!filp)
goto out;
if (unlikely(filp->f_mode & FMODE_PATH)) {
if (!check_fcntl_cmd(cmd)) {
fput(filp);
goto out;
}
}
err = security_file_fcntl(filp, cmd, arg);
if (err) {
fput(filp);
@ -456,10 +476,17 @@ SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd,
long err;
err = -EBADF;
filp = fget(fd);
filp = fget_raw(fd);
if (!filp)
goto out;
if (unlikely(filp->f_mode & FMODE_PATH)) {
if (!check_fcntl_cmd(cmd)) {
fput(filp);
goto out;
}
}
err = security_file_fcntl(filp, cmd, arg);
if (err) {
fput(filp);
@ -808,14 +835,14 @@ static int __init fcntl_init(void)
* Exceptions: O_NONBLOCK is a two bit define on parisc; O_NDELAY
* is defined as O_NONBLOCK on some platforms and not on others.
*/
BUILD_BUG_ON(18 - 1 /* for O_RDONLY being 0 */ != HWEIGHT32(
BUILD_BUG_ON(19 - 1 /* for O_RDONLY being 0 */ != HWEIGHT32(
O_RDONLY | O_WRONLY | O_RDWR |
O_CREAT | O_EXCL | O_NOCTTY |
O_TRUNC | O_APPEND | /* O_NONBLOCK | */
__O_SYNC | O_DSYNC | FASYNC |
O_DIRECT | O_LARGEFILE | O_DIRECTORY |
O_NOFOLLOW | O_NOATIME | O_CLOEXEC |
__FMODE_EXEC
__FMODE_EXEC | O_PATH
));
fasync_cache = kmem_cache_create("fasync_cache",

265
fs/fhandle.c Normal file
View File

@ -0,0 +1,265 @@
#include <linux/syscalls.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/mount.h>
#include <linux/namei.h>
#include <linux/exportfs.h>
#include <linux/fs_struct.h>
#include <linux/fsnotify.h>
#include <asm/uaccess.h>
#include "internal.h"
static long do_sys_name_to_handle(struct path *path,
struct file_handle __user *ufh,
int __user *mnt_id)
{
long retval;
struct file_handle f_handle;
int handle_dwords, handle_bytes;
struct file_handle *handle = NULL;
/*
* We need t make sure wether the file system
* support decoding of the file handle
*/
if (!path->mnt->mnt_sb->s_export_op ||
!path->mnt->mnt_sb->s_export_op->fh_to_dentry)
return -EOPNOTSUPP;
if (copy_from_user(&f_handle, ufh, sizeof(struct file_handle)))
return -EFAULT;
if (f_handle.handle_bytes > MAX_HANDLE_SZ)
return -EINVAL;
handle = kmalloc(sizeof(struct file_handle) + f_handle.handle_bytes,
GFP_KERNEL);
if (!handle)
return -ENOMEM;
/* convert handle size to multiple of sizeof(u32) */
handle_dwords = f_handle.handle_bytes >> 2;
/* we ask for a non connected handle */
retval = exportfs_encode_fh(path->dentry,
(struct fid *)handle->f_handle,
&handle_dwords, 0);
handle->handle_type = retval;
/* convert handle size to bytes */
handle_bytes = handle_dwords * sizeof(u32);
handle->handle_bytes = handle_bytes;
if ((handle->handle_bytes > f_handle.handle_bytes) ||
(retval == 255) || (retval == -ENOSPC)) {
/* As per old exportfs_encode_fh documentation
* we could return ENOSPC to indicate overflow
* But file system returned 255 always. So handle
* both the values
*/
/*
* set the handle size to zero so we copy only
* non variable part of the file_handle
*/
handle_bytes = 0;
retval = -EOVERFLOW;
} else
retval = 0;
/* copy the mount id */
if (copy_to_user(mnt_id, &path->mnt->mnt_id, sizeof(*mnt_id)) ||
copy_to_user(ufh, handle,
sizeof(struct file_handle) + handle_bytes))
retval = -EFAULT;
kfree(handle);
return retval;
}
/**
* sys_name_to_handle_at: convert name to handle
* @dfd: directory relative to which name is interpreted if not absolute
* @name: name that should be converted to handle.
* @handle: resulting file handle
* @mnt_id: mount id of the file system containing the file
* @flag: flag value to indicate whether to follow symlink or not
*
* @handle->handle_size indicate the space available to store the
* variable part of the file handle in bytes. If there is not
* enough space, the field is updated to return the minimum
* value required.
*/
SYSCALL_DEFINE5(name_to_handle_at, int, dfd, const char __user *, name,
struct file_handle __user *, handle, int __user *, mnt_id,
int, flag)
{
struct path path;
int lookup_flags;
int err;
if ((flag & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH)) != 0)
return -EINVAL;
lookup_flags = (flag & AT_SYMLINK_FOLLOW) ? LOOKUP_FOLLOW : 0;
if (flag & AT_EMPTY_PATH)
lookup_flags |= LOOKUP_EMPTY;
err = user_path_at(dfd, name, lookup_flags, &path);
if (!err) {
err = do_sys_name_to_handle(&path, handle, mnt_id);
path_put(&path);
}
return err;
}
static struct vfsmount *get_vfsmount_from_fd(int fd)
{
struct path path;
if (fd == AT_FDCWD) {
struct fs_struct *fs = current->fs;
spin_lock(&fs->lock);
path = fs->pwd;
mntget(path.mnt);
spin_unlock(&fs->lock);
} else {
int fput_needed;
struct file *file = fget_light(fd, &fput_needed);
if (!file)
return ERR_PTR(-EBADF);
path = file->f_path;
mntget(path.mnt);
fput_light(file, fput_needed);
}
return path.mnt;
}
static int vfs_dentry_acceptable(void *context, struct dentry *dentry)
{
return 1;
}
static int do_handle_to_path(int mountdirfd, struct file_handle *handle,
struct path *path)
{
int retval = 0;
int handle_dwords;
path->mnt = get_vfsmount_from_fd(mountdirfd);
if (IS_ERR(path->mnt)) {
retval = PTR_ERR(path->mnt);
goto out_err;
}
/* change the handle size to multiple of sizeof(u32) */
handle_dwords = handle->handle_bytes >> 2;
path->dentry = exportfs_decode_fh(path->mnt,
(struct fid *)handle->f_handle,
handle_dwords, handle->handle_type,
vfs_dentry_acceptable, NULL);
if (IS_ERR(path->dentry)) {
retval = PTR_ERR(path->dentry);
goto out_mnt;
}
return 0;
out_mnt:
mntput(path->mnt);
out_err:
return retval;
}
static int handle_to_path(int mountdirfd, struct file_handle __user *ufh,
struct path *path)
{
int retval = 0;
struct file_handle f_handle;
struct file_handle *handle = NULL;
/*
* With handle we don't look at the execute bit on the
* the directory. Ideally we would like CAP_DAC_SEARCH.
* But we don't have that
*/
if (!capable(CAP_DAC_READ_SEARCH)) {
retval = -EPERM;
goto out_err;
}
if (copy_from_user(&f_handle, ufh, sizeof(struct file_handle))) {
retval = -EFAULT;
goto out_err;
}
if ((f_handle.handle_bytes > MAX_HANDLE_SZ) ||
(f_handle.handle_bytes == 0)) {
retval = -EINVAL;
goto out_err;
}
handle = kmalloc(sizeof(struct file_handle) + f_handle.handle_bytes,
GFP_KERNEL);
if (!handle) {
retval = -ENOMEM;
goto out_err;
}
/* copy the full handle */
if (copy_from_user(handle, ufh,
sizeof(struct file_handle) +
f_handle.handle_bytes)) {
retval = -EFAULT;
goto out_handle;
}
retval = do_handle_to_path(mountdirfd, handle, path);
out_handle:
kfree(handle);
out_err:
return retval;
}
long do_handle_open(int mountdirfd,
struct file_handle __user *ufh, int open_flag)
{
long retval = 0;
struct path path;
struct file *file;
int fd;
retval = handle_to_path(mountdirfd, ufh, &path);
if (retval)
return retval;
fd = get_unused_fd_flags(open_flag);
if (fd < 0) {
path_put(&path);
return fd;
}
file = file_open_root(path.dentry, path.mnt, "", open_flag);
if (IS_ERR(file)) {
put_unused_fd(fd);
retval = PTR_ERR(file);
} else {
retval = fd;
fsnotify_open(file);
fd_install(fd, file);
}
path_put(&path);
return retval;
}
/**
* sys_open_by_handle_at: Open the file handle
* @mountdirfd: directory file descriptor
* @handle: file handle to be opened
* @flag: open flags.
*
* @mountdirfd indicate the directory file descriptor
* of the mount point. file handle is decoded relative
* to the vfsmount pointed by the @mountdirfd. @flags
* value is same as the open(2) flags.
*/
SYSCALL_DEFINE3(open_by_handle_at, int, mountdirfd,
struct file_handle __user *, handle,
int, flags)
{
long ret;
if (force_o_largefile())
flags |= O_LARGEFILE;
ret = do_handle_open(mountdirfd, handle, flags);
return ret;
}

View File

@ -276,11 +276,10 @@ struct file *fget(unsigned int fd)
rcu_read_lock();
file = fcheck_files(files, fd);
if (file) {
if (!atomic_long_inc_not_zero(&file->f_count)) {
/* File object ref couldn't be taken */
rcu_read_unlock();
return NULL;
}
/* File object ref couldn't be taken */
if (file->f_mode & FMODE_PATH ||
!atomic_long_inc_not_zero(&file->f_count))
file = NULL;
}
rcu_read_unlock();
@ -289,6 +288,25 @@ struct file *fget(unsigned int fd)
EXPORT_SYMBOL(fget);
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;
}
EXPORT_SYMBOL(fget_raw);
/*
* Lightweight file lookup - no refcnt increment if fd table isn't shared.
*
@ -310,6 +328,33 @@ 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;
}
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);

View File

@ -637,8 +637,10 @@ static int fuse_encode_fh(struct dentry *dentry, u32 *fh, int *max_len,
u64 nodeid;
u32 generation;
if (*max_len < len)
if (*max_len < len) {
*max_len = len;
return 255;
}
nodeid = get_fuse_inode(inode)->nodeid;
generation = inode->i_generation;

View File

@ -36,9 +36,13 @@ static int gfs2_encode_fh(struct dentry *dentry, __u32 *p, int *len,
struct super_block *sb = inode->i_sb;
struct gfs2_inode *ip = GFS2_I(inode);
if (*len < GFS2_SMALL_FH_SIZE ||
(connectable && *len < GFS2_LARGE_FH_SIZE))
if (connectable && (*len < GFS2_LARGE_FH_SIZE)) {
*len = GFS2_LARGE_FH_SIZE;
return 255;
} else if (*len < GFS2_SMALL_FH_SIZE) {
*len = GFS2_SMALL_FH_SIZE;
return 255;
}
fh[0] = cpu_to_be32(ip->i_no_formal_ino >> 32);
fh[1] = cpu_to_be32(ip->i_no_formal_ino & 0xFFFFFFFF);

View File

@ -106,6 +106,19 @@ extern void put_super(struct super_block *sb);
struct nameidata;
extern struct file *nameidata_to_filp(struct nameidata *);
extern void release_open_intent(struct nameidata *);
struct open_flags {
int open_flag;
int mode;
int acc_mode;
int intent;
};
extern struct file *do_filp_open(int dfd, const char *pathname,
const struct open_flags *op, int lookup_flags);
extern struct file *do_file_open_root(struct dentry *, struct vfsmount *,
const char *, const struct open_flags *, int lookup_flags);
extern long do_handle_open(int mountdirfd,
struct file_handle __user *ufh, int open_flag);
/*
* inode.c

View File

@ -124,9 +124,13 @@ isofs_export_encode_fh(struct dentry *dentry,
* offset of the inode and the upper 16 bits of fh32[1] to
* hold the offset of the parent.
*/
if (len < 3 || (connectable && len < 5))
if (connectable && (len < 5)) {
*max_len = 5;
return 255;
} else if (len < 3) {
*max_len = 3;
return 255;
}
len = 3;
fh32[0] = ei->i_iget5_block;

View File

@ -809,9 +809,6 @@ static int jfs_link(struct dentry *old_dentry,
if (ip->i_nlink == JFS_LINK_MAX)
return -EMLINK;
if (ip->i_nlink == 0)
return -ENOENT;
dquot_initialize(dir);
tid = txBegin(ip->i_sb, 0);

1526
fs/namei.c

File diff suppressed because it is too large Load Diff

View File

@ -1002,6 +1002,18 @@ const struct seq_operations mounts_op = {
.show = show_vfsmnt
};
static int uuid_is_nil(u8 *uuid)
{
int i;
u8 *cp = (u8 *)uuid;
for (i = 0; i < 16; i++) {
if (*cp++)
return 0;
}
return 1;
}
static int show_mountinfo(struct seq_file *m, void *v)
{
struct proc_mounts *p = m->private;
@ -1040,6 +1052,10 @@ static int show_mountinfo(struct seq_file *m, void *v)
if (IS_MNT_UNBINDABLE(mnt))
seq_puts(m, " unbindable");
if (!uuid_is_nil(mnt->mnt_sb->s_uuid))
/* print the uuid */
seq_printf(m, " uuid:%pU", mnt->mnt_sb->s_uuid);
/* Filesystem specific data */
seq_puts(m, " - ");
show_type(m, sb);

View File

@ -22,30 +22,17 @@
static struct file *do_open(char *name, int flags)
{
struct nameidata nd;
struct vfsmount *mnt;
int error;
struct file *file;
mnt = do_kern_mount("nfsd", 0, "nfsd", NULL);
if (IS_ERR(mnt))
return (struct file *)mnt;
error = vfs_path_lookup(mnt->mnt_root, mnt, name, 0, &nd);
file = file_open_root(mnt->mnt_root, mnt, name, flags);
mntput(mnt); /* drop do_kern_mount reference */
if (error)
return ERR_PTR(error);
if (flags == O_RDWR)
error = may_open(&nd.path, MAY_READ|MAY_WRITE, flags);
else
error = may_open(&nd.path, MAY_WRITE, flags);
if (!error)
return dentry_open(nd.path.dentry, nd.path.mnt, flags,
current_cred());
path_put(&nd.path);
return ERR_PTR(error);
return file;
}
static struct {

View File

@ -197,8 +197,12 @@ static int ocfs2_encode_fh(struct dentry *dentry, u32 *fh_in, int *max_len,
dentry->d_name.len, dentry->d_name.name,
fh, len, connectable);
if (len < 3 || (connectable && len < 6)) {
mlog(ML_ERROR, "fh buffer is too small for encoding\n");
if (connectable && (len < 6)) {
*max_len = 6;
type = 255;
goto bail;
} else if (len < 3) {
*max_len = 3;
type = 255;
goto bail;
}

View File

@ -4379,7 +4379,7 @@ static int ocfs2_user_path_parent(const char __user *path,
if (IS_ERR(s))
return PTR_ERR(s);
error = path_lookup(s, LOOKUP_PARENT, nd);
error = kern_path_parent(s, nd);
if (error)
putname(s);
else

126
fs/open.c
View File

@ -573,13 +573,15 @@ SYSCALL_DEFINE5(fchownat, int, dfd, const char __user *, filename, uid_t, user,
{
struct path path;
int error = -EINVAL;
int follow;
int lookup_flags;
if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0)
if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) != 0)
goto out;
follow = (flag & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW;
error = user_path_at(dfd, filename, follow, &path);
lookup_flags = (flag & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW;
if (flag & AT_EMPTY_PATH)
lookup_flags |= LOOKUP_EMPTY;
error = user_path_at(dfd, filename, lookup_flags, &path);
if (error)
goto out;
error = mnt_want_write(path.mnt);
@ -669,11 +671,16 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
int (*open)(struct inode *, struct file *),
const struct cred *cred)
{
static const struct file_operations empty_fops = {};
struct inode *inode;
int error;
f->f_mode = OPEN_FMODE(f->f_flags) | FMODE_LSEEK |
FMODE_PREAD | FMODE_PWRITE;
if (unlikely(f->f_flags & O_PATH))
f->f_mode = FMODE_PATH;
inode = dentry->d_inode;
if (f->f_mode & FMODE_WRITE) {
error = __get_file_write_access(inode, mnt);
@ -687,9 +694,15 @@ static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
f->f_path.dentry = dentry;
f->f_path.mnt = mnt;
f->f_pos = 0;
f->f_op = fops_get(inode->i_fop);
file_sb_list_add(f, inode->i_sb);
if (unlikely(f->f_mode & FMODE_PATH)) {
f->f_op = &empty_fops;
return f;
}
f->f_op = fops_get(inode->i_fop);
error = security_dentry_open(f, cred);
if (error)
goto cleanup_all;
@ -890,15 +903,110 @@ void fd_install(unsigned int fd, struct file *file)
EXPORT_SYMBOL(fd_install);
static inline int build_open_flags(int flags, int mode, struct open_flags *op)
{
int lookup_flags = 0;
int acc_mode;
if (!(flags & O_CREAT))
mode = 0;
op->mode = mode;
/* Must never be set by userspace */
flags &= ~FMODE_NONOTIFY;
/*
* O_SYNC is implemented as __O_SYNC|O_DSYNC. As many places only
* check for O_DSYNC if the need any syncing at all we enforce it's
* always set instead of having to deal with possibly weird behaviour
* for malicious applications setting only __O_SYNC.
*/
if (flags & __O_SYNC)
flags |= O_DSYNC;
/*
* If we have O_PATH in the open flag. Then we
* cannot have anything other than the below set of flags
*/
if (flags & O_PATH) {
flags &= O_DIRECTORY | O_NOFOLLOW | O_PATH;
acc_mode = 0;
} else {
acc_mode = MAY_OPEN | ACC_MODE(flags);
}
op->open_flag = flags;
/* O_TRUNC implies we need access checks for write permissions */
if (flags & O_TRUNC)
acc_mode |= MAY_WRITE;
/* Allow the LSM permission hook to distinguish append
access from general write access. */
if (flags & O_APPEND)
acc_mode |= MAY_APPEND;
op->acc_mode = acc_mode;
op->intent = flags & O_PATH ? 0 : LOOKUP_OPEN;
if (flags & O_CREAT) {
op->intent |= LOOKUP_CREATE;
if (flags & O_EXCL)
op->intent |= LOOKUP_EXCL;
}
if (flags & O_DIRECTORY)
lookup_flags |= LOOKUP_DIRECTORY;
if (!(flags & O_NOFOLLOW))
lookup_flags |= LOOKUP_FOLLOW;
return lookup_flags;
}
/**
* filp_open - open file and return file pointer
*
* @filename: path to open
* @flags: open flags as per the open(2) second argument
* @mode: mode for the new file if O_CREAT is set, else ignored
*
* This is the helper to open a file from kernelspace if you really
* have to. But in generally you should not do this, so please move
* along, nothing to see here..
*/
struct file *filp_open(const char *filename, int flags, int mode)
{
struct open_flags op;
int lookup = build_open_flags(flags, mode, &op);
return do_filp_open(AT_FDCWD, filename, &op, lookup);
}
EXPORT_SYMBOL(filp_open);
struct file *file_open_root(struct dentry *dentry, struct vfsmount *mnt,
const char *filename, int flags)
{
struct open_flags op;
int lookup = build_open_flags(flags, 0, &op);
if (flags & O_CREAT)
return ERR_PTR(-EINVAL);
if (!filename && (flags & O_DIRECTORY))
if (!dentry->d_inode->i_op->lookup)
return ERR_PTR(-ENOTDIR);
return do_file_open_root(dentry, mnt, filename, &op, lookup);
}
EXPORT_SYMBOL(file_open_root);
long do_sys_open(int dfd, const char __user *filename, int flags, int mode)
{
struct open_flags op;
int lookup = build_open_flags(flags, mode, &op);
char *tmp = getname(filename);
int fd = PTR_ERR(tmp);
if (!IS_ERR(tmp)) {
fd = get_unused_fd_flags(flags);
if (fd >= 0) {
struct file *f = do_filp_open(dfd, tmp, flags, mode, 0);
struct file *f = do_filp_open(dfd, tmp, &op, lookup);
if (IS_ERR(f)) {
put_unused_fd(fd);
fd = PTR_ERR(f);
@ -968,8 +1076,10 @@ int filp_close(struct file *filp, fl_owner_t id)
if (filp->f_op && filp->f_op->flush)
retval = filp->f_op->flush(filp, id);
dnotify_flush(filp, id);
locks_remove_posix(filp, id);
if (likely(!(filp->f_mode & FMODE_PATH))) {
dnotify_flush(filp, id);
locks_remove_posix(filp, id);
}
fput(filp);
return retval;
}

View File

@ -1593,8 +1593,13 @@ int reiserfs_encode_fh(struct dentry *dentry, __u32 * data, int *lenp,
struct inode *inode = dentry->d_inode;
int maxlen = *lenp;
if (maxlen < 3)
if (need_parent && (maxlen < 5)) {
*lenp = 5;
return 255;
} else if (maxlen < 3) {
*lenp = 3;
return 255;
}
data[0] = inode->i_ino;
data[1] = le32_to_cpu(INODE_PKEY(inode)->k_dir_id);

View File

@ -1122,10 +1122,6 @@ static int reiserfs_link(struct dentry *old_dentry, struct inode *dir,
reiserfs_write_unlock(dir->i_sb);
return -EMLINK;
}
if (inode->i_nlink == 0) {
reiserfs_write_unlock(dir->i_sb);
return -ENOENT;
}
/* inc before scheduling so reiserfs_unlink knows we are here */
inc_nlink(inode);

View File

@ -75,13 +75,16 @@ int vfs_fstatat(int dfd, const char __user *filename, struct kstat *stat,
int error = -EINVAL;
int lookup_flags = 0;
if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT)) != 0)
if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT |
AT_EMPTY_PATH)) != 0)
goto out;
if (!(flag & AT_SYMLINK_NOFOLLOW))
lookup_flags |= LOOKUP_FOLLOW;
if (flag & AT_NO_AUTOMOUNT)
lookup_flags |= LOOKUP_NO_AUTOMOUNT;
if (flag & AT_EMPTY_PATH)
lookup_flags |= LOOKUP_EMPTY;
error = user_path_at(dfd, filename, lookup_flags, &path);
if (error)
@ -297,7 +300,7 @@ SYSCALL_DEFINE4(readlinkat, int, dfd, const char __user *, pathname,
if (bufsiz <= 0)
return -EINVAL;
error = user_path_at(dfd, pathname, 0, &path);
error = user_path_at(dfd, pathname, LOOKUP_EMPTY, &path);
if (!error) {
struct inode *inode = path.dentry->d_inode;

View File

@ -73,149 +73,135 @@ int vfs_statfs(struct path *path, struct kstatfs *buf)
}
EXPORT_SYMBOL(vfs_statfs);
static int do_statfs_native(struct path *path, struct statfs *buf)
int user_statfs(const char __user *pathname, struct kstatfs *st)
{
struct kstatfs st;
int retval;
struct path path;
int error = user_path(pathname, &path);
if (!error) {
error = vfs_statfs(&path, st);
path_put(&path);
}
return error;
}
retval = vfs_statfs(path, &st);
if (retval)
return retval;
int fd_statfs(int fd, struct kstatfs *st)
{
struct file *file = fget(fd);
int error = -EBADF;
if (file) {
error = vfs_statfs(&file->f_path, st);
fput(file);
}
return error;
}
if (sizeof(*buf) == sizeof(st))
memcpy(buf, &st, sizeof(st));
static int do_statfs_native(struct kstatfs *st, struct statfs __user *p)
{
struct statfs buf;
if (sizeof(buf) == sizeof(*st))
memcpy(&buf, st, sizeof(*st));
else {
if (sizeof buf->f_blocks == 4) {
if ((st.f_blocks | st.f_bfree | st.f_bavail |
st.f_bsize | st.f_frsize) &
if (sizeof buf.f_blocks == 4) {
if ((st->f_blocks | st->f_bfree | st->f_bavail |
st->f_bsize | st->f_frsize) &
0xffffffff00000000ULL)
return -EOVERFLOW;
/*
* f_files and f_ffree may be -1; it's okay to stuff
* that into 32 bits
*/
if (st.f_files != -1 &&
(st.f_files & 0xffffffff00000000ULL))
if (st->f_files != -1 &&
(st->f_files & 0xffffffff00000000ULL))
return -EOVERFLOW;
if (st.f_ffree != -1 &&
(st.f_ffree & 0xffffffff00000000ULL))
if (st->f_ffree != -1 &&
(st->f_ffree & 0xffffffff00000000ULL))
return -EOVERFLOW;
}
buf->f_type = st.f_type;
buf->f_bsize = st.f_bsize;
buf->f_blocks = st.f_blocks;
buf->f_bfree = st.f_bfree;
buf->f_bavail = st.f_bavail;
buf->f_files = st.f_files;
buf->f_ffree = st.f_ffree;
buf->f_fsid = st.f_fsid;
buf->f_namelen = st.f_namelen;
buf->f_frsize = st.f_frsize;
buf->f_flags = st.f_flags;
memset(buf->f_spare, 0, sizeof(buf->f_spare));
buf.f_type = st->f_type;
buf.f_bsize = st->f_bsize;
buf.f_blocks = st->f_blocks;
buf.f_bfree = st->f_bfree;
buf.f_bavail = st->f_bavail;
buf.f_files = st->f_files;
buf.f_ffree = st->f_ffree;
buf.f_fsid = st->f_fsid;
buf.f_namelen = st->f_namelen;
buf.f_frsize = st->f_frsize;
buf.f_flags = st->f_flags;
memset(buf.f_spare, 0, sizeof(buf.f_spare));
}
if (copy_to_user(p, &buf, sizeof(buf)))
return -EFAULT;
return 0;
}
static int do_statfs64(struct path *path, struct statfs64 *buf)
static int do_statfs64(struct kstatfs *st, struct statfs64 __user *p)
{
struct kstatfs st;
int retval;
retval = vfs_statfs(path, &st);
if (retval)
return retval;
if (sizeof(*buf) == sizeof(st))
memcpy(buf, &st, sizeof(st));
struct statfs64 buf;
if (sizeof(buf) == sizeof(*st))
memcpy(&buf, st, sizeof(*st));
else {
buf->f_type = st.f_type;
buf->f_bsize = st.f_bsize;
buf->f_blocks = st.f_blocks;
buf->f_bfree = st.f_bfree;
buf->f_bavail = st.f_bavail;
buf->f_files = st.f_files;
buf->f_ffree = st.f_ffree;
buf->f_fsid = st.f_fsid;
buf->f_namelen = st.f_namelen;
buf->f_frsize = st.f_frsize;
buf->f_flags = st.f_flags;
memset(buf->f_spare, 0, sizeof(buf->f_spare));
buf.f_type = st->f_type;
buf.f_bsize = st->f_bsize;
buf.f_blocks = st->f_blocks;
buf.f_bfree = st->f_bfree;
buf.f_bavail = st->f_bavail;
buf.f_files = st->f_files;
buf.f_ffree = st->f_ffree;
buf.f_fsid = st->f_fsid;
buf.f_namelen = st->f_namelen;
buf.f_frsize = st->f_frsize;
buf.f_flags = st->f_flags;
memset(buf.f_spare, 0, sizeof(buf.f_spare));
}
if (copy_to_user(p, &buf, sizeof(buf)))
return -EFAULT;
return 0;
}
SYSCALL_DEFINE2(statfs, const char __user *, pathname, struct statfs __user *, buf)
{
struct path path;
int error;
error = user_path(pathname, &path);
if (!error) {
struct statfs tmp;
error = do_statfs_native(&path, &tmp);
if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
error = -EFAULT;
path_put(&path);
}
struct kstatfs st;
int error = user_statfs(pathname, &st);
if (!error)
error = do_statfs_native(&st, buf);
return error;
}
SYSCALL_DEFINE3(statfs64, const char __user *, pathname, size_t, sz, struct statfs64 __user *, buf)
{
struct path path;
long error;
struct kstatfs st;
int error;
if (sz != sizeof(*buf))
return -EINVAL;
error = user_path(pathname, &path);
if (!error) {
struct statfs64 tmp;
error = do_statfs64(&path, &tmp);
if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
error = -EFAULT;
path_put(&path);
}
error = user_statfs(pathname, &st);
if (!error)
error = do_statfs64(&st, buf);
return error;
}
SYSCALL_DEFINE2(fstatfs, unsigned int, fd, struct statfs __user *, buf)
{
struct file *file;
struct statfs tmp;
int error;
error = -EBADF;
file = fget(fd);
if (!file)
goto out;
error = do_statfs_native(&file->f_path, &tmp);
if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
error = -EFAULT;
fput(file);
out:
struct kstatfs st;
int error = fd_statfs(fd, &st);
if (!error)
error = do_statfs_native(&st, buf);
return error;
}
SYSCALL_DEFINE3(fstatfs64, unsigned int, fd, size_t, sz, struct statfs64 __user *, buf)
{
struct file *file;
struct statfs64 tmp;
struct kstatfs st;
int error;
if (sz != sizeof(*buf))
return -EINVAL;
error = -EBADF;
file = fget(fd);
if (!file)
goto out;
error = do_statfs64(&file->f_path, &tmp);
if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
error = -EFAULT;
fput(file);
out:
error = fd_statfs(fd, &st);
if (!error)
error = do_statfs64(&st, buf);
return error;
}

View File

@ -522,24 +522,6 @@ static int ubifs_link(struct dentry *old_dentry, struct inode *dir,
ubifs_assert(mutex_is_locked(&dir->i_mutex));
ubifs_assert(mutex_is_locked(&inode->i_mutex));
/*
* Return -ENOENT if we've raced with unlink and i_nlink is 0. Doing
* otherwise has the potential to corrupt the orphan inode list.
*
* Indeed, consider a scenario when 'vfs_link(dirA/fileA)' and
* 'vfs_unlink(dirA/fileA, dirB/fileB)' race. 'vfs_link()' does not
* lock 'dirA->i_mutex', so this is possible. Both of the functions
* lock 'fileA->i_mutex' though. Suppose 'vfs_unlink()' wins, and takes
* 'fileA->i_mutex' mutex first. Suppose 'fileA->i_nlink' is 1. In this
* case 'ubifs_unlink()' will drop the last reference, and put 'inodeA'
* to the list of orphans. After this, 'vfs_link()' will link
* 'dirB/fileB' to 'inodeA'. This is a problem because, for example,
* the subsequent 'vfs_unlink(dirB/fileB)' will add the same inode
* to the list of orphans.
*/
if (inode->i_nlink == 0)
return -ENOENT;
err = dbg_check_synced_i_size(inode);
if (err)
return err;

View File

@ -1286,8 +1286,13 @@ static int udf_encode_fh(struct dentry *de, __u32 *fh, int *lenp,
struct fid *fid = (struct fid *)fh;
int type = FILEID_UDF_WITHOUT_PARENT;
if (len < 3 || (connectable && len < 5))
if (connectable && (len < 5)) {
*lenp = 5;
return 255;
} else if (len < 3) {
*lenp = 3;
return 255;
}
*lenp = 3;
fid->udf.block = location.logicalBlockNum;

View File

@ -89,8 +89,10 @@ xfs_fs_encode_fh(
* seven combinations work. The real answer is "don't use v2".
*/
len = xfs_fileid_length(fileid_type);
if (*max_len < len)
if (*max_len < len) {
*max_len = len;
return 255;
}
*max_len = len;
switch (fileid_type) {

View File

@ -80,6 +80,10 @@
#define O_SYNC (__O_SYNC|O_DSYNC)
#endif
#ifndef O_PATH
#define O_PATH 010000000
#endif
#ifndef O_NDELAY
#define O_NDELAY O_NONBLOCK
#endif

View File

@ -646,9 +646,13 @@ __SYSCALL(__NR_prlimit64, sys_prlimit64)
__SYSCALL(__NR_fanotify_init, sys_fanotify_init)
#define __NR_fanotify_mark 263
__SYSCALL(__NR_fanotify_mark, sys_fanotify_mark)
#define __NR_name_to_handle_at 264
__SYSCALL(__NR_name_to_handle_at, sys_name_to_handle_at)
#define __NR_open_by_handle_at 265
__SYSCALL(__NR_open_by_handle_at, sys_open_by_handle_at)
#undef __NR_syscalls
#define __NR_syscalls 264
#define __NR_syscalls 266
/*
* All syscalls below here should go away really,

View File

@ -8,6 +8,9 @@ struct inode;
struct super_block;
struct vfsmount;
/* limit the handle size to NFSv4 handle size now */
#define MAX_HANDLE_SZ 128
/*
* The fileid_type identifies how the file within the filesystem is encoded.
* In theory this is freely set and parsed by the filesystem, but we try to
@ -121,8 +124,10 @@ struct fid {
* set, the encode_fh() should store sufficient information so that a good
* attempt can be made to find not only the file but also it's place in the
* filesystem. This typically means storing a reference to de->d_parent in
* the filehandle fragment. encode_fh() should return the number of bytes
* stored or a negative error code such as %-ENOSPC
* the filehandle fragment. encode_fh() should return the fileid_type on
* success and on error returns 255 (if the space needed to encode fh is
* greater than @max_len*4 bytes). On error @max_len contains the minimum
* size(in 4 byte unit) needed to encode the file handle.
*
* fh_to_dentry:
* @fh_to_dentry is given a &struct super_block (@sb) and a file handle

View File

@ -46,6 +46,7 @@
unlinking file. */
#define AT_SYMLINK_FOLLOW 0x400 /* Follow symbolic links. */
#define AT_NO_AUTOMOUNT 0x800 /* Suppress terminal automount traversal */
#define AT_EMPTY_PATH 0x1000 /* Allow empty relative pathname */
#ifdef __KERNEL__

View File

@ -29,6 +29,8 @@ static inline void fput_light(struct file *file, int fput_needed)
extern struct file *fget(unsigned int fd);
extern struct file *fget_light(unsigned int fd, int *fput_needed);
extern struct file *fget_raw(unsigned int fd);
extern struct file *fget_raw_light(unsigned int fd, int *fput_needed);
extern void set_close_on_exec(unsigned int fd, int flag);
extern void put_filp(struct file *);
extern int alloc_fd(unsigned start, unsigned flags);

View File

@ -102,6 +102,9 @@ struct inodes_stat_t {
/* File is huge (eg. /dev/kmem): treat loff_t as unsigned */
#define FMODE_UNSIGNED_OFFSET ((__force fmode_t)0x2000)
/* File is opened with O_PATH; almost nothing can be done with it */
#define FMODE_PATH ((__force fmode_t)0x4000)
/* File was opened by fanotify and shouldn't generate fanotify events */
#define FMODE_NONOTIFY ((__force fmode_t)0x1000000)
@ -978,6 +981,13 @@ struct file {
#endif
};
struct file_handle {
__u32 handle_bytes;
int handle_type;
/* file identifier */
unsigned char f_handle[0];
};
#define get_file(x) atomic_long_inc(&(x)->f_count)
#define fput_atomic(x) atomic_long_add_unless(&(x)->f_count, -1, 1)
#define file_count(x) atomic_long_read(&(x)->f_count)
@ -1401,6 +1411,7 @@ struct super_block {
wait_queue_head_t s_wait_unfrozen;
char s_id[32]; /* Informational name */
u8 s_uuid[16]; /* UUID */
void *s_fs_info; /* Filesystem private info */
fmode_t s_mode;
@ -1874,6 +1885,8 @@ extern void drop_collected_mounts(struct vfsmount *);
extern int iterate_mounts(int (*)(struct vfsmount *, void *), void *,
struct vfsmount *);
extern int vfs_statfs(struct path *, struct kstatfs *);
extern int user_statfs(const char __user *, struct kstatfs *);
extern int fd_statfs(int, struct kstatfs *);
extern int statfs_by_dentry(struct dentry *, struct kstatfs *);
extern int freeze_super(struct super_block *super);
extern int thaw_super(struct super_block *super);
@ -1990,6 +2003,8 @@ extern int do_fallocate(struct file *file, int mode, loff_t offset,
extern long do_sys_open(int dfd, const char __user *filename, int flags,
int mode);
extern struct file *filp_open(const char *, int, int);
extern struct file *file_open_root(struct dentry *, struct vfsmount *,
const char *, int);
extern struct file * dentry_open(struct dentry *, struct vfsmount *, int,
const struct cred *);
extern int filp_close(struct file *, fl_owner_t id);
@ -2205,10 +2220,6 @@ extern struct file *create_read_pipe(struct file *f, int flags);
extern struct file *create_write_pipe(int flags);
extern void free_write_pipe(struct file *);
extern struct file *do_filp_open(int dfd, const char *pathname,
int open_flag, int mode, int acc_mode);
extern int may_open(struct path *, int, int);
extern int kernel_read(struct file *, loff_t, char *, unsigned long);
extern struct file * open_exec(const char *);

View File

@ -19,7 +19,6 @@ struct nameidata {
struct path path;
struct qstr last;
struct path root;
struct file *file;
struct inode *inode; /* path.dentry.d_inode */
unsigned int flags;
unsigned seq;
@ -63,6 +62,10 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND};
#define LOOKUP_EXCL 0x0400
#define LOOKUP_RENAME_TARGET 0x0800
#define LOOKUP_JUMPED 0x1000
#define LOOKUP_ROOT 0x2000
#define LOOKUP_EMPTY 0x4000
extern int user_path_at(int, const char __user *, unsigned, struct path *);
#define user_path(name, path) user_path_at(AT_FDCWD, name, LOOKUP_FOLLOW, path)
@ -72,7 +75,7 @@ extern int user_path_at(int, const char __user *, unsigned, struct path *);
extern int kern_path(const char *, unsigned, struct path *);
extern int path_lookup(const char *, unsigned, struct nameidata *);
extern int kern_path_parent(const char *, struct nameidata *);
extern int vfs_path_lookup(struct dentry *, struct vfsmount *,
const char *, unsigned int, struct nameidata *);

View File

@ -62,6 +62,7 @@ struct robust_list_head;
struct getcpu_cache;
struct old_linux_dirent;
struct perf_event_attr;
struct file_handle;
#include <linux/types.h>
#include <linux/aio_abi.h>
@ -832,5 +833,10 @@ asmlinkage long sys_mmap_pgoff(unsigned long addr, unsigned long len,
unsigned long prot, unsigned long flags,
unsigned long fd, unsigned long pgoff);
asmlinkage long sys_old_mmap(struct mmap_arg_struct __user *arg);
asmlinkage long sys_name_to_handle_at(int dfd, const char __user *name,
struct file_handle __user *handle,
int __user *mnt_id, int flag);
asmlinkage long sys_open_by_handle_at(int mountdirfd,
struct file_handle __user *handle,
int flags);
#endif

View File

@ -287,6 +287,18 @@ config BSD_PROCESS_ACCT_V3
for processing it. A preliminary version of these tools is available
at <http://www.gnu.org/software/acct/>.
config FHANDLE
bool "open by fhandle syscalls"
select EXPORTFS
help
If you say Y here, a user level program will be able to map
file names to handle and then later use the handle for
different file system operations. This is useful in implementing
userspace file servers, which now track files using handles instead
of names. The handle would remain the same even if file names
get renamed. Enables open_by_handle_at(2) and name_to_handle_at(2)
syscalls.
config TASKSTATS
bool "Export task/process statistics through netlink (EXPERIMENTAL)"
depends on NET

View File

@ -144,9 +144,9 @@ int audit_watch_compare(struct audit_watch *watch, unsigned long ino, dev_t dev)
}
/* Initialize a parent watch entry. */
static struct audit_parent *audit_init_parent(struct nameidata *ndp)
static struct audit_parent *audit_init_parent(struct path *path)
{
struct inode *inode = ndp->path.dentry->d_inode;
struct inode *inode = path->dentry->d_inode;
struct audit_parent *parent;
int ret;
@ -353,53 +353,40 @@ static void audit_remove_parent_watches(struct audit_parent *parent)
}
/* Get path information necessary for adding watches. */
static int audit_get_nd(char *path, struct nameidata **ndp, struct nameidata **ndw)
static int audit_get_nd(struct audit_watch *watch, struct path *parent)
{
struct nameidata *ndparent, *ndwatch;
struct nameidata nd;
struct dentry *d;
int err;
ndparent = kmalloc(sizeof(*ndparent), GFP_KERNEL);
if (unlikely(!ndparent))
return -ENOMEM;
ndwatch = kmalloc(sizeof(*ndwatch), GFP_KERNEL);
if (unlikely(!ndwatch)) {
kfree(ndparent);
return -ENOMEM;
}
err = path_lookup(path, LOOKUP_PARENT, ndparent);
if (err) {
kfree(ndparent);
kfree(ndwatch);
err = kern_path_parent(watch->path, &nd);
if (err)
return err;
if (nd.last_type != LAST_NORM) {
path_put(&nd.path);
return -EINVAL;
}
err = path_lookup(path, 0, ndwatch);
if (err) {
kfree(ndwatch);
ndwatch = NULL;
mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
d = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len);
if (IS_ERR(d)) {
mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
path_put(&nd.path);
return PTR_ERR(d);
}
if (d->d_inode) {
/* update watch filter fields */
watch->dev = d->d_inode->i_sb->s_dev;
watch->ino = d->d_inode->i_ino;
}
mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
*ndp = ndparent;
*ndw = ndwatch;
*parent = nd.path;
dput(d);
return 0;
}
/* Release resources used for watch path information. */
static void audit_put_nd(struct nameidata *ndp, struct nameidata *ndw)
{
if (ndp) {
path_put(&ndp->path);
kfree(ndp);
}
if (ndw) {
path_put(&ndw->path);
kfree(ndw);
}
}
/* Associate the given rule with an existing parent.
* Caller must hold audit_filter_mutex. */
static void audit_add_to_parent(struct audit_krule *krule,
@ -440,31 +427,24 @@ int audit_add_watch(struct audit_krule *krule, struct list_head **list)
{
struct audit_watch *watch = krule->watch;
struct audit_parent *parent;
struct nameidata *ndp = NULL, *ndw = NULL;
struct path parent_path;
int h, ret = 0;
mutex_unlock(&audit_filter_mutex);
/* Avoid calling path_lookup under audit_filter_mutex. */
ret = audit_get_nd(watch->path, &ndp, &ndw);
if (ret) {
/* caller expects mutex locked */
mutex_lock(&audit_filter_mutex);
goto error;
}
ret = audit_get_nd(watch, &parent_path);
/* caller expects mutex locked */
mutex_lock(&audit_filter_mutex);
/* update watch filter fields */
if (ndw) {
watch->dev = ndw->path.dentry->d_inode->i_sb->s_dev;
watch->ino = ndw->path.dentry->d_inode->i_ino;
}
if (ret)
return ret;
/* either find an old parent or attach a new one */
parent = audit_find_parent(ndp->path.dentry->d_inode);
parent = audit_find_parent(parent_path.dentry->d_inode);
if (!parent) {
parent = audit_init_parent(ndp);
parent = audit_init_parent(&parent_path);
if (IS_ERR(parent)) {
ret = PTR_ERR(parent);
goto error;
@ -479,9 +459,8 @@ int audit_add_watch(struct audit_krule *krule, struct list_head **list)
h = audit_hash_ino((u32)watch->ino);
*list = &audit_inode_hash[h];
error:
audit_put_nd(ndp, ndw); /* NULL args OK */
path_put(&parent_path);
return ret;
}
void audit_remove_watch_rule(struct audit_krule *krule)

View File

@ -186,3 +186,8 @@ cond_syscall(sys_perf_event_open);
/* fanotify! */
cond_syscall(sys_fanotify_init);
cond_syscall(sys_fanotify_mark);
/* open by handle */
cond_syscall(sys_name_to_handle_at);
cond_syscall(sys_open_by_handle_at);
cond_syscall(compat_sys_open_by_handle_at);

View File

@ -1321,13 +1321,11 @@ 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 nameidata nd;
struct vfsmount *mnt;
struct file *file;
ssize_t result;
char *pathname;
int flags;
int acc_mode;
pathname = sysctl_getname(name, nlen, &table);
result = PTR_ERR(pathname);
@ -1337,28 +1335,17 @@ static ssize_t binary_sysctl(const int *name, int nlen,
/* How should the sysctl be accessed? */
if (oldval && oldlen && newval && newlen) {
flags = O_RDWR;
acc_mode = MAY_READ | MAY_WRITE;
} else if (newval && newlen) {
flags = O_WRONLY;
acc_mode = MAY_WRITE;
} else if (oldval && oldlen) {
flags = O_RDONLY;
acc_mode = MAY_READ;
} else {
result = 0;
goto out_putname;
}
mnt = current->nsproxy->pid_ns->proc_mnt;
result = vfs_path_lookup(mnt->mnt_root, mnt, pathname, 0, &nd);
if (result)
goto out_putname;
result = may_open(&nd.path, acc_mode, flags);
if (result)
goto out_putpath;
file = dentry_open(nd.path.dentry, nd.path.mnt, flags, current_cred());
file = file_open_root(mnt->mnt_root, mnt, pathname, flags);
result = PTR_ERR(file);
if (IS_ERR(file))
goto out_putname;
@ -1370,10 +1357,6 @@ out_putname:
putname(pathname);
out:
return result;
out_putpath:
path_put(&nd.path);
goto out_putname;
}

View File

@ -2144,8 +2144,10 @@ static int shmem_encode_fh(struct dentry *dentry, __u32 *fh, int *len,
{
struct inode *inode = dentry->d_inode;
if (*len < 3)
if (*len < 3) {
*len = 3;
return 255;
}
if (inode_unhashed(inode)) {
/* Unfortunately insert_inode_hash is not idempotent,

View File

@ -95,7 +95,7 @@ static int scm_fp_copy(struct cmsghdr *cmsg, struct scm_fp_list **fplp)
int fd = fdp[i];
struct file *file;
if (fd < 0 || !(file = fget(fd)))
if (fd < 0 || !(file = fget_raw(fd)))
return -EBADF;
*fpp++ = file;
fpl->count++;

View File

@ -850,7 +850,7 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
* Get the parent directory, calculate the hash for last
* component.
*/
err = path_lookup(sunaddr->sun_path, LOOKUP_PARENT, &nd);
err = kern_path_parent(sunaddr->sun_path, &nd);
if (err)
goto out_mknod_parent;

View File

@ -104,7 +104,7 @@ struct sock *unix_get_socket(struct file *filp)
/*
* Socket ?
*/
if (S_ISSOCK(inode->i_mode)) {
if (S_ISSOCK(inode->i_mode) && !(filp->f_mode & FMODE_PATH)) {
struct socket *sock = SOCKET_I(inode);
struct sock *s = sock->sk;