mirror of https://gitee.com/openkylin/linux.git
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: reiserfs: fix j_last_flush_trans_id type fs: Mark get_filesystem_list() as __init function. kill vfs_stat_fd / vfs_lstat_fd Separate out common fstatat code into vfs_fstatat ecryptfs: use memdup_user() ncpfs: use memdup_user() xfs: use memdup_user() sysfs: use memdup_user() btrfs: use memdup_user() xattr: use memdup_user() autofs4: use memchr() in invalid_string() Documentation/filesystems: remove out of date reference to BKL being held Fix i_mutex vs. readdir handling in nfsd fs/compat_ioctl: fix build when !BLOCK Fix autofs_expire() No need for crossing to mountpoint in audit_tag_tree() Safer nfsd_cross_mnt() Touch all affected namespaces on propagation of mount Fix AUTOFS_DEV_IOCTL_REQUESTER_CMD
This commit is contained in:
commit
9a41fe3415
|
@ -277,8 +277,7 @@ or bottom half).
|
|||
unfreeze_fs: called when VFS is unlocking a filesystem and making it writable
|
||||
again.
|
||||
|
||||
statfs: called when the VFS needs to get filesystem statistics. This
|
||||
is called with the kernel lock held
|
||||
statfs: called when the VFS needs to get filesystem statistics.
|
||||
|
||||
remount_fs: called when the filesystem is remounted. This is called
|
||||
with the kernel lock held
|
||||
|
|
|
@ -177,21 +177,12 @@ asmlinkage long sys_oabi_fstatat64(int dfd,
|
|||
int flag)
|
||||
{
|
||||
struct kstat stat;
|
||||
int error = -EINVAL;
|
||||
int error;
|
||||
|
||||
if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0)
|
||||
goto out;
|
||||
|
||||
if (flag & AT_SYMLINK_NOFOLLOW)
|
||||
error = vfs_lstat_fd(dfd, filename, &stat);
|
||||
else
|
||||
error = vfs_stat_fd(dfd, filename, &stat);
|
||||
|
||||
if (!error)
|
||||
error = cp_oldabi_stat64(&stat, statbuf);
|
||||
|
||||
out:
|
||||
return error;
|
||||
error = vfs_fstatat(dfd, filename, &stat, flag);
|
||||
if (error)
|
||||
return error;
|
||||
return cp_oldabi_stat64(&stat, statbuf);
|
||||
}
|
||||
|
||||
struct oabi_flock64 {
|
||||
|
|
|
@ -702,20 +702,12 @@ asmlinkage long sys32_fstatat64(unsigned int dfd, char __user *filename,
|
|||
struct stat64_emu31 __user* statbuf, int flag)
|
||||
{
|
||||
struct kstat stat;
|
||||
int error = -EINVAL;
|
||||
int error;
|
||||
|
||||
if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0)
|
||||
goto out;
|
||||
|
||||
if (flag & AT_SYMLINK_NOFOLLOW)
|
||||
error = vfs_lstat_fd(dfd, filename, &stat);
|
||||
else
|
||||
error = vfs_stat_fd(dfd, filename, &stat);
|
||||
|
||||
if (!error)
|
||||
error = cp_stat64(statbuf, &stat);
|
||||
out:
|
||||
return error;
|
||||
error = vfs_fstatat(dfd, filename, &stat, flag);
|
||||
if (error)
|
||||
return error;
|
||||
return cp_stat64(statbuf, &stat);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -206,21 +206,12 @@ asmlinkage long compat_sys_fstatat64(unsigned int dfd, char __user *filename,
|
|||
struct compat_stat64 __user * statbuf, int flag)
|
||||
{
|
||||
struct kstat stat;
|
||||
int error = -EINVAL;
|
||||
int error;
|
||||
|
||||
if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0)
|
||||
goto out;
|
||||
|
||||
if (flag & AT_SYMLINK_NOFOLLOW)
|
||||
error = vfs_lstat_fd(dfd, filename, &stat);
|
||||
else
|
||||
error = vfs_stat_fd(dfd, filename, &stat);
|
||||
|
||||
if (!error)
|
||||
error = cp_compat_stat64(&stat, statbuf);
|
||||
|
||||
out:
|
||||
return error;
|
||||
error = vfs_fstatat(dfd, filename, &stat, flag);
|
||||
if (error)
|
||||
return error;
|
||||
return cp_compat_stat64(&stat, statbuf);
|
||||
}
|
||||
|
||||
asmlinkage long compat_sys_sysfs(int option, u32 arg1, u32 arg2)
|
||||
|
|
|
@ -129,21 +129,12 @@ asmlinkage long sys32_fstatat(unsigned int dfd, char __user *filename,
|
|||
struct stat64 __user *statbuf, int flag)
|
||||
{
|
||||
struct kstat stat;
|
||||
int error = -EINVAL;
|
||||
int error;
|
||||
|
||||
if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0)
|
||||
goto out;
|
||||
|
||||
if (flag & AT_SYMLINK_NOFOLLOW)
|
||||
error = vfs_lstat_fd(dfd, filename, &stat);
|
||||
else
|
||||
error = vfs_stat_fd(dfd, filename, &stat);
|
||||
|
||||
if (!error)
|
||||
error = cp_stat64(statbuf, &stat);
|
||||
|
||||
out:
|
||||
return error;
|
||||
error = vfs_fstatat(dfd, filename, &stat, flag);
|
||||
if (error)
|
||||
return error;
|
||||
return cp_stat64(statbuf, &stat);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -39,10 +39,12 @@ struct autofs_dir_ent *autofs_expire(struct super_block *sb,
|
|||
{
|
||||
struct autofs_dirhash *dh = &sbi->dirhash;
|
||||
struct autofs_dir_ent *ent;
|
||||
struct dentry *dentry;
|
||||
unsigned long timeout = sbi->exp_timeout;
|
||||
|
||||
while (1) {
|
||||
struct path path;
|
||||
int umount_ok;
|
||||
|
||||
if ( list_empty(&dh->expiry_head) || sbi->catatonic )
|
||||
return NULL; /* No entries */
|
||||
/* We keep the list sorted by last_usage and want old stuff */
|
||||
|
@ -57,17 +59,17 @@ struct autofs_dir_ent *autofs_expire(struct super_block *sb,
|
|||
return ent; /* Symlinks are always expirable */
|
||||
|
||||
/* Get the dentry for the autofs subdirectory */
|
||||
dentry = ent->dentry;
|
||||
path.dentry = ent->dentry;
|
||||
|
||||
if ( !dentry ) {
|
||||
if (!path.dentry) {
|
||||
/* Should only happen in catatonic mode */
|
||||
printk("autofs: dentry == NULL but inode range is directory, entry %s\n", ent->name);
|
||||
autofs_delete_usage(ent);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( !dentry->d_inode ) {
|
||||
dput(dentry);
|
||||
if (!path.dentry->d_inode) {
|
||||
dput(path.dentry);
|
||||
printk("autofs: negative dentry on expiry queue: %s\n",
|
||||
ent->name);
|
||||
autofs_delete_usage(ent);
|
||||
|
@ -76,29 +78,29 @@ struct autofs_dir_ent *autofs_expire(struct super_block *sb,
|
|||
|
||||
/* Make sure entry is mounted and unused; note that dentry will
|
||||
point to the mounted-on-top root. */
|
||||
if (!S_ISDIR(dentry->d_inode->i_mode)||!d_mountpoint(dentry)) {
|
||||
if (!S_ISDIR(path.dentry->d_inode->i_mode) ||
|
||||
!d_mountpoint(path.dentry)) {
|
||||
DPRINTK(("autofs: not expirable (not a mounted directory): %s\n", ent->name));
|
||||
continue;
|
||||
}
|
||||
mntget(mnt);
|
||||
dget(dentry);
|
||||
if (!follow_down(&mnt, &dentry)) {
|
||||
dput(dentry);
|
||||
mntput(mnt);
|
||||
path.mnt = mnt;
|
||||
path_get(&path);
|
||||
if (!follow_down(&path.mnt, &path.dentry)) {
|
||||
path_put(&path);
|
||||
DPRINTK(("autofs: not expirable (not a mounted directory): %s\n", ent->name));
|
||||
continue;
|
||||
}
|
||||
while (d_mountpoint(dentry) && follow_down(&mnt, &dentry))
|
||||
while (d_mountpoint(path.dentry) &&
|
||||
follow_down(&path.mnt, &path.dentry))
|
||||
;
|
||||
dput(dentry);
|
||||
umount_ok = may_umount(path.mnt);
|
||||
path_put(&path);
|
||||
|
||||
if ( may_umount(mnt) ) {
|
||||
mntput(mnt);
|
||||
if (umount_ok) {
|
||||
DPRINTK(("autofs: signaling expire on %s\n", ent->name));
|
||||
return ent; /* Expirable! */
|
||||
}
|
||||
DPRINTK(("autofs: didn't expire due to may_umount: %s\n", ent->name));
|
||||
mntput(mnt);
|
||||
}
|
||||
return NULL; /* No expirable entries */
|
||||
}
|
||||
|
|
|
@ -54,11 +54,10 @@ static int check_name(const char *name)
|
|||
* Check a string doesn't overrun the chunk of
|
||||
* memory we copied from user land.
|
||||
*/
|
||||
static int invalid_str(char *str, void *end)
|
||||
static int invalid_str(char *str, size_t size)
|
||||
{
|
||||
while ((void *) str <= end)
|
||||
if (!*str++)
|
||||
return 0;
|
||||
if (memchr(str, 0, size))
|
||||
return 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -138,8 +137,7 @@ static int validate_dev_ioctl(int cmd, struct autofs_dev_ioctl *param)
|
|||
}
|
||||
|
||||
if (param->size > sizeof(*param)) {
|
||||
err = invalid_str(param->path,
|
||||
(void *) ((size_t) param + param->size));
|
||||
err = invalid_str(param->path, param->size - sizeof(*param));
|
||||
if (err) {
|
||||
AUTOFS_WARN(
|
||||
"path string terminator missing for cmd(0x%08x)",
|
||||
|
@ -488,7 +486,7 @@ static int autofs_dev_ioctl_requester(struct file *fp,
|
|||
}
|
||||
|
||||
path = param->path;
|
||||
devid = sbi->sb->s_dev;
|
||||
devid = new_encode_dev(sbi->sb->s_dev);
|
||||
|
||||
param->requester.uid = param->requester.gid = -1;
|
||||
|
||||
|
|
|
@ -461,15 +461,9 @@ static int btrfs_ioctl_resize(struct btrfs_root *root, void __user *arg)
|
|||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
vol_args = kmalloc(sizeof(*vol_args), GFP_NOFS);
|
||||
|
||||
if (!vol_args)
|
||||
return -ENOMEM;
|
||||
|
||||
if (copy_from_user(vol_args, arg, sizeof(*vol_args))) {
|
||||
ret = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
vol_args = memdup_user(arg, sizeof(*vol_args));
|
||||
if (IS_ERR(vol_args))
|
||||
return PTR_ERR(vol_args);
|
||||
|
||||
vol_args->name[BTRFS_PATH_NAME_MAX] = '\0';
|
||||
namelen = strlen(vol_args->name);
|
||||
|
@ -545,7 +539,6 @@ static int btrfs_ioctl_resize(struct btrfs_root *root, void __user *arg)
|
|||
|
||||
out_unlock:
|
||||
mutex_unlock(&root->fs_info->volume_mutex);
|
||||
out:
|
||||
kfree(vol_args);
|
||||
return ret;
|
||||
}
|
||||
|
@ -565,15 +558,9 @@ static noinline int btrfs_ioctl_snap_create(struct file *file,
|
|||
if (root->fs_info->sb->s_flags & MS_RDONLY)
|
||||
return -EROFS;
|
||||
|
||||
vol_args = kmalloc(sizeof(*vol_args), GFP_NOFS);
|
||||
|
||||
if (!vol_args)
|
||||
return -ENOMEM;
|
||||
|
||||
if (copy_from_user(vol_args, arg, sizeof(*vol_args))) {
|
||||
ret = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
vol_args = memdup_user(arg, sizeof(*vol_args));
|
||||
if (IS_ERR(vol_args))
|
||||
return PTR_ERR(vol_args);
|
||||
|
||||
vol_args->name[BTRFS_PATH_NAME_MAX] = '\0';
|
||||
namelen = strlen(vol_args->name);
|
||||
|
@ -675,19 +662,13 @@ static long btrfs_ioctl_add_dev(struct btrfs_root *root, void __user *arg)
|
|||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
vol_args = kmalloc(sizeof(*vol_args), GFP_NOFS);
|
||||
vol_args = memdup_user(arg, sizeof(*vol_args));
|
||||
if (IS_ERR(vol_args))
|
||||
return PTR_ERR(vol_args);
|
||||
|
||||
if (!vol_args)
|
||||
return -ENOMEM;
|
||||
|
||||
if (copy_from_user(vol_args, arg, sizeof(*vol_args))) {
|
||||
ret = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
vol_args->name[BTRFS_PATH_NAME_MAX] = '\0';
|
||||
ret = btrfs_init_new_device(root, vol_args->name);
|
||||
|
||||
out:
|
||||
kfree(vol_args);
|
||||
return ret;
|
||||
}
|
||||
|
@ -703,19 +684,13 @@ static long btrfs_ioctl_rm_dev(struct btrfs_root *root, void __user *arg)
|
|||
if (root->fs_info->sb->s_flags & MS_RDONLY)
|
||||
return -EROFS;
|
||||
|
||||
vol_args = kmalloc(sizeof(*vol_args), GFP_NOFS);
|
||||
vol_args = memdup_user(arg, sizeof(*vol_args));
|
||||
if (IS_ERR(vol_args))
|
||||
return PTR_ERR(vol_args);
|
||||
|
||||
if (!vol_args)
|
||||
return -ENOMEM;
|
||||
|
||||
if (copy_from_user(vol_args, arg, sizeof(*vol_args))) {
|
||||
ret = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
vol_args->name[BTRFS_PATH_NAME_MAX] = '\0';
|
||||
ret = btrfs_rm_device(root, vol_args->name);
|
||||
|
||||
out:
|
||||
kfree(vol_args);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -635,14 +635,9 @@ static long btrfs_control_ioctl(struct file *file, unsigned int cmd,
|
|||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
vol = kmalloc(sizeof(*vol), GFP_KERNEL);
|
||||
if (!vol)
|
||||
return -ENOMEM;
|
||||
|
||||
if (copy_from_user(vol, (void __user *)arg, sizeof(*vol))) {
|
||||
ret = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
vol = memdup_user((void __user *)arg, sizeof(*vol));
|
||||
if (IS_ERR(vol))
|
||||
return PTR_ERR(vol);
|
||||
|
||||
switch (cmd) {
|
||||
case BTRFS_IOC_SCAN_DEV:
|
||||
|
@ -650,7 +645,7 @@ static long btrfs_control_ioctl(struct file *file, unsigned int cmd,
|
|||
&btrfs_fs_type, &fs_devices);
|
||||
break;
|
||||
}
|
||||
out:
|
||||
|
||||
kfree(vol);
|
||||
return ret;
|
||||
}
|
||||
|
|
37
fs/compat.c
37
fs/compat.c
|
@ -181,22 +181,24 @@ asmlinkage long compat_sys_newstat(char __user * filename,
|
|||
struct compat_stat __user *statbuf)
|
||||
{
|
||||
struct kstat stat;
|
||||
int error = vfs_stat_fd(AT_FDCWD, filename, &stat);
|
||||
int error;
|
||||
|
||||
if (!error)
|
||||
error = cp_compat_stat(&stat, statbuf);
|
||||
return error;
|
||||
error = vfs_stat(filename, &stat);
|
||||
if (error)
|
||||
return error;
|
||||
return cp_compat_stat(&stat, statbuf);
|
||||
}
|
||||
|
||||
asmlinkage long compat_sys_newlstat(char __user * filename,
|
||||
struct compat_stat __user *statbuf)
|
||||
{
|
||||
struct kstat stat;
|
||||
int error = vfs_lstat_fd(AT_FDCWD, filename, &stat);
|
||||
int error;
|
||||
|
||||
if (!error)
|
||||
error = cp_compat_stat(&stat, statbuf);
|
||||
return error;
|
||||
error = vfs_lstat(filename, &stat);
|
||||
if (error)
|
||||
return error;
|
||||
return cp_compat_stat(&stat, statbuf);
|
||||
}
|
||||
|
||||
#ifndef __ARCH_WANT_STAT64
|
||||
|
@ -204,21 +206,12 @@ asmlinkage long compat_sys_newfstatat(unsigned int dfd, char __user *filename,
|
|||
struct compat_stat __user *statbuf, int flag)
|
||||
{
|
||||
struct kstat stat;
|
||||
int error = -EINVAL;
|
||||
int error;
|
||||
|
||||
if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0)
|
||||
goto out;
|
||||
|
||||
if (flag & AT_SYMLINK_NOFOLLOW)
|
||||
error = vfs_lstat_fd(dfd, filename, &stat);
|
||||
else
|
||||
error = vfs_stat_fd(dfd, filename, &stat);
|
||||
|
||||
if (!error)
|
||||
error = cp_compat_stat(&stat, statbuf);
|
||||
|
||||
out:
|
||||
return error;
|
||||
error = vfs_fstatat(dfd, filename, &stat, flag);
|
||||
if (error)
|
||||
return error;
|
||||
return cp_compat_stat(&stat, statbuf);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -58,7 +58,6 @@
|
|||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-dev.h>
|
||||
#include <linux/atalk.h>
|
||||
#include <linux/loop.h>
|
||||
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
#include <net/bluetooth/hci.h>
|
||||
|
@ -68,6 +67,7 @@
|
|||
#include <linux/gigaset_dev.h>
|
||||
|
||||
#ifdef CONFIG_BLOCK
|
||||
#include <linux/loop.h>
|
||||
#include <scsi/scsi.h>
|
||||
#include <scsi/scsi_ioctl.h>
|
||||
#include <scsi/sg.h>
|
||||
|
@ -2660,6 +2660,8 @@ HANDLE_IOCTL(SONET_GETFRAMING, do_atm_ioctl)
|
|||
HANDLE_IOCTL(SONET_GETFRSENSE, do_atm_ioctl)
|
||||
/* block stuff */
|
||||
#ifdef CONFIG_BLOCK
|
||||
/* loop */
|
||||
IGNORE_IOCTL(LOOP_CLR_FD)
|
||||
/* Raw devices */
|
||||
HANDLE_IOCTL(RAW_SETBIND, raw_ioctl)
|
||||
HANDLE_IOCTL(RAW_GETBIND, raw_ioctl)
|
||||
|
@ -2728,9 +2730,6 @@ HANDLE_IOCTL(LPSETTIMEOUT, lp_timeout_trans)
|
|||
IGNORE_IOCTL(VFAT_IOCTL_READDIR_BOTH32)
|
||||
IGNORE_IOCTL(VFAT_IOCTL_READDIR_SHORT32)
|
||||
|
||||
/* loop */
|
||||
IGNORE_IOCTL(LOOP_CLR_FD)
|
||||
|
||||
#ifdef CONFIG_SPARC
|
||||
/* Sparc framebuffers, handled in sbusfb_compat_ioctl() */
|
||||
IGNORE_IOCTL(FBIOGTYPE)
|
||||
|
|
|
@ -2149,7 +2149,6 @@ int is_subdir(struct dentry *new_dentry, struct dentry *old_dentry)
|
|||
int result;
|
||||
unsigned long seq;
|
||||
|
||||
/* FIXME: This is old behavior, needed? Please check callers. */
|
||||
if (new_dentry == old_dentry)
|
||||
return 1;
|
||||
|
||||
|
|
|
@ -418,18 +418,13 @@ ecryptfs_miscdev_write(struct file *file, const char __user *buf,
|
|||
|
||||
if (count == 0)
|
||||
goto out;
|
||||
data = kmalloc(count, GFP_KERNEL);
|
||||
if (!data) {
|
||||
printk(KERN_ERR "%s: Out of memory whilst attempting to "
|
||||
"kmalloc([%zd], GFP_KERNEL)\n", __func__, count);
|
||||
|
||||
data = memdup_user(buf, count);
|
||||
if (IS_ERR(data)) {
|
||||
printk(KERN_ERR "%s: memdup_user returned error [%ld]\n",
|
||||
__func__, PTR_ERR(data));
|
||||
goto out;
|
||||
}
|
||||
rc = copy_from_user(data, buf, count);
|
||||
if (rc) {
|
||||
printk(KERN_ERR "%s: copy_from_user returned error [%d]\n",
|
||||
__func__, rc);
|
||||
goto out_free;
|
||||
}
|
||||
sz = count;
|
||||
i = 0;
|
||||
switch (data[i++]) {
|
||||
|
|
|
@ -199,7 +199,7 @@ SYSCALL_DEFINE3(sysfs, int, option, unsigned long, arg1, unsigned long, arg2)
|
|||
return retval;
|
||||
}
|
||||
|
||||
int get_filesystem_list(char * buf)
|
||||
int __init get_filesystem_list(char *buf)
|
||||
{
|
||||
int len = 0;
|
||||
struct file_system_type * tmp;
|
||||
|
|
|
@ -1248,6 +1248,8 @@ struct dentry *lookup_one_len(const char *name, struct dentry *base, int len)
|
|||
int err;
|
||||
struct qstr this;
|
||||
|
||||
WARN_ON_ONCE(!mutex_is_locked(&base->d_inode->i_mutex));
|
||||
|
||||
err = __lookup_one_len(name, &this, base, len);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
|
|
@ -1377,7 +1377,7 @@ static int attach_recursive_mnt(struct vfsmount *source_mnt,
|
|||
if (parent_path) {
|
||||
detach_mnt(source_mnt, parent_path);
|
||||
attach_mnt(source_mnt, path);
|
||||
touch_mnt_namespace(current->nsproxy->mnt_ns);
|
||||
touch_mnt_namespace(parent_path->mnt->mnt_ns);
|
||||
} else {
|
||||
mnt_set_mountpoint(dest_mnt, dest_dentry, source_mnt);
|
||||
commit_tree(source_mnt);
|
||||
|
|
|
@ -660,13 +660,10 @@ static int __ncp_ioctl(struct inode *inode, struct file *filp,
|
|||
if (user.object_name_len > NCP_OBJECT_NAME_MAX_LEN)
|
||||
return -ENOMEM;
|
||||
if (user.object_name_len) {
|
||||
newname = kmalloc(user.object_name_len, GFP_USER);
|
||||
if (!newname)
|
||||
return -ENOMEM;
|
||||
if (copy_from_user(newname, user.object_name, user.object_name_len)) {
|
||||
kfree(newname);
|
||||
return -EFAULT;
|
||||
}
|
||||
newname = memdup_user(user.object_name,
|
||||
user.object_name_len);
|
||||
if (IS_ERR(newname))
|
||||
return PTR_ERR(newname);
|
||||
} else {
|
||||
newname = NULL;
|
||||
}
|
||||
|
@ -760,13 +757,9 @@ static int __ncp_ioctl(struct inode *inode, struct file *filp,
|
|||
if (user.len > NCP_PRIVATE_DATA_MAX_LEN)
|
||||
return -ENOMEM;
|
||||
if (user.len) {
|
||||
new = kmalloc(user.len, GFP_USER);
|
||||
if (!new)
|
||||
return -ENOMEM;
|
||||
if (copy_from_user(new, user.data, user.len)) {
|
||||
kfree(new);
|
||||
return -EFAULT;
|
||||
}
|
||||
new = memdup_user(user.data, user.len);
|
||||
if (IS_ERR(new))
|
||||
return PTR_ERR(new);
|
||||
} else {
|
||||
new = NULL;
|
||||
}
|
||||
|
|
|
@ -229,21 +229,23 @@ nfsd4_list_rec_dir(struct dentry *dir, recdir_func *f)
|
|||
goto out;
|
||||
status = vfs_readdir(filp, nfsd4_build_namelist, &names);
|
||||
fput(filp);
|
||||
mutex_lock(&dir->d_inode->i_mutex);
|
||||
while (!list_empty(&names)) {
|
||||
entry = list_entry(names.next, struct name_list, list);
|
||||
|
||||
dentry = lookup_one_len(entry->name, dir, HEXDIR_LEN-1);
|
||||
if (IS_ERR(dentry)) {
|
||||
status = PTR_ERR(dentry);
|
||||
goto out;
|
||||
break;
|
||||
}
|
||||
status = f(dir, dentry);
|
||||
dput(dentry);
|
||||
if (status)
|
||||
goto out;
|
||||
break;
|
||||
list_del(&entry->list);
|
||||
kfree(entry);
|
||||
}
|
||||
mutex_unlock(&dir->d_inode->i_mutex);
|
||||
out:
|
||||
while (!list_empty(&names)) {
|
||||
entry = list_entry(names.next, struct name_list, list);
|
||||
|
@ -254,36 +256,6 @@ nfsd4_list_rec_dir(struct dentry *dir, recdir_func *f)
|
|||
return status;
|
||||
}
|
||||
|
||||
static int
|
||||
nfsd4_remove_clid_file(struct dentry *dir, struct dentry *dentry)
|
||||
{
|
||||
int status;
|
||||
|
||||
if (!S_ISREG(dir->d_inode->i_mode)) {
|
||||
printk("nfsd4: non-file found in client recovery directory\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT);
|
||||
status = vfs_unlink(dir->d_inode, dentry);
|
||||
mutex_unlock(&dir->d_inode->i_mutex);
|
||||
return status;
|
||||
}
|
||||
|
||||
static int
|
||||
nfsd4_clear_clid_dir(struct dentry *dir, struct dentry *dentry)
|
||||
{
|
||||
int status;
|
||||
|
||||
/* For now this directory should already be empty, but we empty it of
|
||||
* any regular files anyway, just in case the directory was created by
|
||||
* a kernel from the future.... */
|
||||
nfsd4_list_rec_dir(dentry, nfsd4_remove_clid_file);
|
||||
mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT);
|
||||
status = vfs_rmdir(dir->d_inode, dentry);
|
||||
mutex_unlock(&dir->d_inode->i_mutex);
|
||||
return status;
|
||||
}
|
||||
|
||||
static int
|
||||
nfsd4_unlink_clid_dir(char *name, int namlen)
|
||||
{
|
||||
|
@ -294,18 +266,18 @@ nfsd4_unlink_clid_dir(char *name, int namlen)
|
|||
|
||||
mutex_lock(&rec_dir.dentry->d_inode->i_mutex);
|
||||
dentry = lookup_one_len(name, rec_dir.dentry, namlen);
|
||||
mutex_unlock(&rec_dir.dentry->d_inode->i_mutex);
|
||||
if (IS_ERR(dentry)) {
|
||||
status = PTR_ERR(dentry);
|
||||
return status;
|
||||
goto out_unlock;
|
||||
}
|
||||
status = -ENOENT;
|
||||
if (!dentry->d_inode)
|
||||
goto out;
|
||||
|
||||
status = nfsd4_clear_clid_dir(rec_dir.dentry, dentry);
|
||||
status = vfs_rmdir(rec_dir.dentry->d_inode, dentry);
|
||||
out:
|
||||
dput(dentry);
|
||||
out_unlock:
|
||||
mutex_unlock(&rec_dir.dentry->d_inode->i_mutex);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -348,7 +320,7 @@ purge_old(struct dentry *parent, struct dentry *child)
|
|||
if (nfs4_has_reclaimed_state(child->d_name.name, false))
|
||||
return 0;
|
||||
|
||||
status = nfsd4_clear_clid_dir(parent, child);
|
||||
status = vfs_rmdir(parent->d_inode, child);
|
||||
if (status)
|
||||
printk("failed to remove client recovery directory %s\n",
|
||||
child->d_name.name);
|
||||
|
|
|
@ -116,10 +116,15 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
|
|||
}
|
||||
if ((exp->ex_flags & NFSEXP_CROSSMOUNT) || EX_NOHIDE(exp2)) {
|
||||
/* successfully crossed mount point */
|
||||
exp_put(exp);
|
||||
*expp = exp2;
|
||||
/*
|
||||
* This is subtle: dentry is *not* under mnt at this point.
|
||||
* The only reason we are safe is that original mnt is pinned
|
||||
* down by exp, so we should dput before putting exp.
|
||||
*/
|
||||
dput(dentry);
|
||||
*dpp = mounts;
|
||||
exp_put(exp);
|
||||
*expp = exp2;
|
||||
} else {
|
||||
exp_put(exp2);
|
||||
dput(mounts);
|
||||
|
@ -1885,8 +1890,8 @@ static int nfsd_buffered_filldir(void *__buf, const char *name, int namlen,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int nfsd_buffered_readdir(struct file *file, filldir_t func,
|
||||
struct readdir_cd *cdp, loff_t *offsetp)
|
||||
static __be32 nfsd_buffered_readdir(struct file *file, filldir_t func,
|
||||
struct readdir_cd *cdp, loff_t *offsetp)
|
||||
{
|
||||
struct readdir_data buf;
|
||||
struct buffered_dirent *de;
|
||||
|
@ -1896,11 +1901,12 @@ static int nfsd_buffered_readdir(struct file *file, filldir_t func,
|
|||
|
||||
buf.dirent = (void *)__get_free_page(GFP_KERNEL);
|
||||
if (!buf.dirent)
|
||||
return -ENOMEM;
|
||||
return nfserrno(-ENOMEM);
|
||||
|
||||
offset = *offsetp;
|
||||
|
||||
while (1) {
|
||||
struct inode *dir_inode = file->f_path.dentry->d_inode;
|
||||
unsigned int reclen;
|
||||
|
||||
cdp->err = nfserr_eof; /* will be cleared on successful read */
|
||||
|
@ -1919,26 +1925,38 @@ static int nfsd_buffered_readdir(struct file *file, filldir_t func,
|
|||
if (!size)
|
||||
break;
|
||||
|
||||
/*
|
||||
* Various filldir functions may end up calling back into
|
||||
* lookup_one_len() and the file system's ->lookup() method.
|
||||
* These expect i_mutex to be held, as it would within readdir.
|
||||
*/
|
||||
host_err = mutex_lock_killable(&dir_inode->i_mutex);
|
||||
if (host_err)
|
||||
break;
|
||||
|
||||
de = (struct buffered_dirent *)buf.dirent;
|
||||
while (size > 0) {
|
||||
offset = de->offset;
|
||||
|
||||
if (func(cdp, de->name, de->namlen, de->offset,
|
||||
de->ino, de->d_type))
|
||||
goto done;
|
||||
break;
|
||||
|
||||
if (cdp->err != nfs_ok)
|
||||
goto done;
|
||||
break;
|
||||
|
||||
reclen = ALIGN(sizeof(*de) + de->namlen,
|
||||
sizeof(u64));
|
||||
size -= reclen;
|
||||
de = (struct buffered_dirent *)((char *)de + reclen);
|
||||
}
|
||||
mutex_unlock(&dir_inode->i_mutex);
|
||||
if (size > 0) /* We bailed out early */
|
||||
break;
|
||||
|
||||
offset = vfs_llseek(file, 0, SEEK_CUR);
|
||||
}
|
||||
|
||||
done:
|
||||
free_page((unsigned long)(buf.dirent));
|
||||
|
||||
if (host_err)
|
||||
|
|
151
fs/stat.c
151
fs/stat.c
|
@ -55,46 +55,6 @@ int vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
|
|||
|
||||
EXPORT_SYMBOL(vfs_getattr);
|
||||
|
||||
int vfs_stat_fd(int dfd, char __user *name, struct kstat *stat)
|
||||
{
|
||||
struct path path;
|
||||
int error;
|
||||
|
||||
error = user_path_at(dfd, name, LOOKUP_FOLLOW, &path);
|
||||
if (!error) {
|
||||
error = vfs_getattr(path.mnt, path.dentry, stat);
|
||||
path_put(&path);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
int vfs_stat(char __user *name, struct kstat *stat)
|
||||
{
|
||||
return vfs_stat_fd(AT_FDCWD, name, stat);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(vfs_stat);
|
||||
|
||||
int vfs_lstat_fd(int dfd, char __user *name, struct kstat *stat)
|
||||
{
|
||||
struct path path;
|
||||
int error;
|
||||
|
||||
error = user_path_at(dfd, name, 0, &path);
|
||||
if (!error) {
|
||||
error = vfs_getattr(path.mnt, path.dentry, stat);
|
||||
path_put(&path);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
int vfs_lstat(char __user *name, struct kstat *stat)
|
||||
{
|
||||
return vfs_lstat_fd(AT_FDCWD, name, stat);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(vfs_lstat);
|
||||
|
||||
int vfs_fstat(unsigned int fd, struct kstat *stat)
|
||||
{
|
||||
struct file *f = fget(fd);
|
||||
|
@ -106,9 +66,44 @@ int vfs_fstat(unsigned int fd, struct kstat *stat)
|
|||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(vfs_fstat);
|
||||
|
||||
int vfs_fstatat(int dfd, char __user *filename, struct kstat *stat, int flag)
|
||||
{
|
||||
struct path path;
|
||||
int error = -EINVAL;
|
||||
int lookup_flags = 0;
|
||||
|
||||
if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0)
|
||||
goto out;
|
||||
|
||||
if (!(flag & AT_SYMLINK_NOFOLLOW))
|
||||
lookup_flags |= LOOKUP_FOLLOW;
|
||||
|
||||
error = user_path_at(dfd, filename, lookup_flags, &path);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
error = vfs_getattr(path.mnt, path.dentry, stat);
|
||||
path_put(&path);
|
||||
out:
|
||||
return error;
|
||||
}
|
||||
EXPORT_SYMBOL(vfs_fstatat);
|
||||
|
||||
int vfs_stat(char __user *name, struct kstat *stat)
|
||||
{
|
||||
return vfs_fstatat(AT_FDCWD, name, stat, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(vfs_stat);
|
||||
|
||||
int vfs_lstat(char __user *name, struct kstat *stat)
|
||||
{
|
||||
return vfs_fstatat(AT_FDCWD, name, stat, AT_SYMLINK_NOFOLLOW);
|
||||
}
|
||||
EXPORT_SYMBOL(vfs_lstat);
|
||||
|
||||
|
||||
#ifdef __ARCH_WANT_OLD_STAT
|
||||
|
||||
/*
|
||||
|
@ -155,23 +150,25 @@ static int cp_old_stat(struct kstat *stat, struct __old_kernel_stat __user * sta
|
|||
SYSCALL_DEFINE2(stat, char __user *, filename, struct __old_kernel_stat __user *, statbuf)
|
||||
{
|
||||
struct kstat stat;
|
||||
int error = vfs_stat_fd(AT_FDCWD, filename, &stat);
|
||||
int error;
|
||||
|
||||
if (!error)
|
||||
error = cp_old_stat(&stat, statbuf);
|
||||
error = vfs_stat(filename, &stat);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
return error;
|
||||
return cp_old_stat(&stat, statbuf);
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE2(lstat, char __user *, filename, struct __old_kernel_stat __user *, statbuf)
|
||||
{
|
||||
struct kstat stat;
|
||||
int error = vfs_lstat_fd(AT_FDCWD, filename, &stat);
|
||||
int error;
|
||||
|
||||
if (!error)
|
||||
error = cp_old_stat(&stat, statbuf);
|
||||
error = vfs_lstat(filename, &stat);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
return error;
|
||||
return cp_old_stat(&stat, statbuf);
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE2(fstat, unsigned int, fd, struct __old_kernel_stat __user *, statbuf)
|
||||
|
@ -240,23 +237,23 @@ static int cp_new_stat(struct kstat *stat, struct stat __user *statbuf)
|
|||
SYSCALL_DEFINE2(newstat, char __user *, filename, struct stat __user *, statbuf)
|
||||
{
|
||||
struct kstat stat;
|
||||
int error = vfs_stat_fd(AT_FDCWD, filename, &stat);
|
||||
int error = vfs_stat(filename, &stat);
|
||||
|
||||
if (!error)
|
||||
error = cp_new_stat(&stat, statbuf);
|
||||
|
||||
return error;
|
||||
if (error)
|
||||
return error;
|
||||
return cp_new_stat(&stat, statbuf);
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE2(newlstat, char __user *, filename, struct stat __user *, statbuf)
|
||||
{
|
||||
struct kstat stat;
|
||||
int error = vfs_lstat_fd(AT_FDCWD, filename, &stat);
|
||||
int error;
|
||||
|
||||
if (!error)
|
||||
error = cp_new_stat(&stat, statbuf);
|
||||
error = vfs_lstat(filename, &stat);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
return error;
|
||||
return cp_new_stat(&stat, statbuf);
|
||||
}
|
||||
|
||||
#if !defined(__ARCH_WANT_STAT64) || defined(__ARCH_WANT_SYS_NEWFSTATAT)
|
||||
|
@ -264,21 +261,12 @@ SYSCALL_DEFINE4(newfstatat, int, dfd, char __user *, filename,
|
|||
struct stat __user *, statbuf, int, flag)
|
||||
{
|
||||
struct kstat stat;
|
||||
int error = -EINVAL;
|
||||
int error;
|
||||
|
||||
if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0)
|
||||
goto out;
|
||||
|
||||
if (flag & AT_SYMLINK_NOFOLLOW)
|
||||
error = vfs_lstat_fd(dfd, filename, &stat);
|
||||
else
|
||||
error = vfs_stat_fd(dfd, filename, &stat);
|
||||
|
||||
if (!error)
|
||||
error = cp_new_stat(&stat, statbuf);
|
||||
|
||||
out:
|
||||
return error;
|
||||
error = vfs_fstatat(dfd, filename, &stat, flag);
|
||||
if (error)
|
||||
return error;
|
||||
return cp_new_stat(&stat, statbuf);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -404,21 +392,12 @@ SYSCALL_DEFINE4(fstatat64, int, dfd, char __user *, filename,
|
|||
struct stat64 __user *, statbuf, int, flag)
|
||||
{
|
||||
struct kstat stat;
|
||||
int error = -EINVAL;
|
||||
int error;
|
||||
|
||||
if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0)
|
||||
goto out;
|
||||
|
||||
if (flag & AT_SYMLINK_NOFOLLOW)
|
||||
error = vfs_lstat_fd(dfd, filename, &stat);
|
||||
else
|
||||
error = vfs_stat_fd(dfd, filename, &stat);
|
||||
|
||||
if (!error)
|
||||
error = cp_new_stat64(&stat, statbuf);
|
||||
|
||||
out:
|
||||
return error;
|
||||
error = vfs_fstatat(dfd, filename, &stat, flag);
|
||||
if (error)
|
||||
return error;
|
||||
return cp_new_stat64(&stat, statbuf);
|
||||
}
|
||||
#endif /* __ARCH_WANT_STAT64 */
|
||||
|
||||
|
|
|
@ -157,14 +157,9 @@ static ssize_t write(struct file *file, const char __user *userbuf,
|
|||
count = size - offs;
|
||||
}
|
||||
|
||||
temp = kmalloc(count, GFP_KERNEL);
|
||||
if (!temp)
|
||||
return -ENOMEM;
|
||||
|
||||
if (copy_from_user(temp, userbuf, count)) {
|
||||
count = -EFAULT;
|
||||
goto out_free;
|
||||
}
|
||||
temp = memdup_user(userbuf, count);
|
||||
if (IS_ERR(temp))
|
||||
return PTR_ERR(temp);
|
||||
|
||||
mutex_lock(&bb->mutex);
|
||||
|
||||
|
@ -176,8 +171,6 @@ static ssize_t write(struct file *file, const char __user *userbuf,
|
|||
if (count > 0)
|
||||
*off = offs + count;
|
||||
|
||||
out_free:
|
||||
kfree(temp);
|
||||
return count;
|
||||
}
|
||||
|
||||
|
|
10
fs/xattr.c
10
fs/xattr.c
|
@ -237,13 +237,9 @@ setxattr(struct dentry *d, const char __user *name, const void __user *value,
|
|||
if (size) {
|
||||
if (size > XATTR_SIZE_MAX)
|
||||
return -E2BIG;
|
||||
kvalue = kmalloc(size, GFP_KERNEL);
|
||||
if (!kvalue)
|
||||
return -ENOMEM;
|
||||
if (copy_from_user(kvalue, value, size)) {
|
||||
kfree(kvalue);
|
||||
return -EFAULT;
|
||||
}
|
||||
kvalue = memdup_user(value, size);
|
||||
if (IS_ERR(kvalue))
|
||||
return PTR_ERR(kvalue);
|
||||
}
|
||||
|
||||
error = vfs_setxattr(d, kname, kvalue, size, flags);
|
||||
|
|
|
@ -489,17 +489,12 @@ xfs_attrmulti_attr_set(
|
|||
if (len > XATTR_SIZE_MAX)
|
||||
return EINVAL;
|
||||
|
||||
kbuf = kmalloc(len, GFP_KERNEL);
|
||||
if (!kbuf)
|
||||
return ENOMEM;
|
||||
|
||||
if (copy_from_user(kbuf, ubuf, len))
|
||||
goto out_kfree;
|
||||
kbuf = memdup_user(ubuf, len);
|
||||
if (IS_ERR(kbuf))
|
||||
return PTR_ERR(kbuf);
|
||||
|
||||
error = xfs_attr_set(XFS_I(inode), name, kbuf, len, flags);
|
||||
|
||||
out_kfree:
|
||||
kfree(kbuf);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -540,20 +535,16 @@ xfs_attrmulti_by_handle(
|
|||
if (!size || size > 16 * PAGE_SIZE)
|
||||
goto out_dput;
|
||||
|
||||
error = ENOMEM;
|
||||
ops = kmalloc(size, GFP_KERNEL);
|
||||
if (!ops)
|
||||
ops = memdup_user(am_hreq.ops, size);
|
||||
if (IS_ERR(ops)) {
|
||||
error = PTR_ERR(ops);
|
||||
goto out_dput;
|
||||
|
||||
error = EFAULT;
|
||||
if (copy_from_user(ops, am_hreq.ops, size))
|
||||
goto out_kfree_ops;
|
||||
}
|
||||
|
||||
attr_name = kmalloc(MAXNAMELEN, GFP_KERNEL);
|
||||
if (!attr_name)
|
||||
goto out_kfree_ops;
|
||||
|
||||
|
||||
error = 0;
|
||||
for (i = 0; i < am_hreq.opcount; i++) {
|
||||
ops[i].am_error = strncpy_from_user(attr_name,
|
||||
|
|
|
@ -427,20 +427,16 @@ xfs_compat_attrmulti_by_handle(
|
|||
if (!size || size > 16 * PAGE_SIZE)
|
||||
goto out_dput;
|
||||
|
||||
error = ENOMEM;
|
||||
ops = kmalloc(size, GFP_KERNEL);
|
||||
if (!ops)
|
||||
ops = memdup_user(compat_ptr(am_hreq.ops), size);
|
||||
if (IS_ERR(ops)) {
|
||||
error = PTR_ERR(ops);
|
||||
goto out_dput;
|
||||
|
||||
error = EFAULT;
|
||||
if (copy_from_user(ops, compat_ptr(am_hreq.ops), size))
|
||||
goto out_kfree_ops;
|
||||
}
|
||||
|
||||
attr_name = kmalloc(MAXNAMELEN, GFP_KERNEL);
|
||||
if (!attr_name)
|
||||
goto out_kfree_ops;
|
||||
|
||||
|
||||
error = 0;
|
||||
for (i = 0; i < am_hreq.opcount; i++) {
|
||||
ops[i].am_error = strncpy_from_user(attr_name,
|
||||
|
|
|
@ -2299,9 +2299,8 @@ extern int vfs_readdir(struct file *, filldir_t, void *);
|
|||
|
||||
extern int vfs_stat(char __user *, struct kstat *);
|
||||
extern int vfs_lstat(char __user *, struct kstat *);
|
||||
extern int vfs_stat_fd(int dfd, char __user *, struct kstat *);
|
||||
extern int vfs_lstat_fd(int dfd, char __user *, struct kstat *);
|
||||
extern int vfs_fstat(unsigned int, struct kstat *);
|
||||
extern int vfs_fstatat(int , char __user *, struct kstat *, int);
|
||||
|
||||
extern int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd,
|
||||
unsigned long arg);
|
||||
|
@ -2449,7 +2448,7 @@ struct ctl_table;
|
|||
int proc_nr_files(struct ctl_table *table, int write, struct file *filp,
|
||||
void __user *buffer, size_t *lenp, loff_t *ppos);
|
||||
|
||||
int get_filesystem_list(char * buf);
|
||||
int __init get_filesystem_list(char *buf);
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
#endif /* _LINUX_FS_H */
|
||||
|
|
|
@ -193,7 +193,7 @@ struct reiserfs_journal {
|
|||
atomic_t j_wcount; /* count of writers for current commit */
|
||||
unsigned long j_bcount; /* batch count. allows turning X transactions into 1 */
|
||||
unsigned long j_first_unflushed_offset; /* first unflushed transactions offset */
|
||||
unsigned long j_last_flush_trans_id; /* last fully flushed journal timestamp */
|
||||
unsigned j_last_flush_trans_id; /* last fully flushed journal timestamp */
|
||||
struct buffer_head *j_header_bh;
|
||||
|
||||
time_t j_trans_start_time; /* time this transaction started */
|
||||
|
|
|
@ -734,9 +734,6 @@ int audit_tag_tree(char *old, char *new)
|
|||
dentry = dget(path.dentry);
|
||||
path_put(&path);
|
||||
|
||||
if (dentry == tagged->mnt_root && dentry == mnt->mnt_root)
|
||||
follow_up(&mnt, &dentry);
|
||||
|
||||
list_add_tail(&list, &tagged->mnt_list);
|
||||
|
||||
mutex_lock(&audit_filter_mutex);
|
||||
|
|
Loading…
Reference in New Issue