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: [patch 2/3] vfs: dcache cleanups [patch 1/3] vfs: dcache sparse fixes [patch 3/3] vfs: make d_path() consistent across mount operations [patch 4/4] flock: remove unused fields from file_lock_operations [patch 3/4] vfs: fix ERR_PTR abuse in generic_readlink [patch 2/4] fs: make struct file arg to d_path const [patch 1/4] vfs: path_{get,put}() cleanups [patch for 2.6.26 4/4] vfs: utimensat(): fix write access check for futimens() [patch for 2.6.26 3/4] vfs: utimensat(): fix error checking for {UTIME_NOW,UTIME_OMIT} case [patch for 2.6.26 1/4] vfs: utimensat(): ignore tv_sec if tv_nsec == UTIME_OMIT or UTIME_NOW [patch for 2.6.26 2/4] vfs: utimensat(): be consistent with utime() for immutable and append-only files [PATCH] fix cgroup-inflicted breakage in block_dev.c
This commit is contained in:
@@ -931,8 +931,16 @@ static int do_open(struct block_device *bdev, struct file *file, int for_part)
|
|||||||
struct gendisk *disk;
|
struct gendisk *disk;
|
||||||
int ret;
|
int ret;
|
||||||
int part;
|
int part;
|
||||||
|
int perm = 0;
|
||||||
|
|
||||||
ret = devcgroup_inode_permission(bdev->bd_inode, file->f_mode);
|
if (file->f_mode & FMODE_READ)
|
||||||
|
perm |= MAY_READ;
|
||||||
|
if (file->f_mode & FMODE_WRITE)
|
||||||
|
perm |= MAY_WRITE;
|
||||||
|
/*
|
||||||
|
* hooks: /n/, see "layering violations".
|
||||||
|
*/
|
||||||
|
ret = devcgroup_inode_permission(bdev->bd_inode, perm);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
64
fs/dcache.c
64
fs/dcache.c
@@ -17,6 +17,7 @@
|
|||||||
#include <linux/syscalls.h>
|
#include <linux/syscalls.h>
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
|
#include <linux/fdtable.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <linux/fsnotify.h>
|
#include <linux/fsnotify.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
@@ -106,9 +107,10 @@ static void dentry_lru_remove(struct dentry *dentry)
|
|||||||
/*
|
/*
|
||||||
* Release the dentry's inode, using the filesystem
|
* Release the dentry's inode, using the filesystem
|
||||||
* d_iput() operation if defined.
|
* d_iput() operation if defined.
|
||||||
* Called with dcache_lock and per dentry lock held, drops both.
|
|
||||||
*/
|
*/
|
||||||
static void dentry_iput(struct dentry * dentry)
|
static void dentry_iput(struct dentry * dentry)
|
||||||
|
__releases(dentry->d_lock)
|
||||||
|
__releases(dcache_lock)
|
||||||
{
|
{
|
||||||
struct inode *inode = dentry->d_inode;
|
struct inode *inode = dentry->d_inode;
|
||||||
if (inode) {
|
if (inode) {
|
||||||
@@ -132,12 +134,13 @@ static void dentry_iput(struct dentry * dentry)
|
|||||||
* d_kill - kill dentry and return parent
|
* d_kill - kill dentry and return parent
|
||||||
* @dentry: dentry to kill
|
* @dentry: dentry to kill
|
||||||
*
|
*
|
||||||
* Called with dcache_lock and d_lock, releases both. The dentry must
|
* The dentry must already be unhashed and removed from the LRU.
|
||||||
* already be unhashed and removed from the LRU.
|
|
||||||
*
|
*
|
||||||
* If this is the root of the dentry tree, return NULL.
|
* If this is the root of the dentry tree, return NULL.
|
||||||
*/
|
*/
|
||||||
static struct dentry *d_kill(struct dentry *dentry)
|
static struct dentry *d_kill(struct dentry *dentry)
|
||||||
|
__releases(dentry->d_lock)
|
||||||
|
__releases(dcache_lock)
|
||||||
{
|
{
|
||||||
struct dentry *parent;
|
struct dentry *parent;
|
||||||
|
|
||||||
@@ -383,11 +386,11 @@ restart:
|
|||||||
* Try to prune ancestors as well. This is necessary to prevent
|
* Try to prune ancestors as well. This is necessary to prevent
|
||||||
* quadratic behavior of shrink_dcache_parent(), but is also expected
|
* quadratic behavior of shrink_dcache_parent(), but is also expected
|
||||||
* to be beneficial in reducing dentry cache fragmentation.
|
* to be beneficial in reducing dentry cache fragmentation.
|
||||||
*
|
|
||||||
* Called with dcache_lock, drops it and then regains.
|
|
||||||
* Called with dentry->d_lock held, drops it.
|
|
||||||
*/
|
*/
|
||||||
static void prune_one_dentry(struct dentry * dentry)
|
static void prune_one_dentry(struct dentry * dentry)
|
||||||
|
__releases(dentry->d_lock)
|
||||||
|
__releases(dcache_lock)
|
||||||
|
__acquires(dcache_lock)
|
||||||
{
|
{
|
||||||
__d_drop(dentry);
|
__d_drop(dentry);
|
||||||
dentry = d_kill(dentry);
|
dentry = d_kill(dentry);
|
||||||
@@ -1604,10 +1607,9 @@ static int d_isparent(struct dentry *p1, struct dentry *p2)
|
|||||||
*
|
*
|
||||||
* Note: If ever the locking in lock_rename() changes, then please
|
* Note: If ever the locking in lock_rename() changes, then please
|
||||||
* remember to update this too...
|
* remember to update this too...
|
||||||
*
|
|
||||||
* On return, dcache_lock will have been unlocked.
|
|
||||||
*/
|
*/
|
||||||
static struct dentry *__d_unalias(struct dentry *dentry, struct dentry *alias)
|
static struct dentry *__d_unalias(struct dentry *dentry, struct dentry *alias)
|
||||||
|
__releases(dcache_lock)
|
||||||
{
|
{
|
||||||
struct mutex *m1 = NULL, *m2 = NULL;
|
struct mutex *m1 = NULL, *m2 = NULL;
|
||||||
struct dentry *ret;
|
struct dentry *ret;
|
||||||
@@ -1743,11 +1745,9 @@ out_nolock:
|
|||||||
shouldnt_be_hashed:
|
shouldnt_be_hashed:
|
||||||
spin_unlock(&dcache_lock);
|
spin_unlock(&dcache_lock);
|
||||||
BUG();
|
BUG();
|
||||||
goto shouldnt_be_hashed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int prepend(char **buffer, int *buflen, const char *str,
|
static int prepend(char **buffer, int *buflen, const char *str, int namelen)
|
||||||
int namelen)
|
|
||||||
{
|
{
|
||||||
*buflen -= namelen;
|
*buflen -= namelen;
|
||||||
if (*buflen < 0)
|
if (*buflen < 0)
|
||||||
@@ -1757,8 +1757,13 @@ static int prepend(char **buffer, int *buflen, const char *str,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int prepend_name(char **buffer, int *buflen, struct qstr *name)
|
||||||
|
{
|
||||||
|
return prepend(buffer, buflen, name->name, name->len);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* d_path - return the path of a dentry
|
* __d_path - return the path of a dentry
|
||||||
* @path: the dentry/vfsmount to report
|
* @path: the dentry/vfsmount to report
|
||||||
* @root: root vfsmnt/dentry (may be modified by this function)
|
* @root: root vfsmnt/dentry (may be modified by this function)
|
||||||
* @buffer: buffer to return value in
|
* @buffer: buffer to return value in
|
||||||
@@ -1782,6 +1787,7 @@ char *__d_path(const struct path *path, struct path *root,
|
|||||||
char *end = buffer + buflen;
|
char *end = buffer + buflen;
|
||||||
char *retval;
|
char *retval;
|
||||||
|
|
||||||
|
spin_lock(&vfsmount_lock);
|
||||||
prepend(&end, &buflen, "\0", 1);
|
prepend(&end, &buflen, "\0", 1);
|
||||||
if (!IS_ROOT(dentry) && d_unhashed(dentry) &&
|
if (!IS_ROOT(dentry) && d_unhashed(dentry) &&
|
||||||
(prepend(&end, &buflen, " (deleted)", 10) != 0))
|
(prepend(&end, &buflen, " (deleted)", 10) != 0))
|
||||||
@@ -1800,38 +1806,37 @@ char *__d_path(const struct path *path, struct path *root,
|
|||||||
break;
|
break;
|
||||||
if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
|
if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) {
|
||||||
/* Global root? */
|
/* Global root? */
|
||||||
spin_lock(&vfsmount_lock);
|
|
||||||
if (vfsmnt->mnt_parent == vfsmnt) {
|
if (vfsmnt->mnt_parent == vfsmnt) {
|
||||||
spin_unlock(&vfsmount_lock);
|
|
||||||
goto global_root;
|
goto global_root;
|
||||||
}
|
}
|
||||||
dentry = vfsmnt->mnt_mountpoint;
|
dentry = vfsmnt->mnt_mountpoint;
|
||||||
vfsmnt = vfsmnt->mnt_parent;
|
vfsmnt = vfsmnt->mnt_parent;
|
||||||
spin_unlock(&vfsmount_lock);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
parent = dentry->d_parent;
|
parent = dentry->d_parent;
|
||||||
prefetch(parent);
|
prefetch(parent);
|
||||||
if ((prepend(&end, &buflen, dentry->d_name.name,
|
if ((prepend_name(&end, &buflen, &dentry->d_name) != 0) ||
|
||||||
dentry->d_name.len) != 0) ||
|
|
||||||
(prepend(&end, &buflen, "/", 1) != 0))
|
(prepend(&end, &buflen, "/", 1) != 0))
|
||||||
goto Elong;
|
goto Elong;
|
||||||
retval = end;
|
retval = end;
|
||||||
dentry = parent;
|
dentry = parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
spin_unlock(&vfsmount_lock);
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
global_root:
|
global_root:
|
||||||
retval += 1; /* hit the slash */
|
retval += 1; /* hit the slash */
|
||||||
if (prepend(&retval, &buflen, dentry->d_name.name,
|
if (prepend_name(&retval, &buflen, &dentry->d_name) != 0)
|
||||||
dentry->d_name.len) != 0)
|
|
||||||
goto Elong;
|
goto Elong;
|
||||||
root->mnt = vfsmnt;
|
root->mnt = vfsmnt;
|
||||||
root->dentry = dentry;
|
root->dentry = dentry;
|
||||||
return retval;
|
goto out;
|
||||||
|
|
||||||
Elong:
|
Elong:
|
||||||
return ERR_PTR(-ENAMETOOLONG);
|
retval = ERR_PTR(-ENAMETOOLONG);
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1845,9 +1850,9 @@ Elong:
|
|||||||
*
|
*
|
||||||
* Returns the buffer or an error code if the path was too long.
|
* Returns the buffer or an error code if the path was too long.
|
||||||
*
|
*
|
||||||
* "buflen" should be positive. Caller holds the dcache_lock.
|
* "buflen" should be positive.
|
||||||
*/
|
*/
|
||||||
char *d_path(struct path *path, char *buf, int buflen)
|
char *d_path(const struct path *path, char *buf, int buflen)
|
||||||
{
|
{
|
||||||
char *res;
|
char *res;
|
||||||
struct path root;
|
struct path root;
|
||||||
@@ -1915,16 +1920,11 @@ char *dentry_path(struct dentry *dentry, char *buf, int buflen)
|
|||||||
retval = end-1;
|
retval = end-1;
|
||||||
*retval = '/';
|
*retval = '/';
|
||||||
|
|
||||||
for (;;) {
|
while (!IS_ROOT(dentry)) {
|
||||||
struct dentry *parent;
|
struct dentry *parent = dentry->d_parent;
|
||||||
if (IS_ROOT(dentry))
|
|
||||||
break;
|
|
||||||
|
|
||||||
parent = dentry->d_parent;
|
|
||||||
prefetch(parent);
|
prefetch(parent);
|
||||||
|
if ((prepend_name(&end, &buflen, &dentry->d_name) != 0) ||
|
||||||
if ((prepend(&end, &buflen, dentry->d_name.name,
|
|
||||||
dentry->d_name.len) != 0) ||
|
|
||||||
(prepend(&end, &buflen, "/", 1) != 0))
|
(prepend(&end, &buflen, "/", 1) != 0))
|
||||||
goto Elong;
|
goto Elong;
|
||||||
|
|
||||||
@@ -1975,7 +1975,7 @@ asmlinkage long sys_getcwd(char __user *buf, unsigned long size)
|
|||||||
error = -ENOENT;
|
error = -ENOENT;
|
||||||
/* Has the current directory has been unlinked? */
|
/* Has the current directory has been unlinked? */
|
||||||
spin_lock(&dcache_lock);
|
spin_lock(&dcache_lock);
|
||||||
if (pwd.dentry->d_parent == pwd.dentry || !d_unhashed(pwd.dentry)) {
|
if (IS_ROOT(pwd.dentry) || !d_unhashed(pwd.dentry)) {
|
||||||
unsigned long len;
|
unsigned long len;
|
||||||
struct path tmp = root;
|
struct path tmp = root;
|
||||||
char * cwd;
|
char * cwd;
|
||||||
|
@@ -561,9 +561,6 @@ static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl)
|
|||||||
/* insert into file's list */
|
/* insert into file's list */
|
||||||
fl->fl_next = *pos;
|
fl->fl_next = *pos;
|
||||||
*pos = fl;
|
*pos = fl;
|
||||||
|
|
||||||
if (fl->fl_ops && fl->fl_ops->fl_insert)
|
|
||||||
fl->fl_ops->fl_insert(fl);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -586,9 +583,6 @@ static void locks_delete_lock(struct file_lock **thisfl_p)
|
|||||||
fl->fl_fasync = NULL;
|
fl->fl_fasync = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fl->fl_ops && fl->fl_ops->fl_remove)
|
|
||||||
fl->fl_ops->fl_remove(fl);
|
|
||||||
|
|
||||||
if (fl->fl_nspid) {
|
if (fl->fl_nspid) {
|
||||||
put_pid(fl->fl_nspid);
|
put_pid(fl->fl_nspid);
|
||||||
fl->fl_nspid = NULL;
|
fl->fl_nspid = NULL;
|
||||||
|
22
fs/namei.c
22
fs/namei.c
@@ -581,15 +581,13 @@ static __always_inline int link_path_walk(const char *name, struct nameidata *nd
|
|||||||
int result;
|
int result;
|
||||||
|
|
||||||
/* make sure the stuff we saved doesn't go away */
|
/* make sure the stuff we saved doesn't go away */
|
||||||
dget(save.dentry);
|
path_get(&save);
|
||||||
mntget(save.mnt);
|
|
||||||
|
|
||||||
result = __link_path_walk(name, nd);
|
result = __link_path_walk(name, nd);
|
||||||
if (result == -ESTALE) {
|
if (result == -ESTALE) {
|
||||||
/* nd->path had been dropped */
|
/* nd->path had been dropped */
|
||||||
nd->path = save;
|
nd->path = save;
|
||||||
dget(nd->path.dentry);
|
path_get(&nd->path);
|
||||||
mntget(nd->path.mnt);
|
|
||||||
nd->flags |= LOOKUP_REVAL;
|
nd->flags |= LOOKUP_REVAL;
|
||||||
result = __link_path_walk(name, nd);
|
result = __link_path_walk(name, nd);
|
||||||
}
|
}
|
||||||
@@ -1216,8 +1214,9 @@ int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt,
|
|||||||
nd->flags = flags;
|
nd->flags = flags;
|
||||||
nd->depth = 0;
|
nd->depth = 0;
|
||||||
|
|
||||||
nd->path.mnt = mntget(mnt);
|
nd->path.dentry = dentry;
|
||||||
nd->path.dentry = dget(dentry);
|
nd->path.mnt = mnt;
|
||||||
|
path_get(&nd->path);
|
||||||
|
|
||||||
retval = path_walk(name, nd);
|
retval = path_walk(name, nd);
|
||||||
if (unlikely(!retval && !audit_dummy_context() && nd->path.dentry &&
|
if (unlikely(!retval && !audit_dummy_context() && nd->path.dentry &&
|
||||||
@@ -2857,16 +2856,17 @@ int generic_readlink(struct dentry *dentry, char __user *buffer, int buflen)
|
|||||||
{
|
{
|
||||||
struct nameidata nd;
|
struct nameidata nd;
|
||||||
void *cookie;
|
void *cookie;
|
||||||
|
int res;
|
||||||
|
|
||||||
nd.depth = 0;
|
nd.depth = 0;
|
||||||
cookie = dentry->d_inode->i_op->follow_link(dentry, &nd);
|
cookie = dentry->d_inode->i_op->follow_link(dentry, &nd);
|
||||||
if (!IS_ERR(cookie)) {
|
if (IS_ERR(cookie))
|
||||||
int res = vfs_readlink(dentry, buffer, buflen, nd_get_link(&nd));
|
return PTR_ERR(cookie);
|
||||||
|
|
||||||
|
res = vfs_readlink(dentry, buffer, buflen, nd_get_link(&nd));
|
||||||
if (dentry->d_inode->i_op->put_link)
|
if (dentry->d_inode->i_op->put_link)
|
||||||
dentry->d_inode->i_op->put_link(dentry, &nd, cookie);
|
dentry->d_inode->i_op->put_link(dentry, &nd, cookie);
|
||||||
cookie = ERR_PTR(res);
|
return res;
|
||||||
}
|
|
||||||
return PTR_ERR(cookie);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int vfs_follow_link(struct nameidata *nd, const char *link)
|
int vfs_follow_link(struct nameidata *nd, const char *link)
|
||||||
|
10
fs/pipe.c
10
fs/pipe.c
@@ -1003,8 +1003,7 @@ struct file *create_write_pipe(void)
|
|||||||
void free_write_pipe(struct file *f)
|
void free_write_pipe(struct file *f)
|
||||||
{
|
{
|
||||||
free_pipe_info(f->f_dentry->d_inode);
|
free_pipe_info(f->f_dentry->d_inode);
|
||||||
dput(f->f_path.dentry);
|
path_put(&f->f_path);
|
||||||
mntput(f->f_path.mnt);
|
|
||||||
put_filp(f);
|
put_filp(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1015,8 +1014,8 @@ struct file *create_read_pipe(struct file *wrf)
|
|||||||
return ERR_PTR(-ENFILE);
|
return ERR_PTR(-ENFILE);
|
||||||
|
|
||||||
/* Grab pipe from the writer */
|
/* Grab pipe from the writer */
|
||||||
f->f_path.mnt = mntget(wrf->f_path.mnt);
|
f->f_path = wrf->f_path;
|
||||||
f->f_path.dentry = dget(wrf->f_path.dentry);
|
path_get(&wrf->f_path);
|
||||||
f->f_mapping = wrf->f_path.dentry->d_inode->i_mapping;
|
f->f_mapping = wrf->f_path.dentry->d_inode->i_mapping;
|
||||||
|
|
||||||
f->f_pos = 0;
|
f->f_pos = 0;
|
||||||
@@ -1068,8 +1067,7 @@ int do_pipe(int *fd)
|
|||||||
err_fdr:
|
err_fdr:
|
||||||
put_unused_fd(fdr);
|
put_unused_fd(fdr);
|
||||||
err_read_pipe:
|
err_read_pipe:
|
||||||
dput(fr->f_dentry);
|
path_put(&fr->f_path);
|
||||||
mntput(fr->f_vfsmnt);
|
|
||||||
put_filp(fr);
|
put_filp(fr);
|
||||||
err_write_pipe:
|
err_write_pipe:
|
||||||
free_write_pipe(fw);
|
free_write_pipe(fw);
|
||||||
|
49
fs/utimes.c
49
fs/utimes.c
@@ -40,14 +40,9 @@ asmlinkage long sys_utime(char __user *filename, struct utimbuf __user *times)
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static bool nsec_special(long nsec)
|
|
||||||
{
|
|
||||||
return nsec == UTIME_OMIT || nsec == UTIME_NOW;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool nsec_valid(long nsec)
|
static bool nsec_valid(long nsec)
|
||||||
{
|
{
|
||||||
if (nsec_special(nsec))
|
if (nsec == UTIME_OMIT || nsec == UTIME_NOW)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return nsec >= 0 && nsec <= 999999999;
|
return nsec >= 0 && nsec <= 999999999;
|
||||||
@@ -102,7 +97,11 @@ long do_utimes(int dfd, char __user *filename, struct timespec *times, int flags
|
|||||||
if (error)
|
if (error)
|
||||||
goto dput_and_out;
|
goto dput_and_out;
|
||||||
|
|
||||||
/* Don't worry, the checks are done in inode_change_ok() */
|
if (times && times[0].tv_nsec == UTIME_NOW &&
|
||||||
|
times[1].tv_nsec == UTIME_NOW)
|
||||||
|
times = NULL;
|
||||||
|
|
||||||
|
/* In most cases, the checks are done in inode_change_ok() */
|
||||||
newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
|
newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
|
||||||
if (times) {
|
if (times) {
|
||||||
error = -EPERM;
|
error = -EPERM;
|
||||||
@@ -124,30 +123,36 @@ long do_utimes(int dfd, char __user *filename, struct timespec *times, int flags
|
|||||||
newattrs.ia_mtime.tv_nsec = times[1].tv_nsec;
|
newattrs.ia_mtime.tv_nsec = times[1].tv_nsec;
|
||||||
newattrs.ia_valid |= ATTR_MTIME_SET;
|
newattrs.ia_valid |= ATTR_MTIME_SET;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If times is NULL or both times are either UTIME_OMIT or
|
* For the UTIME_OMIT/UTIME_NOW and UTIME_NOW/UTIME_OMIT
|
||||||
* UTIME_NOW, then need to check permissions, because
|
* cases, we need to make an extra check that is not done by
|
||||||
|
* inode_change_ok().
|
||||||
|
*/
|
||||||
|
if (((times[0].tv_nsec == UTIME_NOW &&
|
||||||
|
times[1].tv_nsec == UTIME_OMIT)
|
||||||
|
||
|
||||||
|
(times[0].tv_nsec == UTIME_OMIT &&
|
||||||
|
times[1].tv_nsec == UTIME_NOW))
|
||||||
|
&& !is_owner_or_cap(inode))
|
||||||
|
goto mnt_drop_write_and_out;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If times is NULL (or both times are UTIME_NOW),
|
||||||
|
* then we need to check permissions, because
|
||||||
* inode_change_ok() won't do it.
|
* inode_change_ok() won't do it.
|
||||||
*/
|
*/
|
||||||
if (!times || (nsec_special(times[0].tv_nsec) &&
|
|
||||||
nsec_special(times[1].tv_nsec))) {
|
|
||||||
error = -EACCES;
|
error = -EACCES;
|
||||||
if (IS_IMMUTABLE(inode))
|
if (IS_IMMUTABLE(inode))
|
||||||
goto mnt_drop_write_and_out;
|
goto mnt_drop_write_and_out;
|
||||||
|
|
||||||
if (!is_owner_or_cap(inode)) {
|
if (!is_owner_or_cap(inode)) {
|
||||||
if (f) {
|
error = permission(inode, MAY_WRITE, NULL);
|
||||||
if (!(f->f_mode & FMODE_WRITE))
|
|
||||||
goto mnt_drop_write_and_out;
|
|
||||||
} else {
|
|
||||||
error = vfs_permission(&nd, MAY_WRITE);
|
|
||||||
if (error)
|
if (error)
|
||||||
goto mnt_drop_write_and_out;
|
goto mnt_drop_write_and_out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
mutex_lock(&inode->i_mutex);
|
mutex_lock(&inode->i_mutex);
|
||||||
error = notify_change(dentry, &newattrs);
|
error = notify_change(dentry, &newattrs);
|
||||||
mutex_unlock(&inode->i_mutex);
|
mutex_unlock(&inode->i_mutex);
|
||||||
@@ -169,14 +174,6 @@ asmlinkage long sys_utimensat(int dfd, char __user *filename, struct timespec __
|
|||||||
if (utimes) {
|
if (utimes) {
|
||||||
if (copy_from_user(&tstimes, utimes, sizeof(tstimes)))
|
if (copy_from_user(&tstimes, utimes, sizeof(tstimes)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
if ((tstimes[0].tv_nsec == UTIME_OMIT ||
|
|
||||||
tstimes[0].tv_nsec == UTIME_NOW) &&
|
|
||||||
tstimes[0].tv_sec != 0)
|
|
||||||
return -EINVAL;
|
|
||||||
if ((tstimes[1].tv_nsec == UTIME_OMIT ||
|
|
||||||
tstimes[1].tv_nsec == UTIME_NOW) &&
|
|
||||||
tstimes[1].tv_sec != 0)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/* Nothing to do, we must not even check the path. */
|
/* Nothing to do, we must not even check the path. */
|
||||||
if (tstimes[0].tv_nsec == UTIME_OMIT &&
|
if (tstimes[0].tv_nsec == UTIME_OMIT &&
|
||||||
|
@@ -300,7 +300,7 @@ extern int d_validate(struct dentry *, struct dentry *);
|
|||||||
extern char *dynamic_dname(struct dentry *, char *, int, const char *, ...);
|
extern char *dynamic_dname(struct dentry *, char *, int, const char *, ...);
|
||||||
|
|
||||||
extern char *__d_path(const struct path *path, struct path *root, char *, int);
|
extern char *__d_path(const struct path *path, struct path *root, char *, int);
|
||||||
extern char *d_path(struct path *, char *, int);
|
extern char *d_path(const struct path *, char *, int);
|
||||||
extern char *dentry_path(struct dentry *, char *, int);
|
extern char *dentry_path(struct dentry *, char *, int);
|
||||||
|
|
||||||
/* Allocation counts.. */
|
/* Allocation counts.. */
|
||||||
|
@@ -894,8 +894,6 @@ static inline int file_check_writeable(struct file *filp)
|
|||||||
typedef struct files_struct *fl_owner_t;
|
typedef struct files_struct *fl_owner_t;
|
||||||
|
|
||||||
struct file_lock_operations {
|
struct file_lock_operations {
|
||||||
void (*fl_insert)(struct file_lock *); /* lock insertion callback */
|
|
||||||
void (*fl_remove)(struct file_lock *); /* lock removal callback */
|
|
||||||
void (*fl_copy_lock)(struct file_lock *, struct file_lock *);
|
void (*fl_copy_lock)(struct file_lock *, struct file_lock *);
|
||||||
void (*fl_release_private)(struct file_lock *);
|
void (*fl_release_private)(struct file_lock *);
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user