mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-06-22 14:41:27 +00:00
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:
commit
422e6c4bc4
57 changed files with 1508 additions and 1278 deletions
|
@ -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;
|
return copy_to_user(osf_stat, &tmp_stat, bufsiz) ? -EFAULT : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
SYSCALL_DEFINE3(osf_statfs, const char __user *, pathname,
|
||||||
do_osf_statfs(struct path *path, struct osf_statfs __user *buffer,
|
struct osf_statfs __user *, buffer, unsigned long, bufsiz)
|
||||||
unsigned long bufsiz)
|
|
||||||
{
|
{
|
||||||
struct kstatfs linux_stat;
|
struct kstatfs linux_stat;
|
||||||
int error = vfs_statfs(path, &linux_stat);
|
int error = user_statfs(pathname, &linux_stat);
|
||||||
if (!error)
|
if (!error)
|
||||||
error = linux_to_osf_statfs(&linux_stat, buffer, bufsiz);
|
error = linux_to_osf_statfs(&linux_stat, buffer, bufsiz);
|
||||||
return error;
|
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,
|
SYSCALL_DEFINE3(osf_fstatfs, unsigned long, fd,
|
||||||
struct osf_statfs __user *, buffer, unsigned long, bufsiz)
|
struct osf_statfs __user *, buffer, unsigned long, bufsiz)
|
||||||
{
|
{
|
||||||
struct file *file;
|
struct kstatfs linux_stat;
|
||||||
int retval;
|
int error = fd_statfs(fd, &linux_stat);
|
||||||
|
if (!error)
|
||||||
retval = -EBADF;
|
error = linux_to_osf_statfs(&linux_stat, buffer, bufsiz);
|
||||||
file = fget(fd);
|
return error;
|
||||||
if (file) {
|
|
||||||
retval = do_osf_statfs(&file->f_path, buffer, bufsiz);
|
|
||||||
fput(file);
|
|
||||||
}
|
|
||||||
return retval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -185,26 +185,21 @@ struct hpux_statfs {
|
||||||
int16_t f_pad;
|
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;
|
struct hpux_statfs buf;
|
||||||
int retval;
|
memset(&buf, 0, sizeof(buf));
|
||||||
|
buf.f_type = st->f_type;
|
||||||
retval = vfs_statfs(path, &st);
|
buf.f_bsize = st->f_bsize;
|
||||||
if (retval)
|
buf.f_blocks = st->f_blocks;
|
||||||
return retval;
|
buf.f_bfree = st->f_bfree;
|
||||||
|
buf.f_bavail = st->f_bavail;
|
||||||
memset(buf, 0, sizeof(*buf));
|
buf.f_files = st->f_files;
|
||||||
buf->f_type = st.f_type;
|
buf.f_ffree = st->f_ffree;
|
||||||
buf->f_bsize = st.f_bsize;
|
buf.f_fsid[0] = st->f_fsid.val[0];
|
||||||
buf->f_blocks = st.f_blocks;
|
buf.f_fsid[1] = st->f_fsid.val[1];
|
||||||
buf->f_bfree = st.f_bfree;
|
if (copy_to_user(p, &buf, sizeof(buf)))
|
||||||
buf->f_bavail = st.f_bavail;
|
return -EFAULT;
|
||||||
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];
|
|
||||||
|
|
||||||
return 0;
|
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,
|
asmlinkage long hpux_statfs(const char __user *pathname,
|
||||||
struct hpux_statfs __user *buf)
|
struct hpux_statfs __user *buf)
|
||||||
{
|
{
|
||||||
struct path path;
|
struct kstatfs st;
|
||||||
int error;
|
int error = user_statfs(pathname, &st);
|
||||||
|
if (!error)
|
||||||
error = user_path(pathname, &path);
|
error = do_statfs_hpux(&st, buf);
|
||||||
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);
|
|
||||||
}
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
asmlinkage long hpux_fstatfs(unsigned int fd, struct hpux_statfs __user * buf)
|
asmlinkage long hpux_fstatfs(unsigned int fd, struct hpux_statfs __user * buf)
|
||||||
{
|
{
|
||||||
struct file *file;
|
struct kstatfs st;
|
||||||
struct hpux_statfs tmp;
|
int error = fd_statfs(fd, &st);
|
||||||
int error;
|
if (!error)
|
||||||
|
error = do_statfs_hpux(&st, buf);
|
||||||
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:
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -70,7 +70,7 @@ static long do_spu_create(const char __user *pathname, unsigned int flags,
|
||||||
if (!IS_ERR(tmp)) {
|
if (!IS_ERR(tmp)) {
|
||||||
struct nameidata nd;
|
struct nameidata nd;
|
||||||
|
|
||||||
ret = path_lookup(tmp, LOOKUP_PARENT, &nd);
|
ret = kern_path_parent(tmp, &nd);
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
nd.flags |= LOOKUP_OPEN | LOOKUP_CREATE;
|
nd.flags |= LOOKUP_OPEN | LOOKUP_CREATE;
|
||||||
ret = spufs_create(&nd, flags, mode, neighbor);
|
ret = spufs_create(&nd, flags, mode, neighbor);
|
||||||
|
|
|
@ -124,35 +124,18 @@ void mconsole_log(struct mc_request *req)
|
||||||
#if 0
|
#if 0
|
||||||
void mconsole_proc(struct mc_request *req)
|
void mconsole_proc(struct mc_request *req)
|
||||||
{
|
{
|
||||||
struct nameidata nd;
|
|
||||||
struct vfsmount *mnt = current->nsproxy->pid_ns->proc_mnt;
|
struct vfsmount *mnt = current->nsproxy->pid_ns->proc_mnt;
|
||||||
struct file *file;
|
struct file *file;
|
||||||
int n, err;
|
int n;
|
||||||
char *ptr = req->request.data, *buf;
|
char *ptr = req->request.data, *buf;
|
||||||
mm_segment_t old_fs = get_fs();
|
mm_segment_t old_fs = get_fs();
|
||||||
|
|
||||||
ptr += strlen("proc");
|
ptr += strlen("proc");
|
||||||
ptr = skip_spaces(ptr);
|
ptr = skip_spaces(ptr);
|
||||||
|
|
||||||
err = vfs_path_lookup(mnt->mnt_root, mnt, ptr, LOOKUP_FOLLOW, &nd);
|
file = file_open_root(mnt->mnt_root, mnt, ptr, O_RDONLY);
|
||||||
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);
|
|
||||||
if (IS_ERR(file)) {
|
if (IS_ERR(file)) {
|
||||||
mconsole_reply(req, "Failed to open file", 1, 0);
|
mconsole_reply(req, "Failed to open file", 1, 0);
|
||||||
path_put(&nd.path);
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -851,4 +851,6 @@ ia32_sys_call_table:
|
||||||
.quad sys_fanotify_init
|
.quad sys_fanotify_init
|
||||||
.quad sys32_fanotify_mark
|
.quad sys32_fanotify_mark
|
||||||
.quad sys_prlimit64 /* 340 */
|
.quad sys_prlimit64 /* 340 */
|
||||||
|
.quad sys_name_to_handle_at
|
||||||
|
.quad compat_sys_open_by_handle_at
|
||||||
ia32_syscall_end:
|
ia32_syscall_end:
|
||||||
|
|
|
@ -346,10 +346,12 @@
|
||||||
#define __NR_fanotify_init 338
|
#define __NR_fanotify_init 338
|
||||||
#define __NR_fanotify_mark 339
|
#define __NR_fanotify_mark 339
|
||||||
#define __NR_prlimit64 340
|
#define __NR_prlimit64 340
|
||||||
|
#define __NR_name_to_handle_at 341
|
||||||
|
#define __NR_open_by_handle_at 342
|
||||||
|
|
||||||
#ifdef __KERNEL__
|
#ifdef __KERNEL__
|
||||||
|
|
||||||
#define NR_syscalls 341
|
#define NR_syscalls 343
|
||||||
|
|
||||||
#define __ARCH_WANT_IPC_PARSE_VERSION
|
#define __ARCH_WANT_IPC_PARSE_VERSION
|
||||||
#define __ARCH_WANT_OLD_READDIR
|
#define __ARCH_WANT_OLD_READDIR
|
||||||
|
|
|
@ -669,6 +669,10 @@ __SYSCALL(__NR_fanotify_init, sys_fanotify_init)
|
||||||
__SYSCALL(__NR_fanotify_mark, sys_fanotify_mark)
|
__SYSCALL(__NR_fanotify_mark, sys_fanotify_mark)
|
||||||
#define __NR_prlimit64 302
|
#define __NR_prlimit64 302
|
||||||
__SYSCALL(__NR_prlimit64, sys_prlimit64)
|
__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
|
#ifndef __NO_STUBS
|
||||||
#define __ARCH_WANT_OLD_READDIR
|
#define __ARCH_WANT_OLD_READDIR
|
||||||
|
|
|
@ -340,3 +340,5 @@ ENTRY(sys_call_table)
|
||||||
.long sys_fanotify_init
|
.long sys_fanotify_init
|
||||||
.long sys_fanotify_mark
|
.long sys_fanotify_mark
|
||||||
.long sys_prlimit64 /* 340 */
|
.long sys_prlimit64 /* 340 */
|
||||||
|
.long sys_name_to_handle_at
|
||||||
|
.long sys_open_by_handle_at
|
||||||
|
|
|
@ -47,7 +47,7 @@ config FS_POSIX_ACL
|
||||||
def_bool n
|
def_bool n
|
||||||
|
|
||||||
config EXPORTFS
|
config EXPORTFS
|
||||||
tristate
|
bool
|
||||||
|
|
||||||
config FILE_LOCKING
|
config FILE_LOCKING
|
||||||
bool "Enable POSIX file locking API" if EXPERT
|
bool "Enable POSIX file locking API" if EXPERT
|
||||||
|
|
|
@ -48,6 +48,8 @@ obj-$(CONFIG_FS_POSIX_ACL) += posix_acl.o xattr_acl.o
|
||||||
obj-$(CONFIG_NFS_COMMON) += nfs_common/
|
obj-$(CONFIG_NFS_COMMON) += nfs_common/
|
||||||
obj-$(CONFIG_GENERIC_ACL) += generic_acl.o
|
obj-$(CONFIG_GENERIC_ACL) += generic_acl.o
|
||||||
|
|
||||||
|
obj-$(CONFIG_FHANDLE) += fhandle.o
|
||||||
|
|
||||||
obj-y += quota/
|
obj-y += quota/
|
||||||
|
|
||||||
obj-$(CONFIG_PROC_FS) += proc/
|
obj-$(CONFIG_PROC_FS) += proc/
|
||||||
|
|
|
@ -21,9 +21,13 @@ static int btrfs_encode_fh(struct dentry *dentry, u32 *fh, int *max_len,
|
||||||
int len = *max_len;
|
int len = *max_len;
|
||||||
int type;
|
int type;
|
||||||
|
|
||||||
if ((len < BTRFS_FID_SIZE_NON_CONNECTABLE) ||
|
if (connectable && (len < BTRFS_FID_SIZE_CONNECTABLE)) {
|
||||||
(connectable && len < BTRFS_FID_SIZE_CONNECTABLE))
|
*max_len = BTRFS_FID_SIZE_CONNECTABLE;
|
||||||
return 255;
|
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;
|
len = BTRFS_FID_SIZE_NON_CONNECTABLE;
|
||||||
type = FILEID_BTRFS_WITHOUT_PARENT;
|
type = FILEID_BTRFS_WITHOUT_PARENT;
|
||||||
|
|
|
@ -4806,9 +4806,6 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
|
||||||
int err;
|
int err;
|
||||||
int drop_inode = 0;
|
int drop_inode = 0;
|
||||||
|
|
||||||
if (inode->i_nlink == 0)
|
|
||||||
return -ENOENT;
|
|
||||||
|
|
||||||
/* do not allow sys_link's with other subvols of the same device */
|
/* do not allow sys_link's with other subvols of the same device */
|
||||||
if (root->objectid != BTRFS_I(inode)->root->objectid)
|
if (root->objectid != BTRFS_I(inode)->root->objectid)
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
81
fs/compat.c
81
fs/compat.c
|
@ -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)
|
asmlinkage long compat_sys_statfs(const char __user *pathname, struct compat_statfs __user *buf)
|
||||||
{
|
{
|
||||||
struct path path;
|
struct kstatfs tmp;
|
||||||
int error;
|
int error = user_statfs(pathname, &tmp);
|
||||||
|
if (!error)
|
||||||
error = user_path(pathname, &path);
|
error = put_compat_statfs(buf, &tmp);
|
||||||
if (!error) {
|
|
||||||
struct kstatfs tmp;
|
|
||||||
error = vfs_statfs(&path, &tmp);
|
|
||||||
if (!error)
|
|
||||||
error = put_compat_statfs(buf, &tmp);
|
|
||||||
path_put(&path);
|
|
||||||
}
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
asmlinkage long compat_sys_fstatfs(unsigned int fd, struct compat_statfs __user *buf)
|
asmlinkage long compat_sys_fstatfs(unsigned int fd, struct compat_statfs __user *buf)
|
||||||
{
|
{
|
||||||
struct file * file;
|
|
||||||
struct kstatfs tmp;
|
struct kstatfs tmp;
|
||||||
int error;
|
int error = fd_statfs(fd, &tmp);
|
||||||
|
|
||||||
error = -EBADF;
|
|
||||||
file = fget(fd);
|
|
||||||
if (!file)
|
|
||||||
goto out;
|
|
||||||
error = vfs_statfs(&file->f_path, &tmp);
|
|
||||||
if (!error)
|
if (!error)
|
||||||
error = put_compat_statfs(buf, &tmp);
|
error = put_compat_statfs(buf, &tmp);
|
||||||
fput(file);
|
|
||||||
out:
|
|
||||||
return error;
|
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)
|
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;
|
struct kstatfs tmp;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
if (sz != sizeof(*buf))
|
if (sz != sizeof(*buf))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
error = -EBADF;
|
error = user_statfs(pathname, &tmp);
|
||||||
file = fget(fd);
|
if (!error)
|
||||||
if (!file)
|
error = put_compat_statfs64(buf, &tmp);
|
||||||
goto out;
|
return error;
|
||||||
error = vfs_statfs(&file->f_path, &tmp);
|
}
|
||||||
|
|
||||||
|
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)
|
if (!error)
|
||||||
error = put_compat_statfs64(buf, &tmp);
|
error = put_compat_statfs64(buf, &tmp);
|
||||||
fput(file);
|
|
||||||
out:
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2312,3 +2284,16 @@ asmlinkage long compat_sys_timerfd_gettime(int ufd,
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* CONFIG_TIMERFD */
|
#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
|
||||||
|
|
18
fs/exec.c
18
fs/exec.c
|
@ -115,13 +115,16 @@ SYSCALL_DEFINE1(uselib, const char __user *, library)
|
||||||
struct file *file;
|
struct file *file;
|
||||||
char *tmp = getname(library);
|
char *tmp = getname(library);
|
||||||
int error = PTR_ERR(tmp);
|
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))
|
if (IS_ERR(tmp))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
file = do_filp_open(AT_FDCWD, tmp,
|
file = do_filp_open(AT_FDCWD, tmp, &uselib_flags, LOOKUP_FOLLOW);
|
||||||
O_LARGEFILE | O_RDONLY | __FMODE_EXEC, 0,
|
|
||||||
MAY_READ | MAY_EXEC | MAY_OPEN);
|
|
||||||
putname(tmp);
|
putname(tmp);
|
||||||
error = PTR_ERR(file);
|
error = PTR_ERR(file);
|
||||||
if (IS_ERR(file))
|
if (IS_ERR(file))
|
||||||
|
@ -721,10 +724,13 @@ struct file *open_exec(const char *name)
|
||||||
{
|
{
|
||||||
struct file *file;
|
struct file *file;
|
||||||
int err;
|
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,
|
file = do_filp_open(AT_FDCWD, name, &open_exec_flags, LOOKUP_FOLLOW);
|
||||||
O_LARGEFILE | O_RDONLY | __FMODE_EXEC, 0,
|
|
||||||
MAY_EXEC | MAY_OPEN);
|
|
||||||
if (IS_ERR(file))
|
if (IS_ERR(file))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
|
|
@ -320,9 +320,14 @@ static int export_encode_fh(struct dentry *dentry, struct fid *fid,
|
||||||
struct inode * inode = dentry->d_inode;
|
struct inode * inode = dentry->d_inode;
|
||||||
int len = *max_len;
|
int len = *max_len;
|
||||||
int type = FILEID_INO32_GEN;
|
int type = FILEID_INO32_GEN;
|
||||||
|
|
||||||
if (len < 2 || (connectable && len < 4))
|
if (connectable && (len < 4)) {
|
||||||
|
*max_len = 4;
|
||||||
return 255;
|
return 255;
|
||||||
|
} else if (len < 2) {
|
||||||
|
*max_len = 2;
|
||||||
|
return 255;
|
||||||
|
}
|
||||||
|
|
||||||
len = 2;
|
len = 2;
|
||||||
fid->i32.ino = inode->i_ino;
|
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.
|
* 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);
|
result = nop->fh_to_dentry(mnt->mnt_sb, fid, fh_len, fileid_type);
|
||||||
if (!result)
|
if (!result)
|
||||||
result = ERR_PTR(-ESTALE);
|
result = ERR_PTR(-ESTALE);
|
||||||
|
|
|
@ -2253,13 +2253,6 @@ static int ext3_link (struct dentry * old_dentry,
|
||||||
|
|
||||||
dquot_initialize(dir);
|
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:
|
retry:
|
||||||
handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) +
|
handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) +
|
||||||
EXT3_INDEX_EXTRA_TRANS_BLOCKS);
|
EXT3_INDEX_EXTRA_TRANS_BLOCKS);
|
||||||
|
|
|
@ -1936,6 +1936,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
|
||||||
sb->s_qcop = &ext3_qctl_operations;
|
sb->s_qcop = &ext3_qctl_operations;
|
||||||
sb->dq_op = &ext3_quota_operations;
|
sb->dq_op = &ext3_quota_operations;
|
||||||
#endif
|
#endif
|
||||||
|
memcpy(sb->s_uuid, es->s_uuid, sizeof(es->s_uuid));
|
||||||
INIT_LIST_HEAD(&sbi->s_orphan); /* unlinked but open files */
|
INIT_LIST_HEAD(&sbi->s_orphan); /* unlinked but open files */
|
||||||
mutex_init(&sbi->s_orphan_lock);
|
mutex_init(&sbi->s_orphan_lock);
|
||||||
mutex_init(&sbi->s_resize_lock);
|
mutex_init(&sbi->s_resize_lock);
|
||||||
|
|
|
@ -2304,13 +2304,6 @@ static int ext4_link(struct dentry *old_dentry,
|
||||||
|
|
||||||
dquot_initialize(dir);
|
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:
|
retry:
|
||||||
handle = ext4_journal_start(dir, EXT4_DATA_TRANS_BLOCKS(dir->i_sb) +
|
handle = ext4_journal_start(dir, EXT4_DATA_TRANS_BLOCKS(dir->i_sb) +
|
||||||
EXT4_INDEX_EXTRA_TRANS_BLOCKS);
|
EXT4_INDEX_EXTRA_TRANS_BLOCKS);
|
||||||
|
|
|
@ -3415,6 +3415,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
|
||||||
sb->s_qcop = &ext4_qctl_operations;
|
sb->s_qcop = &ext4_qctl_operations;
|
||||||
sb->dq_op = &ext4_quota_operations;
|
sb->dq_op = &ext4_quota_operations;
|
||||||
#endif
|
#endif
|
||||||
|
memcpy(sb->s_uuid, es->s_uuid, sizeof(es->s_uuid));
|
||||||
|
|
||||||
INIT_LIST_HEAD(&sbi->s_orphan); /* unlinked but open files */
|
INIT_LIST_HEAD(&sbi->s_orphan); /* unlinked but open files */
|
||||||
mutex_init(&sbi->s_orphan_lock);
|
mutex_init(&sbi->s_orphan_lock);
|
||||||
mutex_init(&sbi->s_resize_lock);
|
mutex_init(&sbi->s_resize_lock);
|
||||||
|
|
|
@ -757,8 +757,10 @@ fat_encode_fh(struct dentry *de, __u32 *fh, int *lenp, int connectable)
|
||||||
struct inode *inode = de->d_inode;
|
struct inode *inode = de->d_inode;
|
||||||
u32 ipos_h, ipos_m, ipos_l;
|
u32 ipos_h, ipos_m, ipos_l;
|
||||||
|
|
||||||
if (len < 5)
|
if (len < 5) {
|
||||||
|
*lenp = 5;
|
||||||
return 255; /* no room */
|
return 255; /* no room */
|
||||||
|
}
|
||||||
|
|
||||||
ipos_h = MSDOS_I(inode)->i_pos >> 8;
|
ipos_h = MSDOS_I(inode)->i_pos >> 8;
|
||||||
ipos_m = (MSDOS_I(inode)->i_pos & 0xf0) << 24;
|
ipos_m = (MSDOS_I(inode)->i_pos & 0xf0) << 24;
|
||||||
|
|
37
fs/fcntl.c
37
fs/fcntl.c
|
@ -131,7 +131,7 @@ SYSCALL_DEFINE2(dup2, unsigned int, oldfd, unsigned int, newfd)
|
||||||
SYSCALL_DEFINE1(dup, unsigned int, fildes)
|
SYSCALL_DEFINE1(dup, unsigned int, fildes)
|
||||||
{
|
{
|
||||||
int ret = -EBADF;
|
int ret = -EBADF;
|
||||||
struct file *file = fget(fildes);
|
struct file *file = fget_raw(fildes);
|
||||||
|
|
||||||
if (file) {
|
if (file) {
|
||||||
ret = get_unused_fd();
|
ret = get_unused_fd();
|
||||||
|
@ -426,15 +426,35 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
|
||||||
return err;
|
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)
|
SYSCALL_DEFINE3(fcntl, unsigned int, fd, unsigned int, cmd, unsigned long, arg)
|
||||||
{
|
{
|
||||||
struct file *filp;
|
struct file *filp;
|
||||||
long err = -EBADF;
|
long err = -EBADF;
|
||||||
|
|
||||||
filp = fget(fd);
|
filp = fget_raw(fd);
|
||||||
if (!filp)
|
if (!filp)
|
||||||
goto out;
|
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);
|
err = security_file_fcntl(filp, cmd, arg);
|
||||||
if (err) {
|
if (err) {
|
||||||
fput(filp);
|
fput(filp);
|
||||||
|
@ -456,10 +476,17 @@ SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd,
|
||||||
long err;
|
long err;
|
||||||
|
|
||||||
err = -EBADF;
|
err = -EBADF;
|
||||||
filp = fget(fd);
|
filp = fget_raw(fd);
|
||||||
if (!filp)
|
if (!filp)
|
||||||
goto out;
|
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);
|
err = security_file_fcntl(filp, cmd, arg);
|
||||||
if (err) {
|
if (err) {
|
||||||
fput(filp);
|
fput(filp);
|
||||||
|
@ -808,14 +835,14 @@ static int __init fcntl_init(void)
|
||||||
* Exceptions: O_NONBLOCK is a two bit define on parisc; O_NDELAY
|
* Exceptions: O_NONBLOCK is a two bit define on parisc; O_NDELAY
|
||||||
* is defined as O_NONBLOCK on some platforms and not on others.
|
* 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_RDONLY | O_WRONLY | O_RDWR |
|
||||||
O_CREAT | O_EXCL | O_NOCTTY |
|
O_CREAT | O_EXCL | O_NOCTTY |
|
||||||
O_TRUNC | O_APPEND | /* O_NONBLOCK | */
|
O_TRUNC | O_APPEND | /* O_NONBLOCK | */
|
||||||
__O_SYNC | O_DSYNC | FASYNC |
|
__O_SYNC | O_DSYNC | FASYNC |
|
||||||
O_DIRECT | O_LARGEFILE | O_DIRECTORY |
|
O_DIRECT | O_LARGEFILE | O_DIRECTORY |
|
||||||
O_NOFOLLOW | O_NOATIME | O_CLOEXEC |
|
O_NOFOLLOW | O_NOATIME | O_CLOEXEC |
|
||||||
__FMODE_EXEC
|
__FMODE_EXEC | O_PATH
|
||||||
));
|
));
|
||||||
|
|
||||||
fasync_cache = kmem_cache_create("fasync_cache",
|
fasync_cache = kmem_cache_create("fasync_cache",
|
||||||
|
|
265
fs/fhandle.c
Normal file
265
fs/fhandle.c
Normal 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;
|
||||||
|
}
|
|
@ -276,11 +276,10 @@ struct file *fget(unsigned int fd)
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
file = fcheck_files(files, fd);
|
file = fcheck_files(files, fd);
|
||||||
if (file) {
|
if (file) {
|
||||||
if (!atomic_long_inc_not_zero(&file->f_count)) {
|
/* File object ref couldn't be taken */
|
||||||
/* File object ref couldn't be taken */
|
if (file->f_mode & FMODE_PATH ||
|
||||||
rcu_read_unlock();
|
!atomic_long_inc_not_zero(&file->f_count))
|
||||||
return NULL;
|
file = NULL;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
|
|
||||||
|
@ -289,6 +288,25 @@ struct file *fget(unsigned int fd)
|
||||||
|
|
||||||
EXPORT_SYMBOL(fget);
|
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.
|
* 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 file *file;
|
||||||
struct files_struct *files = current->files;
|
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;
|
*fput_needed = 0;
|
||||||
if (atomic_read(&files->count) == 1) {
|
if (atomic_read(&files->count) == 1) {
|
||||||
file = fcheck_files(files, fd);
|
file = fcheck_files(files, fd);
|
||||||
|
|
|
@ -637,8 +637,10 @@ static int fuse_encode_fh(struct dentry *dentry, u32 *fh, int *max_len,
|
||||||
u64 nodeid;
|
u64 nodeid;
|
||||||
u32 generation;
|
u32 generation;
|
||||||
|
|
||||||
if (*max_len < len)
|
if (*max_len < len) {
|
||||||
|
*max_len = len;
|
||||||
return 255;
|
return 255;
|
||||||
|
}
|
||||||
|
|
||||||
nodeid = get_fuse_inode(inode)->nodeid;
|
nodeid = get_fuse_inode(inode)->nodeid;
|
||||||
generation = inode->i_generation;
|
generation = inode->i_generation;
|
||||||
|
|
|
@ -36,9 +36,13 @@ static int gfs2_encode_fh(struct dentry *dentry, __u32 *p, int *len,
|
||||||
struct super_block *sb = inode->i_sb;
|
struct super_block *sb = inode->i_sb;
|
||||||
struct gfs2_inode *ip = GFS2_I(inode);
|
struct gfs2_inode *ip = GFS2_I(inode);
|
||||||
|
|
||||||
if (*len < GFS2_SMALL_FH_SIZE ||
|
if (connectable && (*len < GFS2_LARGE_FH_SIZE)) {
|
||||||
(connectable && *len < GFS2_LARGE_FH_SIZE))
|
*len = GFS2_LARGE_FH_SIZE;
|
||||||
return 255;
|
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[0] = cpu_to_be32(ip->i_no_formal_ino >> 32);
|
||||||
fh[1] = cpu_to_be32(ip->i_no_formal_ino & 0xFFFFFFFF);
|
fh[1] = cpu_to_be32(ip->i_no_formal_ino & 0xFFFFFFFF);
|
||||||
|
|
|
@ -106,6 +106,19 @@ extern void put_super(struct super_block *sb);
|
||||||
struct nameidata;
|
struct nameidata;
|
||||||
extern struct file *nameidata_to_filp(struct nameidata *);
|
extern struct file *nameidata_to_filp(struct nameidata *);
|
||||||
extern void release_open_intent(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
|
* inode.c
|
||||||
|
|
|
@ -124,9 +124,13 @@ isofs_export_encode_fh(struct dentry *dentry,
|
||||||
* offset of the inode and the upper 16 bits of fh32[1] to
|
* offset of the inode and the upper 16 bits of fh32[1] to
|
||||||
* hold the offset of the parent.
|
* hold the offset of the parent.
|
||||||
*/
|
*/
|
||||||
|
if (connectable && (len < 5)) {
|
||||||
if (len < 3 || (connectable && len < 5))
|
*max_len = 5;
|
||||||
return 255;
|
return 255;
|
||||||
|
} else if (len < 3) {
|
||||||
|
*max_len = 3;
|
||||||
|
return 255;
|
||||||
|
}
|
||||||
|
|
||||||
len = 3;
|
len = 3;
|
||||||
fh32[0] = ei->i_iget5_block;
|
fh32[0] = ei->i_iget5_block;
|
||||||
|
|
|
@ -809,9 +809,6 @@ static int jfs_link(struct dentry *old_dentry,
|
||||||
if (ip->i_nlink == JFS_LINK_MAX)
|
if (ip->i_nlink == JFS_LINK_MAX)
|
||||||
return -EMLINK;
|
return -EMLINK;
|
||||||
|
|
||||||
if (ip->i_nlink == 0)
|
|
||||||
return -ENOENT;
|
|
||||||
|
|
||||||
dquot_initialize(dir);
|
dquot_initialize(dir);
|
||||||
|
|
||||||
tid = txBegin(ip->i_sb, 0);
|
tid = txBegin(ip->i_sb, 0);
|
||||||
|
|
1526
fs/namei.c
1526
fs/namei.c
File diff suppressed because it is too large
Load diff
|
@ -1002,6 +1002,18 @@ const struct seq_operations mounts_op = {
|
||||||
.show = show_vfsmnt
|
.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)
|
static int show_mountinfo(struct seq_file *m, void *v)
|
||||||
{
|
{
|
||||||
struct proc_mounts *p = m->private;
|
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))
|
if (IS_MNT_UNBINDABLE(mnt))
|
||||||
seq_puts(m, " unbindable");
|
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 */
|
/* Filesystem specific data */
|
||||||
seq_puts(m, " - ");
|
seq_puts(m, " - ");
|
||||||
show_type(m, sb);
|
show_type(m, sb);
|
||||||
|
|
21
fs/nfsctl.c
21
fs/nfsctl.c
|
@ -22,30 +22,17 @@
|
||||||
|
|
||||||
static struct file *do_open(char *name, int flags)
|
static struct file *do_open(char *name, int flags)
|
||||||
{
|
{
|
||||||
struct nameidata nd;
|
|
||||||
struct vfsmount *mnt;
|
struct vfsmount *mnt;
|
||||||
int error;
|
struct file *file;
|
||||||
|
|
||||||
mnt = do_kern_mount("nfsd", 0, "nfsd", NULL);
|
mnt = do_kern_mount("nfsd", 0, "nfsd", NULL);
|
||||||
if (IS_ERR(mnt))
|
if (IS_ERR(mnt))
|
||||||
return (struct file *)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 */
|
mntput(mnt); /* drop do_kern_mount reference */
|
||||||
if (error)
|
return file;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
|
|
|
@ -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,
|
dentry->d_name.len, dentry->d_name.name,
|
||||||
fh, len, connectable);
|
fh, len, connectable);
|
||||||
|
|
||||||
if (len < 3 || (connectable && len < 6)) {
|
if (connectable && (len < 6)) {
|
||||||
mlog(ML_ERROR, "fh buffer is too small for encoding\n");
|
*max_len = 6;
|
||||||
|
type = 255;
|
||||||
|
goto bail;
|
||||||
|
} else if (len < 3) {
|
||||||
|
*max_len = 3;
|
||||||
type = 255;
|
type = 255;
|
||||||
goto bail;
|
goto bail;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4379,7 +4379,7 @@ static int ocfs2_user_path_parent(const char __user *path,
|
||||||
if (IS_ERR(s))
|
if (IS_ERR(s))
|
||||||
return PTR_ERR(s);
|
return PTR_ERR(s);
|
||||||
|
|
||||||
error = path_lookup(s, LOOKUP_PARENT, nd);
|
error = kern_path_parent(s, nd);
|
||||||
if (error)
|
if (error)
|
||||||
putname(s);
|
putname(s);
|
||||||
else
|
else
|
||||||
|
|
126
fs/open.c
126
fs/open.c
|
@ -573,13 +573,15 @@ SYSCALL_DEFINE5(fchownat, int, dfd, const char __user *, filename, uid_t, user,
|
||||||
{
|
{
|
||||||
struct path path;
|
struct path path;
|
||||||
int error = -EINVAL;
|
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;
|
goto out;
|
||||||
|
|
||||||
follow = (flag & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW;
|
lookup_flags = (flag & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW;
|
||||||
error = user_path_at(dfd, filename, follow, &path);
|
if (flag & AT_EMPTY_PATH)
|
||||||
|
lookup_flags |= LOOKUP_EMPTY;
|
||||||
|
error = user_path_at(dfd, filename, lookup_flags, &path);
|
||||||
if (error)
|
if (error)
|
||||||
goto out;
|
goto out;
|
||||||
error = mnt_want_write(path.mnt);
|
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 *),
|
int (*open)(struct inode *, struct file *),
|
||||||
const struct cred *cred)
|
const struct cred *cred)
|
||||||
{
|
{
|
||||||
|
static const struct file_operations empty_fops = {};
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
f->f_mode = OPEN_FMODE(f->f_flags) | FMODE_LSEEK |
|
f->f_mode = OPEN_FMODE(f->f_flags) | FMODE_LSEEK |
|
||||||
FMODE_PREAD | FMODE_PWRITE;
|
FMODE_PREAD | FMODE_PWRITE;
|
||||||
|
|
||||||
|
if (unlikely(f->f_flags & O_PATH))
|
||||||
|
f->f_mode = FMODE_PATH;
|
||||||
|
|
||||||
inode = dentry->d_inode;
|
inode = dentry->d_inode;
|
||||||
if (f->f_mode & FMODE_WRITE) {
|
if (f->f_mode & FMODE_WRITE) {
|
||||||
error = __get_file_write_access(inode, mnt);
|
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.dentry = dentry;
|
||||||
f->f_path.mnt = mnt;
|
f->f_path.mnt = mnt;
|
||||||
f->f_pos = 0;
|
f->f_pos = 0;
|
||||||
f->f_op = fops_get(inode->i_fop);
|
|
||||||
file_sb_list_add(f, inode->i_sb);
|
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);
|
error = security_dentry_open(f, cred);
|
||||||
if (error)
|
if (error)
|
||||||
goto cleanup_all;
|
goto cleanup_all;
|
||||||
|
@ -890,15 +903,110 @@ void fd_install(unsigned int fd, struct file *file)
|
||||||
|
|
||||||
EXPORT_SYMBOL(fd_install);
|
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)
|
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);
|
char *tmp = getname(filename);
|
||||||
int fd = PTR_ERR(tmp);
|
int fd = PTR_ERR(tmp);
|
||||||
|
|
||||||
if (!IS_ERR(tmp)) {
|
if (!IS_ERR(tmp)) {
|
||||||
fd = get_unused_fd_flags(flags);
|
fd = get_unused_fd_flags(flags);
|
||||||
if (fd >= 0) {
|
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)) {
|
if (IS_ERR(f)) {
|
||||||
put_unused_fd(fd);
|
put_unused_fd(fd);
|
||||||
fd = PTR_ERR(f);
|
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)
|
if (filp->f_op && filp->f_op->flush)
|
||||||
retval = filp->f_op->flush(filp, id);
|
retval = filp->f_op->flush(filp, id);
|
||||||
|
|
||||||
dnotify_flush(filp, id);
|
if (likely(!(filp->f_mode & FMODE_PATH))) {
|
||||||
locks_remove_posix(filp, id);
|
dnotify_flush(filp, id);
|
||||||
|
locks_remove_posix(filp, id);
|
||||||
|
}
|
||||||
fput(filp);
|
fput(filp);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1593,8 +1593,13 @@ int reiserfs_encode_fh(struct dentry *dentry, __u32 * data, int *lenp,
|
||||||
struct inode *inode = dentry->d_inode;
|
struct inode *inode = dentry->d_inode;
|
||||||
int maxlen = *lenp;
|
int maxlen = *lenp;
|
||||||
|
|
||||||
if (maxlen < 3)
|
if (need_parent && (maxlen < 5)) {
|
||||||
|
*lenp = 5;
|
||||||
return 255;
|
return 255;
|
||||||
|
} else if (maxlen < 3) {
|
||||||
|
*lenp = 3;
|
||||||
|
return 255;
|
||||||
|
}
|
||||||
|
|
||||||
data[0] = inode->i_ino;
|
data[0] = inode->i_ino;
|
||||||
data[1] = le32_to_cpu(INODE_PKEY(inode)->k_dir_id);
|
data[1] = le32_to_cpu(INODE_PKEY(inode)->k_dir_id);
|
||||||
|
|
|
@ -1122,10 +1122,6 @@ static int reiserfs_link(struct dentry *old_dentry, struct inode *dir,
|
||||||
reiserfs_write_unlock(dir->i_sb);
|
reiserfs_write_unlock(dir->i_sb);
|
||||||
return -EMLINK;
|
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 before scheduling so reiserfs_unlink knows we are here */
|
||||||
inc_nlink(inode);
|
inc_nlink(inode);
|
||||||
|
|
|
@ -75,13 +75,16 @@ int vfs_fstatat(int dfd, const char __user *filename, struct kstat *stat,
|
||||||
int error = -EINVAL;
|
int error = -EINVAL;
|
||||||
int lookup_flags = 0;
|
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;
|
goto out;
|
||||||
|
|
||||||
if (!(flag & AT_SYMLINK_NOFOLLOW))
|
if (!(flag & AT_SYMLINK_NOFOLLOW))
|
||||||
lookup_flags |= LOOKUP_FOLLOW;
|
lookup_flags |= LOOKUP_FOLLOW;
|
||||||
if (flag & AT_NO_AUTOMOUNT)
|
if (flag & AT_NO_AUTOMOUNT)
|
||||||
lookup_flags |= LOOKUP_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);
|
error = user_path_at(dfd, filename, lookup_flags, &path);
|
||||||
if (error)
|
if (error)
|
||||||
|
@ -297,7 +300,7 @@ SYSCALL_DEFINE4(readlinkat, int, dfd, const char __user *, pathname,
|
||||||
if (bufsiz <= 0)
|
if (bufsiz <= 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
error = user_path_at(dfd, pathname, 0, &path);
|
error = user_path_at(dfd, pathname, LOOKUP_EMPTY, &path);
|
||||||
if (!error) {
|
if (!error) {
|
||||||
struct inode *inode = path.dentry->d_inode;
|
struct inode *inode = path.dentry->d_inode;
|
||||||
|
|
||||||
|
|
176
fs/statfs.c
176
fs/statfs.c
|
@ -73,149 +73,135 @@ int vfs_statfs(struct path *path, struct kstatfs *buf)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(vfs_statfs);
|
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;
|
struct path path;
|
||||||
int retval;
|
int error = user_path(pathname, &path);
|
||||||
|
if (!error) {
|
||||||
|
error = vfs_statfs(&path, st);
|
||||||
|
path_put(&path);
|
||||||
|
}
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
retval = vfs_statfs(path, &st);
|
int fd_statfs(int fd, struct kstatfs *st)
|
||||||
if (retval)
|
{
|
||||||
return retval;
|
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))
|
static int do_statfs_native(struct kstatfs *st, struct statfs __user *p)
|
||||||
memcpy(buf, &st, sizeof(st));
|
{
|
||||||
|
struct statfs buf;
|
||||||
|
|
||||||
|
if (sizeof(buf) == sizeof(*st))
|
||||||
|
memcpy(&buf, st, sizeof(*st));
|
||||||
else {
|
else {
|
||||||
if (sizeof buf->f_blocks == 4) {
|
if (sizeof buf.f_blocks == 4) {
|
||||||
if ((st.f_blocks | st.f_bfree | st.f_bavail |
|
if ((st->f_blocks | st->f_bfree | st->f_bavail |
|
||||||
st.f_bsize | st.f_frsize) &
|
st->f_bsize | st->f_frsize) &
|
||||||
0xffffffff00000000ULL)
|
0xffffffff00000000ULL)
|
||||||
return -EOVERFLOW;
|
return -EOVERFLOW;
|
||||||
/*
|
/*
|
||||||
* f_files and f_ffree may be -1; it's okay to stuff
|
* f_files and f_ffree may be -1; it's okay to stuff
|
||||||
* that into 32 bits
|
* that into 32 bits
|
||||||
*/
|
*/
|
||||||
if (st.f_files != -1 &&
|
if (st->f_files != -1 &&
|
||||||
(st.f_files & 0xffffffff00000000ULL))
|
(st->f_files & 0xffffffff00000000ULL))
|
||||||
return -EOVERFLOW;
|
return -EOVERFLOW;
|
||||||
if (st.f_ffree != -1 &&
|
if (st->f_ffree != -1 &&
|
||||||
(st.f_ffree & 0xffffffff00000000ULL))
|
(st->f_ffree & 0xffffffff00000000ULL))
|
||||||
return -EOVERFLOW;
|
return -EOVERFLOW;
|
||||||
}
|
}
|
||||||
|
|
||||||
buf->f_type = st.f_type;
|
buf.f_type = st->f_type;
|
||||||
buf->f_bsize = st.f_bsize;
|
buf.f_bsize = st->f_bsize;
|
||||||
buf->f_blocks = st.f_blocks;
|
buf.f_blocks = st->f_blocks;
|
||||||
buf->f_bfree = st.f_bfree;
|
buf.f_bfree = st->f_bfree;
|
||||||
buf->f_bavail = st.f_bavail;
|
buf.f_bavail = st->f_bavail;
|
||||||
buf->f_files = st.f_files;
|
buf.f_files = st->f_files;
|
||||||
buf->f_ffree = st.f_ffree;
|
buf.f_ffree = st->f_ffree;
|
||||||
buf->f_fsid = st.f_fsid;
|
buf.f_fsid = st->f_fsid;
|
||||||
buf->f_namelen = st.f_namelen;
|
buf.f_namelen = st->f_namelen;
|
||||||
buf->f_frsize = st.f_frsize;
|
buf.f_frsize = st->f_frsize;
|
||||||
buf->f_flags = st.f_flags;
|
buf.f_flags = st->f_flags;
|
||||||
memset(buf->f_spare, 0, sizeof(buf->f_spare));
|
memset(buf.f_spare, 0, sizeof(buf.f_spare));
|
||||||
}
|
}
|
||||||
|
if (copy_to_user(p, &buf, sizeof(buf)))
|
||||||
|
return -EFAULT;
|
||||||
return 0;
|
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;
|
struct statfs64 buf;
|
||||||
int retval;
|
if (sizeof(buf) == sizeof(*st))
|
||||||
|
memcpy(&buf, st, sizeof(*st));
|
||||||
retval = vfs_statfs(path, &st);
|
|
||||||
if (retval)
|
|
||||||
return retval;
|
|
||||||
|
|
||||||
if (sizeof(*buf) == sizeof(st))
|
|
||||||
memcpy(buf, &st, sizeof(st));
|
|
||||||
else {
|
else {
|
||||||
buf->f_type = st.f_type;
|
buf.f_type = st->f_type;
|
||||||
buf->f_bsize = st.f_bsize;
|
buf.f_bsize = st->f_bsize;
|
||||||
buf->f_blocks = st.f_blocks;
|
buf.f_blocks = st->f_blocks;
|
||||||
buf->f_bfree = st.f_bfree;
|
buf.f_bfree = st->f_bfree;
|
||||||
buf->f_bavail = st.f_bavail;
|
buf.f_bavail = st->f_bavail;
|
||||||
buf->f_files = st.f_files;
|
buf.f_files = st->f_files;
|
||||||
buf->f_ffree = st.f_ffree;
|
buf.f_ffree = st->f_ffree;
|
||||||
buf->f_fsid = st.f_fsid;
|
buf.f_fsid = st->f_fsid;
|
||||||
buf->f_namelen = st.f_namelen;
|
buf.f_namelen = st->f_namelen;
|
||||||
buf->f_frsize = st.f_frsize;
|
buf.f_frsize = st->f_frsize;
|
||||||
buf->f_flags = st.f_flags;
|
buf.f_flags = st->f_flags;
|
||||||
memset(buf->f_spare, 0, sizeof(buf->f_spare));
|
memset(buf.f_spare, 0, sizeof(buf.f_spare));
|
||||||
}
|
}
|
||||||
|
if (copy_to_user(p, &buf, sizeof(buf)))
|
||||||
|
return -EFAULT;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SYSCALL_DEFINE2(statfs, const char __user *, pathname, struct statfs __user *, buf)
|
SYSCALL_DEFINE2(statfs, const char __user *, pathname, struct statfs __user *, buf)
|
||||||
{
|
{
|
||||||
struct path path;
|
struct kstatfs st;
|
||||||
int error;
|
int error = user_statfs(pathname, &st);
|
||||||
|
if (!error)
|
||||||
error = user_path(pathname, &path);
|
error = do_statfs_native(&st, buf);
|
||||||
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);
|
|
||||||
}
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
SYSCALL_DEFINE3(statfs64, const char __user *, pathname, size_t, sz, struct statfs64 __user *, buf)
|
SYSCALL_DEFINE3(statfs64, const char __user *, pathname, size_t, sz, struct statfs64 __user *, buf)
|
||||||
{
|
{
|
||||||
struct path path;
|
struct kstatfs st;
|
||||||
long error;
|
int error;
|
||||||
|
|
||||||
if (sz != sizeof(*buf))
|
if (sz != sizeof(*buf))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
error = user_path(pathname, &path);
|
error = user_statfs(pathname, &st);
|
||||||
if (!error) {
|
if (!error)
|
||||||
struct statfs64 tmp;
|
error = do_statfs64(&st, buf);
|
||||||
error = do_statfs64(&path, &tmp);
|
|
||||||
if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
|
|
||||||
error = -EFAULT;
|
|
||||||
path_put(&path);
|
|
||||||
}
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
SYSCALL_DEFINE2(fstatfs, unsigned int, fd, struct statfs __user *, buf)
|
SYSCALL_DEFINE2(fstatfs, unsigned int, fd, struct statfs __user *, buf)
|
||||||
{
|
{
|
||||||
struct file *file;
|
struct kstatfs st;
|
||||||
struct statfs tmp;
|
int error = fd_statfs(fd, &st);
|
||||||
int error;
|
if (!error)
|
||||||
|
error = do_statfs_native(&st, buf);
|
||||||
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:
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
SYSCALL_DEFINE3(fstatfs64, unsigned int, fd, size_t, sz, struct statfs64 __user *, buf)
|
SYSCALL_DEFINE3(fstatfs64, unsigned int, fd, size_t, sz, struct statfs64 __user *, buf)
|
||||||
{
|
{
|
||||||
struct file *file;
|
struct kstatfs st;
|
||||||
struct statfs64 tmp;
|
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
if (sz != sizeof(*buf))
|
if (sz != sizeof(*buf))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
error = -EBADF;
|
error = fd_statfs(fd, &st);
|
||||||
file = fget(fd);
|
if (!error)
|
||||||
if (!file)
|
error = do_statfs64(&st, buf);
|
||||||
goto out;
|
|
||||||
error = do_statfs64(&file->f_path, &tmp);
|
|
||||||
if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
|
|
||||||
error = -EFAULT;
|
|
||||||
fput(file);
|
|
||||||
out:
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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(&dir->i_mutex));
|
||||||
ubifs_assert(mutex_is_locked(&inode->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);
|
err = dbg_check_synced_i_size(inode);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
|
@ -1286,8 +1286,13 @@ static int udf_encode_fh(struct dentry *de, __u32 *fh, int *lenp,
|
||||||
struct fid *fid = (struct fid *)fh;
|
struct fid *fid = (struct fid *)fh;
|
||||||
int type = FILEID_UDF_WITHOUT_PARENT;
|
int type = FILEID_UDF_WITHOUT_PARENT;
|
||||||
|
|
||||||
if (len < 3 || (connectable && len < 5))
|
if (connectable && (len < 5)) {
|
||||||
|
*lenp = 5;
|
||||||
return 255;
|
return 255;
|
||||||
|
} else if (len < 3) {
|
||||||
|
*lenp = 3;
|
||||||
|
return 255;
|
||||||
|
}
|
||||||
|
|
||||||
*lenp = 3;
|
*lenp = 3;
|
||||||
fid->udf.block = location.logicalBlockNum;
|
fid->udf.block = location.logicalBlockNum;
|
||||||
|
|
|
@ -89,8 +89,10 @@ xfs_fs_encode_fh(
|
||||||
* seven combinations work. The real answer is "don't use v2".
|
* seven combinations work. The real answer is "don't use v2".
|
||||||
*/
|
*/
|
||||||
len = xfs_fileid_length(fileid_type);
|
len = xfs_fileid_length(fileid_type);
|
||||||
if (*max_len < len)
|
if (*max_len < len) {
|
||||||
|
*max_len = len;
|
||||||
return 255;
|
return 255;
|
||||||
|
}
|
||||||
*max_len = len;
|
*max_len = len;
|
||||||
|
|
||||||
switch (fileid_type) {
|
switch (fileid_type) {
|
||||||
|
|
|
@ -80,6 +80,10 @@
|
||||||
#define O_SYNC (__O_SYNC|O_DSYNC)
|
#define O_SYNC (__O_SYNC|O_DSYNC)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef O_PATH
|
||||||
|
#define O_PATH 010000000
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef O_NDELAY
|
#ifndef O_NDELAY
|
||||||
#define O_NDELAY O_NONBLOCK
|
#define O_NDELAY O_NONBLOCK
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -646,9 +646,13 @@ __SYSCALL(__NR_prlimit64, sys_prlimit64)
|
||||||
__SYSCALL(__NR_fanotify_init, sys_fanotify_init)
|
__SYSCALL(__NR_fanotify_init, sys_fanotify_init)
|
||||||
#define __NR_fanotify_mark 263
|
#define __NR_fanotify_mark 263
|
||||||
__SYSCALL(__NR_fanotify_mark, sys_fanotify_mark)
|
__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
|
#undef __NR_syscalls
|
||||||
#define __NR_syscalls 264
|
#define __NR_syscalls 266
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* All syscalls below here should go away really,
|
* All syscalls below here should go away really,
|
||||||
|
|
|
@ -8,6 +8,9 @@ struct inode;
|
||||||
struct super_block;
|
struct super_block;
|
||||||
struct vfsmount;
|
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.
|
* 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
|
* 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
|
* 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
|
* 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
|
* filesystem. This typically means storing a reference to de->d_parent in
|
||||||
* the filehandle fragment. encode_fh() should return the number of bytes
|
* the filehandle fragment. encode_fh() should return the fileid_type on
|
||||||
* stored or a negative error code such as %-ENOSPC
|
* 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:
|
||||||
* @fh_to_dentry is given a &struct super_block (@sb) and a file handle
|
* @fh_to_dentry is given a &struct super_block (@sb) and a file handle
|
||||||
|
|
|
@ -46,6 +46,7 @@
|
||||||
unlinking file. */
|
unlinking file. */
|
||||||
#define AT_SYMLINK_FOLLOW 0x400 /* Follow symbolic links. */
|
#define AT_SYMLINK_FOLLOW 0x400 /* Follow symbolic links. */
|
||||||
#define AT_NO_AUTOMOUNT 0x800 /* Suppress terminal automount traversal */
|
#define AT_NO_AUTOMOUNT 0x800 /* Suppress terminal automount traversal */
|
||||||
|
#define AT_EMPTY_PATH 0x1000 /* Allow empty relative pathname */
|
||||||
|
|
||||||
#ifdef __KERNEL__
|
#ifdef __KERNEL__
|
||||||
|
|
||||||
|
|
|
@ -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(unsigned int fd);
|
||||||
extern struct file *fget_light(unsigned int fd, int *fput_needed);
|
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 set_close_on_exec(unsigned int fd, int flag);
|
||||||
extern void put_filp(struct file *);
|
extern void put_filp(struct file *);
|
||||||
extern int alloc_fd(unsigned start, unsigned flags);
|
extern int alloc_fd(unsigned start, unsigned flags);
|
||||||
|
|
|
@ -102,6 +102,9 @@ struct inodes_stat_t {
|
||||||
/* File is huge (eg. /dev/kmem): treat loff_t as unsigned */
|
/* File is huge (eg. /dev/kmem): treat loff_t as unsigned */
|
||||||
#define FMODE_UNSIGNED_OFFSET ((__force fmode_t)0x2000)
|
#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 */
|
/* File was opened by fanotify and shouldn't generate fanotify events */
|
||||||
#define FMODE_NONOTIFY ((__force fmode_t)0x1000000)
|
#define FMODE_NONOTIFY ((__force fmode_t)0x1000000)
|
||||||
|
|
||||||
|
@ -978,6 +981,13 @@ struct file {
|
||||||
#endif
|
#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 get_file(x) atomic_long_inc(&(x)->f_count)
|
||||||
#define fput_atomic(x) atomic_long_add_unless(&(x)->f_count, -1, 1)
|
#define fput_atomic(x) atomic_long_add_unless(&(x)->f_count, -1, 1)
|
||||||
#define file_count(x) atomic_long_read(&(x)->f_count)
|
#define file_count(x) atomic_long_read(&(x)->f_count)
|
||||||
|
@ -1401,6 +1411,7 @@ struct super_block {
|
||||||
wait_queue_head_t s_wait_unfrozen;
|
wait_queue_head_t s_wait_unfrozen;
|
||||||
|
|
||||||
char s_id[32]; /* Informational name */
|
char s_id[32]; /* Informational name */
|
||||||
|
u8 s_uuid[16]; /* UUID */
|
||||||
|
|
||||||
void *s_fs_info; /* Filesystem private info */
|
void *s_fs_info; /* Filesystem private info */
|
||||||
fmode_t s_mode;
|
fmode_t s_mode;
|
||||||
|
@ -1874,6 +1885,8 @@ extern void drop_collected_mounts(struct vfsmount *);
|
||||||
extern int iterate_mounts(int (*)(struct vfsmount *, void *), void *,
|
extern int iterate_mounts(int (*)(struct vfsmount *, void *), void *,
|
||||||
struct vfsmount *);
|
struct vfsmount *);
|
||||||
extern int vfs_statfs(struct path *, struct kstatfs *);
|
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 statfs_by_dentry(struct dentry *, struct kstatfs *);
|
||||||
extern int freeze_super(struct super_block *super);
|
extern int freeze_super(struct super_block *super);
|
||||||
extern int thaw_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,
|
extern long do_sys_open(int dfd, const char __user *filename, int flags,
|
||||||
int mode);
|
int mode);
|
||||||
extern struct file *filp_open(const char *, int, int);
|
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,
|
extern struct file * dentry_open(struct dentry *, struct vfsmount *, int,
|
||||||
const struct cred *);
|
const struct cred *);
|
||||||
extern int filp_close(struct file *, fl_owner_t id);
|
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 struct file *create_write_pipe(int flags);
|
||||||
extern void free_write_pipe(struct file *);
|
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 int kernel_read(struct file *, loff_t, char *, unsigned long);
|
||||||
extern struct file * open_exec(const char *);
|
extern struct file * open_exec(const char *);
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,6 @@ struct nameidata {
|
||||||
struct path path;
|
struct path path;
|
||||||
struct qstr last;
|
struct qstr last;
|
||||||
struct path root;
|
struct path root;
|
||||||
struct file *file;
|
|
||||||
struct inode *inode; /* path.dentry.d_inode */
|
struct inode *inode; /* path.dentry.d_inode */
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
unsigned seq;
|
unsigned seq;
|
||||||
|
@ -63,6 +62,10 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND};
|
||||||
#define LOOKUP_EXCL 0x0400
|
#define LOOKUP_EXCL 0x0400
|
||||||
#define LOOKUP_RENAME_TARGET 0x0800
|
#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 *);
|
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)
|
#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 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 *,
|
extern int vfs_path_lookup(struct dentry *, struct vfsmount *,
|
||||||
const char *, unsigned int, struct nameidata *);
|
const char *, unsigned int, struct nameidata *);
|
||||||
|
|
||||||
|
|
|
@ -62,6 +62,7 @@ struct robust_list_head;
|
||||||
struct getcpu_cache;
|
struct getcpu_cache;
|
||||||
struct old_linux_dirent;
|
struct old_linux_dirent;
|
||||||
struct perf_event_attr;
|
struct perf_event_attr;
|
||||||
|
struct file_handle;
|
||||||
|
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/aio_abi.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 prot, unsigned long flags,
|
||||||
unsigned long fd, unsigned long pgoff);
|
unsigned long fd, unsigned long pgoff);
|
||||||
asmlinkage long sys_old_mmap(struct mmap_arg_struct __user *arg);
|
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
|
#endif
|
||||||
|
|
12
init/Kconfig
12
init/Kconfig
|
@ -287,6 +287,18 @@ config BSD_PROCESS_ACCT_V3
|
||||||
for processing it. A preliminary version of these tools is available
|
for processing it. A preliminary version of these tools is available
|
||||||
at <http://www.gnu.org/software/acct/>.
|
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
|
config TASKSTATS
|
||||||
bool "Export task/process statistics through netlink (EXPERIMENTAL)"
|
bool "Export task/process statistics through netlink (EXPERIMENTAL)"
|
||||||
depends on NET
|
depends on NET
|
||||||
|
|
|
@ -144,9 +144,9 @@ int audit_watch_compare(struct audit_watch *watch, unsigned long ino, dev_t dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize a parent watch entry. */
|
/* 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;
|
struct audit_parent *parent;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -353,53 +353,40 @@ static void audit_remove_parent_watches(struct audit_parent *parent)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get path information necessary for adding watches. */
|
/* 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;
|
int err;
|
||||||
|
|
||||||
ndparent = kmalloc(sizeof(*ndparent), GFP_KERNEL);
|
err = kern_path_parent(watch->path, &nd);
|
||||||
if (unlikely(!ndparent))
|
if (err)
|
||||||
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);
|
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
if (nd.last_type != LAST_NORM) {
|
||||||
|
path_put(&nd.path);
|
||||||
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = path_lookup(path, 0, ndwatch);
|
mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
|
||||||
if (err) {
|
d = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len);
|
||||||
kfree(ndwatch);
|
if (IS_ERR(d)) {
|
||||||
ndwatch = NULL;
|
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;
|
*parent = nd.path;
|
||||||
*ndw = ndwatch;
|
dput(d);
|
||||||
|
|
||||||
return 0;
|
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.
|
/* Associate the given rule with an existing parent.
|
||||||
* Caller must hold audit_filter_mutex. */
|
* Caller must hold audit_filter_mutex. */
|
||||||
static void audit_add_to_parent(struct audit_krule *krule,
|
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_watch *watch = krule->watch;
|
||||||
struct audit_parent *parent;
|
struct audit_parent *parent;
|
||||||
struct nameidata *ndp = NULL, *ndw = NULL;
|
struct path parent_path;
|
||||||
int h, ret = 0;
|
int h, ret = 0;
|
||||||
|
|
||||||
mutex_unlock(&audit_filter_mutex);
|
mutex_unlock(&audit_filter_mutex);
|
||||||
|
|
||||||
/* Avoid calling path_lookup under audit_filter_mutex. */
|
/* Avoid calling path_lookup under audit_filter_mutex. */
|
||||||
ret = audit_get_nd(watch->path, &ndp, &ndw);
|
ret = audit_get_nd(watch, &parent_path);
|
||||||
if (ret) {
|
|
||||||
/* caller expects mutex locked */
|
|
||||||
mutex_lock(&audit_filter_mutex);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/* caller expects mutex locked */
|
||||||
mutex_lock(&audit_filter_mutex);
|
mutex_lock(&audit_filter_mutex);
|
||||||
|
|
||||||
/* update watch filter fields */
|
if (ret)
|
||||||
if (ndw) {
|
return ret;
|
||||||
watch->dev = ndw->path.dentry->d_inode->i_sb->s_dev;
|
|
||||||
watch->ino = ndw->path.dentry->d_inode->i_ino;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* either find an old parent or attach a new one */
|
/* 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) {
|
if (!parent) {
|
||||||
parent = audit_init_parent(ndp);
|
parent = audit_init_parent(&parent_path);
|
||||||
if (IS_ERR(parent)) {
|
if (IS_ERR(parent)) {
|
||||||
ret = PTR_ERR(parent);
|
ret = PTR_ERR(parent);
|
||||||
goto error;
|
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);
|
h = audit_hash_ino((u32)watch->ino);
|
||||||
*list = &audit_inode_hash[h];
|
*list = &audit_inode_hash[h];
|
||||||
error:
|
error:
|
||||||
audit_put_nd(ndp, ndw); /* NULL args OK */
|
path_put(&parent_path);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void audit_remove_watch_rule(struct audit_krule *krule)
|
void audit_remove_watch_rule(struct audit_krule *krule)
|
||||||
|
|
|
@ -186,3 +186,8 @@ cond_syscall(sys_perf_event_open);
|
||||||
/* fanotify! */
|
/* fanotify! */
|
||||||
cond_syscall(sys_fanotify_init);
|
cond_syscall(sys_fanotify_init);
|
||||||
cond_syscall(sys_fanotify_mark);
|
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);
|
||||||
|
|
|
@ -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)
|
void __user *oldval, size_t oldlen, void __user *newval, size_t newlen)
|
||||||
{
|
{
|
||||||
const struct bin_table *table = NULL;
|
const struct bin_table *table = NULL;
|
||||||
struct nameidata nd;
|
|
||||||
struct vfsmount *mnt;
|
struct vfsmount *mnt;
|
||||||
struct file *file;
|
struct file *file;
|
||||||
ssize_t result;
|
ssize_t result;
|
||||||
char *pathname;
|
char *pathname;
|
||||||
int flags;
|
int flags;
|
||||||
int acc_mode;
|
|
||||||
|
|
||||||
pathname = sysctl_getname(name, nlen, &table);
|
pathname = sysctl_getname(name, nlen, &table);
|
||||||
result = PTR_ERR(pathname);
|
result = PTR_ERR(pathname);
|
||||||
|
@ -1337,28 +1335,17 @@ static ssize_t binary_sysctl(const int *name, int nlen,
|
||||||
/* How should the sysctl be accessed? */
|
/* How should the sysctl be accessed? */
|
||||||
if (oldval && oldlen && newval && newlen) {
|
if (oldval && oldlen && newval && newlen) {
|
||||||
flags = O_RDWR;
|
flags = O_RDWR;
|
||||||
acc_mode = MAY_READ | MAY_WRITE;
|
|
||||||
} else if (newval && newlen) {
|
} else if (newval && newlen) {
|
||||||
flags = O_WRONLY;
|
flags = O_WRONLY;
|
||||||
acc_mode = MAY_WRITE;
|
|
||||||
} else if (oldval && oldlen) {
|
} else if (oldval && oldlen) {
|
||||||
flags = O_RDONLY;
|
flags = O_RDONLY;
|
||||||
acc_mode = MAY_READ;
|
|
||||||
} else {
|
} else {
|
||||||
result = 0;
|
result = 0;
|
||||||
goto out_putname;
|
goto out_putname;
|
||||||
}
|
}
|
||||||
|
|
||||||
mnt = current->nsproxy->pid_ns->proc_mnt;
|
mnt = current->nsproxy->pid_ns->proc_mnt;
|
||||||
result = vfs_path_lookup(mnt->mnt_root, mnt, pathname, 0, &nd);
|
file = file_open_root(mnt->mnt_root, mnt, pathname, flags);
|
||||||
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());
|
|
||||||
result = PTR_ERR(file);
|
result = PTR_ERR(file);
|
||||||
if (IS_ERR(file))
|
if (IS_ERR(file))
|
||||||
goto out_putname;
|
goto out_putname;
|
||||||
|
@ -1370,10 +1357,6 @@ out_putname:
|
||||||
putname(pathname);
|
putname(pathname);
|
||||||
out:
|
out:
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
out_putpath:
|
|
||||||
path_put(&nd.path);
|
|
||||||
goto out_putname;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2144,8 +2144,10 @@ static int shmem_encode_fh(struct dentry *dentry, __u32 *fh, int *len,
|
||||||
{
|
{
|
||||||
struct inode *inode = dentry->d_inode;
|
struct inode *inode = dentry->d_inode;
|
||||||
|
|
||||||
if (*len < 3)
|
if (*len < 3) {
|
||||||
|
*len = 3;
|
||||||
return 255;
|
return 255;
|
||||||
|
}
|
||||||
|
|
||||||
if (inode_unhashed(inode)) {
|
if (inode_unhashed(inode)) {
|
||||||
/* Unfortunately insert_inode_hash is not idempotent,
|
/* Unfortunately insert_inode_hash is not idempotent,
|
||||||
|
|
|
@ -95,7 +95,7 @@ static int scm_fp_copy(struct cmsghdr *cmsg, struct scm_fp_list **fplp)
|
||||||
int fd = fdp[i];
|
int fd = fdp[i];
|
||||||
struct file *file;
|
struct file *file;
|
||||||
|
|
||||||
if (fd < 0 || !(file = fget(fd)))
|
if (fd < 0 || !(file = fget_raw(fd)))
|
||||||
return -EBADF;
|
return -EBADF;
|
||||||
*fpp++ = file;
|
*fpp++ = file;
|
||||||
fpl->count++;
|
fpl->count++;
|
||||||
|
|
|
@ -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
|
* Get the parent directory, calculate the hash for last
|
||||||
* component.
|
* component.
|
||||||
*/
|
*/
|
||||||
err = path_lookup(sunaddr->sun_path, LOOKUP_PARENT, &nd);
|
err = kern_path_parent(sunaddr->sun_path, &nd);
|
||||||
if (err)
|
if (err)
|
||||||
goto out_mknod_parent;
|
goto out_mknod_parent;
|
||||||
|
|
||||||
|
|
|
@ -104,7 +104,7 @@ struct sock *unix_get_socket(struct file *filp)
|
||||||
/*
|
/*
|
||||||
* Socket ?
|
* 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 socket *sock = SOCKET_I(inode);
|
||||||
struct sock *s = sock->sk;
|
struct sock *s = sock->sk;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue