#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/utime.h>
#include <linux/file.h>
#include <linux/smp_lock.h>
#include <linux/quotaops.h>
#include <linux/pagemap.h>
#include <linux/syscalls.h>
#include <linux/rcupdate.h>
+#include <linux/audit.h>
+#include <linux/vs_base.h>
#include <linux/vs_limit.h>
#include <linux/vs_dlimit.h>
-#include <linux/vserver/xid.h>
+#include <linux/vs_tag.h>
+#include <linux/vs_cowbl.h>
-#include <asm/unistd.h>
-
-int vfs_statfs(struct super_block *sb, struct kstatfs *buf)
+int vfs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
int retval = -ENODEV;
- if (sb) {
+ if (dentry) {
+ struct super_block *sb = dentry->d_sb;
+
retval = -ENOSYS;
if (sb->s_op->statfs) {
memset(buf, 0, sizeof(*buf));
- retval = security_sb_statfs(sb);
+ retval = security_sb_statfs(dentry);
if (retval)
return retval;
- retval = sb->s_op->statfs(sb, buf);
+ retval = sb->s_op->statfs(dentry, buf);
if (retval == 0 && buf->f_frsize == 0)
buf->f_frsize = buf->f_bsize;
}
- if (!vx_check(0, VX_ADMIN|VX_WATCH))
+ if (!vx_check(0, VS_ADMIN|VS_WATCH))
vx_vsi_statfs(sb, buf);
}
return retval;
EXPORT_SYMBOL(vfs_statfs);
-static int vfs_statfs_native(struct super_block *sb, struct statfs *buf)
+static int vfs_statfs_native(struct dentry *dentry, struct statfs *buf)
{
struct kstatfs st;
int retval;
- retval = vfs_statfs(sb, &st);
+ retval = vfs_statfs(dentry, &st);
if (retval)
return retval;
return 0;
}
-static int vfs_statfs64(struct super_block *sb, struct statfs64 *buf)
+static int vfs_statfs64(struct dentry *dentry, struct statfs64 *buf)
{
struct kstatfs st;
int retval;
- retval = vfs_statfs(sb, &st);
+ retval = vfs_statfs(dentry, &st);
if (retval)
return retval;
error = user_path_walk(path, &nd);
if (!error) {
struct statfs tmp;
- error = vfs_statfs_native(nd.dentry->d_inode->i_sb, &tmp);
+ error = vfs_statfs_native(nd.dentry, &tmp);
if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
error = -EFAULT;
path_release(&nd);
error = user_path_walk(path, &nd);
if (!error) {
struct statfs64 tmp;
- error = vfs_statfs64(nd.dentry->d_inode->i_sb, &tmp);
+ error = vfs_statfs64(nd.dentry, &tmp);
if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
error = -EFAULT;
path_release(&nd);
file = fget(fd);
if (!file)
goto out;
- error = vfs_statfs_native(file->f_dentry->d_inode->i_sb, &tmp);
+ error = vfs_statfs_native(file->f_path.dentry, &tmp);
if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
error = -EFAULT;
fput(file);
file = fget(fd);
if (!file)
goto out;
- error = vfs_statfs64(file->f_dentry->d_inode->i_sb, &tmp);
+ error = vfs_statfs64(file->f_path.dentry, &tmp);
if (!error && copy_to_user(buf, &tmp, sizeof(tmp)))
error = -EFAULT;
fput(file);
if (file->f_flags & O_LARGEFILE)
small = 0;
- dentry = file->f_dentry;
+ dentry = file->f_path.dentry;
inode = dentry->d_inode;
error = -EINVAL;
if (!S_ISREG(inode->i_mode) || !(file->f_mode & FMODE_WRITE))
error = locks_verify_truncate(inode, file, length);
if (!error)
- error = do_truncate(dentry, length, 0, file);
+ error = do_truncate(dentry, length, ATTR_MTIME|ATTR_CTIME, file);
out_putf:
fput(file);
out:
}
#endif
-#ifdef __ARCH_WANT_SYS_UTIME
-
-/*
- * sys_utime() can be implemented in user-level using sys_utimes().
- * Is this for backwards compatibility? If so, why not move it
- * into the appropriate arch directory (for those architectures that
- * need it).
- */
-
-/* If times==NULL, set access and modification to current time,
- * must be owner or have write permission.
- * Else, update from *times, must be owner or super user.
- */
-asmlinkage long sys_utime(char __user * filename, struct utimbuf __user * times)
-{
- int error;
- struct nameidata nd;
- struct inode * inode;
- struct iattr newattrs;
-
- error = user_path_walk(filename, &nd);
- if (error)
- goto out;
- inode = nd.dentry->d_inode;
-
- error = -EROFS;
- if (IS_RDONLY(inode) || MNT_IS_RDONLY(nd.mnt))
- goto dput_and_out;
-
- /* Don't worry, the checks are done in inode_change_ok() */
- newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
- if (times) {
- error = -EPERM;
- if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
- goto dput_and_out;
-
- error = get_user(newattrs.ia_atime.tv_sec, ×->actime);
- newattrs.ia_atime.tv_nsec = 0;
- if (!error)
- error = get_user(newattrs.ia_mtime.tv_sec, ×->modtime);
- newattrs.ia_mtime.tv_nsec = 0;
- if (error)
- goto dput_and_out;
-
- newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
- } else {
- error = -EACCES;
- if (IS_IMMUTABLE(inode))
- goto dput_and_out;
-
- if (current->fsuid != inode->i_uid &&
- (error = vfs_permission(&nd, MAY_WRITE)) != 0)
- goto dput_and_out;
- }
- mutex_lock(&inode->i_mutex);
- error = notify_change(nd.dentry, &newattrs);
- mutex_unlock(&inode->i_mutex);
-dput_and_out:
- path_release(&nd);
-out:
- return error;
-}
-
-#endif
-
-/* If times==NULL, set access and modification to current time,
- * must be owner or have write permission.
- * Else, update from *times, must be owner or super user.
- */
-long do_utimes(int dfd, char __user *filename, struct timeval *times)
-{
- int error;
- struct nameidata nd;
- struct inode * inode;
- struct iattr newattrs;
-
- error = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW, &nd);
-
- if (error)
- goto out;
- inode = nd.dentry->d_inode;
-
- error = -EROFS;
- if (IS_RDONLY(inode) || MNT_IS_RDONLY(nd.mnt))
- goto dput_and_out;
-
- /* Don't worry, the checks are done in inode_change_ok() */
- newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
- if (times) {
- error = -EPERM;
- if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
- goto dput_and_out;
-
- newattrs.ia_atime.tv_sec = times[0].tv_sec;
- newattrs.ia_atime.tv_nsec = times[0].tv_usec * 1000;
- newattrs.ia_mtime.tv_sec = times[1].tv_sec;
- newattrs.ia_mtime.tv_nsec = times[1].tv_usec * 1000;
- newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
- } else {
- error = -EACCES;
- if (IS_IMMUTABLE(inode))
- goto dput_and_out;
-
- if (current->fsuid != inode->i_uid &&
- (error = vfs_permission(&nd, MAY_WRITE)) != 0)
- goto dput_and_out;
- }
- mutex_lock(&inode->i_mutex);
- error = notify_change(nd.dentry, &newattrs);
- mutex_unlock(&inode->i_mutex);
-dput_and_out:
- path_release(&nd);
-out:
- return error;
-}
-
-asmlinkage long sys_futimesat(int dfd, char __user *filename, struct timeval __user *utimes)
-{
- struct timeval times[2];
-
- if (utimes && copy_from_user(×, utimes, sizeof(times)))
- return -EFAULT;
- return do_utimes(dfd, filename, utimes ? times : NULL);
-}
-
-asmlinkage long sys_utimes(char __user *filename, struct timeval __user *utimes)
-{
- return sys_futimesat(AT_FDCWD, filename, utimes);
-}
-
-
/*
* access() needs to use the real uid/gid, not the effective uid/gid.
* We do this by temporarily clearing all FS-related capabilities and
current->cap_effective = current->cap_permitted;
res = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW|LOOKUP_ACCESS, &nd);
- if (!res) {
- res = vfs_permission(&nd, mode);
- /* SuS v2 requires we report a read only fs too */
- if(!res && (mode & S_IWOTH)
- && (IS_RDONLY(nd.dentry->d_inode) || MNT_IS_RDONLY(nd.mnt))
- && !special_file(nd.dentry->d_inode->i_mode))
- res = -EROFS;
- path_release(&nd);
- }
+ if (res)
+ goto out;
+
+ res = vfs_permission(&nd, mode);
+ /* SuS v2 requires we report a read only fs too */
+ if(res || !(mode & S_IWOTH) ||
+ special_file(nd.dentry->d_inode->i_mode))
+ goto out_path_release;
+
+ if(IS_RDONLY(nd.dentry->d_inode) || MNT_IS_RDONLY(nd.mnt))
+ res = -EROFS;
+out_path_release:
+ path_release(&nd);
+out:
current->fsuid = old_fsuid;
current->fsgid = old_fsgid;
current->cap_effective = old_cap;
struct nameidata nd;
int error;
- error = __user_walk(filename, LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &nd);
+ error = __user_walk(filename,
+ LOOKUP_FOLLOW|LOOKUP_DIRECTORY|LOOKUP_CHDIR, &nd);
if (error)
goto out;
if (!file)
goto out;
- dentry = file->f_dentry;
- mnt = file->f_vfsmnt;
+ dentry = file->f_path.dentry;
+ mnt = file->f_path.mnt;
inode = dentry->d_inode;
error = -ENOTDIR;
if (!file)
goto out;
- dentry = file->f_dentry;
+ dentry = file->f_path.dentry;
inode = dentry->d_inode;
+ audit_inode(NULL, inode);
+
err = -EROFS;
if (IS_RDONLY(inode) || MNT_IS_RDONLY(file->f_vfsmnt))
goto out_putf;
error = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW, &nd);
if (error)
goto out;
- inode = nd.dentry->d_inode;
- error = -EROFS;
- if (IS_RDONLY(inode) || MNT_IS_RDONLY(nd.mnt))
+ error = cow_check_and_break(&nd);
+ if (error)
goto dput_and_out;
+ inode = nd.dentry->d_inode;
error = -EPERM;
if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
newattrs.ia_valid = ATTR_CTIME;
if (user != (uid_t) -1) {
newattrs.ia_valid |= ATTR_UID;
- newattrs.ia_uid = vx_map_uid(user);
+ newattrs.ia_uid = dx_map_uid(user);
}
if (group != (gid_t) -1) {
newattrs.ia_valid |= ATTR_GID;
- newattrs.ia_gid = vx_map_gid(group);
+ newattrs.ia_gid = dx_map_gid(group);
}
if (!S_ISDIR(inode->i_mode))
newattrs.ia_valid |= ATTR_KILL_SUID|ATTR_KILL_SGID;
int error;
error = user_path_walk(filename, &nd);
- if (!error) {
+ if (error)
+ goto out;
+#ifdef CONFIG_VSERVER_COWBL
+ error = cow_check_and_break(&nd);
+ if (!error)
+#endif
error = chown_common(nd.dentry, nd.mnt, user, group);
- path_release(&nd);
- }
+ path_release(&nd);
+out:
return error;
}
follow = (flag & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW;
error = __user_walk_fd(dfd, filename, follow, &nd);
- if (!error) {
+ if (error)
+ goto out;
+#ifdef CONFIG_VSERVER_COWBL
+ error = cow_check_and_break(&nd);
+ if (!error)
+#endif
error = chown_common(nd.dentry, nd.mnt, user, group);
- path_release(&nd);
- }
+ path_release(&nd);
out:
return error;
}
int error;
error = user_path_walk_link(filename, &nd);
- if (!error) {
+ if (error)
+ goto out;
+#ifdef CONFIG_VSERVER_COWBL
+ error = cow_check_and_break(&nd);
+ if (!error)
+#endif
error = chown_common(nd.dentry, nd.mnt, user, group);
- path_release(&nd);
- }
+ path_release(&nd);
+out:
return error;
}
{
struct file * file;
int error = -EBADF;
+ struct dentry * dentry;
file = fget(fd);
- if (file) {
- error = chown_common(file->f_dentry, file->f_vfsmnt, user, group);
- fput(file);
- }
+ if (!file)
+ goto out;
+
+ dentry = file->f_path.dentry;
+ audit_inode(NULL, dentry->d_inode);
+ error = chown_common(dentry, file->f_vfsmnt, user, group);
+ fput(file);
+out:
return error;
}
}
f->f_mapping = inode->i_mapping;
- f->f_dentry = dentry;
- f->f_vfsmnt = mnt;
+ f->f_path.dentry = dentry;
+ f->f_path.mnt = mnt;
f->f_pos = 0;
f->f_op = fops_get(inode->i_fop);
file_move(f, &inode->i_sb->s_files);
if (f->f_mode & FMODE_WRITE)
put_write_access(inode);
file_kill(f);
- f->f_dentry = NULL;
- f->f_vfsmnt = NULL;
+ f->f_path.dentry = NULL;
+ f->f_path.mnt = NULL;
cleanup_file:
put_filp(f);
dput(dentry);
* a fully instantiated struct file to the caller.
* This function is meant to be called from within a filesystem's
* lookup method.
+ * Beware of calling it for non-regular files! Those ->open methods might block
+ * (e.g. in fifo_open), leaving you with parent locked (and in case of fifo,
+ * leading to a deadlock, as nobody can open that fifo anymore, because
+ * another process to open fifo will block on locked parent when doing lookup).
* Note that in case of error, nd->intent.open.file is destroyed, but the
* path information remains valid.
* If the open callback is set to NULL, then the standard f_op->open()
/* Pick up the filp from the open intent */
filp = nd->intent.open.file;
/* Has the filesystem initialised the file for us? */
- if (filp->f_dentry == NULL)
+ if (filp->f_path.dentry == NULL)
filp = __dentry_open(nd->dentry, nd->mnt, flags, filp, NULL);
else
path_release(nd);
repeat:
fdt = files_fdtable(files);
- fd = find_next_zero_bit(fdt->open_fds->fds_bits,
- fdt->max_fdset,
- fdt->next_fd);
+ fd = find_next_zero_bit(fdt->open_fds->fds_bits, fdt->max_fds,
+ files->next_fd);
/*
* N.B. For clone tasks sharing a files structure, this test
FD_SET(fd, fdt->open_fds);
FD_CLR(fd, fdt->close_on_exec);
- fdt->next_fd = fd + 1;
+ files->next_fd = fd + 1;
vx_openfd_inc(fd);
#if 1
/* Sanity check */
{
struct fdtable *fdt = files_fdtable(files);
__FD_CLR(fd, fdt->open_fds);
- if (fd < fdt->next_fd)
- fdt->next_fd = fd;
+ if (fd < files->next_fd)
+ files->next_fd = fd;
vx_openfd_dec(fd);
}
put_unused_fd(fd);
fd = PTR_ERR(f);
} else {
- fsnotify_open(f->f_dentry);
+ fsnotify_open(f->f_path.dentry);
fd_install(fd, f);
}
}
prevent_tail_call(ret);
return ret;
}
-EXPORT_SYMBOL_GPL(sys_open);
asmlinkage long sys_openat(int dfd, const char __user *filename, int flags,
int mode)
prevent_tail_call(ret);
return ret;
}
-EXPORT_SYMBOL_GPL(sys_openat);
#ifndef __alpha__
}
if (filp->f_op && filp->f_op->flush)
- retval = filp->f_op->flush(filp);
+ retval = filp->f_op->flush(filp, id);
dnotify_flush(filp, id);
locks_remove_posix(filp, id);
struct file * filp;
struct files_struct *files = current->files;
struct fdtable *fdt;
+ int retval;
spin_lock(&files->file_lock);
fdt = files_fdtable(files);
FD_CLR(fd, fdt->close_on_exec);
__put_unused_fd(files, fd);
spin_unlock(&files->file_lock);
- return filp_close(filp, files);
+ retval = filp_close(filp, files);
+
+ /* can't restart close syscall because file table entry was cleared */
+ if (unlikely(retval == -ERESTARTSYS ||
+ retval == -ERESTARTNOINTR ||
+ retval == -ERESTARTNOHAND ||
+ retval == -ERESTART_RESTARTBLOCK))
+ retval = -EINTR;
+
+ return retval;
out_unlock:
spin_unlock(&files->file_lock);
asmlinkage long sys_vhangup(void)
{
if (capable(CAP_SYS_TTY_CONFIG)) {
+ /* XXX: this needs locking */
tty_vhangup(current->signal->tty);
return 0;
}