Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
This commit is contained in:
21
fs/9p/v9fs.c
21
fs/9p/v9fs.c
@@ -76,7 +76,7 @@ static const match_table_t tokens = {
|
||||
* Return 0 upon success, -ERRNO upon failure.
|
||||
*/
|
||||
|
||||
static int v9fs_parse_options(struct v9fs_session_info *v9ses)
|
||||
static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts)
|
||||
{
|
||||
char *options;
|
||||
substring_t args[MAX_OPT_ARGS];
|
||||
@@ -90,10 +90,10 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses)
|
||||
v9ses->debug = 0;
|
||||
v9ses->cache = 0;
|
||||
|
||||
if (!v9ses->options)
|
||||
if (!opts)
|
||||
return 0;
|
||||
|
||||
options = kstrdup(v9ses->options, GFP_KERNEL);
|
||||
options = kstrdup(opts, GFP_KERNEL);
|
||||
if (!options) {
|
||||
P9_DPRINTK(P9_DEBUG_ERROR,
|
||||
"failed to allocate copy of option string\n");
|
||||
@@ -206,24 +206,14 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
|
||||
v9ses->uid = ~0;
|
||||
v9ses->dfltuid = V9FS_DEFUID;
|
||||
v9ses->dfltgid = V9FS_DEFGID;
|
||||
if (data) {
|
||||
v9ses->options = kstrdup(data, GFP_KERNEL);
|
||||
if (!v9ses->options) {
|
||||
P9_DPRINTK(P9_DEBUG_ERROR,
|
||||
"failed to allocate copy of option string\n");
|
||||
retval = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
rc = v9fs_parse_options(v9ses);
|
||||
rc = v9fs_parse_options(v9ses, data);
|
||||
if (rc < 0) {
|
||||
retval = rc;
|
||||
goto error;
|
||||
}
|
||||
|
||||
v9ses->clnt = p9_client_create(dev_name, v9ses->options);
|
||||
|
||||
v9ses->clnt = p9_client_create(dev_name, data);
|
||||
if (IS_ERR(v9ses->clnt)) {
|
||||
retval = PTR_ERR(v9ses->clnt);
|
||||
v9ses->clnt = NULL;
|
||||
@@ -280,7 +270,6 @@ void v9fs_session_close(struct v9fs_session_info *v9ses)
|
||||
|
||||
__putname(v9ses->uname);
|
||||
__putname(v9ses->aname);
|
||||
kfree(v9ses->options);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -85,7 +85,6 @@ struct v9fs_session_info {
|
||||
unsigned int afid;
|
||||
unsigned int cache;
|
||||
|
||||
char *options; /* copy of mount options */
|
||||
char *uname; /* user name to mount as */
|
||||
char *aname; /* name of remote hierarchy being mounted */
|
||||
unsigned int maxdata; /* max data for client interface */
|
||||
|
@@ -171,7 +171,6 @@ int v9fs_uflags2omode(int uflags, int extended)
|
||||
|
||||
/**
|
||||
* v9fs_blank_wstat - helper function to setup a 9P stat structure
|
||||
* @v9ses: 9P session info (for determining extended mode)
|
||||
* @wstat: structure to initialize
|
||||
*
|
||||
*/
|
||||
@@ -207,65 +206,72 @@ v9fs_blank_wstat(struct p9_wstat *wstat)
|
||||
|
||||
struct inode *v9fs_get_inode(struct super_block *sb, int mode)
|
||||
{
|
||||
int err;
|
||||
struct inode *inode;
|
||||
struct v9fs_session_info *v9ses = sb->s_fs_info;
|
||||
|
||||
P9_DPRINTK(P9_DEBUG_VFS, "super block: %p mode: %o\n", sb, mode);
|
||||
|
||||
inode = new_inode(sb);
|
||||
if (inode) {
|
||||
inode->i_mode = mode;
|
||||
inode->i_uid = current_fsuid();
|
||||
inode->i_gid = current_fsgid();
|
||||
inode->i_blocks = 0;
|
||||
inode->i_rdev = 0;
|
||||
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
|
||||
inode->i_mapping->a_ops = &v9fs_addr_operations;
|
||||
|
||||
switch (mode & S_IFMT) {
|
||||
case S_IFIFO:
|
||||
case S_IFBLK:
|
||||
case S_IFCHR:
|
||||
case S_IFSOCK:
|
||||
if (!v9fs_extended(v9ses)) {
|
||||
P9_DPRINTK(P9_DEBUG_ERROR,
|
||||
"special files without extended mode\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
init_special_inode(inode, inode->i_mode,
|
||||
inode->i_rdev);
|
||||
break;
|
||||
case S_IFREG:
|
||||
inode->i_op = &v9fs_file_inode_operations;
|
||||
inode->i_fop = &v9fs_file_operations;
|
||||
break;
|
||||
case S_IFLNK:
|
||||
if (!v9fs_extended(v9ses)) {
|
||||
P9_DPRINTK(P9_DEBUG_ERROR,
|
||||
"extended modes used w/o 9P2000.u\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
inode->i_op = &v9fs_symlink_inode_operations;
|
||||
break;
|
||||
case S_IFDIR:
|
||||
inc_nlink(inode);
|
||||
if (v9fs_extended(v9ses))
|
||||
inode->i_op = &v9fs_dir_inode_operations_ext;
|
||||
else
|
||||
inode->i_op = &v9fs_dir_inode_operations;
|
||||
inode->i_fop = &v9fs_dir_operations;
|
||||
break;
|
||||
default:
|
||||
P9_DPRINTK(P9_DEBUG_ERROR,
|
||||
"BAD mode 0x%x S_IFMT 0x%x\n",
|
||||
mode, mode & S_IFMT);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
} else {
|
||||
if (!inode) {
|
||||
P9_EPRINTK(KERN_WARNING, "Problem allocating inode\n");
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
inode->i_mode = mode;
|
||||
inode->i_uid = current_fsuid();
|
||||
inode->i_gid = current_fsgid();
|
||||
inode->i_blocks = 0;
|
||||
inode->i_rdev = 0;
|
||||
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
|
||||
inode->i_mapping->a_ops = &v9fs_addr_operations;
|
||||
|
||||
switch (mode & S_IFMT) {
|
||||
case S_IFIFO:
|
||||
case S_IFBLK:
|
||||
case S_IFCHR:
|
||||
case S_IFSOCK:
|
||||
if (!v9fs_extended(v9ses)) {
|
||||
P9_DPRINTK(P9_DEBUG_ERROR,
|
||||
"special files without extended mode\n");
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
init_special_inode(inode, inode->i_mode, inode->i_rdev);
|
||||
break;
|
||||
case S_IFREG:
|
||||
inode->i_op = &v9fs_file_inode_operations;
|
||||
inode->i_fop = &v9fs_file_operations;
|
||||
break;
|
||||
case S_IFLNK:
|
||||
if (!v9fs_extended(v9ses)) {
|
||||
P9_DPRINTK(P9_DEBUG_ERROR,
|
||||
"extended modes used w/o 9P2000.u\n");
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
inode->i_op = &v9fs_symlink_inode_operations;
|
||||
break;
|
||||
case S_IFDIR:
|
||||
inc_nlink(inode);
|
||||
if (v9fs_extended(v9ses))
|
||||
inode->i_op = &v9fs_dir_inode_operations_ext;
|
||||
else
|
||||
inode->i_op = &v9fs_dir_inode_operations;
|
||||
inode->i_fop = &v9fs_dir_operations;
|
||||
break;
|
||||
default:
|
||||
P9_DPRINTK(P9_DEBUG_ERROR, "BAD mode 0x%x S_IFMT 0x%x\n",
|
||||
mode, mode & S_IFMT);
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
return inode;
|
||||
|
||||
error:
|
||||
iput(inode);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -338,30 +344,25 @@ v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid,
|
||||
|
||||
ret = NULL;
|
||||
st = p9_client_stat(fid);
|
||||
if (IS_ERR(st)) {
|
||||
err = PTR_ERR(st);
|
||||
st = NULL;
|
||||
goto error;
|
||||
}
|
||||
if (IS_ERR(st))
|
||||
return ERR_CAST(st);
|
||||
|
||||
umode = p9mode2unixmode(v9ses, st->mode);
|
||||
ret = v9fs_get_inode(sb, umode);
|
||||
if (IS_ERR(ret)) {
|
||||
err = PTR_ERR(ret);
|
||||
ret = NULL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
v9fs_stat2inode(st, ret, sb);
|
||||
ret->i_ino = v9fs_qid2ino(&st->qid);
|
||||
p9stat_free(st);
|
||||
kfree(st);
|
||||
return ret;
|
||||
|
||||
error:
|
||||
p9stat_free(st);
|
||||
kfree(st);
|
||||
if (ret)
|
||||
iput(ret);
|
||||
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
@@ -403,9 +404,9 @@ v9fs_open_created(struct inode *inode, struct file *file)
|
||||
* @v9ses: session information
|
||||
* @dir: directory that dentry is being created in
|
||||
* @dentry: dentry that is being created
|
||||
* @extension: 9p2000.u extension string to support devices, etc.
|
||||
* @perm: create permissions
|
||||
* @mode: open mode
|
||||
* @extension: 9p2000.u extension string to support devices, etc.
|
||||
*
|
||||
*/
|
||||
static struct p9_fid *
|
||||
@@ -470,7 +471,10 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
|
||||
dentry->d_op = &v9fs_dentry_operations;
|
||||
|
||||
d_instantiate(dentry, inode);
|
||||
v9fs_fid_add(dentry, fid);
|
||||
err = v9fs_fid_add(dentry, fid);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
return ofid;
|
||||
|
||||
error:
|
||||
|
@@ -81,7 +81,7 @@ static int v9fs_set_super(struct super_block *s, void *data)
|
||||
|
||||
static void
|
||||
v9fs_fill_super(struct super_block *sb, struct v9fs_session_info *v9ses,
|
||||
int flags)
|
||||
int flags, void *data)
|
||||
{
|
||||
sb->s_maxbytes = MAX_LFS_FILESIZE;
|
||||
sb->s_blocksize_bits = fls(v9ses->maxdata - 1);
|
||||
@@ -91,6 +91,8 @@ v9fs_fill_super(struct super_block *sb, struct v9fs_session_info *v9ses,
|
||||
|
||||
sb->s_flags = flags | MS_ACTIVE | MS_SYNCHRONOUS | MS_DIRSYNC |
|
||||
MS_NOATIME;
|
||||
|
||||
save_mount_options(sb, data);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -113,14 +115,11 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags,
|
||||
struct v9fs_session_info *v9ses = NULL;
|
||||
struct p9_wstat *st = NULL;
|
||||
int mode = S_IRWXUGO | S_ISVTX;
|
||||
uid_t uid = current_fsuid();
|
||||
gid_t gid = current_fsgid();
|
||||
struct p9_fid *fid;
|
||||
int retval = 0;
|
||||
|
||||
P9_DPRINTK(P9_DEBUG_VFS, " \n");
|
||||
|
||||
st = NULL;
|
||||
v9ses = kzalloc(sizeof(struct v9fs_session_info), GFP_KERNEL);
|
||||
if (!v9ses)
|
||||
return -ENOMEM;
|
||||
@@ -142,7 +141,7 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags,
|
||||
retval = PTR_ERR(sb);
|
||||
goto free_stat;
|
||||
}
|
||||
v9fs_fill_super(sb, v9ses, flags);
|
||||
v9fs_fill_super(sb, v9ses, flags, data);
|
||||
|
||||
inode = v9fs_get_inode(sb, S_IFDIR | mode);
|
||||
if (IS_ERR(inode)) {
|
||||
@@ -150,9 +149,6 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags,
|
||||
goto release_sb;
|
||||
}
|
||||
|
||||
inode->i_uid = uid;
|
||||
inode->i_gid = gid;
|
||||
|
||||
root = d_alloc_root(inode);
|
||||
if (!root) {
|
||||
iput(inode);
|
||||
@@ -173,10 +169,8 @@ P9_DPRINTK(P9_DEBUG_VFS, " simple set mount, return 0\n");
|
||||
simple_set_mnt(mnt, sb);
|
||||
return 0;
|
||||
|
||||
release_sb:
|
||||
deactivate_locked_super(sb);
|
||||
|
||||
free_stat:
|
||||
p9stat_free(st);
|
||||
kfree(st);
|
||||
|
||||
clunk_fid:
|
||||
@@ -185,7 +179,12 @@ clunk_fid:
|
||||
close_session:
|
||||
v9fs_session_close(v9ses);
|
||||
kfree(v9ses);
|
||||
return retval;
|
||||
|
||||
release_sb:
|
||||
p9stat_free(st);
|
||||
kfree(st);
|
||||
deactivate_locked_super(sb);
|
||||
return retval;
|
||||
}
|
||||
|
||||
@@ -207,24 +206,10 @@ static void v9fs_kill_super(struct super_block *s)
|
||||
|
||||
v9fs_session_close(v9ses);
|
||||
kfree(v9ses);
|
||||
s->s_fs_info = NULL;
|
||||
P9_DPRINTK(P9_DEBUG_VFS, "exiting kill_super\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* v9fs_show_options - Show mount options in /proc/mounts
|
||||
* @m: seq_file to write to
|
||||
* @mnt: mount descriptor
|
||||
*
|
||||
*/
|
||||
|
||||
static int v9fs_show_options(struct seq_file *m, struct vfsmount *mnt)
|
||||
{
|
||||
struct v9fs_session_info *v9ses = mnt->mnt_sb->s_fs_info;
|
||||
|
||||
seq_printf(m, "%s", v9ses->options);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
v9fs_umount_begin(struct super_block *sb)
|
||||
{
|
||||
@@ -237,7 +222,7 @@ v9fs_umount_begin(struct super_block *sb)
|
||||
static const struct super_operations v9fs_super_ops = {
|
||||
.statfs = simple_statfs,
|
||||
.clear_inode = v9fs_clear_inode,
|
||||
.show_options = v9fs_show_options,
|
||||
.show_options = generic_show_options,
|
||||
.umount_begin = v9fs_umount_begin,
|
||||
};
|
||||
|
||||
|
@@ -134,9 +134,16 @@ static int afs_readpage(struct file *file, struct page *page)
|
||||
|
||||
inode = page->mapping->host;
|
||||
|
||||
ASSERT(file != NULL);
|
||||
key = file->private_data;
|
||||
ASSERT(key != NULL);
|
||||
if (file) {
|
||||
key = file->private_data;
|
||||
ASSERT(key != NULL);
|
||||
} else {
|
||||
key = afs_request_key(AFS_FS_S(inode->i_sb)->volume->cell);
|
||||
if (IS_ERR(key)) {
|
||||
ret = PTR_ERR(key);
|
||||
goto error_nokey;
|
||||
}
|
||||
}
|
||||
|
||||
_enter("{%x},{%lu},{%lu}", key_serial(key), inode->i_ino, page->index);
|
||||
|
||||
@@ -207,12 +214,17 @@ static int afs_readpage(struct file *file, struct page *page)
|
||||
unlock_page(page);
|
||||
}
|
||||
|
||||
if (!file)
|
||||
key_put(key);
|
||||
_leave(" = 0");
|
||||
return 0;
|
||||
|
||||
error:
|
||||
SetPageError(page);
|
||||
unlock_page(page);
|
||||
if (!file)
|
||||
key_put(key);
|
||||
error_nokey:
|
||||
_leave(" = %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
@@ -77,7 +77,7 @@ static int autofs4_mount_busy(struct vfsmount *mnt, struct dentry *dentry)
|
||||
}
|
||||
|
||||
/* Update the expiry counter if fs is busy */
|
||||
if (!may_umount_tree(mnt)) {
|
||||
if (!may_umount_tree(path.mnt)) {
|
||||
struct autofs_info *ino = autofs4_dentry_ino(top);
|
||||
ino->last_used = jiffies;
|
||||
goto done;
|
||||
|
@@ -3099,8 +3099,12 @@ static void inode_tree_add(struct inode *inode)
|
||||
{
|
||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||
struct btrfs_inode *entry;
|
||||
struct rb_node **p = &root->inode_tree.rb_node;
|
||||
struct rb_node *parent = NULL;
|
||||
struct rb_node **p;
|
||||
struct rb_node *parent;
|
||||
|
||||
again:
|
||||
p = &root->inode_tree.rb_node;
|
||||
parent = NULL;
|
||||
|
||||
spin_lock(&root->inode_lock);
|
||||
while (*p) {
|
||||
@@ -3108,13 +3112,16 @@ static void inode_tree_add(struct inode *inode)
|
||||
entry = rb_entry(parent, struct btrfs_inode, rb_node);
|
||||
|
||||
if (inode->i_ino < entry->vfs_inode.i_ino)
|
||||
p = &(*p)->rb_left;
|
||||
p = &parent->rb_left;
|
||||
else if (inode->i_ino > entry->vfs_inode.i_ino)
|
||||
p = &(*p)->rb_right;
|
||||
p = &parent->rb_right;
|
||||
else {
|
||||
WARN_ON(!(entry->vfs_inode.i_state &
|
||||
(I_WILL_FREE | I_FREEING | I_CLEAR)));
|
||||
break;
|
||||
rb_erase(parent, &root->inode_tree);
|
||||
RB_CLEAR_NODE(parent);
|
||||
spin_unlock(&root->inode_lock);
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
rb_link_node(&BTRFS_I(inode)->rb_node, parent, p);
|
||||
@@ -3126,12 +3133,12 @@ static void inode_tree_del(struct inode *inode)
|
||||
{
|
||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||
|
||||
spin_lock(&root->inode_lock);
|
||||
if (!RB_EMPTY_NODE(&BTRFS_I(inode)->rb_node)) {
|
||||
spin_lock(&root->inode_lock);
|
||||
rb_erase(&BTRFS_I(inode)->rb_node, &root->inode_tree);
|
||||
spin_unlock(&root->inode_lock);
|
||||
RB_CLEAR_NODE(&BTRFS_I(inode)->rb_node);
|
||||
}
|
||||
spin_unlock(&root->inode_lock);
|
||||
}
|
||||
|
||||
static noinline void init_btrfs_i(struct inode *inode)
|
||||
|
@@ -1165,8 +1165,11 @@ void mark_buffer_dirty(struct buffer_head *bh)
|
||||
|
||||
if (!test_set_buffer_dirty(bh)) {
|
||||
struct page *page = bh->b_page;
|
||||
if (!TestSetPageDirty(page))
|
||||
__set_page_dirty(page, page_mapping(page), 0);
|
||||
if (!TestSetPageDirty(page)) {
|
||||
struct address_space *mapping = page_mapping(page);
|
||||
if (mapping)
|
||||
__set_page_dirty(page, mapping, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
17
fs/compat.c
17
fs/compat.c
@@ -1485,20 +1485,15 @@ int compat_do_execve(char * filename,
|
||||
if (!bprm)
|
||||
goto out_files;
|
||||
|
||||
retval = -ERESTARTNOINTR;
|
||||
if (mutex_lock_interruptible(¤t->cred_guard_mutex))
|
||||
retval = prepare_bprm_creds(bprm);
|
||||
if (retval)
|
||||
goto out_free;
|
||||
current->in_execve = 1;
|
||||
|
||||
retval = -ENOMEM;
|
||||
bprm->cred = prepare_exec_creds();
|
||||
if (!bprm->cred)
|
||||
goto out_unlock;
|
||||
|
||||
retval = check_unsafe_exec(bprm);
|
||||
if (retval < 0)
|
||||
goto out_unlock;
|
||||
goto out_free;
|
||||
clear_in_exec = retval;
|
||||
current->in_execve = 1;
|
||||
|
||||
file = open_exec(filename);
|
||||
retval = PTR_ERR(file);
|
||||
@@ -1547,7 +1542,6 @@ int compat_do_execve(char * filename,
|
||||
/* execve succeeded */
|
||||
current->fs->in_exec = 0;
|
||||
current->in_execve = 0;
|
||||
mutex_unlock(¤t->cred_guard_mutex);
|
||||
acct_update_integrals(current);
|
||||
free_bprm(bprm);
|
||||
if (displaced)
|
||||
@@ -1567,10 +1561,7 @@ out_file:
|
||||
out_unmark:
|
||||
if (clear_in_exec)
|
||||
current->fs->in_exec = 0;
|
||||
|
||||
out_unlock:
|
||||
current->in_execve = 0;
|
||||
mutex_unlock(¤t->cred_guard_mutex);
|
||||
|
||||
out_free:
|
||||
free_bprm(bprm);
|
||||
|
67
fs/exec.c
67
fs/exec.c
@@ -678,8 +678,8 @@ exit:
|
||||
}
|
||||
EXPORT_SYMBOL(open_exec);
|
||||
|
||||
int kernel_read(struct file *file, unsigned long offset,
|
||||
char *addr, unsigned long count)
|
||||
int kernel_read(struct file *file, loff_t offset,
|
||||
char *addr, unsigned long count)
|
||||
{
|
||||
mm_segment_t old_fs;
|
||||
loff_t pos = offset;
|
||||
@@ -1015,6 +1015,35 @@ out:
|
||||
|
||||
EXPORT_SYMBOL(flush_old_exec);
|
||||
|
||||
/*
|
||||
* Prepare credentials and lock ->cred_guard_mutex.
|
||||
* install_exec_creds() commits the new creds and drops the lock.
|
||||
* Or, if exec fails before, free_bprm() should release ->cred and
|
||||
* and unlock.
|
||||
*/
|
||||
int prepare_bprm_creds(struct linux_binprm *bprm)
|
||||
{
|
||||
if (mutex_lock_interruptible(¤t->cred_guard_mutex))
|
||||
return -ERESTARTNOINTR;
|
||||
|
||||
bprm->cred = prepare_exec_creds();
|
||||
if (likely(bprm->cred))
|
||||
return 0;
|
||||
|
||||
mutex_unlock(¤t->cred_guard_mutex);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
void free_bprm(struct linux_binprm *bprm)
|
||||
{
|
||||
free_arg_pages(bprm);
|
||||
if (bprm->cred) {
|
||||
mutex_unlock(¤t->cred_guard_mutex);
|
||||
abort_creds(bprm->cred);
|
||||
}
|
||||
kfree(bprm);
|
||||
}
|
||||
|
||||
/*
|
||||
* install the new credentials for this executable
|
||||
*/
|
||||
@@ -1024,12 +1053,13 @@ void install_exec_creds(struct linux_binprm *bprm)
|
||||
|
||||
commit_creds(bprm->cred);
|
||||
bprm->cred = NULL;
|
||||
|
||||
/* cred_guard_mutex must be held at least to this point to prevent
|
||||
/*
|
||||
* cred_guard_mutex must be held at least to this point to prevent
|
||||
* ptrace_attach() from altering our determination of the task's
|
||||
* credentials; any time after this it may be unlocked */
|
||||
|
||||
* credentials; any time after this it may be unlocked.
|
||||
*/
|
||||
security_bprm_committed_creds(bprm);
|
||||
mutex_unlock(¤t->cred_guard_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL(install_exec_creds);
|
||||
|
||||
@@ -1246,14 +1276,6 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs)
|
||||
|
||||
EXPORT_SYMBOL(search_binary_handler);
|
||||
|
||||
void free_bprm(struct linux_binprm *bprm)
|
||||
{
|
||||
free_arg_pages(bprm);
|
||||
if (bprm->cred)
|
||||
abort_creds(bprm->cred);
|
||||
kfree(bprm);
|
||||
}
|
||||
|
||||
/*
|
||||
* sys_execve() executes a new program.
|
||||
*/
|
||||
@@ -1277,20 +1299,15 @@ int do_execve(char * filename,
|
||||
if (!bprm)
|
||||
goto out_files;
|
||||
|
||||
retval = -ERESTARTNOINTR;
|
||||
if (mutex_lock_interruptible(¤t->cred_guard_mutex))
|
||||
retval = prepare_bprm_creds(bprm);
|
||||
if (retval)
|
||||
goto out_free;
|
||||
current->in_execve = 1;
|
||||
|
||||
retval = -ENOMEM;
|
||||
bprm->cred = prepare_exec_creds();
|
||||
if (!bprm->cred)
|
||||
goto out_unlock;
|
||||
|
||||
retval = check_unsafe_exec(bprm);
|
||||
if (retval < 0)
|
||||
goto out_unlock;
|
||||
goto out_free;
|
||||
clear_in_exec = retval;
|
||||
current->in_execve = 1;
|
||||
|
||||
file = open_exec(filename);
|
||||
retval = PTR_ERR(file);
|
||||
@@ -1340,7 +1357,6 @@ int do_execve(char * filename,
|
||||
/* execve succeeded */
|
||||
current->fs->in_exec = 0;
|
||||
current->in_execve = 0;
|
||||
mutex_unlock(¤t->cred_guard_mutex);
|
||||
acct_update_integrals(current);
|
||||
free_bprm(bprm);
|
||||
if (displaced)
|
||||
@@ -1360,10 +1376,7 @@ out_file:
|
||||
out_unmark:
|
||||
if (clear_in_exec)
|
||||
current->fs->in_exec = 0;
|
||||
|
||||
out_unlock:
|
||||
current->in_execve = 0;
|
||||
mutex_unlock(¤t->cred_guard_mutex);
|
||||
|
||||
out_free:
|
||||
free_bprm(bprm);
|
||||
|
@@ -362,6 +362,10 @@ static int ext2_rename (struct inode * old_dir, struct dentry * old_dentry,
|
||||
if (dir_de) {
|
||||
if (old_dir != new_dir)
|
||||
ext2_set_link(old_inode, dir_de, dir_page, new_dir, 0);
|
||||
else {
|
||||
kunmap(dir_page);
|
||||
page_cache_release(dir_page);
|
||||
}
|
||||
inode_dec_link_count(old_dir);
|
||||
}
|
||||
return 0;
|
||||
|
@@ -29,23 +29,25 @@ config EXT3_FS
|
||||
module will be called ext3.
|
||||
|
||||
config EXT3_DEFAULTS_TO_ORDERED
|
||||
bool "Default to 'data=ordered' in ext3 (legacy option)"
|
||||
bool "Default to 'data=ordered' in ext3"
|
||||
depends on EXT3_FS
|
||||
help
|
||||
If a filesystem does not explicitly specify a data ordering
|
||||
mode, and the journal capability allowed it, ext3 used to
|
||||
historically default to 'data=ordered'.
|
||||
The journal mode options for ext3 have different tradeoffs
|
||||
between when data is guaranteed to be on disk and
|
||||
performance. The use of "data=writeback" can cause
|
||||
unwritten data to appear in files after an system crash or
|
||||
power failure, which can be a security issue. However,
|
||||
"data=ordered" mode can also result in major performance
|
||||
problems, including seconds-long delays before an fsync()
|
||||
call returns. For details, see:
|
||||
|
||||
That was a rather unfortunate choice, because it leads to all
|
||||
kinds of latency problems, and the 'data=writeback' mode is more
|
||||
appropriate these days.
|
||||
http://ext4.wiki.kernel.org/index.php/Ext3_data_mode_tradeoffs
|
||||
|
||||
You should probably always answer 'n' here, and if you really
|
||||
want to use 'data=ordered' mode, set it in the filesystem itself
|
||||
with 'tune2fs -o journal_data_ordered'.
|
||||
|
||||
But if you really want to enable the legacy default, you can do
|
||||
so by answering 'y' to this question.
|
||||
If you have been historically happy with ext3's performance,
|
||||
data=ordered mode will be a safe choice and you should
|
||||
answer 'y' here. If you understand the reliability and data
|
||||
privacy issues of data=writeback and are willing to make
|
||||
that trade off, answer 'n'.
|
||||
|
||||
config EXT3_FS_XATTR
|
||||
bool "Ext3 extended attributes"
|
||||
|
@@ -543,6 +543,19 @@ static inline void ext3_show_quota_options(struct seq_file *seq, struct super_bl
|
||||
#endif
|
||||
}
|
||||
|
||||
static char *data_mode_string(unsigned long mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case EXT3_MOUNT_JOURNAL_DATA:
|
||||
return "journal";
|
||||
case EXT3_MOUNT_ORDERED_DATA:
|
||||
return "ordered";
|
||||
case EXT3_MOUNT_WRITEBACK_DATA:
|
||||
return "writeback";
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
/*
|
||||
* Show an option if
|
||||
* - it's set to a non-default value OR
|
||||
@@ -616,13 +629,8 @@ static int ext3_show_options(struct seq_file *seq, struct vfsmount *vfs)
|
||||
if (test_opt(sb, NOBH))
|
||||
seq_puts(seq, ",nobh");
|
||||
|
||||
if (test_opt(sb, DATA_FLAGS) == EXT3_MOUNT_JOURNAL_DATA)
|
||||
seq_puts(seq, ",data=journal");
|
||||
else if (test_opt(sb, DATA_FLAGS) == EXT3_MOUNT_ORDERED_DATA)
|
||||
seq_puts(seq, ",data=ordered");
|
||||
else if (test_opt(sb, DATA_FLAGS) == EXT3_MOUNT_WRITEBACK_DATA)
|
||||
seq_puts(seq, ",data=writeback");
|
||||
|
||||
seq_printf(seq, ",data=%s", data_mode_string(sbi->s_mount_opt &
|
||||
EXT3_MOUNT_DATA_FLAGS));
|
||||
if (test_opt(sb, DATA_ERR_ABORT))
|
||||
seq_puts(seq, ",data_err=abort");
|
||||
|
||||
@@ -1024,12 +1032,18 @@ static int parse_options (char *options, struct super_block *sb,
|
||||
datacheck:
|
||||
if (is_remount) {
|
||||
if ((sbi->s_mount_opt & EXT3_MOUNT_DATA_FLAGS)
|
||||
!= data_opt) {
|
||||
printk(KERN_ERR
|
||||
"EXT3-fs: cannot change data "
|
||||
"mode on remount\n");
|
||||
return 0;
|
||||
}
|
||||
== data_opt)
|
||||
break;
|
||||
printk(KERN_ERR
|
||||
"EXT3-fs (device %s): Cannot change "
|
||||
"data mode on remount. The filesystem "
|
||||
"is mounted in data=%s mode and you "
|
||||
"try to remount it in data=%s mode.\n",
|
||||
sb->s_id,
|
||||
data_mode_string(sbi->s_mount_opt &
|
||||
EXT3_MOUNT_DATA_FLAGS),
|
||||
data_mode_string(data_opt));
|
||||
return 0;
|
||||
} else {
|
||||
sbi->s_mount_opt &= ~EXT3_MOUNT_DATA_FLAGS;
|
||||
sbi->s_mount_opt |= data_opt;
|
||||
|
@@ -935,26 +935,28 @@ static int can_do_hugetlb_shm(void)
|
||||
return capable(CAP_IPC_LOCK) || in_group_p(sysctl_hugetlb_shm_group);
|
||||
}
|
||||
|
||||
struct file *hugetlb_file_setup(const char *name, size_t size, int acctflag)
|
||||
struct file *hugetlb_file_setup(const char *name, size_t size, int acctflag,
|
||||
struct user_struct **user)
|
||||
{
|
||||
int error = -ENOMEM;
|
||||
int unlock_shm = 0;
|
||||
struct file *file;
|
||||
struct inode *inode;
|
||||
struct dentry *dentry, *root;
|
||||
struct qstr quick_string;
|
||||
struct user_struct *user = current_user();
|
||||
|
||||
*user = NULL;
|
||||
if (!hugetlbfs_vfsmount)
|
||||
return ERR_PTR(-ENOENT);
|
||||
|
||||
if (!can_do_hugetlb_shm()) {
|
||||
if (user_shm_lock(size, user)) {
|
||||
unlock_shm = 1;
|
||||
*user = current_user();
|
||||
if (user_shm_lock(size, *user)) {
|
||||
WARN_ONCE(1,
|
||||
"Using mlock ulimits for SHM_HUGETLB deprecated\n");
|
||||
} else
|
||||
} else {
|
||||
*user = NULL;
|
||||
return ERR_PTR(-EPERM);
|
||||
}
|
||||
}
|
||||
|
||||
root = hugetlbfs_vfsmount->mnt_root;
|
||||
@@ -996,8 +998,10 @@ out_inode:
|
||||
out_dentry:
|
||||
dput(dentry);
|
||||
out_shm_unlock:
|
||||
if (unlock_shm)
|
||||
user_shm_unlock(size, user);
|
||||
if (*user) {
|
||||
user_shm_unlock(size, *user);
|
||||
*user = NULL;
|
||||
}
|
||||
return ERR_PTR(error);
|
||||
}
|
||||
|
||||
|
@@ -1268,10 +1268,20 @@ int jffs2_nor_wbuf_flash_setup(struct jffs2_sb_info *c) {
|
||||
if (!c->wbuf)
|
||||
return -ENOMEM;
|
||||
|
||||
#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY
|
||||
c->wbuf_verify = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
|
||||
if (!c->wbuf_verify) {
|
||||
kfree(c->wbuf);
|
||||
return -ENOMEM;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
void jffs2_nor_wbuf_flash_cleanup(struct jffs2_sb_info *c) {
|
||||
#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY
|
||||
kfree(c->wbuf_verify);
|
||||
#endif
|
||||
kfree(c->wbuf);
|
||||
}
|
||||
|
||||
|
@@ -217,7 +217,7 @@ int get_sb_pseudo(struct file_system_type *fs_type, char *name,
|
||||
return PTR_ERR(s);
|
||||
|
||||
s->s_flags = MS_NOUSER;
|
||||
s->s_maxbytes = ~0ULL;
|
||||
s->s_maxbytes = MAX_LFS_FILESIZE;
|
||||
s->s_blocksize = PAGE_SIZE;
|
||||
s->s_blocksize_bits = PAGE_SHIFT;
|
||||
s->s_magic = magic;
|
||||
|
22
fs/namei.c
22
fs/namei.c
@@ -1542,28 +1542,31 @@ int may_open(struct path *path, int acc_mode, int flag)
|
||||
* An append-only file must be opened in append mode for writing.
|
||||
*/
|
||||
if (IS_APPEND(inode)) {
|
||||
error = -EPERM;
|
||||
if ((flag & FMODE_WRITE) && !(flag & O_APPEND))
|
||||
return -EPERM;
|
||||
goto err_out;
|
||||
if (flag & O_TRUNC)
|
||||
return -EPERM;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
/* O_NOATIME can only be set by the owner or superuser */
|
||||
if (flag & O_NOATIME)
|
||||
if (!is_owner_or_cap(inode))
|
||||
return -EPERM;
|
||||
if (!is_owner_or_cap(inode)) {
|
||||
error = -EPERM;
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure there are no outstanding leases on the file.
|
||||
*/
|
||||
error = break_lease(inode, flag);
|
||||
if (error)
|
||||
return error;
|
||||
goto err_out;
|
||||
|
||||
if (flag & O_TRUNC) {
|
||||
error = get_write_access(inode);
|
||||
if (error)
|
||||
return error;
|
||||
goto err_out;
|
||||
|
||||
/*
|
||||
* Refuse to truncate files with mandatory locks held on them.
|
||||
@@ -1581,12 +1584,17 @@ int may_open(struct path *path, int acc_mode, int flag)
|
||||
}
|
||||
put_write_access(inode);
|
||||
if (error)
|
||||
return error;
|
||||
goto err_out;
|
||||
} else
|
||||
if (flag & FMODE_WRITE)
|
||||
vfs_dq_init(inode);
|
||||
|
||||
return 0;
|
||||
err_out:
|
||||
ima_counts_put(path, acc_mode ?
|
||||
acc_mode & (MAY_READ | MAY_WRITE | MAY_EXEC) :
|
||||
ACC_MODE(flag) & (MAY_READ | MAY_WRITE));
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@@ -1250,8 +1250,8 @@ static void nfs4_state_manager(struct nfs_client *clp)
|
||||
continue;
|
||||
}
|
||||
/* Initialize or reset the session */
|
||||
if (nfs4_has_session(clp) &&
|
||||
test_and_clear_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state)) {
|
||||
if (test_and_clear_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state)
|
||||
&& nfs4_has_session(clp)) {
|
||||
if (clp->cl_cons_state == NFS_CS_SESSION_INITING)
|
||||
status = nfs4_initialize_session(clp);
|
||||
else
|
||||
|
@@ -209,6 +209,7 @@ int nilfs_btnode_prepare_change_key(struct address_space *btnc,
|
||||
* We cannot call radix_tree_preload for the kernels older
|
||||
* than 2.6.23, because it is not exported for modules.
|
||||
*/
|
||||
retry:
|
||||
err = radix_tree_preload(GFP_NOFS & ~__GFP_HIGHMEM);
|
||||
if (err)
|
||||
goto failed_unlock;
|
||||
@@ -219,7 +220,6 @@ int nilfs_btnode_prepare_change_key(struct address_space *btnc,
|
||||
(unsigned long long)oldkey,
|
||||
(unsigned long long)newkey);
|
||||
|
||||
retry:
|
||||
spin_lock_irq(&btnc->tree_lock);
|
||||
err = radix_tree_insert(&btnc->page_tree, newkey, obh->b_page);
|
||||
spin_unlock_irq(&btnc->tree_lock);
|
||||
|
@@ -416,8 +416,10 @@ int nilfs_attach_checkpoint(struct nilfs_sb_info *sbi, __u64 cno)
|
||||
if (unlikely(err))
|
||||
goto failed;
|
||||
|
||||
down_read(&nilfs->ns_segctor_sem);
|
||||
err = nilfs_cpfile_get_checkpoint(nilfs->ns_cpfile, cno, 0, &raw_cp,
|
||||
&bh_cp);
|
||||
up_read(&nilfs->ns_segctor_sem);
|
||||
if (unlikely(err)) {
|
||||
if (err == -ENOENT || err == -EINVAL) {
|
||||
printk(KERN_ERR
|
||||
|
@@ -253,7 +253,7 @@ nilfs_detach_writer(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi)
|
||||
|
||||
static inline void nilfs_put_sbinfo(struct nilfs_sb_info *sbi)
|
||||
{
|
||||
if (!atomic_dec_and_test(&sbi->s_count))
|
||||
if (atomic_dec_and_test(&sbi->s_count))
|
||||
kfree(sbi);
|
||||
}
|
||||
|
||||
|
@@ -62,13 +62,14 @@ static int inotify_handle_event(struct fsnotify_group *group, struct fsnotify_ev
|
||||
event_priv->wd = wd;
|
||||
|
||||
ret = fsnotify_add_notify_event(group, event, fsn_event_priv);
|
||||
/* EEXIST is not an error */
|
||||
if (ret == -EEXIST)
|
||||
ret = 0;
|
||||
|
||||
/* did event_priv get attached? */
|
||||
if (list_empty(&fsn_event_priv->event_list))
|
||||
if (ret) {
|
||||
inotify_free_event_priv(fsn_event_priv);
|
||||
/* EEXIST says we tail matched, EOVERFLOW isn't something
|
||||
* to report up the stack. */
|
||||
if ((ret == -EEXIST) ||
|
||||
(ret == -EOVERFLOW))
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we hold the entry until after the event is on the queue
|
||||
@@ -104,16 +105,45 @@ static bool inotify_should_send_event(struct fsnotify_group *group, struct inode
|
||||
return send;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is NEVER supposed to be called. Inotify marks should either have been
|
||||
* removed from the idr when the watch was removed or in the
|
||||
* fsnotify_destroy_mark_by_group() call when the inotify instance was being
|
||||
* torn down. This is only called if the idr is about to be freed but there
|
||||
* are still marks in it.
|
||||
*/
|
||||
static int idr_callback(int id, void *p, void *data)
|
||||
{
|
||||
BUG();
|
||||
struct fsnotify_mark_entry *entry;
|
||||
struct inotify_inode_mark_entry *ientry;
|
||||
static bool warned = false;
|
||||
|
||||
if (warned)
|
||||
return 0;
|
||||
|
||||
warned = false;
|
||||
entry = p;
|
||||
ientry = container_of(entry, struct inotify_inode_mark_entry, fsn_entry);
|
||||
|
||||
WARN(1, "inotify closing but id=%d for entry=%p in group=%p still in "
|
||||
"idr. Probably leaking memory\n", id, p, data);
|
||||
|
||||
/*
|
||||
* I'm taking the liberty of assuming that the mark in question is a
|
||||
* valid address and I'm dereferencing it. This might help to figure
|
||||
* out why we got here and the panic is no worse than the original
|
||||
* BUG() that was here.
|
||||
*/
|
||||
if (entry)
|
||||
printk(KERN_WARNING "entry->group=%p inode=%p wd=%d\n",
|
||||
entry->group, entry->inode, ientry->wd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void inotify_free_group_priv(struct fsnotify_group *group)
|
||||
{
|
||||
/* ideally the idr is empty and we won't hit the BUG in teh callback */
|
||||
idr_for_each(&group->inotify_data.idr, idr_callback, NULL);
|
||||
idr_for_each(&group->inotify_data.idr, idr_callback, group);
|
||||
idr_remove_all(&group->inotify_data.idr);
|
||||
idr_destroy(&group->inotify_data.idr);
|
||||
}
|
||||
|
@@ -47,9 +47,6 @@
|
||||
|
||||
static struct vfsmount *inotify_mnt __read_mostly;
|
||||
|
||||
/* this just sits here and wastes global memory. used to just pad userspace messages with zeros */
|
||||
static struct inotify_event nul_inotify_event;
|
||||
|
||||
/* these are configurable via /proc/sys/fs/inotify/ */
|
||||
static int inotify_max_user_instances __read_mostly;
|
||||
static int inotify_max_queued_events __read_mostly;
|
||||
@@ -157,7 +154,8 @@ static struct fsnotify_event *get_one_event(struct fsnotify_group *group,
|
||||
|
||||
event = fsnotify_peek_notify_event(group);
|
||||
|
||||
event_size += roundup(event->name_len, event_size);
|
||||
if (event->name_len)
|
||||
event_size += roundup(event->name_len + 1, event_size);
|
||||
|
||||
if (event_size > count)
|
||||
return ERR_PTR(-EINVAL);
|
||||
@@ -183,7 +181,7 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group,
|
||||
struct fsnotify_event_private_data *fsn_priv;
|
||||
struct inotify_event_private_data *priv;
|
||||
size_t event_size = sizeof(struct inotify_event);
|
||||
size_t name_len;
|
||||
size_t name_len = 0;
|
||||
|
||||
/* we get the inotify watch descriptor from the event private data */
|
||||
spin_lock(&event->lock);
|
||||
@@ -199,8 +197,12 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group,
|
||||
inotify_free_event_priv(fsn_priv);
|
||||
}
|
||||
|
||||
/* round up event->name_len so it is a multiple of event_size */
|
||||
name_len = roundup(event->name_len, event_size);
|
||||
/*
|
||||
* round up event->name_len so it is a multiple of event_size
|
||||
* plus an extra byte for the terminating '\0'.
|
||||
*/
|
||||
if (event->name_len)
|
||||
name_len = roundup(event->name_len + 1, event_size);
|
||||
inotify_event.len = name_len;
|
||||
|
||||
inotify_event.mask = inotify_mask_to_arg(event->mask);
|
||||
@@ -224,8 +226,8 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group,
|
||||
return -EFAULT;
|
||||
buf += event->name_len;
|
||||
|
||||
/* fill userspace with 0's from nul_inotify_event */
|
||||
if (copy_to_user(buf, &nul_inotify_event, len_to_zero))
|
||||
/* fill userspace with 0's */
|
||||
if (clear_user(buf, len_to_zero))
|
||||
return -EFAULT;
|
||||
buf += len_to_zero;
|
||||
event_size += name_len;
|
||||
@@ -326,8 +328,9 @@ static long inotify_ioctl(struct file *file, unsigned int cmd,
|
||||
list_for_each_entry(holder, &group->notification_list, event_list) {
|
||||
event = holder->event;
|
||||
send_len += sizeof(struct inotify_event);
|
||||
send_len += roundup(event->name_len,
|
||||
sizeof(struct inotify_event));
|
||||
if (event->name_len)
|
||||
send_len += roundup(event->name_len + 1,
|
||||
sizeof(struct inotify_event));
|
||||
}
|
||||
mutex_unlock(&group->notification_mutex);
|
||||
ret = put_user(send_len, (int __user *) p);
|
||||
@@ -364,20 +367,53 @@ static int inotify_find_inode(const char __user *dirname, struct path *path, uns
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove the mark from the idr (if present) and drop the reference
|
||||
* on the mark because it was in the idr.
|
||||
*/
|
||||
static void inotify_remove_from_idr(struct fsnotify_group *group,
|
||||
struct inotify_inode_mark_entry *ientry)
|
||||
{
|
||||
struct idr *idr;
|
||||
struct fsnotify_mark_entry *entry;
|
||||
struct inotify_inode_mark_entry *found_ientry;
|
||||
int wd;
|
||||
|
||||
spin_lock(&group->inotify_data.idr_lock);
|
||||
idr = &group->inotify_data.idr;
|
||||
idr_remove(idr, ientry->wd);
|
||||
spin_unlock(&group->inotify_data.idr_lock);
|
||||
wd = ientry->wd;
|
||||
|
||||
if (wd == -1)
|
||||
goto out;
|
||||
|
||||
entry = idr_find(&group->inotify_data.idr, wd);
|
||||
if (unlikely(!entry))
|
||||
goto out;
|
||||
|
||||
found_ientry = container_of(entry, struct inotify_inode_mark_entry, fsn_entry);
|
||||
if (unlikely(found_ientry != ientry)) {
|
||||
/* We found an entry in the idr with the right wd, but it's
|
||||
* not the entry we were told to remove. eparis seriously
|
||||
* fucked up somewhere. */
|
||||
WARN_ON(1);
|
||||
ientry->wd = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* One ref for being in the idr, one ref held by the caller */
|
||||
BUG_ON(atomic_read(&entry->refcnt) < 2);
|
||||
|
||||
idr_remove(idr, wd);
|
||||
ientry->wd = -1;
|
||||
|
||||
/* removed from the idr, drop that ref */
|
||||
fsnotify_put_mark(entry);
|
||||
out:
|
||||
spin_unlock(&group->inotify_data.idr_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Send IN_IGNORED for this wd, remove this wd from the idr, and drop the
|
||||
* internal reference help on the mark because it is in the idr.
|
||||
* Send IN_IGNORED for this wd, remove this wd from the idr.
|
||||
*/
|
||||
void inotify_ignored_and_remove_idr(struct fsnotify_mark_entry *entry,
|
||||
struct fsnotify_group *group)
|
||||
@@ -386,6 +422,7 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark_entry *entry,
|
||||
struct fsnotify_event *ignored_event;
|
||||
struct inotify_event_private_data *event_priv;
|
||||
struct fsnotify_event_private_data *fsn_event_priv;
|
||||
int ret;
|
||||
|
||||
ignored_event = fsnotify_create_event(NULL, FS_IN_IGNORED, NULL,
|
||||
FSNOTIFY_EVENT_NONE, NULL, 0,
|
||||
@@ -404,10 +441,8 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark_entry *entry,
|
||||
fsn_event_priv->group = group;
|
||||
event_priv->wd = ientry->wd;
|
||||
|
||||
fsnotify_add_notify_event(group, ignored_event, fsn_event_priv);
|
||||
|
||||
/* did the private data get added? */
|
||||
if (list_empty(&fsn_event_priv->event_list))
|
||||
ret = fsnotify_add_notify_event(group, ignored_event, fsn_event_priv);
|
||||
if (ret)
|
||||
inotify_free_event_priv(fsn_event_priv);
|
||||
|
||||
skip_send_ignore:
|
||||
@@ -418,9 +453,6 @@ skip_send_ignore:
|
||||
/* remove this entry from the idr */
|
||||
inotify_remove_from_idr(group, ientry);
|
||||
|
||||
/* removed from idr, drop that reference */
|
||||
fsnotify_put_mark(entry);
|
||||
|
||||
atomic_dec(&group->inotify_data.user->inotify_watches);
|
||||
}
|
||||
|
||||
@@ -432,80 +464,29 @@ static void inotify_free_mark(struct fsnotify_mark_entry *entry)
|
||||
kmem_cache_free(inotify_inode_mark_cachep, ientry);
|
||||
}
|
||||
|
||||
static int inotify_update_watch(struct fsnotify_group *group, struct inode *inode, u32 arg)
|
||||
static int inotify_update_existing_watch(struct fsnotify_group *group,
|
||||
struct inode *inode,
|
||||
u32 arg)
|
||||
{
|
||||
struct fsnotify_mark_entry *entry = NULL;
|
||||
struct fsnotify_mark_entry *entry;
|
||||
struct inotify_inode_mark_entry *ientry;
|
||||
struct inotify_inode_mark_entry *tmp_ientry;
|
||||
int ret = 0;
|
||||
int add = (arg & IN_MASK_ADD);
|
||||
__u32 mask;
|
||||
__u32 old_mask, new_mask;
|
||||
__u32 mask;
|
||||
int add = (arg & IN_MASK_ADD);
|
||||
int ret;
|
||||
|
||||
/* don't allow invalid bits: we don't want flags set */
|
||||
mask = inotify_arg_to_mask(arg);
|
||||
if (unlikely(!mask))
|
||||
return -EINVAL;
|
||||
|
||||
tmp_ientry = kmem_cache_alloc(inotify_inode_mark_cachep, GFP_KERNEL);
|
||||
if (unlikely(!tmp_ientry))
|
||||
return -ENOMEM;
|
||||
/* we set the mask at the end after attaching it */
|
||||
fsnotify_init_mark(&tmp_ientry->fsn_entry, inotify_free_mark);
|
||||
tmp_ientry->wd = -1;
|
||||
|
||||
find_entry:
|
||||
spin_lock(&inode->i_lock);
|
||||
entry = fsnotify_find_mark_entry(group, inode);
|
||||
spin_unlock(&inode->i_lock);
|
||||
if (entry) {
|
||||
ientry = container_of(entry, struct inotify_inode_mark_entry, fsn_entry);
|
||||
} else {
|
||||
ret = -ENOSPC;
|
||||
if (atomic_read(&group->inotify_data.user->inotify_watches) >= inotify_max_user_watches)
|
||||
goto out_err;
|
||||
retry:
|
||||
ret = -ENOMEM;
|
||||
if (unlikely(!idr_pre_get(&group->inotify_data.idr, GFP_KERNEL)))
|
||||
goto out_err;
|
||||
if (!entry)
|
||||
return -ENOENT;
|
||||
|
||||
spin_lock(&group->inotify_data.idr_lock);
|
||||
ret = idr_get_new_above(&group->inotify_data.idr, &tmp_ientry->fsn_entry,
|
||||
group->inotify_data.last_wd,
|
||||
&tmp_ientry->wd);
|
||||
spin_unlock(&group->inotify_data.idr_lock);
|
||||
if (ret) {
|
||||
if (ret == -EAGAIN)
|
||||
goto retry;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
ret = fsnotify_add_mark(&tmp_ientry->fsn_entry, group, inode);
|
||||
if (ret) {
|
||||
inotify_remove_from_idr(group, tmp_ientry);
|
||||
if (ret == -EEXIST)
|
||||
goto find_entry;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
/* tmp_ientry has been added to the inode, so we are all set up.
|
||||
* now we just need to make sure tmp_ientry doesn't get freed and
|
||||
* we need to set up entry and ientry so the generic code can
|
||||
* do its thing. */
|
||||
ientry = tmp_ientry;
|
||||
entry = &ientry->fsn_entry;
|
||||
tmp_ientry = NULL;
|
||||
|
||||
atomic_inc(&group->inotify_data.user->inotify_watches);
|
||||
|
||||
/* update the idr hint */
|
||||
group->inotify_data.last_wd = ientry->wd;
|
||||
|
||||
/* we put the mark on the idr, take a reference */
|
||||
fsnotify_get_mark(entry);
|
||||
}
|
||||
|
||||
ret = ientry->wd;
|
||||
ientry = container_of(entry, struct inotify_inode_mark_entry, fsn_entry);
|
||||
|
||||
spin_lock(&entry->lock);
|
||||
|
||||
@@ -537,19 +518,108 @@ retry:
|
||||
fsnotify_recalc_group_mask(group);
|
||||
}
|
||||
|
||||
/* this either matches fsnotify_find_mark_entry, or init_mark_entry
|
||||
* depending on which path we took... */
|
||||
/* return the wd */
|
||||
ret = ientry->wd;
|
||||
|
||||
/* match the get from fsnotify_find_mark_entry() */
|
||||
fsnotify_put_mark(entry);
|
||||
|
||||
out_err:
|
||||
/* could be an error, could be that we found an existing mark */
|
||||
if (tmp_ientry) {
|
||||
/* on the idr but didn't make it on the inode */
|
||||
if (tmp_ientry->wd != -1)
|
||||
inotify_remove_from_idr(group, tmp_ientry);
|
||||
kmem_cache_free(inotify_inode_mark_cachep, tmp_ientry);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int inotify_new_watch(struct fsnotify_group *group,
|
||||
struct inode *inode,
|
||||
u32 arg)
|
||||
{
|
||||
struct inotify_inode_mark_entry *tmp_ientry;
|
||||
__u32 mask;
|
||||
int ret;
|
||||
|
||||
/* don't allow invalid bits: we don't want flags set */
|
||||
mask = inotify_arg_to_mask(arg);
|
||||
if (unlikely(!mask))
|
||||
return -EINVAL;
|
||||
|
||||
tmp_ientry = kmem_cache_alloc(inotify_inode_mark_cachep, GFP_KERNEL);
|
||||
if (unlikely(!tmp_ientry))
|
||||
return -ENOMEM;
|
||||
|
||||
fsnotify_init_mark(&tmp_ientry->fsn_entry, inotify_free_mark);
|
||||
tmp_ientry->fsn_entry.mask = mask;
|
||||
tmp_ientry->wd = -1;
|
||||
|
||||
ret = -ENOSPC;
|
||||
if (atomic_read(&group->inotify_data.user->inotify_watches) >= inotify_max_user_watches)
|
||||
goto out_err;
|
||||
retry:
|
||||
ret = -ENOMEM;
|
||||
if (unlikely(!idr_pre_get(&group->inotify_data.idr, GFP_KERNEL)))
|
||||
goto out_err;
|
||||
|
||||
spin_lock(&group->inotify_data.idr_lock);
|
||||
ret = idr_get_new_above(&group->inotify_data.idr, &tmp_ientry->fsn_entry,
|
||||
group->inotify_data.last_wd,
|
||||
&tmp_ientry->wd);
|
||||
spin_unlock(&group->inotify_data.idr_lock);
|
||||
if (ret) {
|
||||
/* idr was out of memory allocate and try again */
|
||||
if (ret == -EAGAIN)
|
||||
goto retry;
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
/* we put the mark on the idr, take a reference */
|
||||
fsnotify_get_mark(&tmp_ientry->fsn_entry);
|
||||
|
||||
/* we are on the idr, now get on the inode */
|
||||
ret = fsnotify_add_mark(&tmp_ientry->fsn_entry, group, inode);
|
||||
if (ret) {
|
||||
/* we failed to get on the inode, get off the idr */
|
||||
inotify_remove_from_idr(group, tmp_ientry);
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
/* update the idr hint, who cares about races, it's just a hint */
|
||||
group->inotify_data.last_wd = tmp_ientry->wd;
|
||||
|
||||
/* increment the number of watches the user has */
|
||||
atomic_inc(&group->inotify_data.user->inotify_watches);
|
||||
|
||||
/* return the watch descriptor for this new entry */
|
||||
ret = tmp_ientry->wd;
|
||||
|
||||
/* match the ref from fsnotify_init_markentry() */
|
||||
fsnotify_put_mark(&tmp_ientry->fsn_entry);
|
||||
|
||||
/* if this mark added a new event update the group mask */
|
||||
if (mask & ~group->mask)
|
||||
fsnotify_recalc_group_mask(group);
|
||||
|
||||
out_err:
|
||||
if (ret < 0)
|
||||
kmem_cache_free(inotify_inode_mark_cachep, tmp_ientry);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int inotify_update_watch(struct fsnotify_group *group, struct inode *inode, u32 arg)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
retry:
|
||||
/* try to update and existing watch with the new arg */
|
||||
ret = inotify_update_existing_watch(group, inode, arg);
|
||||
/* no mark present, try to add a new one */
|
||||
if (ret == -ENOENT)
|
||||
ret = inotify_new_watch(group, inode, arg);
|
||||
/*
|
||||
* inotify_new_watch could race with another thread which did an
|
||||
* inotify_new_watch between the update_existing and the add watch
|
||||
* here, go back and try to update an existing mark again.
|
||||
*/
|
||||
if (ret == -EEXIST)
|
||||
goto retry;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -568,7 +638,7 @@ static struct fsnotify_group *inotify_new_group(struct user_struct *user, unsign
|
||||
|
||||
spin_lock_init(&group->inotify_data.idr_lock);
|
||||
idr_init(&group->inotify_data.idr);
|
||||
group->inotify_data.last_wd = 0;
|
||||
group->inotify_data.last_wd = 1;
|
||||
group->inotify_data.user = user;
|
||||
group->inotify_data.fa = NULL;
|
||||
|
||||
|
@@ -153,6 +153,10 @@ static bool event_compare(struct fsnotify_event *old, struct fsnotify_event *new
|
||||
return true;
|
||||
break;
|
||||
case (FSNOTIFY_EVENT_NONE):
|
||||
if (old->mask & FS_Q_OVERFLOW)
|
||||
return true;
|
||||
else if (old->mask & FS_IN_IGNORED)
|
||||
return false;
|
||||
return false;
|
||||
};
|
||||
}
|
||||
@@ -171,9 +175,7 @@ int fsnotify_add_notify_event(struct fsnotify_group *group, struct fsnotify_even
|
||||
struct list_head *list = &group->notification_list;
|
||||
struct fsnotify_event_holder *last_holder;
|
||||
struct fsnotify_event *last_event;
|
||||
|
||||
/* easy to tell if priv was attached to the event */
|
||||
INIT_LIST_HEAD(&priv->event_list);
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
* There is one fsnotify_event_holder embedded inside each fsnotify_event.
|
||||
@@ -194,6 +196,7 @@ alloc_holder:
|
||||
|
||||
if (group->q_len >= group->max_events) {
|
||||
event = &q_overflow_event;
|
||||
ret = -EOVERFLOW;
|
||||
/* sorry, no private data on the overflow event */
|
||||
priv = NULL;
|
||||
}
|
||||
@@ -235,7 +238,7 @@ alloc_holder:
|
||||
mutex_unlock(&group->notification_mutex);
|
||||
|
||||
wake_up(&group->notification_waitq);
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@@ -6851,7 +6851,7 @@ static int ocfs2_do_truncate(struct ocfs2_super *osb,
|
||||
}
|
||||
status = 0;
|
||||
bail:
|
||||
|
||||
brelse(last_eb_bh);
|
||||
mlog_exit(status);
|
||||
return status;
|
||||
}
|
||||
|
@@ -1747,8 +1747,8 @@ int ocfs2_write_begin_nolock(struct address_space *mapping,
|
||||
* we know zeros will only be needed in the first and/or last cluster.
|
||||
*/
|
||||
if (clusters_to_alloc || extents_to_split ||
|
||||
wc->w_desc[0].c_needs_zero ||
|
||||
wc->w_desc[wc->w_clen - 1].c_needs_zero)
|
||||
(wc->w_clen && (wc->w_desc[0].c_needs_zero ||
|
||||
wc->w_desc[wc->w_clen - 1].c_needs_zero)))
|
||||
cluster_of_pages = 1;
|
||||
else
|
||||
cluster_of_pages = 0;
|
||||
|
@@ -85,6 +85,17 @@ static int ocfs2_dentry_revalidate(struct dentry *dentry,
|
||||
goto bail;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the last lookup failed to create dentry lock, let us
|
||||
* redo it.
|
||||
*/
|
||||
if (!dentry->d_fsdata) {
|
||||
mlog(0, "Inode %llu doesn't have dentry lock, "
|
||||
"returning false\n",
|
||||
(unsigned long long)OCFS2_I(inode)->ip_blkno);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
|
||||
bail:
|
||||
|
@@ -122,7 +122,7 @@ static enum dlm_status dlmunlock_common(struct dlm_ctxt *dlm,
|
||||
* that still has AST's pending... */
|
||||
in_use = !list_empty(&lock->ast_list);
|
||||
spin_unlock(&dlm->ast_lock);
|
||||
if (in_use) {
|
||||
if (in_use && !(flags & LKM_CANCEL)) {
|
||||
mlog(ML_ERROR, "lockres %.*s: Someone is calling dlmunlock "
|
||||
"while waiting for an ast!", res->lockname.len,
|
||||
res->lockname.name);
|
||||
@@ -131,7 +131,7 @@ static enum dlm_status dlmunlock_common(struct dlm_ctxt *dlm,
|
||||
|
||||
spin_lock(&res->spinlock);
|
||||
if (res->state & DLM_LOCK_RES_IN_PROGRESS) {
|
||||
if (master_node) {
|
||||
if (master_node && !(flags & LKM_CANCEL)) {
|
||||
mlog(ML_ERROR, "lockres in progress!\n");
|
||||
spin_unlock(&res->spinlock);
|
||||
return DLM_FORWARD;
|
||||
|
@@ -108,6 +108,7 @@ static char *ocfs2_lock_type_strings[] = {
|
||||
[OCFS2_LOCK_TYPE_OPEN] = "Open",
|
||||
[OCFS2_LOCK_TYPE_FLOCK] = "Flock",
|
||||
[OCFS2_LOCK_TYPE_QINFO] = "Quota",
|
||||
[OCFS2_LOCK_TYPE_NFS_SYNC] = "NFSSync",
|
||||
[OCFS2_LOCK_TYPE_ORPHAN_SCAN] = "OrphanScan",
|
||||
};
|
||||
|
||||
|
@@ -23,6 +23,7 @@
|
||||
#include "sysfile.h"
|
||||
#include "dlmglue.h"
|
||||
#include "uptodate.h"
|
||||
#include "super.h"
|
||||
#include "quota.h"
|
||||
|
||||
static struct workqueue_struct *ocfs2_quota_wq = NULL;
|
||||
@@ -114,6 +115,15 @@ int ocfs2_read_quota_block(struct inode *inode, u64 v_block,
|
||||
int rc = 0;
|
||||
struct buffer_head *tmp = *bh;
|
||||
|
||||
if (i_size_read(inode) >> inode->i_sb->s_blocksize_bits <= v_block) {
|
||||
ocfs2_error(inode->i_sb,
|
||||
"Quota file %llu is probably corrupted! Requested "
|
||||
"to read block %Lu but file has size only %Lu\n",
|
||||
(unsigned long long)OCFS2_I(inode)->ip_blkno,
|
||||
(unsigned long long)v_block,
|
||||
(unsigned long long)i_size_read(inode));
|
||||
return -EIO;
|
||||
}
|
||||
rc = ocfs2_read_virt_blocks(inode, v_block, 1, &tmp, 0,
|
||||
ocfs2_validate_quota_block);
|
||||
if (rc)
|
||||
|
@@ -1218,13 +1218,17 @@ static void ocfs2_kill_sb(struct super_block *sb)
|
||||
{
|
||||
struct ocfs2_super *osb = OCFS2_SB(sb);
|
||||
|
||||
/* Failed mount? */
|
||||
if (!osb || atomic_read(&osb->vol_state) == VOLUME_DISABLED)
|
||||
goto out;
|
||||
|
||||
/* Prevent further queueing of inode drop events */
|
||||
spin_lock(&dentry_list_lock);
|
||||
ocfs2_set_osb_flag(osb, OCFS2_OSB_DROP_DENTRY_LOCK_IMMED);
|
||||
spin_unlock(&dentry_list_lock);
|
||||
/* Wait for work to finish and/or remove it */
|
||||
cancel_work_sync(&osb->dentry_lock_work);
|
||||
|
||||
out:
|
||||
kill_block_super(sb);
|
||||
}
|
||||
|
||||
|
@@ -1003,12 +1003,7 @@ static ssize_t oom_adjust_read(struct file *file, char __user *buf,
|
||||
|
||||
if (!task)
|
||||
return -ESRCH;
|
||||
task_lock(task);
|
||||
if (task->mm)
|
||||
oom_adjust = task->mm->oom_adj;
|
||||
else
|
||||
oom_adjust = OOM_DISABLE;
|
||||
task_unlock(task);
|
||||
oom_adjust = task->oomkilladj;
|
||||
put_task_struct(task);
|
||||
|
||||
len = snprintf(buffer, sizeof(buffer), "%i\n", oom_adjust);
|
||||
@@ -1037,19 +1032,11 @@ static ssize_t oom_adjust_write(struct file *file, const char __user *buf,
|
||||
task = get_proc_task(file->f_path.dentry->d_inode);
|
||||
if (!task)
|
||||
return -ESRCH;
|
||||
task_lock(task);
|
||||
if (!task->mm) {
|
||||
task_unlock(task);
|
||||
put_task_struct(task);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (oom_adjust < task->mm->oom_adj && !capable(CAP_SYS_RESOURCE)) {
|
||||
task_unlock(task);
|
||||
if (oom_adjust < task->oomkilladj && !capable(CAP_SYS_RESOURCE)) {
|
||||
put_task_struct(task);
|
||||
return -EACCES;
|
||||
}
|
||||
task->mm->oom_adj = oom_adjust;
|
||||
task_unlock(task);
|
||||
task->oomkilladj = oom_adjust;
|
||||
put_task_struct(task);
|
||||
if (end - buffer == 0)
|
||||
return -EIO;
|
||||
|
Reference in New Issue
Block a user