提交 9a41fe34 编写于 作者: L Linus Torvalds

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
......@@ -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;
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);
int error;
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;
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);
int error;
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;
}
......
......@@ -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;
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);
int error;
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)
......
......@@ -55,59 +55,54 @@ 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)
int vfs_fstat(unsigned int fd, struct kstat *stat)
{
struct path path;
int error;
struct file *f = fget(fd);
int error = -EBADF;
error = user_path_at(dfd, name, LOOKUP_FOLLOW, &path);
if (!error) {
error = vfs_getattr(path.mnt, path.dentry, stat);
path_put(&path);
if (f) {
error = vfs_getattr(f->f_path.mnt, f->f_path.dentry, stat);
fput(f);
}
return error;
}
EXPORT_SYMBOL(vfs_fstat);
int vfs_stat(char __user *name, struct kstat *stat)
int vfs_fstatat(int dfd, char __user *filename, struct kstat *stat, int flag)
{
return vfs_stat_fd(AT_FDCWD, name, stat);
}
struct path path;
int error = -EINVAL;
int lookup_flags = 0;
EXPORT_SYMBOL(vfs_stat);
if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0)
goto out;
int vfs_lstat_fd(int dfd, char __user *name, struct kstat *stat)
{
struct path path;
int error;
if (!(flag & AT_SYMLINK_NOFOLLOW))
lookup_flags |= LOOKUP_FOLLOW;
error = user_path_at(dfd, name, 0, &path);
if (!error) {
error = vfs_getattr(path.mnt, path.dentry, stat);
path_put(&path);
}
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_lstat(char __user *name, struct kstat *stat)
int vfs_stat(char __user *name, struct kstat *stat)
{
return vfs_lstat_fd(AT_FDCWD, name, stat);
return vfs_fstatat(AT_FDCWD, name, stat, 0);
}
EXPORT_SYMBOL(vfs_stat);
EXPORT_SYMBOL(vfs_lstat);
int vfs_fstat(unsigned int fd, struct kstat *stat)
int vfs_lstat(char __user *name, struct kstat *stat)
{
struct file *f = fget(fd);
int error = -EBADF;
if (f) {
error = vfs_getattr(f->f_path.mnt, f->f_path.dentry, stat);
fput(f);
}
return error;
return vfs_fstatat(AT_FDCWD, name, stat, AT_SYMLINK_NOFOLLOW);
}
EXPORT_SYMBOL(vfs_lstat);
EXPORT_SYMBOL(vfs_fstat);
#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);
if (!error)
error = cp_new_stat(&stat, statbuf);
int error = vfs_stat(filename, &stat);
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;
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);
int error;
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;
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);
int error;
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;
}
......
......@@ -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);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册