Skip to content

Commit

Permalink
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/viro/vfs

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  autofs4: deal with autofs4_write/autofs4_write races
  autofs4: catatonic_mode vs. notify_daemon race
  autofs4: autofs4_wait() vs. autofs4_catatonic_mode() race
  hfsplus: creation of hidden dir on mount can fail
  block_dev: Suppress bdev_cache_init() kmemleak warninig
  fix shrink_dcache_parent() livelock
  coda: switch coda_cnode_make() to sane API as well, clean coda_lookup()
  coda: deal correctly with allocation failure from coda_cnode_makectl()
  securityfs: fix object creation races
  • Loading branch information
Linus Torvalds committed Jan 11, 2012
2 parents e343a89 + d668dc5 commit 5cd9599
Show file tree
Hide file tree
Showing 12 changed files with 137 additions and 214 deletions.
1 change: 1 addition & 0 deletions fs/autofs4/autofs_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ struct autofs_sb_info {
int needs_reghost;
struct super_block *sb;
struct mutex wq_mutex;
struct mutex pipe_mutex;
spinlock_t fs_lock;
struct autofs_wait_queue *queues; /* Wait queue pointer */
spinlock_t lookup_lock;
Expand Down
1 change: 1 addition & 0 deletions fs/autofs4/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent)
sbi->min_proto = 0;
sbi->max_proto = 0;
mutex_init(&sbi->wq_mutex);
mutex_init(&sbi->pipe_mutex);
spin_lock_init(&sbi->fs_lock);
sbi->queues = NULL;
spin_lock_init(&sbi->lookup_lock);
Expand Down
40 changes: 25 additions & 15 deletions fs/autofs4/waitq.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,26 +56,27 @@ void autofs4_catatonic_mode(struct autofs_sb_info *sbi)
mutex_unlock(&sbi->wq_mutex);
}

static int autofs4_write(struct file *file, const void *addr, int bytes)
static int autofs4_write(struct autofs_sb_info *sbi,
struct file *file, const void *addr, int bytes)
{
unsigned long sigpipe, flags;
mm_segment_t fs;
const char *data = (const char *)addr;
ssize_t wr = 0;

/** WARNING: this is not safe for writing more than PIPE_BUF bytes! **/

sigpipe = sigismember(&current->pending.signal, SIGPIPE);

/* Save pointer to user space and point back to kernel space */
fs = get_fs();
set_fs(KERNEL_DS);

mutex_lock(&sbi->pipe_mutex);
while (bytes &&
(wr = file->f_op->write(file,data,bytes,&file->f_pos)) > 0) {
data += wr;
bytes -= wr;
}
mutex_lock(&sbi->pipe_mutex);

set_fs(fs);

Expand Down Expand Up @@ -110,6 +111,13 @@ static void autofs4_notify_daemon(struct autofs_sb_info *sbi,

pkt.hdr.proto_version = sbi->version;
pkt.hdr.type = type;
mutex_lock(&sbi->wq_mutex);

/* Check if we have become catatonic */
if (sbi->catatonic) {
mutex_unlock(&sbi->wq_mutex);
return;
}
switch (type) {
/* Kernel protocol v4 missing and expire packets */
case autofs_ptype_missing:
Expand Down Expand Up @@ -163,22 +171,18 @@ static void autofs4_notify_daemon(struct autofs_sb_info *sbi,
}
default:
printk("autofs4_notify_daemon: bad type %d!\n", type);
mutex_unlock(&sbi->wq_mutex);
return;
}

/* Check if we have become catatonic */
mutex_lock(&sbi->wq_mutex);
if (!sbi->catatonic) {
pipe = sbi->pipe;
get_file(pipe);
}
pipe = sbi->pipe;
get_file(pipe);

mutex_unlock(&sbi->wq_mutex);

if (pipe) {
if (autofs4_write(pipe, &pkt, pktsz))
autofs4_catatonic_mode(sbi);
fput(pipe);
}
if (autofs4_write(sbi, pipe, &pkt, pktsz))
autofs4_catatonic_mode(sbi);
fput(pipe);
}

static int autofs4_getpath(struct autofs_sb_info *sbi,
Expand Down Expand Up @@ -257,6 +261,9 @@ static int validate_request(struct autofs_wait_queue **wait,
struct autofs_wait_queue *wq;
struct autofs_info *ino;

if (sbi->catatonic)
return -ENOENT;

/* Wait in progress, continue; */
wq = autofs4_find_wait(sbi, qstr);
if (wq) {
Expand Down Expand Up @@ -289,6 +296,9 @@ static int validate_request(struct autofs_wait_queue **wait,
if (mutex_lock_interruptible(&sbi->wq_mutex))
return -EINTR;

if (sbi->catatonic)
return -ENOENT;

wq = autofs4_find_wait(sbi, qstr);
if (wq) {
*wait = wq;
Expand Down Expand Up @@ -389,7 +399,7 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry,

ret = validate_request(&wq, sbi, &qstr, dentry, notify);
if (ret <= 0) {
if (ret == 0)
if (ret != -EINTR)
mutex_unlock(&sbi->wq_mutex);
kfree(qstr.name);
return ret;
Expand Down
10 changes: 2 additions & 8 deletions fs/block_dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
#include <linux/uio.h>
#include <linux/namei.h>
#include <linux/log2.h>
#include <linux/kmemleak.h>
#include <linux/cleancache.h>
#include <asm/uaccess.h>
#include "internal.h"
Expand Down Expand Up @@ -521,7 +520,7 @@ static struct super_block *blockdev_superblock __read_mostly;
void __init bdev_cache_init(void)
{
int err;
struct vfsmount *bd_mnt;
static struct vfsmount *bd_mnt;

bdev_cachep = kmem_cache_create("bdev_cache", sizeof(struct bdev_inode),
0, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|
Expand All @@ -533,12 +532,7 @@ void __init bdev_cache_init(void)
bd_mnt = kern_mount(&bd_type);
if (IS_ERR(bd_mnt))
panic("Cannot create bdev pseudo-fs");
/*
* This vfsmount structure is only used to obtain the
* blockdev_superblock, so tell kmemleak not to report it.
*/
kmemleak_not_leak(bd_mnt);
blockdev_superblock = bd_mnt->mnt_sb; /* For writeback */
blockdev_superblock = bd_mnt->mnt_sb; /* For writeback */
}

/*
Expand Down
38 changes: 16 additions & 22 deletions fs/coda/cnode.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,24 +88,21 @@ struct inode * coda_iget(struct super_block * sb, struct CodaFid * fid,
- link the two up if this is needed
- fill in the attributes
*/
int coda_cnode_make(struct inode **inode, struct CodaFid *fid, struct super_block *sb)
struct inode *coda_cnode_make(struct CodaFid *fid, struct super_block *sb)
{
struct coda_vattr attr;
struct inode *inode;
int error;

/* We get inode numbers from Venus -- see venus source */
error = venus_getattr(sb, fid, &attr);
if ( error ) {
*inode = NULL;
return error;
}
if (error)
return ERR_PTR(error);

*inode = coda_iget(sb, fid, &attr);
if ( IS_ERR(*inode) ) {
inode = coda_iget(sb, fid, &attr);
if (IS_ERR(inode))
printk("coda_cnode_make: coda_iget failed\n");
return PTR_ERR(*inode);
}
return 0;
return inode;
}


Expand Down Expand Up @@ -156,19 +153,16 @@ struct inode *coda_fid_to_inode(struct CodaFid *fid, struct super_block *sb)
}

/* the CONTROL inode is made without asking attributes from Venus */
int coda_cnode_makectl(struct inode **inode, struct super_block *sb)
struct inode *coda_cnode_makectl(struct super_block *sb)
{
int error = -ENOMEM;

*inode = new_inode(sb);
if (*inode) {
(*inode)->i_ino = CTL_INO;
(*inode)->i_op = &coda_ioctl_inode_operations;
(*inode)->i_fop = &coda_ioctl_operations;
(*inode)->i_mode = 0444;
error = 0;
struct inode *inode = new_inode(sb);
if (inode) {
inode->i_ino = CTL_INO;
inode->i_op = &coda_ioctl_inode_operations;
inode->i_fop = &coda_ioctl_operations;
inode->i_mode = 0444;
return inode;
}

return error;
return ERR_PTR(-ENOMEM);
}

4 changes: 2 additions & 2 deletions fs/coda/coda_fs_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ struct coda_file_info {
#define C_DYING 0x4 /* from venus (which died) */
#define C_PURGE 0x8

int coda_cnode_make(struct inode **, struct CodaFid *, struct super_block *);
struct inode *coda_cnode_make(struct CodaFid *, struct super_block *);
struct inode *coda_iget(struct super_block *sb, struct CodaFid *fid, struct coda_vattr *attr);
int coda_cnode_makectl(struct inode **inode, struct super_block *sb);
struct inode *coda_cnode_makectl(struct super_block *sb);
struct inode *coda_fid_to_inode(struct CodaFid *fid, struct super_block *sb);
void coda_replace_fid(struct inode *, struct CodaFid *, struct CodaFid *);

Expand Down
29 changes: 13 additions & 16 deletions fs/coda/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,11 @@ const struct file_operations coda_dir_operations = {
/* access routines: lookup, readlink, permission */
static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry, struct nameidata *nd)
{
struct inode *inode = NULL;
struct CodaFid resfid = { { 0, } };
int type = 0;
int error = 0;
struct super_block *sb = dir->i_sb;
const char *name = entry->d_name.name;
size_t length = entry->d_name.len;
struct inode *inode;
int type = 0;

if (length > CODA_MAXNAMLEN) {
printk(KERN_ERR "name too long: lookup, %s (%*s)\n",
Expand All @@ -111,23 +110,21 @@ static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry, struc

/* control object, create inode on the fly */
if (coda_isroot(dir) && coda_iscontrol(name, length)) {
error = coda_cnode_makectl(&inode, dir->i_sb);
inode = coda_cnode_makectl(sb);
type = CODA_NOCACHE;
goto exit;
} else {
struct CodaFid fid = { { 0, } };
int error = venus_lookup(sb, coda_i2f(dir), name, length,
&type, &fid);
inode = !error ? coda_cnode_make(&fid, sb) : ERR_PTR(error);
}

error = venus_lookup(dir->i_sb, coda_i2f(dir), name, length,
&type, &resfid);
if (!error)
error = coda_cnode_make(&inode, &resfid, dir->i_sb);

if (error && error != -ENOENT)
return ERR_PTR(error);

exit:
if (inode && (type & CODA_NOCACHE))
if (!IS_ERR(inode) && (type & CODA_NOCACHE))
coda_flag_inode(inode, C_VATTR | C_PURGE);

if (inode == ERR_PTR(-ENOENT))
inode = NULL;

return d_splice_alias(inode, entry);
}

Expand Down
10 changes: 6 additions & 4 deletions fs/coda/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -204,10 +204,12 @@ static int coda_fill_super(struct super_block *sb, void *data, int silent)
printk("coda_read_super: rootfid is %s\n", coda_f2s(&fid));

/* make root inode */
error = coda_cnode_make(&root, &fid, sb);
if ( error || !root ) {
printk("Failure of coda_cnode_make for root: error %d\n", error);
goto error;
root = coda_cnode_make(&fid, sb);
if (IS_ERR(root)) {
error = PTR_ERR(root);
printk("Failure of coda_cnode_make for root: error %d\n", error);
root = NULL;
goto error;
}

printk("coda_read_super: rootinode is %ld dev %s\n",
Expand Down
15 changes: 11 additions & 4 deletions fs/dcache.c
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ static void dentry_lru_add(struct dentry *dentry)
static void __dentry_lru_del(struct dentry *dentry)
{
list_del_init(&dentry->d_lru);
dentry->d_flags &= ~DCACHE_SHRINK_LIST;
dentry->d_sb->s_nr_dentry_unused--;
dentry_stat.nr_unused--;
}
Expand Down Expand Up @@ -806,6 +807,7 @@ void prune_dcache_sb(struct super_block *sb, int count)
spin_unlock(&dentry->d_lock);
} else {
list_move_tail(&dentry->d_lru, &tmp);
dentry->d_flags |= DCACHE_SHRINK_LIST;
spin_unlock(&dentry->d_lock);
if (!--count)
break;
Expand Down Expand Up @@ -1097,14 +1099,19 @@ static int select_parent(struct dentry *parent, struct list_head *dispose)

/*
* move only zero ref count dentries to the dispose list.
*
* Those which are presently on the shrink list, being processed
* by shrink_dentry_list(), shouldn't be moved. Otherwise the
* loop in shrink_dcache_parent() might not make any progress
* and loop forever.
*/
if (!dentry->d_count) {
if (dentry->d_count) {
dentry_lru_del(dentry);
} else if (!(dentry->d_flags & DCACHE_SHRINK_LIST)) {
dentry_lru_move_list(dentry, dispose);
dentry->d_flags |= DCACHE_SHRINK_LIST;
found++;
} else {
dentry_lru_del(dentry);
}

/*
* We can return to the caller if we have found some (this
* ensures forward progress). We'll be coming back to find
Expand Down
11 changes: 9 additions & 2 deletions fs/hfsplus/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -499,9 +499,16 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
if (!sbi->hidden_dir) {
mutex_lock(&sbi->vh_mutex);
sbi->hidden_dir = hfsplus_new_inode(sb, S_IFDIR);
hfsplus_create_cat(sbi->hidden_dir->i_ino, root, &str,
sbi->hidden_dir);
if (!sbi->hidden_dir) {
mutex_unlock(&sbi->vh_mutex);
err = -ENOMEM;
goto out_put_root;
}
err = hfsplus_create_cat(sbi->hidden_dir->i_ino, root,
&str, sbi->hidden_dir);
mutex_unlock(&sbi->vh_mutex);
if (err)
goto out_put_hidden_dir;

hfsplus_mark_inode_dirty(sbi->hidden_dir,
HFSPLUS_I_CAT_DIRTY);
Expand Down
1 change: 1 addition & 0 deletions include/linux/dcache.h
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ struct dentry_operations {

#define DCACHE_CANT_MOUNT 0x0100
#define DCACHE_GENOCIDE 0x0200
#define DCACHE_SHRINK_LIST 0x0400

#define DCACHE_NFSFS_RENAMED 0x1000
/* this dentry has been "silly renamed" and has to be deleted on the last
Expand Down
Loading

0 comments on commit 5cd9599

Please sign in to comment.